diff --git a/source/RobotAPI/components/ArViz/CMakeLists.txt b/source/RobotAPI/components/ArViz/CMakeLists.txt index 28c1a21d9e549011313e6e0d36368cd5c7edee23..9638058676450ed6fcb7d8ff884cf7ebf8beb67e 100644 --- a/source/RobotAPI/components/ArViz/CMakeLists.txt +++ b/source/RobotAPI/components/ArViz/CMakeLists.txt @@ -142,7 +142,7 @@ set(HEADERS ArVizStorage.h ) -armarx_add_component_executable("${SOURCES}" "${HEADERS}") +armarx_add_component_executable("${SOURCES};${HEADERS}" "${HEADERS}") add_subdirectory(Example) diff --git a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp index e7fdc5eaa92b960a964d78deecce66dfd242227f..7fea318b5249b557e92cb1e207f3f04e0de70321 100644 --- a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp +++ b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp @@ -205,6 +205,8 @@ namespace armarx return armem::MemoryID(result.segmentID); } + // COMMIT + armem::MemoryID ExampleMemoryClient::commitSingleSnapshot(const armem::MemoryID& entityID) { @@ -272,10 +274,12 @@ namespace armarx } } + // QUERY + void ExampleMemoryClient::queryLatestSnapshot(const armem::MemoryID& entityID) { - ARMARX_IMPORTANT << "Querying latest snapshot: " + ARMARX_IMPORTANT << "Querying latest snapshot in entity: " << "\n- entityID: \t'" << entityID << "'"; armem::client::query::Builder builder; @@ -295,6 +299,8 @@ namespace armarx ARMARX_IMPORTANT << "Getting entity via ID"; armem::wm::Memory& memory = qResult.memory; + ARMARX_CHECK(memory.hasInstances()); + ARMARX_CHECK_GREATER_EQUAL(memory.size(), 1); const armem::wm::Entity* entity = memory.findEntity(entityID); @@ -335,13 +341,23 @@ namespace armarx if (qResult.success) { armem::wm::Memory memory = std::move(qResult.memory); - const armem::wm::EntitySnapshot& entitySnapshot = - memory.getEntity(snapshotID).getLatestSnapshot(); + { + const armem::wm::EntitySnapshot& entitySnapshot = memory.getLatestSnapshot(); - ARMARX_INFO << "Result snapshot: " - << "\n- time: \t" << entitySnapshot.time() << "\n- # instances: \t" - << entitySnapshot.size(); + ARMARX_INFO << "Result snapshot: " + << "\n- time: \t" << entitySnapshot.time() + << "\n- # instances: \t" << entitySnapshot.size(); + } + { + const armem::wm::EntitySnapshot& entitySnapshot = + memory.getEntity(snapshotID).getLatestSnapshot(); + + ARMARX_INFO << "Result snapshot: " + << "\n- time: \t" << entitySnapshot.time() + << "\n- # instances: \t" << entitySnapshot.size(); + } } + else { ARMARX_ERROR << qResult.errorMessage; diff --git a/source/RobotAPI/libraries/armem/client/Query.h b/source/RobotAPI/libraries/armem/client/Query.h index bee999f073bc57cd53db0b9031cba9feee1cfbb7..8e14c5b5a7aa22ea260779c95bb63a24891cc29b 100644 --- a/source/RobotAPI/libraries/armem/client/Query.h +++ b/source/RobotAPI/libraries/armem/client/Query.h @@ -1,44 +1,60 @@ #pragma once -// RobotAPI #include <RobotAPI/interface/armem/query.h> - -#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> #include <RobotAPI/libraries/armem/core/SuccessHeader.h> #include <RobotAPI/libraries/armem/core/query/DataMode.h> #include <RobotAPI/libraries/armem/core/query/QueryTarget.h> +#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h> #include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> - namespace armarx::armem::client::query { // #include <RobotAPI/libraries/armem/client/query/Builder.h> class Builder; -} +} // namespace armarx::armem::client::query namespace armarx::armem::client { using QueryBuilder = query::Builder; - /** - * @brief An update of an entity for a specific point in time. + * @brief A query for parts of a memory. */ struct QueryInput { + /** + * @brief The queries. + */ armem::query::data::MemoryQuerySeq memoryQueries; + /** + * @brief Whether entity instance data (i.e., their payload) should be transferred. + */ armem::query::DataMode dataMode; static QueryInput fromIce(const armem::query::data::Input& ice); armem::query::data::Input toIce() const; }; - /** - * @brief Result of an `EntityUpdate`. + * @brief Result of a `QueryInput`. + * + * If `success` is false, an error occurred during the query. In this case, `errorMessage` can + * contain more information. + * + * @note An empty result is valid, i.e. successful. In other words, an empty result is not a + * failure. To check whether any entity snapshot matched the query, use `memory.hasSnapshots()` + * or `memory.hasInstances()`. + * + * @see wm::Memory::hasInstances(), wm::Memory::hasSnapshots() */ struct QueryResult : public detail::SuccessHeader { + /** + * @brief The slice of the memory that matched the query. + * + * To check whether the memory contains any snapshots or instances, use + * `memory.hasSnapshots()` or `memory.hasInstances()`. + */ wm::Memory memory; @@ -48,11 +64,10 @@ namespace armarx::armem::client friend std::ostream& operator<<(std::ostream& os, const QueryResult& rhs); }; - void toIce(armem::query::data::Input& ice, const QueryInput& input); void fromIce(const armem::query::data::Input& ice, QueryInput& input); void toIce(armem::query::data::Result& ice, const QueryResult& result); void fromIce(const armem::query::data::Result& ice, QueryResult& result); -} +} // namespace armarx::armem::client diff --git a/source/RobotAPI/libraries/armem/core/base/EntityBase.h b/source/RobotAPI/libraries/armem/core/base/EntityBase.h index 7b6972a93bf7dcad9d804a03136869472b364082..1dbfeaebfa8eae9cfcf1cb54fc6017d6963b3ecf 100644 --- a/source/RobotAPI/libraries/armem/core/base/EntityBase.h +++ b/source/RobotAPI/libraries/armem/core/base/EntityBase.h @@ -17,7 +17,6 @@ #include "detail/lookup_mixins.h" #include "detail/negative_index_semantics.h" - namespace armarx::armem::base { @@ -25,7 +24,7 @@ namespace armarx::armem::base * @brief An entity over a period of time. * * An entity should be a physical thing or abstract concept existing - * (and potentially evolving) over some time. + * (and potentially evolving) over time. * * Examples are: * - objects (the green box) @@ -42,16 +41,17 @@ namespace armarx::armem::base */ template <class _EntitySnapshotT, class _Derived> class EntityBase : - public detail::MemoryContainerBase<std::map<Time, _EntitySnapshotT>, _Derived> - , public detail::ForEachEntityInstanceMixin<_Derived> - , public detail::GetFindInstanceMixin<_Derived> + public detail::MemoryContainerBase<std::map<Time, _EntitySnapshotT>, _Derived>, + public detail::ForEachEntityInstanceMixin<_Derived>, + public detail::GetFindInstanceMixin<_Derived>, + public detail::GetLatestInstanceMixin<_Derived>, + public detail::GetLatestSnapshotMixin<_Derived> { using Base = detail::MemoryContainerBase<std::map<Time, _EntitySnapshotT>, _Derived>; public: - - using typename Base::DerivedT; using typename Base::ContainerT; + using typename Base::DerivedT; using EntitySnapshotT = _EntitySnapshotT; using EntityInstanceT = typename EntitySnapshotT::EntityInstanceT; @@ -68,58 +68,69 @@ namespace armarx::armem::base }; public: - EntityBase() { } + explicit EntityBase(const std::string& name, const MemoryID& parentID = {}) : EntityBase(parentID.withEntityName(name)) { } - explicit EntityBase(const MemoryID& id) : - Base(id) + + explicit EntityBase(const MemoryID& id) : Base(id) { } - EntityBase(const EntityBase& other) = default; EntityBase(EntityBase&& other) = default; EntityBase& operator=(const EntityBase& other) = default; EntityBase& operator=(EntityBase&& other) = default; - // READING // Get key - inline std::string& name() + inline std::string& + name() { return this->id().entityName; } - inline const std::string& name() const + + inline const std::string& + name() const { return this->id().entityName; } + /// Indicate whether the entity has any snapshots. + bool + hasSnapshots() const + { + return not this->empty(); + } - // Has child by key - /// Indicates whether a history entry for the given time exists. - bool hasSnapshot(const Time& time) const + // Has child with key + /// Indicate whether a snapshot at the given time exists. + bool + hasSnapshot(const Time& time) const { return this->findSnapshot(time) != nullptr; } - // Has child by MemoryID - bool hasSnapshot(const MemoryID& snapshotID) const + + // Has child with MemoryID + /// Indicate whether a snapshot with the given ID exists. + bool + hasSnapshot(const MemoryID& snapshotID) const { return this->findSnapshot(snapshotID) != nullptr; } - // Find child via key EntitySnapshotT* findSnapshot(const Time& timestamp) { return detail::findChildByKey(timestamp, this->_container); } + const EntitySnapshotT* findSnapshot(const Time& timestamp) const { @@ -137,18 +148,21 @@ namespace armarx::armem::base EntitySnapshotT& getSnapshot(const Time& time) { - return detail::getChildByKey(time, this->_container, *this, [](const Time & time) - { - return toDateTimeMilliSeconds(time); - }); + return detail::getChildByKey(time, + this->_container, + *this, + [](const Time& time) + { return toDateTimeMilliSeconds(time); }); } + const EntitySnapshotT& getSnapshot(const Time& time) const { - return detail::getChildByKey(time, this->_container, *this, [](const Time & time) - { - return toDateTimeMilliSeconds(time); - }); + return detail::getChildByKey(time, + this->_container, + *this, + [](const Time& time) + { return toDateTimeMilliSeconds(time); }); } // Find child via MemoryID @@ -158,6 +172,7 @@ namespace armarx::armem::base detail::checkHasTimestamp(snapshotID); return this->findSnapshot(snapshotID.timestamp); } + const EntitySnapshotT* findSnapshot(const MemoryID& snapshotID) const { @@ -172,12 +187,12 @@ namespace armarx::armem::base detail::checkHasTimestamp(snapshotID); return this->getSnapshot(snapshotID.timestamp); } + const EntitySnapshotT& getSnapshot(const MemoryID& snapshotID) const { detail::checkHasTimestamp(snapshotID); return this->getSnapshot(snapshotID.timestamp); - } // get/findInstance are provided by GetFindInstanceMixin @@ -189,15 +204,18 @@ namespace armarx::armem::base * @brief Get the latest timestamp. * @throw `armem::error::EntityHistoryEmpty` If the history is empty. */ - Time getLatestTimestamp() const + Time + getLatestTimestamp() const { return this->getLatestSnapshot().time(); } + /** * @brief Get the oldest timestamp. * @throw `armem::error::EntityHistoryEmpty` If the history is empty. */ - Time getFirstTimestamp() const + Time + getFirstTimestamp() const { return this->getFirstSnapshot().time(); } @@ -206,46 +224,30 @@ namespace armarx::armem::base * @brief Return the snapshot with the most recent timestamp. * @return The latest snapshot or nullptr if the entity is empty. */ - EntitySnapshotT* findLatestSnapshot() - { - return this->empty() ? nullptr : &this->_container.rbegin()->second; - } - const EntitySnapshotT* findLatestSnapshot() const + EntitySnapshotT* + findLatestSnapshot() { return this->empty() ? nullptr : &this->_container.rbegin()->second; } - /** - * @brief Return the snapshot with the most recent timestamp. - * @return The latest snapshot. - * @throw `armem::error::EntityHistoryEmpty` If the history is empty. - */ - EntitySnapshotT& getLatestSnapshot() - { - return const_cast<EntitySnapshotT&>(const_cast<const EntityBase*>(this)->getLatestSnapshot()); - } - const EntitySnapshotT& getLatestSnapshot() const + const EntitySnapshotT* + findLatestSnapshot() const { - if (const EntitySnapshotT* snapshot = this->findLatestSnapshot()) - { - return *snapshot; - } - else - { - throw armem::error::EntityHistoryEmpty(name(), "when getting the latest snapshot."); - } + return this->empty() ? nullptr : &this->_container.rbegin()->second; } - /** * @brief Return the snapshot with the least recent timestamp. * @return The first snapshot or nullptr if the entity is empty. */ - EntitySnapshotT* findFirstSnapshot() + EntitySnapshotT* + findFirstSnapshot() { return this->empty() ? nullptr : &this->_container.begin()->second; } - const EntitySnapshotT* findFirstSnapshot() const + + const EntitySnapshotT* + findFirstSnapshot() const { return this->empty() ? nullptr : &this->_container.begin()->second; } @@ -255,11 +257,15 @@ namespace armarx::armem::base * @return The first snapshot. * @throw `armem::error::EntityHistoryEmpty` If the history is empty. */ - EntitySnapshotT& getFirstSnapshot() + EntitySnapshotT& + getFirstSnapshot() { - return const_cast<EntitySnapshotT&>(const_cast<const EntityBase*>(this)->getFirstSnapshot()); + return const_cast<EntitySnapshotT&>( + const_cast<const EntityBase*>(this)->getFirstSnapshot()); } - const EntitySnapshotT& getFirstSnapshot() const + + const EntitySnapshotT& + getFirstSnapshot() const { if (const EntitySnapshotT* snapshot = this->findFirstSnapshot()) { @@ -271,13 +277,13 @@ namespace armarx::armem::base } } - /** * @brief Return the lastest snapshot before time. * @param time The time. * @return The latest snapshot < time or nullptr if none was found. */ - const EntitySnapshotT* findLatestSnapshotBefore(const Time& time) const + const EntitySnapshotT* + findLatestSnapshotBefore(const Time& time) const { if (this->empty()) { @@ -309,7 +315,8 @@ namespace armarx::armem::base * @param time The time. * @return The latest snapshot <= time or nullptr if none was found. */ - const EntitySnapshotT* findLatestSnapshotBeforeOrAt(const Time& time) const + const EntitySnapshotT* + findLatestSnapshotBeforeOrAt(const Time& time) const { return findLatestSnapshotBefore(time + Duration::MicroSeconds(1)); } @@ -319,7 +326,8 @@ namespace armarx::armem::base * @param time The time. * @return The first snapshot >= time or nullptr if none was found. */ - const EntitySnapshotT* findFirstSnapshotAfterOrAt(const Time& time) const + const EntitySnapshotT* + findFirstSnapshotAfterOrAt(const Time& time) const { // We want the leftmost element >= time. // That's lower bound. @@ -337,24 +345,28 @@ namespace armarx::armem::base * @param time The time. * @return The first snapshot >= time or nullptr if none was found. */ - const EntitySnapshotT* findFirstSnapshotAfter(const Time& time) const + const EntitySnapshotT* + findFirstSnapshotAfter(const Time& time) const { return findFirstSnapshotAfter(time - Duration::MicroSeconds(1)); } - - auto* findLatestInstance(int instanceIndex = 0) + auto* + findLatestInstance(int instanceIndex = 0) { auto* snapshot = this->findLatestSnapshot(); return snapshot ? snapshot->findInstance(instanceIndex) : nullptr; } - const auto* findLatestInstance(int instanceIndex = 0) const + + const auto* + findLatestInstance(int instanceIndex = 0) const { auto* snapshot = this->findLatestSnapshot(); return snapshot ? snapshot->findInstance(instanceIndex) : nullptr; } -#if 0 // Do not offer this yet. + +#if 0 // Do not offer this yet. auto* findLatestInstanceData(int instanceIndex = 0) { auto* instance = this->findLatestInstance(instanceIndex); @@ -374,31 +386,38 @@ namespace armarx::armem::base * @param func Function like: bool process(EntitySnapshotT& snapshot) */ template <class SnapshotFunctionT> - bool forEachSnapshot(SnapshotFunctionT&& func) + bool + forEachSnapshot(SnapshotFunctionT&& func) { return this->forEachChild(func); } + /** * @param func Function like void process(const EntitySnapshotT& snapshot) */ template <class SnapshotFunctionT> - bool forEachSnapshot(SnapshotFunctionT&& func) const + bool + forEachSnapshot(SnapshotFunctionT&& func) const { return this->forEachChild(func); } + /** * @param func Function like: bool process(EntitySnapshotT& snapshot) */ template <class SnapshotFunctionT> - bool forEachSnapshotIn(const MemoryID& id, SnapshotFunctionT&& func) + bool + forEachSnapshotIn(const MemoryID& id, SnapshotFunctionT&& func) { return this->forEachChild(func); } + /** * @param func Function like void process(const EntitySnapshotT& snapshot) */ template <class SnapshotFunctionT> - bool forEachSnapshotIn(const MemoryID& id, SnapshotFunctionT&& func) const + bool + forEachSnapshotIn(const MemoryID& id, SnapshotFunctionT&& func) const { if (id.hasTimestamp()) { @@ -409,6 +428,7 @@ namespace armarx::armem::base } return this->forEachChild(func); } + // forEachInstance() is provided by ForEachEntityInstanceMixin. @@ -418,7 +438,8 @@ namespace armarx::armem::base * @return The latest snapshots. */ template <class FunctionT> - void forEachSnapshotBefore(const Time& time, FunctionT&& func) const + void + forEachSnapshotBefore(const Time& time, FunctionT&& func) const { for (const auto& [timestamp, snapshot] : this->_container) { @@ -439,12 +460,12 @@ namespace armarx::armem::base * @return The latest snapshots. */ template <class FunctionT> - void forEachSnapshotBeforeOrAt(const Time& time, FunctionT&& func) const + void + forEachSnapshotBeforeOrAt(const Time& time, FunctionT&& func) const { getSnapshotsBefore(time + Duration::MicroSeconds(1), func); } - /** * @brief Return all snapshots between, including, min and max. * @param min The lowest time to include. @@ -452,12 +473,15 @@ namespace armarx::armem::base * @return The snapshots in [min, max]. */ template <class FunctionT> - void forEachSnapshotInTimeRange(const Time& min, const Time& max, FunctionT&& func) const + void + forEachSnapshotInTimeRange(const Time& min, const Time& max, FunctionT&& func) const { // Returns an iterator pointing to the first element that is not less than (i.e. greater or equal to) key. - auto begin = min.toMicroSecondsSinceEpoch() > 0 ? this->_container.lower_bound(min) : this->_container.begin(); + auto begin = min.toMicroSecondsSinceEpoch() > 0 ? this->_container.lower_bound(min) + : this->_container.begin(); // Returns an iterator pointing to the first element that is *greater than* key. - auto end = max.toMicroSecondsSinceEpoch() > 0 ? this->_container.upper_bound(max) : this->_container.end(); + auto end = max.toMicroSecondsSinceEpoch() > 0 ? this->_container.upper_bound(max) + : this->_container.end(); for (auto it = begin; it != end && it != this->_container.end(); ++it) { @@ -479,7 +503,8 @@ namespace armarx::armem::base * @return The snapshots in [first, last]. */ template <class FunctionT> - void forEachSnapshotInIndexRange(long first, long last, FunctionT&& func) const + void + forEachSnapshotInIndexRange(long first, long last, FunctionT&& func) const { if (this->empty()) { @@ -494,7 +519,7 @@ namespace armarx::armem::base auto it = this->_container.begin(); std::advance(it, first_); - size_t num = last_ - first_ + 1; // +1 to make last inclusive + size_t num = last_ - first_ + 1; // +1 to make last inclusive for (size_t i = 0; i < num; ++i, ++it) { if (not call(func, it->second)) @@ -505,39 +530,44 @@ namespace armarx::armem::base } } - /** * @param func Function like void process(EntityInstanceT& instance)> */ template <class InstanceFunctionT> - bool forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) + bool + forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) { - return detail::forEachInstanceIn( - id, func, *this, - id.hasTimestamp(), - id.hasTimestamp() ? this->findSnapshot(id.timestamp) : nullptr); + return detail::forEachInstanceIn(id, + func, + *this, + id.hasTimestamp(), + id.hasTimestamp() ? this->findSnapshot(id.timestamp) + : nullptr); } + /** * @param func Function like void process(EntityInstanceT& instance)> */ template <class InstanceFunctionT> - bool forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) const + bool + forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) const { - return detail::forEachInstanceIn( - id, func, *this, - id.hasTimestamp(), - id.hasTimestamp() ? this->findSnapshot(id.timestamp) : nullptr); + return detail::forEachInstanceIn(id, + func, + *this, + id.hasTimestamp(), + id.hasTimestamp() ? this->findSnapshot(id.timestamp) + : nullptr); } - // Get child keys /// @brief Get all timestamps in the history. - std::vector<Time> getTimestamps() const + std::vector<Time> + getTimestamps() const { return simox::alg::get_keys(this->_container); } - // MODIFICATION /** @@ -545,7 +575,8 @@ namespace armarx::armem::base * @param update The update. * @return The snapshot ID of the update. */ - UpdateResult update(const EntityUpdate& update) + UpdateResult + update(const EntityUpdate& update) { this->_checkContainerName(update.entityID.entityName, this->name()); UpdateResult ret; @@ -572,59 +603,63 @@ namespace armarx::armem::base return ret; } - template <class OtherDerivedT> - void append(const OtherDerivedT& other) + void + append(const OtherDerivedT& other) { - other.forEachSnapshot([this](const auto& snapshot) - { - auto it = this->_container.find(snapshot.time()); - if (it == this->_container.end()) + other.forEachSnapshot( + [this](const auto& snapshot) { - EntitySnapshotT copy { snapshot }; - copy.id() = this->id().withTimestamp(snapshot.time()); // update id (e.g. memory name) if necessary - this->_container.emplace(snapshot.time(), copy); - } - // else: snapshot already exists - // We assume that a snapshot does not change, so ignore - return true; - }); + auto it = this->_container.find(snapshot.time()); + if (it == this->_container.end()) + { + EntitySnapshotT copy{snapshot}; + copy.id() = this->id().withTimestamp( + snapshot.time()); // update id (e.g. memory name) if necessary + this->_container.emplace(snapshot.time(), copy); + } + // else: snapshot already exists + // We assume that a snapshot does not change, so ignore + return true; + }); } - /// Add a snapshot at the given time. - EntitySnapshotT& addSnapshot(const Time& timestamp) + EntitySnapshotT& + addSnapshot(const Time& timestamp) { return this->addSnapshot(timestamp, EntitySnapshotT(timestamp)); } /// Copy and insert a snapshot - EntitySnapshotT& addSnapshot(const EntitySnapshotT& snapshot) + EntitySnapshotT& + addSnapshot(const EntitySnapshotT& snapshot) { return this->addSnapshot(snapshot.time(), EntitySnapshotT(snapshot)); } /// Move and insert a snapshot - EntitySnapshotT& addSnapshot(EntitySnapshotT&& snapshot) + EntitySnapshotT& + addSnapshot(EntitySnapshotT&& snapshot) { - Time timestamp = snapshot.time(); // Copy before move. + Time timestamp = snapshot.time(); // Copy before move. return this->addSnapshot(timestamp, std::move(snapshot)); } /// Insert a snapshot in-place. - template <class ...Args> - EntitySnapshotT& addSnapshot(const Time& timestamp, Args... args) + template <class... Args> + EntitySnapshotT& + addSnapshot(const Time& timestamp, Args... args) { auto it = this->_container.emplace_hint(this->_container.end(), timestamp, args...); it->second.id() = this->id().withTimestamp(timestamp); return it->second; } - - // MISC - bool equalsDeep(const DerivedT& other) const + bool + equalsDeep(const DerivedT& other) const { //std::cout << "Entity::equalsDeep" << std::endl; if (this->size() != other.size()) @@ -645,15 +680,17 @@ namespace armarx::armem::base return true; } - std::string getKeyString() const + std::string + getKeyString() const { return this->id().entityName; } - static std::string getLevelName() + + static std::string + getLevelName() { return "entity"; } - }; -} +} // namespace armarx::armem::base diff --git a/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h b/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h index 0bd03af1448d99536640c0b9f4a2f83036afc307..892c5db2ada839176eb42ff682e948d1d57b53a0 100644 --- a/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h +++ b/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h @@ -5,7 +5,6 @@ #include "detail/MemoryItem.h" - namespace armarx::armem::base { @@ -16,17 +15,19 @@ namespace armarx::armem::base { virtual ~NoData() = default; - bool operator==(const NoData& other) + bool + operator==(const NoData& other) { return true; } - bool operator!=(const NoData& other) + + bool + operator!=(const NoData& other) { return false; } }; - /** * @brief Metadata of an entity instance. */ @@ -62,7 +63,9 @@ namespace armarx::armem::base void access() const; bool operator==(const EntityInstanceMetadata& other) const; - inline bool operator!=(const EntityInstanceMetadata& other) const + + inline bool + operator!=(const EntityInstanceMetadata& other) const { return !(*this == other); } @@ -70,109 +73,123 @@ namespace armarx::armem::base std::ostream& operator<<(std::ostream& os, const EntityInstanceMetadata& rhs); - - /** * @brief Data of a single entity instance. */ template <class _DataT = NoData, class _MetadataT = EntityInstanceMetadata> - class EntityInstanceBase : - public detail::MemoryItem + class EntityInstanceBase : public detail::MemoryItem { using Base = detail::MemoryItem; public: - using MetadataT = _MetadataT; using DataT = _DataT; - EntityInstanceBase() { } + explicit EntityInstanceBase(int index, const MemoryID& parentID = {}) : EntityInstanceBase(parentID.withInstanceIndex(index)) { } - explicit EntityInstanceBase(const MemoryID& id) : - Base(id) + + explicit EntityInstanceBase(const MemoryID& id) : Base(id) { } - // Key - inline int& index() + inline int& + index() { return id().instanceIndex; } - inline int index() const + + inline int + index() const { return id().instanceIndex; } - // Data - MetadataT& metadata() + MetadataT& + metadata() { return _metadata; } - const MetadataT& metadata() const + + const MetadataT& + metadata() const { return _metadata; } - const DataT& data() const + const DataT& + data() const { return _data; } - DataT& data() + DataT& + data() { return _data; } - void setData(DataT& d) + void + setData(const DataT& data) { - _data = d; + _data = data; } - void setMetadata(MetadataT& m) + void + setMetadata(const MetadataT& metadata) { - _metadata = m; + _metadata = metadata; } /** * @brief Get the data converted to a generated Aron DTO class. */ template <class AronDtoT> - AronDtoT dataAs() const + AronDtoT + dataAs() const { return AronDtoT::FromAron(_data); } + template <class AronDtoT> + EntityInstanceBase<AronDtoT, MetadataT> + withDataAs() const + { + EntityInstanceBase<AronDtoT, MetadataT> instance{_id}; + instance.data() = dataAs<AronDtoT>(); + instance.metadata() = _metadata; + return instance; + } // Misc - static std::string getLevelName() + static std::string + getLevelName() { return "entity instance"; } - std::string getKeyString() const + std::string + getKeyString() const { return std::to_string(index()); } protected: - /// The metadata. MetadataT _metadata; /// The data. May be nullptr. DataT _data; - }; -} +} // namespace armarx::armem::base diff --git a/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h b/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h index b7048a6328990d6be2152c0559466cf1ff142b9e..2fb8bd3cc6ffcb217f7882e66fa2ed1e1b52d429 100644 --- a/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h +++ b/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h @@ -10,11 +10,11 @@ #include "detail/iteration_mixins.h" #include "detail/lookup_mixins.h" - namespace armarx::armem::base::detail { void throwIfNotEqual(const Time& ownTime, const Time& updateTime); } + namespace armarx::armem::base { /** @@ -27,24 +27,23 @@ namespace armarx::armem::base using Base = detail::MemoryContainerBase<std::vector<_EntityInstanceT>, _Derived>; public: - - using typename Base::DerivedT; using typename Base::ContainerT; + using typename Base::DerivedT; using EntityInstanceT = _EntityInstanceT; public: - EntitySnapshotBase() { } + explicit EntitySnapshotBase(Time time, const MemoryID& parentID = {}) : EntitySnapshotBase(parentID.withTimestamp(time)) { } - explicit EntitySnapshotBase(const MemoryID& id) : - Base(id) + + explicit EntitySnapshotBase(const MemoryID& id) : Base(id) { } @@ -53,43 +52,55 @@ namespace armarx::armem::base EntitySnapshotBase& operator=(const EntitySnapshotBase& other) = default; EntitySnapshotBase& operator=(EntitySnapshotBase&& other) = default; - // READING // Get key - inline Time& time() + inline Time& + time() { return this->id().timestamp; } - inline const Time& time() const + + inline const Time& + time() const { return this->id().timestamp; } + /// Indicate whether this snapshot has any instances. + bool + hasInstances() const + { + return not this->empty(); + } // Has child by key - bool hasInstance(int index) const + bool + hasInstance(int index) const { return this->findInstance(index) != nullptr; } + // Has child by ID - bool hasInstance(const MemoryID& instanceID) const + bool + hasInstance(const MemoryID& instanceID) const { return this->findInstance(instanceID) != nullptr; } - // Find child by key - EntityInstanceT* findInstance(int index) + EntityInstanceT* + findInstance(int index) { - return const_cast<EntityInstanceT*>(const_cast<const EntitySnapshotBase*>(this)->findInstance(index)); + return const_cast<EntityInstanceT*>( + const_cast<const EntitySnapshotBase*>(this)->findInstance(index)); } - const EntityInstanceT* findInstance(int index) const + + const EntityInstanceT* + findInstance(int index) const { const size_t si = static_cast<size_t>(index); - return (index >= 0 && si < this->_container.size()) - ? &this->_container[si] - : nullptr; + return (index >= 0 && si < this->_container.size()) ? &this->_container[si] : nullptr; } // Get child by key @@ -102,8 +113,10 @@ namespace armarx::armem::base EntityInstanceT& getInstance(int index) { - return const_cast<EntityInstanceT&>(const_cast<const EntitySnapshotBase*>(this)->getInstance(index)); + return const_cast<EntityInstanceT&>( + const_cast<const EntitySnapshotBase*>(this)->getInstance(index)); } + const EntityInstanceT& getInstance(int index) const { @@ -113,7 +126,8 @@ namespace armarx::armem::base } else { - throw armem::error::MissingEntry::create<EntityInstanceT>(std::to_string(index), *this); + throw armem::error::MissingEntry::create<EntityInstanceT>(std::to_string(index), + *this); } } @@ -124,6 +138,7 @@ namespace armarx::armem::base detail::checkHasInstanceIndex(instanceID); return this->findInstance(instanceID.instanceIndex); } + const EntityInstanceT* findInstance(const MemoryID& instanceID) const { @@ -145,6 +160,7 @@ namespace armarx::armem::base detail::checkHasInstanceIndex(instanceID); return this->getInstance(instanceID.instanceIndex); } + const EntityInstanceT& getInstance(const MemoryID& instanceID) const { @@ -152,22 +168,24 @@ namespace armarx::armem::base return this->getInstance(instanceID.instanceIndex); } - // ITERATION /** * @param func Function like void process(EntityInstanceT& instance)> */ template <class InstanceFunctionT> - bool forEachInstance(InstanceFunctionT&& func) + bool + forEachInstance(InstanceFunctionT&& func) { return this->forEachChild(func); } + /** * @param func Function like void process (const EntityInstanceT& instance) */ template <class InstanceFunctionT> - bool forEachInstance(InstanceFunctionT&& func) const + bool + forEachInstance(InstanceFunctionT&& func) const { return this->forEachChild(func); } @@ -176,7 +194,8 @@ namespace armarx::armem::base * @param func Function like void process(EntityInstanceT& instance)> */ template <class InstanceFunctionT> - bool forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) + bool + forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) { if (id.hasInstanceIndex()) { @@ -188,11 +207,13 @@ namespace armarx::armem::base return this->forEachInstance(func); } } + /** * @param func Function like void process (const EntityInstanceT& instance) */ template <class InstanceFunctionT> - bool forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) const + bool + forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) const { if (id.hasInstanceIndex()) { @@ -205,9 +226,9 @@ namespace armarx::armem::base } } - // Get child keys - std::vector<int> getInstanceIndices() const + std::vector<int> + getInstanceIndices() const { std::vector<int> indices; indices.reserve(this->size()); @@ -218,10 +239,10 @@ namespace armarx::armem::base return indices; } - // MODIFICATION - void update(const EntityUpdate& update) + void + update(const EntityUpdate& update) { detail::throwIfNotEqual(time(), update.referencedTime); @@ -239,22 +260,30 @@ namespace armarx::armem::base * @return The stored instance. * @throw `armem::error::InvalidArgument` If the given index is invalid. Must be equal to container.size() or -1 (meaning push_back) */ - EntityInstanceT& addInstance(const EntityInstanceT& instance) + EntityInstanceT& + addInstance(const EntityInstanceT& instance) { return addInstance(EntityInstanceT(instance)); } - EntityInstanceT& addInstance(EntityInstanceT&& instance) + EntityInstanceT& + addInstance(EntityInstanceT&& instance) { - if (instance.index() > 0 && static_cast<size_t>(instance.index()) < this->_container.size()) + if (instance.index() > 0 && + static_cast<size_t>(instance.index()) < this->_container.size()) { - throw error::InvalidArgument(std::to_string(instance.index()), "EntitySnapshot::addInstance", - "Cannot add an EntityInstance because its index already exists."); + throw error::InvalidArgument( + std::to_string(instance.index()), + "EntitySnapshot::addInstance", + "Cannot add an EntityInstance because its index already exists."); } - if (instance.index() > 0 && static_cast<size_t>(instance.index()) > this->_container.size()) + if (instance.index() > 0 && + static_cast<size_t>(instance.index()) > this->_container.size()) { - throw error::InvalidArgument(std::to_string(instance.index()), "EntitySnapshot::addInstance", - "Cannot add an EntityInstance because its index is too big."); + throw error::InvalidArgument( + std::to_string(instance.index()), + "EntitySnapshot::addInstance", + "Cannot add an EntityInstance because its index is too big."); } int index = static_cast<int>(this->_container.size()); @@ -263,7 +292,8 @@ namespace armarx::armem::base return added; } - EntityInstanceT& addInstance() + EntityInstanceT& + addInstance() { int index = static_cast<int>(this->size()); EntityInstanceT& added = this->_container.emplace_back(EntityInstanceT()); @@ -271,10 +301,10 @@ namespace armarx::armem::base return added; } - // MISC - bool equalsDeep(const DerivedT& other) const + bool + equalsDeep(const DerivedT& other) const { //std::cout << "EntitySnapshot::equalsDeep" << std::endl; if (this->size() != other.size()) @@ -293,17 +323,17 @@ namespace armarx::armem::base return true; } - - std::string getKeyString() const + std::string + getKeyString() const { return toDateTimeMilliSeconds(this->time()); } - static std::string getLevelName() + static std::string + getLevelName() { return "entity snapshot"; } - }; -} +} // namespace armarx::armem::base diff --git a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h index 6cd70391660d6f61fe073837052a9b06fb57da1c..ce5b8d7ea9a0ab258dabe04a3266f102ee9f4dbf 100644 --- a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h +++ b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h @@ -7,12 +7,11 @@ #include "EntityBase.h" #include "detail/AronTyped.h" -#include "detail/Predictive.h" #include "detail/MemoryContainerBase.h" +#include "detail/Predictive.h" #include "detail/iteration_mixins.h" #include "detail/lookup_mixins.h" - namespace armarx::armem::base { @@ -21,20 +20,19 @@ namespace armarx::armem::base */ template <class _EntityT, class _Derived> class ProviderSegmentBase : - public detail::MemoryContainerBase<std::map<std::string, _EntityT>, _Derived> - , public detail::AronTyped - , public detail::Predictive<_Derived> - , public detail::ForEachEntityInstanceMixin<_Derived> - , public detail::ForEachEntitySnapshotMixin<_Derived> - , public detail::GetFindInstanceMixin<_Derived> - , public detail::GetFindSnapshotMixin<_Derived> + public detail::MemoryContainerBase<std::map<std::string, _EntityT>, _Derived>, + public detail::AronTyped, + public detail::Predictive<_Derived>, + public detail::ForEachEntityInstanceMixin<_Derived>, + public detail::ForEachEntitySnapshotMixin<_Derived>, + public detail::GetFindInstanceMixin<_Derived>, + public detail::GetFindSnapshotMixin<_Derived> { using Base = detail::MemoryContainerBase<std::map<std::string, _EntityT>, _Derived>; public: - - using typename Base::DerivedT; using typename Base::ContainerT; + using typename Base::DerivedT; using EntityT = _EntityT; using EntitySnapshotT = typename EntityT::EntitySnapshotT; @@ -50,39 +48,37 @@ namespace armarx::armem::base std::vector<EntitySnapshotT> removedSnapshots; UpdateResult() = default; + UpdateResult(const typename EntityT::UpdateResult& c) : - entityUpdateType(c.entityUpdateType), - id(c.id), - removedSnapshots(c.removedSnapshots) - {} + entityUpdateType(c.entityUpdateType), id(c.id), removedSnapshots(c.removedSnapshots) + { + } }; public: - ProviderSegmentBase() { } - explicit ProviderSegmentBase( - const std::string& name, - aron::type::ObjectPtr aronType = nullptr, - const std::vector<PredictionEngine>& predictionEngines = {}) : + explicit ProviderSegmentBase(const std::string& name, + aron::type::ObjectPtr aronType = nullptr, + const std::vector<PredictionEngine>& predictionEngines = {}) : ProviderSegmentBase(name, MemoryID(), aronType, predictionEngines) { } - explicit ProviderSegmentBase( - const std::string& name, - const MemoryID parentID, - aron::type::ObjectPtr aronType = nullptr, - const std::vector<PredictionEngine>& predictionEngines = {}) : + + explicit ProviderSegmentBase(const std::string& name, + const MemoryID parentID, + aron::type::ObjectPtr aronType = nullptr, + const std::vector<PredictionEngine>& predictionEngines = {}) : ProviderSegmentBase(parentID.withProviderSegmentName(name), aronType, predictionEngines) { } - explicit ProviderSegmentBase( - const MemoryID id, - aron::type::ObjectPtr aronType = nullptr, - const std::vector<PredictionEngine>& predictionEngines = {}) : + + explicit ProviderSegmentBase(const MemoryID id, + aron::type::ObjectPtr aronType = nullptr, + const std::vector<PredictionEngine>& predictionEngines = {}) : Base(id), AronTyped(aronType), detail::Predictive<_Derived>(predictionEngines) { } @@ -92,71 +88,86 @@ namespace armarx::armem::base ProviderSegmentBase& operator=(const ProviderSegmentBase& other) = default; ProviderSegmentBase& operator=(ProviderSegmentBase&& other) = default; - // READ ACCESS // Get key - inline std::string& name() + inline std::string& + name() { return this->id().providerSegmentName; } - inline const std::string& name() const + + inline const std::string& + name() const { return this->id().providerSegmentName; } - // Has child by key - bool hasEntity(const std::string& name) const + bool + hasEntity(const std::string& name) const { return this->findEntity(name) != nullptr; } + // Has child by ID - bool hasEntity(const MemoryID& entityID) const + bool + hasEntity(const MemoryID& entityID) const { return this->findEntity(entityID) != nullptr; } - // Find child by key - EntityT* findEntity(const std::string& name) + EntityT* + findEntity(const std::string& name) { return detail::findChildByKey(name, this->_container); } - const EntityT* findEntity(const std::string& name) const + + const EntityT* + findEntity(const std::string& name) const { return detail::findChildByKey(name, this->_container); } // Get child by key - EntityT& getEntity(const std::string& name) + EntityT& + getEntity(const std::string& name) { return detail::getChildByKey(name, this->_container, *this); } - const EntityT& getEntity(const std::string& name) const + + const EntityT& + getEntity(const std::string& name) const { return detail::getChildByKey(name, this->_container, *this); } // Find child by MemoryID - EntityT* findEntity(const MemoryID& entityID) + EntityT* + findEntity(const MemoryID& entityID) { detail::checkHasEntityName(entityID); return this->findEntity(entityID.entityName); } - const EntityT* findEntity(const MemoryID& entityID) const + + const EntityT* + findEntity(const MemoryID& entityID) const { detail::checkHasEntityName(entityID); return this->findEntity(entityID.entityName); } // Get child by MemoryID - EntityT& getEntity(const MemoryID& entityID) + EntityT& + getEntity(const MemoryID& entityID) { detail::checkHasEntityName(entityID); return this->getEntity(entityID.entityName); } - const EntityT& getEntity(const MemoryID& entityID) const + + const EntityT& + getEntity(const MemoryID& entityID) const { detail::checkHasEntityName(entityID); return this->getEntity(entityID.entityName); @@ -174,15 +185,18 @@ namespace armarx::armem::base * @param func Function like: bool process(EntityT& entity) */ template <class EntityFunctionT> - bool forEachEntity(EntityFunctionT&& func) + bool + forEachEntity(EntityFunctionT&& func) { return this->forEachChild(func); } + /** * @param func Function like: bool process(const EntityT& entity) */ template <class EntityFunctionT> - bool forEachEntity(EntityFunctionT&& func) const + bool + forEachEntity(EntityFunctionT&& func) const { return this->forEachChild(func); } @@ -194,33 +208,39 @@ namespace armarx::armem::base * @param func Function like void process(EntityInstanceT& instance)> */ template <class InstanceFunctionT> - bool forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) + bool + forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) { - return detail::forEachInstanceIn( - id, func, *this, - id.hasEntityName(), - id.hasEntityName() ? this->findEntity(id.entityName) : nullptr); + return detail::forEachInstanceIn(id, + func, + *this, + id.hasEntityName(), + id.hasEntityName() ? this->findEntity(id.entityName) + : nullptr); } + /** * @param func Function like void process(EntityInstanceT& instance)> */ template <class InstanceFunctionT> - bool forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) const + bool + forEachInstanceIn(const MemoryID& id, InstanceFunctionT&& func) const { - return detail::forEachInstanceIn( - id, func, *this, - id.hasEntityName(), - id.hasEntityName() ? this->findEntity(id.entityName) : nullptr); + return detail::forEachInstanceIn(id, + func, + *this, + id.hasEntityName(), + id.hasEntityName() ? this->findEntity(id.entityName) + : nullptr); } - // Get child keys - std::vector<std::string> getEntityNames() const + std::vector<std::string> + getEntityNames() const { return simox::alg::get_keys(this->_container); } - // MODIFICATION /** @@ -228,7 +248,8 @@ namespace armarx::armem::base * * Missing entity entries are added before updating. */ - UpdateResult update(const EntityUpdate& update) + UpdateResult + update(const EntityUpdate& update) { this->_checkContainerName(update.entityID.providerSegmentName, this->name()); @@ -253,55 +274,61 @@ namespace armarx::armem::base return ret; } - template <class OtherDerivedT> - void append(const OtherDerivedT& other) + void + append(const OtherDerivedT& other) { - other.forEachEntity([this](const auto& entity) - { - auto it = this->_container.find(entity.name()); - if (it == this->_container.end()) + other.forEachEntity( + [this](const auto& entity) { - it = this->_container.emplace(entity.name(), this->id().withEntityName(entity.name())).first; - } - it->second.append(entity); - return true; - }); + auto it = this->_container.find(entity.name()); + if (it == this->_container.end()) + { + it = this->_container + .emplace(entity.name(), this->id().withEntityName(entity.name())) + .first; + } + it->second.append(entity); + return true; + }); } - /// Add an empty entity with the given name. - EntityT& addEntity(const std::string& name) + EntityT& + addEntity(const std::string& name) { return this->_derived().addEntity(name, name); } /// Copy and insert an entity. - EntityT& addEntity(const EntityT& entity) + EntityT& + addEntity(const EntityT& entity) { return this->_derived().addEntity(entity.name(), EntityT(entity)); } /// Move and insert an entity. - EntityT& addEntity(EntityT&& entity) + EntityT& + addEntity(EntityT&& entity) { - const std::string name = entity.name(); // Copy before move. + const std::string name = entity.name(); // Copy before move. return this->_derived().addEntity(name, std::move(entity)); } /// Insert an entity in-place. - template <class ...Args> - EntityT& addEntity(const std::string& name, Args... args) + template <class... Args> + EntityT& + addEntity(const std::string& name, Args... args) { ChildT& child = this->template _addChild<ChildT>(name, args...); child.id() = this->id().withEntityName(name); return child; } - // MISC - bool equalsDeep(const DerivedT& other) const + bool + equalsDeep(const DerivedT& other) const { if (this->size() != other.size()) { @@ -322,17 +349,17 @@ namespace armarx::armem::base return true; } - - static std::string getLevelName() + static std::string + getLevelName() { return "provider segment"; } - std::string getKeyString() const + std::string + getKeyString() const { return this->name(); } - }; -} +} // namespace armarx::armem::base diff --git a/source/RobotAPI/libraries/armem/core/base/detail/iteration_mixins.h b/source/RobotAPI/libraries/armem/core/base/detail/iteration_mixins.h index b686b1cc7b304e780579808a6bd3b3f4d1b50ff9..9f5190364d66b999fa9d15d64bf9c12454d05715 100644 --- a/source/RobotAPI/libraries/armem/core/base/detail/iteration_mixins.h +++ b/source/RobotAPI/libraries/armem/core/base/detail/iteration_mixins.h @@ -5,13 +5,14 @@ #include <RobotAPI/libraries/armem/core/MemoryID.h> +#include "derived.h" namespace { - template<typename F, typename Ret, typename A, typename... Rest> + template <typename F, typename Ret, typename A, typename... Rest> A helper(Ret (F::*)(A, Rest...)); - template<typename F, typename Ret, typename A, typename... Rest> + template <typename F, typename Ret, typename A, typename... Rest> A helper(Ret (F::*)(A, Rest...) const); // volatile or lvalue/rvalue *this not required for lambdas (phew) @@ -19,12 +20,12 @@ namespace template <typename FuncT> struct first_argument { - using type = decltype( helper(&FuncT::operator()) ); + using type = decltype(helper(&FuncT::operator())); }; template <typename FuncT> using first_argument_t = typename first_argument<FuncT>::type; -} +} // namespace namespace armarx::armem::base::detail { @@ -33,9 +34,10 @@ namespace armarx::armem::base::detail // Handle functions with different return type. template <class FunctionT, class ChildT> - bool call(FunctionT&& func, ChildT&& child) + bool + call(FunctionT&& func, ChildT&& child) { - if constexpr(std::is_same_v<decltype(func(child)), bool>) + if constexpr (std::is_same_v<decltype(func(child)), bool>) { if (!func(child)) { @@ -50,10 +52,10 @@ namespace armarx::armem::base::detail } } - // Single-valued containers. template <class ContainerT, class FunctionT> - bool forEachChildSingle(ContainerT& container, FunctionT&& func) + bool + forEachChildSingle(ContainerT& container, FunctionT&& func) { for (auto& child : container) { @@ -65,10 +67,10 @@ namespace armarx::armem::base::detail return true; } - // Pair-valued containers. template <class ContainerT, class FunctionT> - bool forEachChildPair(ContainerT& container, FunctionT&& func) + bool + forEachChildPair(ContainerT& container, FunctionT&& func) { for (auto& [_, child] : container) { @@ -80,22 +82,25 @@ namespace armarx::armem::base::detail return true; } - // see: https://en.cppreference.com/w/cpp/types/void_t // primary template handles types that have no nested ::type member: - template< class, class = void > - struct has_mapped_type : std::false_type { }; + template <class, class = void> + struct has_mapped_type : std::false_type + { + }; // specialization recognizes types that do have a nested ::type member: - template< class T > - struct has_mapped_type<T, std::void_t<typename T::mapped_type>> : std::true_type { }; - + template <class T> + struct has_mapped_type<T, std::void_t<typename T::mapped_type>> : std::true_type + { + }; template <class ContainerT, class FunctionT> - bool forEachChild(ContainerT& container, FunctionT&& func) + bool + forEachChild(ContainerT& container, FunctionT&& func) { - if constexpr(has_mapped_type<ContainerT>::value) + if constexpr (has_mapped_type<ContainerT>::value) { return forEachChildPair(container, func); } @@ -105,20 +110,15 @@ namespace armarx::armem::base::detail } } - template <class FunctionT, class ParentT, class ChildT> - bool forEachInstanceIn( - const MemoryID& id, - FunctionT&& func, - ParentT& parent, - bool single, - ChildT* child - ) + bool + forEachInstanceIn(const MemoryID& id, + FunctionT&& func, + ParentT& parent, + bool single, + ChildT* child) { - auto childFn = [&id,&func](auto& child) - { - return child.forEachInstanceIn(id, func); - }; + auto childFn = [&id, &func](auto& child) { return child.forEachInstanceIn(id, func); }; if (single) { return child ? childFn(*child) : true; @@ -129,8 +129,6 @@ namespace armarx::armem::base::detail } } - - // We use auto instead of, e.g. DerivedT::EntitySnapshotT, // as we cannot use the typedef before DerivedT was completely defined. @@ -143,33 +141,29 @@ namespace armarx::armem::base::detail * @param func Function like: bool process(EntityInstanceT& instance)> */ template <class InstanceFunctionT> - bool forEachInstance(InstanceFunctionT&& func) + bool + forEachInstance(InstanceFunctionT&& func) { - return static_cast<DerivedT*>(this)->forEachSnapshot( - [&func](auto & snapshot) -> bool - { - return snapshot.forEachInstance(func); - }); + return derived<DerivedT>(this).forEachSnapshot( + [&func](auto& snapshot) -> bool { return snapshot.forEachInstance(func); }); } /** * @param func Function like: bool process(const EntityInstanceT& instance) */ template <class InstanceFunctionT> - bool forEachInstance(InstanceFunctionT&& func) const + bool + forEachInstance(InstanceFunctionT&& func) const { - return static_cast<const DerivedT*>(this)->forEachSnapshot( - [&func](const auto & snapshot) -> bool - { - return snapshot.forEachInstance(func); - }); + return derived<DerivedT>(this).forEachSnapshot( + [&func](const auto& snapshot) -> bool { return snapshot.forEachInstance(func); }); } /** - * Call `func` on the data of each instances converted to Aron DTO class. + * @brief Call `func` on the data of each instance converted to Aron DTO class. * * @code - * ().forEachEntityInstanceAs([](const my::arondto::CoolData& data) + * ().forEachEntityInstanceAs([](my::arondto::CoolData data) * { * ... * }); @@ -177,21 +171,54 @@ namespace armarx::armem::base::detail * * The Aron DTO type is deduced from the passed function's first argument. * - * @param func Function like: `bool process(const my::arondto::CoolData& data)` + * @param func Function like: `bool process(my::arondto::CoolData data)` */ template <class AronDtoFunctionT> - bool forEachInstanceAs(AronDtoFunctionT&& func) const + bool + forEachInstanceAs(AronDtoFunctionT&& func) const { - return static_cast<const DerivedT*>(this)->forEachInstance( - [&func](const auto & instance) -> bool - { - using AronDtoT = typename std::remove_reference_t<first_argument_t<AronDtoFunctionT>>; - return func(instance.template dataAs<AronDtoT>()); - }); + using AronDtoT = typename std::remove_const_t< + std::remove_reference_t<first_argument_t<AronDtoFunctionT>>>; + + return derived<DerivedT>(this).forEachInstance( + [&func](const auto& instance) + { return func(instance.template dataAs<AronDtoT>()); }); } - }; + /** + * @brief Call `func` on each instance with its data converted to Aron DTO class. + * + * @code + * ().forEachEntityInstanceWithDataAs( + * [](armem::wm::EntityInstanceBase<my::arondto::CoolData> instance) + * { + * const armarx::armem::MemoryID id = instance.id(); + * const armarx::DateTime timestamp = instance.id().timestamp; + * const armarx::arondto::Duration& data = instance.data(); + * ... + * }); + * @endcode + * + * Compared to forEachInstanceAs(), this function allows accessing the full metadata of the + * instances in addition to the payload data converted to the ARON DTO. + * + * The Aron DTO type is deduced from the passed function's signature. + * + * @param func Function like: + * `bool process(armem::wm::EntityInstanceBase<my::arondto::CoolData> instance)` + */ + template <class EntityInstanceBaseAronDtoFunctionT> + bool + forEachInstanceWithDataAs(EntityInstanceBaseAronDtoFunctionT&& func) const + { + using AronDtoT = typename std::remove_reference_t< + first_argument_t<EntityInstanceBaseAronDtoFunctionT>>::DataT; + return derived<DerivedT>(this).forEachInstance( + [&func](const auto& instance) + { return func(instance.template withDataAs<AronDtoT>()); }); + } + }; template <class DerivedT> struct ForEachEntitySnapshotMixin @@ -200,30 +227,25 @@ namespace armarx::armem::base::detail * @param func Function like: bool process(EntitySnapshotT& snapshot)> */ template <class SnapshotFunctionT> - bool forEachSnapshot(SnapshotFunctionT&& func) + bool + forEachSnapshot(SnapshotFunctionT&& func) { - return static_cast<DerivedT*>(this)->forEachEntity( - [&func](auto & entity) -> bool - { - return entity.forEachSnapshot(func); - }); + return derived<DerivedT>(this).forEachEntity([&func](auto& entity) -> bool + { return entity.forEachSnapshot(func); }); } /** * @param func Function like: bool process(const EntitySnapshotT& snapshot) */ template <class SnapshotFunctionT> - bool forEachSnapshot(SnapshotFunctionT&& func) const + bool + forEachSnapshot(SnapshotFunctionT&& func) const { - return static_cast<const DerivedT*>(this)->forEachEntity( - [&func](const auto & entity) -> bool - { - return entity.forEachSnapshot(func); - }); + return derived<DerivedT>(this).forEachEntity([&func](const auto& entity) -> bool + { return entity.forEachSnapshot(func); }); } }; - template <class DerivedT> struct ForEachEntityMixin { @@ -231,30 +253,27 @@ namespace armarx::armem::base::detail * @param func Function like: bool process(EntityT& entity)> */ template <class FunctionT> - bool forEachEntity(FunctionT&& func) + bool + forEachEntity(FunctionT&& func) { - return static_cast<DerivedT*>(this)->forEachProviderSegment( - [&func](auto & providerSegment) -> bool - { - return providerSegment.forEachEntity(func); - }); + return derived<DerivedT>(this).forEachProviderSegment( + [&func](auto& providerSegment) -> bool + { return providerSegment.forEachEntity(func); }); } /** * @param func Function like: bool process(const EntityT& entity) */ template <class FunctionT> - bool forEachEntity(FunctionT&& func) const + bool + forEachEntity(FunctionT&& func) const { - return static_cast<const DerivedT*>(this)->forEachProviderSegment( - [&func](const auto & providerSegment) -> bool - { - return providerSegment.forEachEntity(func); - }); + return derived<DerivedT>(this).forEachProviderSegment( + [&func](const auto& providerSegment) -> bool + { return providerSegment.forEachEntity(func); }); } }; - template <class DerivedT> struct ForEachProviderSegmentMixin { @@ -262,27 +281,25 @@ namespace armarx::armem::base::detail * @param func Function like: bool process(ProviderSegmentT& providerSegment)> */ template <class FunctionT> - bool forEachProviderSegment(FunctionT&& func) + bool + forEachProviderSegment(FunctionT&& func) { - return static_cast<DerivedT*>(this)->forEachCoreSegment( - [&func](auto & coreSegment) -> bool - { - return coreSegment.forEachProviderSegment(func); - }); + return derived<DerivedT>(this).forEachCoreSegment( + [&func](auto& coreSegment) -> bool + { return coreSegment.forEachProviderSegment(func); }); } /** * @param func Function like: bool process(const ProviderSegmentT& providerSegment) */ template <class FunctionT> - bool forEachProviderSegment(FunctionT&& func) const + bool + forEachProviderSegment(FunctionT&& func) const { - return static_cast<const DerivedT*>(this)->forEachCoreSegment( - [&func](const auto & coreSegment) -> bool - { - return coreSegment.forEachProviderSegment(func); - }); + return derived<DerivedT>(this).forEachCoreSegment( + [&func](const auto& coreSegment) -> bool + { return coreSegment.forEachProviderSegment(func); }); } }; -} +} // namespace armarx::armem::base::detail diff --git a/source/RobotAPI/libraries/armem/core/base/detail/lookup_mixins.h b/source/RobotAPI/libraries/armem/core/base/detail/lookup_mixins.h index ce63b1ee78d4dbc97fe99b9efddd783dc6e5e315..204b1644d15217b028592c2bebb94cb874993ccf 100644 --- a/source/RobotAPI/libraries/armem/core/base/detail/lookup_mixins.h +++ b/source/RobotAPI/libraries/armem/core/base/detail/lookup_mixins.h @@ -8,13 +8,25 @@ namespace armarx::armem::base::detail { + /// Throw armem::error::InvalidMemoryID if the given ID has no instance index. void checkHasInstanceIndex(const MemoryID& instanceID); + /// Throw armem::error::InvalidMemoryID if the given ID has no timestamp. void checkHasTimestamp(const MemoryID& snapshotID); + /// Throw armem::error::InvalidMemoryID if the given ID has no entity name. void checkHasEntityName(const MemoryID& entityID); + /// Throw armem::error::InvalidMemoryID if the given ID has provider segment name. void checkHasProviderSegmentName(const MemoryID& providerSegmentID); + /// Throw armem::error::InvalidMemoryID if the given ID has core segment name. void checkHasCoreSegmentName(const MemoryID& coreSegmentID); + /// Throw armem::error::InvalidMemoryID if the given ID has memory name. void checkHasMemoryName(const MemoryID& memory); + /** + * @brief Find a child in a container by its key. + * @param key The child's key. + * @param container The child's container. + * @return A pointer to the child, or nullptr if it was not found. + */ template <class KeyT, class ContainerT> auto* findChildByKey(const KeyT& key, ContainerT&& container) @@ -23,11 +35,20 @@ namespace armarx::armem::base::detail return it != container.end() ? &it->second : nullptr; } + /** + * @brief Retrieve a child in a container by its key. + * @param key The child's key. + * @param container The container. + * @param parent The container's owner. Used for the error message. + * @param keyStringFn A function which turns key into a string. Used for the error message. + * @return A reference to the child. + * @throw armem::error::ArMemError If the child was not found. + */ template <class KeyT, class ContainerT, class ParentT, class KeyStringFn> auto& getChildByKey(const KeyT& key, ContainerT&& container, - const ParentT& parent, + const ParentT& owner, KeyStringFn&& keyStringFn) { if (auto* child = findChildByKey(key, container)) @@ -37,10 +58,18 @@ namespace armarx::armem::base::detail else { throw armem::error::MissingEntry::create<typename ParentT::ChildT>(keyStringFn(key), - parent); + owner); } } + /** + * @brief Retrieve a child in a container by its key. + * @param key The child's key. + * @param container The container. + * @param parent The container's owner. Used for the error message. + * @return A reference to the child. + * @throw armem::error::ArMemError If the child was not found. + */ template <class KeyT, class ContainerT, class ParentT> auto& getChildByKey(const KeyT& key, ContainerT&& container, const ParentT& parent) @@ -51,8 +80,30 @@ namespace armarx::armem::base::detail template <class DerivedT> struct GetFindInstanceMixin { - // Relies on this->find/getSnapshot() + // Relies on this->find/get/forEachInstance() + /** + * @brief Indicate whether this container contains at least one entity instance. + * @return True if there is at least one entity instance. + */ + bool + hasInstances() const + { + bool has = false; + derived<DerivedT>(this).forEachInstance( + [&has](const auto& snapshot) + { + has = true; + return false; + }); + return has; + } + + /** + * @brief Indicate whether this container has an instance with the given ID. + * @param instanceID The instance ID. + * @return ... WIP + */ bool hasInstance(const MemoryID& instanceID) const { @@ -82,7 +133,7 @@ namespace armarx::armem::base::detail * @brief Retrieve an entity instance. * @param id The instance ID. * @return The instance if it is found. - * @throw `armem::error::ArMemError` if it is missing. + * @throw armem::error::ArMemError if it is missing. */ auto& getInstance(const MemoryID& instanceID) @@ -98,20 +149,118 @@ namespace armarx::armem::base::detail }; template <class DerivedT> - struct GetFindSnapshotMixin + struct GetLatestInstanceMixin { - // Relies on this->find/getEntity() + // Relies on findLatestInstance() + + /** + * @brief Retrieve the latest entity instance. + * @param instanceIndex The instance's index in the latest snapshot. + * @return The latest entity instance. + * @throw armem::error::ArMemError If there is no entity instance. + */ + auto& + getLatestInstance(int instanceIndex = 0) + { + auto* instance = derived<DerivedT>(this).findLatestInstance(); + if (not instance) + { + throw armem::error::NoSuchEntries( + "entity instances", DerivedT::getLevelName(), derived<DerivedT>(this).id()); + } + return *instance; + } + + const auto& + getLatestInstance(int instanceIndex = 0) const + { + const auto* instance = derived<DerivedT>(this).findLatestInstance(); + if (not instance) + { + throw armem::error::NoSuchEntries( + "entity instances", DerivedT::getLevelName(), derived<DerivedT>(this).id()); + } + return *instance; + } + }; + + template <class DerivedT> + struct GetLatestSnapshotMixin + { + // Relies on findLatestSnapshot() + + /** + * @brief Retrieve the latest entity snapshot. + * @param snapshotIndex The snapshot's index in the latest snapshot. + * @return The latest entity snapshot. + * @throw armem::error::ArMemError If there is no entity snapshot. + */ + auto& + getLatestSnapshot(int snapshotIndex = 0) + { + auto* snapshot = derived<DerivedT>(this).findLatestSnapshot(); + if (not snapshot) + { + throw armem::error::NoSuchEntries( + "entity snapshots", DerivedT::getLevelName(), derived<DerivedT>(this).id()); + } + return *snapshot; + } + + const auto& + getLatestSnapshot(int snapshotIndex = 0) const + { + const auto* snapshot = derived<DerivedT>(this).findLatestSnapshot(); + if (not snapshot) + { + throw armem::error::NoSuchEntries( + "entity snapshots", DerivedT::getLevelName(), derived<DerivedT>(this).id()); + } + return *snapshot; + } + }; + + template <class DerivedT> + struct GetFindSnapshotMixin : + public GetLatestInstanceMixin<DerivedT>, + public GetLatestSnapshotMixin<DerivedT> + { + // Relies on this->find/getEntity, forEachSnapshot() + + /** + * @brief Indicate whether this container contains at least one entity snapshot. + * @return True if there is at least one entity snapshot. + */ + bool + hasSnapshots() const + { + bool has = false; + derived<DerivedT>(this).forEachSnapshot( + [&has](const auto& snapshot) + { + has = true; + return false; + }); + return has; + } + /** + * @brief Indicates whether a snapshot with the given ID exists. + * @param snapshotID The snapshot ID. + * @return True if the snapshot exists, false otherwise. + */ bool hasSnapshot(const MemoryID& snapshotID) const { return derived<DerivedT>(this).findSnapshot(snapshotID) != nullptr; } + // Snapshot by ID + /** * @brief Find an entity snapshot. * @param id The snapshot ID. - * @return The snapshot or nullptr if it is missing. + * @return The snapshot, or nullptr if it is missing. */ auto* findSnapshot(const MemoryID& snapshotID) @@ -131,7 +280,7 @@ namespace armarx::armem::base::detail * @brief Retrieve an entity snapshot. * @param id The snapshot ID. * @return The snapshot if it is found. - * @throw `armem::error::ArMemError` if it is missing. + * @throw armem::error::ArMemError if it is missing. */ auto& getSnapshot(const MemoryID& snapshotID) @@ -145,8 +294,60 @@ namespace armarx::armem::base::detail return derived<DerivedT>(this).getEntity(snapshotID).getSnapshot(snapshotID); } - // More elaborate cases + // Latest snapshot in container. + + /** + * @brief Find the latest entity snapshot. + * @return A pointer to the latest instance, or nullptr if there is no snapshot. + */ + const auto* + findLatestSnapshot() const + { + const typename DerivedT::EntitySnapshotT* latestSnapshot = nullptr; + derived<DerivedT>(this).forEachEntity( + [&latestSnapshot](const auto& entity) + { + const auto* snapshot = entity.findLatestSnapshot(); + if (latestSnapshot == nullptr) + { + latestSnapshot = snapshot; + } + else if (snapshot and snapshot->time() > latestSnapshot->time()) + { + latestSnapshot = snapshot; + } + }); + return latestSnapshot; + } + auto* + findLatestSnapshot() + { + typename DerivedT::EntitySnapshotT* latestSnapshot = nullptr; + derived<DerivedT>(this).forEachEntity( + [&latestSnapshot](auto& entity) + { + auto* snapshot = entity.findLatestSnapshot(); + if (latestSnapshot == nullptr) + { + latestSnapshot = snapshot; + } + else if (snapshot and snapshot->time() > latestSnapshot->time()) + { + latestSnapshot = snapshot; + } + }); + return latestSnapshot; + } + + // Latest snapshot in entity + + /** + * @brief Find the latest entity snapshot in the given entity. + * @param entityID The entity's ID. + * @return A pointer to the latest snapshot in the specified entity, or nullptr if the + * entity does not exist or it has no snapshot. + */ auto* findLatestSnapshot(const MemoryID& entityID) { @@ -161,6 +362,34 @@ namespace armarx::armem::base::detail return entity ? entity->findLatestSnapshot() : nullptr; } + // Latest instance in container. + + /** + * @brief Find the latest entity instance. + * @return A pointer to the latest instance, or nullptr if there is no instance. + */ + const auto* + findLatestInstance(int instanceIndex = 0) const + { + auto* snapshot = derived<DerivedT>(this).findLatestSnapshot(); + return snapshot ? snapshot->findInstance(instanceIndex) : nullptr; + } + + auto* + findLatestInstance(int instanceIndex = 0) + { + auto* snapshot = derived<DerivedT>(this).findLatestSnapshot(); + return snapshot ? snapshot->findInstance(instanceIndex) : nullptr; + } + + // Latest instance in entity. + + /** + * @brief Find the latest entity instance in the given entity. + * @param entityID The entity's ID. + * @return A pointer to the latest instance in the specified entity, or nullptr if the + * entity does not exist or it has no instance. + */ auto* findLatestInstance(const MemoryID& entityID, int instanceIndex = 0) { @@ -210,7 +439,7 @@ namespace armarx::armem::base::detail * @brief Retrieve an entity. * @param id The entity ID. * @return The entity if it is found. - * @throw `armem::error::ArMemError` if it is missing. + * @throw armem::error::ArMemError if it is missing. */ auto& getEntity(const MemoryID& entityID) @@ -259,7 +488,7 @@ namespace armarx::armem::base::detail * @brief Retrieve a provider segment. * @param id The provider segment ID. * @return The provider segment if it is found. - * @throw `armem::error::ArMemError` if it is missing. + * @throw armem::error::ArMemError if it is missing. */ auto& getProviderSegment(const MemoryID& providerSegmentID) diff --git a/source/RobotAPI/libraries/armem/core/base/ice_conversions.h b/source/RobotAPI/libraries/armem/core/base/ice_conversions.h index e808e01ace5165eb3fb38109cc850138e20061df..344073dc9361546d47e815638d054ea632ac6100 100644 --- a/source/RobotAPI/libraries/armem/core/base/ice_conversions.h +++ b/source/RobotAPI/libraries/armem/core/base/ice_conversions.h @@ -1,21 +1,19 @@ #pragma once -#include "EntityInstanceBase.h" -#include "EntitySnapshotBase.h" -#include "EntityBase.h" -#include "ProviderSegmentBase.h" -#include "CoreSegmentBase.h" -#include "MemoryBase.h" - -#include <RobotAPI/libraries/armem/core/ice_conversions.h> -#include <RobotAPI/libraries/aron/core/type/variant/forward_declarations.h> - -#include <RobotAPI/interface/armem/memory.h> - #include <ArmarXCore/core/exceptions/local/ExpressionException.h> #include <ArmarXCore/core/ice_conversions/ice_conversions_templates.h> #include <ArmarXCore/core/time/ice_conversions.h> +#include <RobotAPI/interface/armem/memory.h> +#include <RobotAPI/libraries/armem/core/ice_conversions.h> +#include <RobotAPI/libraries/aron/core/type/variant/forward_declarations.h> + +#include "CoreSegmentBase.h" +#include "EntityBase.h" +#include "EntityInstanceBase.h" +#include "EntitySnapshotBase.h" +#include "MemoryBase.h" +#include "ProviderSegmentBase.h" namespace armarx::armem::base::detail { @@ -27,7 +25,8 @@ namespace armarx::armem::base::detail void toIce(aron::type::dto::GenericTypePtr& ice, const aron::type::ObjectPtr& bo); void fromIce(const aron::type::dto::GenericTypePtr& ice, aron::type::ObjectPtr& bo); -} +} // namespace armarx::armem::base::detail + namespace armarx::armem::base { void toIce(data::EntityInstanceMetadata& ice, const EntityInstanceMetadata& metadata); @@ -36,9 +35,9 @@ namespace armarx::armem::base void toIce(data::EntityInstanceMetadataPtr& ice, const EntityInstanceMetadata& metadata); void fromIce(const data::EntityInstanceMetadataPtr& ice, EntityInstanceMetadata& metadata); - - template <class ...Args> - void toIce(data::EntityInstance& ice, const EntityInstanceBase<Args...>& data) + template <class... Args> + void + toIce(data::EntityInstance& ice, const EntityInstanceBase<Args...>& data) { detail::toIceItem(ice, data); @@ -46,8 +45,10 @@ namespace armarx::armem::base detail::toIce(ice.data, data.data()); toIce(ice.metadata, data.metadata()); } - template <class ...Args> - void fromIce(const data::EntityInstance& ice, EntityInstanceBase<Args...>& data) + + template <class... Args> + void + fromIce(const data::EntityInstance& ice, EntityInstanceBase<Args...>& data) { detail::fromIceItem(ice, data); @@ -55,55 +56,61 @@ namespace armarx::armem::base fromIce(ice.metadata, data.metadata()); } - template <class ...Args> - void toIce(data::EntitySnapshot& ice, const EntitySnapshotBase<Args...>& snapshot) + template <class... Args> + void + toIce(data::EntitySnapshot& ice, const EntitySnapshotBase<Args...>& snapshot) { detail::toIceItem(ice, snapshot); ice.instances.clear(); - snapshot.forEachInstance([&ice](const auto & instance) - { - armarx::toIce(ice.instances.emplace_back(), instance); - }); + snapshot.forEachInstance([&ice](const auto& instance) + { armarx::toIce(ice.instances.emplace_back(), instance); }); } - template <class ...Args> - void fromIce(const data::EntitySnapshot& ice, EntitySnapshotBase<Args...>& snapshot) + + template <class... Args> + void + fromIce(const data::EntitySnapshot& ice, EntitySnapshotBase<Args...>& snapshot) { detail::fromIceItem(ice, snapshot); snapshot.clear(); for (const data::EntityInstancePtr& iceInstance : ice.instances) { - snapshot.addInstance(armarx::fromIce<typename EntitySnapshotBase<Args...>::EntityInstanceT>(iceInstance)); + snapshot.addInstance( + armarx::fromIce<typename EntitySnapshotBase<Args...>::EntityInstanceT>( + iceInstance)); } } - template <class ...Args> - void toIce(data::Entity& ice, const EntityBase<Args...>& entity) + template <class... Args> + void + toIce(data::Entity& ice, const EntityBase<Args...>& entity) { detail::toIceItem(ice, entity); ice.history.clear(); - entity.forEachSnapshot([&ice](const auto & snapshot) - { - armarx::toIce(ice.history[armarx::toIce<dto::Time>(snapshot.time())], snapshot); - }); + entity.forEachSnapshot( + [&ice](const auto& snapshot) + { armarx::toIce(ice.history[armarx::toIce<dto::Time>(snapshot.time())], snapshot); }); } - template <class ...Args> - void fromIce(const data::Entity& ice, EntityBase<Args...>& entity) + + template <class... Args> + void + fromIce(const data::Entity& ice, EntityBase<Args...>& entity) { detail::fromIceItem(ice, entity); entity.clear(); for (const auto& [key, snapshot] : ice.history) { - entity.addSnapshot(armarx::fromIce<typename EntityBase<Args...>::EntitySnapshotT>(snapshot)); + entity.addSnapshot( + armarx::fromIce<typename EntityBase<Args...>::EntitySnapshotT>(snapshot)); } } - - template <class ...Args> - void toIce(data::ProviderSegment& ice, const ProviderSegmentBase<Args...>& providerSegment) + template <class... Args> + void + toIce(data::ProviderSegment& ice, const ProviderSegmentBase<Args...>& providerSegment) { detail::toIceItem(ice, providerSegment); @@ -111,13 +118,13 @@ namespace armarx::armem::base ARMARX_CHECK(!providerSegment.aronType() || ice.aronType); ice.entities.clear(); - providerSegment.forEachEntity([&ice](const auto & entity) - { - armarx::toIce(ice.entities[entity.name()], entity); - }); + providerSegment.forEachEntity([&ice](const auto& entity) + { armarx::toIce(ice.entities[entity.name()], entity); }); } - template <class ...Args> - void fromIce(const data::ProviderSegment& ice, ProviderSegmentBase<Args...>& providerSegment) + + template <class... Args> + void + fromIce(const data::ProviderSegment& ice, ProviderSegmentBase<Args...>& providerSegment) { detail::fromIceItem(ice, providerSegment); @@ -132,8 +139,9 @@ namespace armarx::armem::base } } - template <class ...Args> - void toIce(data::CoreSegment& ice, const CoreSegmentBase<Args...>& coreSegment) + template <class... Args> + void + toIce(data::CoreSegment& ice, const CoreSegmentBase<Args...>& coreSegment) { detail::toIceItem(ice, coreSegment); @@ -141,13 +149,14 @@ namespace armarx::armem::base ARMARX_CHECK(!coreSegment.aronType() || ice.aronType); ice.providerSegments.clear(); - coreSegment.forEachProviderSegment([&ice](const auto & providerSegment) - { - armarx::toIce(ice.providerSegments[providerSegment.name()], providerSegment); - }); + coreSegment.forEachProviderSegment( + [&ice](const auto& providerSegment) + { armarx::toIce(ice.providerSegments[providerSegment.name()], providerSegment); }); } - template <class ...Args> - void fromIce(const data::CoreSegment& ice, CoreSegmentBase<Args...>& coreSegment) + + template <class... Args> + void + fromIce(const data::CoreSegment& ice, CoreSegmentBase<Args...>& coreSegment) { detail::fromIceItem(ice, coreSegment); @@ -159,23 +168,26 @@ namespace armarx::armem::base for (const auto& [key, providerSegment] : ice.providerSegments) { coreSegment.addProviderSegment( - armarx::fromIce<typename CoreSegmentBase<Args...>::ProviderSegmentT>(providerSegment)); + armarx::fromIce<typename CoreSegmentBase<Args...>::ProviderSegmentT>( + providerSegment)); } } - template <class ...Args> - void toIce(data::Memory& ice, const MemoryBase<Args...>& memory) + template <class... Args> + void + toIce(data::Memory& ice, const MemoryBase<Args...>& memory) { base::detail::toIceItem(ice, memory); ice.coreSegments.clear(); - memory.forEachCoreSegment([&ice](const auto & coreSegment) - { - armarx::toIce(ice.coreSegments[coreSegment.name()], coreSegment); - }); + memory.forEachCoreSegment( + [&ice](const auto& coreSegment) + { armarx::toIce(ice.coreSegments[coreSegment.name()], coreSegment); }); } - template <class ...Args> - void fromIce(const data::Memory& ice, MemoryBase<Args...>& memory) + + template <class... Args> + void + fromIce(const data::Memory& ice, MemoryBase<Args...>& memory) { base::detail::fromIceItem(ice, memory); @@ -187,4 +199,4 @@ namespace armarx::armem::base } } -} +} // namespace armarx::armem::base diff --git a/source/RobotAPI/libraries/armem/core/error/ArMemError.cpp b/source/RobotAPI/libraries/armem/core/error/ArMemError.cpp index 87b687447b7277cbd3861d7c29e3df566e3e26b3..354b95712761f6a14d3fb6deb5baeff6b2a18aba 100644 --- a/source/RobotAPI/libraries/armem/core/error/ArMemError.cpp +++ b/source/RobotAPI/libraries/armem/core/error/ArMemError.cpp @@ -6,7 +6,6 @@ #include "../MemoryID.h" - namespace armarx::armem::error { @@ -15,7 +14,6 @@ namespace armarx::armem::error { } - InvalidArgument::InvalidArgument(const std::string& argument, const std::string& function, const std::string& message) : @@ -41,7 +39,6 @@ namespace armarx::armem::error return ss.str(); } - ContainerNameMismatch::ContainerNameMismatch(const std::string& gottenName, const std::string& ownTerm, const std::string& containerName) : @@ -60,7 +57,6 @@ namespace armarx::armem::error return ss.str(); } - ContainerEntryAlreadyExists::ContainerEntryAlreadyExists(const std::string& existingTerm, const std::string& existingName, const std::string& ownTerm, @@ -81,7 +77,6 @@ namespace armarx::armem::error return ss.str(); } - MissingEntry::MissingEntry(const std::string& missingTerm, const std::string& missingName, const std::string& containerTerm, @@ -104,6 +99,24 @@ namespace armarx::armem::error return ss.str(); } + NoSuchEntries::NoSuchEntries(const std::string& missingTerm, + const std::string& containerTerm, + const MemoryID& containerID, + const std::string& message) : + ArMemError(makeMsg(missingTerm, containerTerm, containerID, message)) + { + } + + std::string + NoSuchEntries::makeMsg(const std::string& missingTerm, + const std::string& containerTerm, + const MemoryID& containerID, + const std::string& message) + { + std::stringstream ss; + ss << "No " << missingTerm << " in " << containerTerm << " " << containerID << "."; + return ss.str(); + } MissingData::MissingData(const std::string& missingTerm, const std::string& missingName, @@ -125,7 +138,6 @@ namespace armarx::armem::error return ss.str(); } - ParseIntegerError::ParseIntegerError(std::string string, std::string semanticName) : ArMemError(makeMsg(string, semanticName)) { @@ -139,7 +151,6 @@ namespace armarx::armem::error return ss.str(); } - InvalidMemoryID::InvalidMemoryID(const MemoryID& id, const std::string& message) : ArMemError(makeMsg(id, message)) { @@ -153,7 +164,6 @@ namespace armarx::armem::error return ss.str(); } - EntityHistoryEmpty::EntityHistoryEmpty(const std::string& entityName, const std::string& message) : ArMemError(makeMsg(entityName, message)) @@ -176,7 +186,6 @@ namespace armarx::armem::error return ss.str(); } - UnknownQueryType::UnknownQueryType(const std::string& term, const std::string& typeName) : ArMemError(makeMsg(term, typeName)) { @@ -195,7 +204,8 @@ namespace armarx::armem::error { } - std::string QueryFailed::makeMsg(const std::string& memory, const std::string& message) + std::string + QueryFailed::makeMsg(const std::string& memory, const std::string& message) { std::stringstream ss; ss << "Query from memory " << memory << " failed with message: " << message; @@ -207,7 +217,6 @@ namespace armarx::armem::error { } - std::string IOError::makeMsg(const std::string& path, const std::string& message) { diff --git a/source/RobotAPI/libraries/armem/core/error/ArMemError.h b/source/RobotAPI/libraries/armem/core/error/ArMemError.h index 6f5be02a243e9e953d56b67f5f1726be214b2745..69ab7d4ddff8e22791272c520386e2fdff3d6e6f 100644 --- a/source/RobotAPI/libraries/armem/core/error/ArMemError.h +++ b/source/RobotAPI/libraries/armem/core/error/ArMemError.h @@ -4,7 +4,6 @@ #include <SimoxUtility/meta/type_name.h> - namespace armarx::armem { class MemoryID; @@ -19,85 +18,103 @@ namespace armarx::armem::error class ArMemError : public std::runtime_error { public: - ArMemError(const std::string& msg); - }; - /** * @brief Indicates that an argument was invalid. */ class InvalidArgument : public ArMemError { public: - - InvalidArgument(const std::string& argument, const std::string& function, + InvalidArgument(const std::string& argument, + const std::string& function, const std::string& message); - static std::string makeMsg(const std::string& argument, const std::string& function, + static std::string makeMsg(const std::string& argument, + const std::string& function, const std::string& message); - }; - - /** * @brief Indicates that a name in a given ID does not match a container's own name. */ class ContainerNameMismatch : public ArMemError { public: - ContainerNameMismatch(const std::string& gottenName, - const std::string& containerTerm, const std::string& containerName); + const std::string& containerTerm, + const std::string& containerName); static std::string makeMsg(const std::string& gottenName, - const std::string& containerTerm, const std::string& containerName); - + const std::string& containerTerm, + const std::string& containerName); }; - /** * @brief Indicates that a name in a given ID does not match a container's own name. */ class ContainerEntryAlreadyExists : public ArMemError { public: - - ContainerEntryAlreadyExists(const std::string& existingTerm, const std::string& existingName, - const std::string& ownTerm, const std::string& ownName); - - static std::string makeMsg(const std::string& existingTerm, const std::string& existingName, - const std::string& ownTerm, const std::string& ownName); - + ContainerEntryAlreadyExists(const std::string& existingTerm, + const std::string& existingName, + const std::string& ownTerm, + const std::string& ownName); + + static std::string makeMsg(const std::string& existingTerm, + const std::string& existingName, + const std::string& ownTerm, + const std::string& ownName); }; - /** * @brief Indicates that a container did not have an entry under a given name. */ class MissingEntry : public ArMemError { public: - template <class MissingT, class ContainerT> - static MissingEntry create(const std::string& missingKey, const ContainerT& container) + static MissingEntry + create(const std::string& missingKey, const ContainerT& container) { - return MissingEntry(MissingT::getLevelName(), missingKey, - ContainerT::getLevelName(), container.getKeyString(), container.size()); + return MissingEntry(MissingT::getLevelName(), + missingKey, + ContainerT::getLevelName(), + container.getKeyString(), + container.size()); } - - MissingEntry(const std::string& missingTerm, const std::string& missingName, - const std::string& containerTerm, const std::string& containerName, + MissingEntry(const std::string& missingTerm, + const std::string& missingName, + const std::string& containerTerm, + const std::string& containerName, size_t containerSize); - static std::string makeMsg(const std::string& missingTerm, const std::string& missingName, - const std::string& containerTerm, const std::string& containerName, + static std::string makeMsg(const std::string& missingTerm, + const std::string& missingName, + const std::string& containerTerm, + const std::string& containerName, size_t size); }; + /** + * @brief Indicates that an operation requiring at least one element to exist + * failed because there were no such entries. + */ + class NoSuchEntries : public ArMemError + { + public: + NoSuchEntries(const std::string& missingTerm, + const std::string& containerTerm, + const MemoryID& containerID, + const std::string& message = ""); + + static std::string makeMsg(const std::string& missingTerm, + const std::string& containerTerm, + const MemoryID& containerID, + const std::string& message = ""); + }; /** * @brief Indicates that a container did have an entry, but the entry's data was @@ -106,14 +123,17 @@ namespace armarx::armem::error class MissingData : public ArMemError { public: - MissingData(const std::string& missingTerm, const std::string& missingName, - const std::string& ownTerm, const std::string& ownName); - - static std::string makeMsg(const std::string& missingTerm, const std::string& missingName, - const std::string& ownTerm, const std::string& ownName); + MissingData(const std::string& missingTerm, + const std::string& missingName, + const std::string& ownTerm, + const std::string& ownName); + + static std::string makeMsg(const std::string& missingTerm, + const std::string& missingName, + const std::string& ownTerm, + const std::string& ownName); }; - /** * @brief Indicates that a string could not be parsed as integer. */ @@ -125,52 +145,43 @@ namespace armarx::armem::error static std::string makeMsg(std::string string, std::string semanticName); }; - - /** * @brief Indicates that a memory ID is invalid, e.g. does not contain necessary information. */ class InvalidMemoryID : public ArMemError { public: - InvalidMemoryID(const MemoryID& id, const std::string& message); static std::string makeMsg(const MemoryID& id, const std::string& message); - }; - /** * @brief Indicates that an entity's history was queried, but is empty. */ class EntityHistoryEmpty : public ArMemError { public: - EntityHistoryEmpty(const std::string& entityName, const std::string& message = ""); static std::string makeMsg(const std::string& entityName, const std::string& message = ""); - }; - /** * @brief Indicates that an entity's history was queried, but is empty. */ class UnknownQueryType : public ArMemError { public: - template <class QueryType> UnknownQueryType(const std::string& term, const QueryType& query) : UnknownQueryType(term, simox::meta::get_type_name(query)) { } + UnknownQueryType(const std::string& term, const std::string& typeName); static std::string makeMsg(const std::string& term, const std::string& typeName); - }; /** @@ -179,28 +190,23 @@ namespace armarx::armem::error class QueryFailed : public ArMemError { public: - QueryFailed(const std::string& memory, const std::string& message = ""); static std::string makeMsg(const std::string& memory, const std::string& message = ""); - }; - /** * @brief Indicates that something went wrong when accessing the filesystem. */ class IOError : public ArMemError { public: - IOError(const std::string& path, const std::string& message = ""); static std::string makeMsg(const std::string& path, const std::string& message = ""); std::string path; - }; /** diff --git a/source/RobotAPI/libraries/armem/core/wm/memory_definitions.cpp b/source/RobotAPI/libraries/armem/core/wm/memory_definitions.cpp index bfc408ac99a98a5bf1826f37334e1c331196ed1b..1da7db6bc21c98a33f93c2c52f5f38da4a505a88 100644 --- a/source/RobotAPI/libraries/armem/core/wm/memory_definitions.cpp +++ b/source/RobotAPI/libraries/armem/core/wm/memory_definitions.cpp @@ -1,25 +1,23 @@ #include "memory_definitions.h" -#include "error.h" - -#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> - #include <map> #include <vector> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> + +#include "error.h" namespace armarx::armem::wm { - bool EntityInstance::equalsDeep(const EntityInstance& other) const + bool + EntityInstance::equalsDeep(const EntityInstance& other) const { if (_data and other.data()) { - return id() == other.id() - && _metadata == other.metadata() - && *_data == *other.data(); + return id() == other.id() && _metadata == other.metadata() && *_data == *other.data(); } if (_data or other.data()) { @@ -28,8 +26,8 @@ namespace armarx::armem::wm return id() == other.id() && _metadata == other.metadata(); } - - void EntityInstance::update(const EntityUpdate& update) + void + EntityInstance::update(const EntityUpdate& update) { ARMARX_CHECK_FITS_SIZE(this->index(), update.instancesData.size()); @@ -42,4 +40,4 @@ namespace armarx::armem::wm this->_metadata.arrivedTime = update.arrivedTime; } -} +} // namespace armarx::armem::wm diff --git a/source/RobotAPI/libraries/armem/core/wm/memory_definitions.h b/source/RobotAPI/libraries/armem/core/wm/memory_definitions.h index 642cc50eda5e34a90e482c7bc5b26d48e3847081..dcc82878286cf3387e0381ca21312f76bff89bcb 100644 --- a/source/RobotAPI/libraries/armem/core/wm/memory_definitions.h +++ b/source/RobotAPI/libraries/armem/core/wm/memory_definitions.h @@ -1,35 +1,42 @@ #pragma once -#include "detail/data_lookup_mixins.h" - +#include <RobotAPI/libraries/armem/core/base/CoreSegmentBase.h> +#include <RobotAPI/libraries/armem/core/base/EntityBase.h> #include <RobotAPI/libraries/armem/core/base/EntityInstanceBase.h> #include <RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h> -#include <RobotAPI/libraries/armem/core/base/EntityBase.h> -#include <RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h> -#include <RobotAPI/libraries/armem/core/base/CoreSegmentBase.h> #include <RobotAPI/libraries/armem/core/base/MemoryBase.h> - +#include <RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h> #include <RobotAPI/libraries/aron/core/data/variant/forward_declarations.h> +#include "detail/data_lookup_mixins.h" namespace armarx::armem::wm { + /** + * @brief Client-side working memory entity instance metadata. + */ using EntityInstanceMetadata = base::EntityInstanceMetadata; + /** + * @brief Client-side working memory entity instance data (payload). + */ using EntityInstanceData = armarx::aron::data::Dict; + /** + * @brief Pointer type of EntityInstanceData. + */ using EntityInstanceDataPtr = armarx::aron::data::DictPtr; - - /// @see base::EntityInstanceBase + /** + * @brief Client-side working entity instance. + * @see base::EntityInstanceBase + */ class EntityInstance : public base::EntityInstanceBase<EntityInstanceDataPtr, EntityInstanceMetadata> { using Base = base::EntityInstanceBase<EntityInstanceDataPtr, EntityInstanceMetadata>; public: - using Base::EntityInstanceBase; - /** * @brief Fill `*this` with the update's values. * @param update The update. @@ -38,78 +45,99 @@ namespace armarx::armem::wm void update(const EntityUpdate& update); bool equalsDeep(const EntityInstance& other) const; - }; - - - /// @see base::EntitySnapshotBase + /** + * @brief Entity instance with a concrete ARON DTO type as data. + * + * This is the return type of EntityInstance::withDataAs<AronDtoT>(). + * + * Usage example: + * @code + * #include <RobotAPI/libraries/aron/common/aron/time.aron.generated.h> + * + * armarx::arondto::Duration duration; + * duration.microSeconds = 1000; + * + * armarx::armem::wm::EntityInstance instance; + * instance.data() = duration.toAron(); + * + * const armarx::armem::wm::EntityInstanceBase<armarx::arondto::Duration> cast = + * instance.withDataAs<armarx::arondto::Duration>(); + * + * const armarx::arondto::Duration& durationOut = cast.data(); + * + * assert(durationOut.microseconds == 1000); + * @endcode + */ + template <class AronDtoT> + using EntityInstanceBase = base::EntityInstanceBase<AronDtoT, EntityInstanceMetadata>; + + /** + * @brief Client-side working memory entity snapshot. + * @see base::EntitySnapshotBase + */ class EntitySnapshot : - public base::EntitySnapshotBase<EntityInstance, EntitySnapshot> - , public detail::FindInstanceDataMixinForSnapshot<EntitySnapshot> + public base::EntitySnapshotBase<EntityInstance, EntitySnapshot>, + public detail::FindInstanceDataMixinForSnapshot<EntitySnapshot> + { public: - using base::EntitySnapshotBase<EntityInstance, EntitySnapshot>::EntitySnapshotBase; - }; - - /// @see base::EntityBase + /** + * @brief Client-side working memory entity. + * @see base::EntityBase + */ class Entity : - public base::EntityBase<EntitySnapshot, Entity> - , public detail::FindInstanceDataMixinForEntity<Entity> + public base::EntityBase<EntitySnapshot, Entity>, + public detail::FindInstanceDataMixinForEntity<Entity> { public: - using base::EntityBase<EntitySnapshot, Entity>::EntityBase; - }; - - - /// @see base::ProviderSegmentBase + /** + * @brief Client-side working memory provider segment. + * @see base::ProviderSegmentBase + */ class ProviderSegment : - public base::ProviderSegmentBase<Entity, ProviderSegment> - , public detail::FindInstanceDataMixin<ProviderSegment> + public base::ProviderSegmentBase<Entity, ProviderSegment>, + public detail::FindInstanceDataMixin<ProviderSegment> { using Base = base::ProviderSegmentBase<Entity, ProviderSegment>; public: - using Base::ProviderSegmentBase; - }; - - - /// @see base::CoreSegmentBase + /** + * @brief Client-side working memory core segment. + * @see base::CoreSegmentBase + */ class CoreSegment : - public base::CoreSegmentBase<ProviderSegment, CoreSegment> - , public detail::FindInstanceDataMixin<CoreSegment> + public base::CoreSegmentBase<ProviderSegment, CoreSegment>, + public detail::FindInstanceDataMixin<CoreSegment> { using Base = base::CoreSegmentBase<ProviderSegment, CoreSegment>; public: - using Base::CoreSegmentBase; - }; - - - /// @see base::MemoryBase + /** + * @brief Client-side working memory. + * @see base::MemoryBase + */ class Memory : - public base::MemoryBase<CoreSegment, Memory> - , public detail::FindInstanceDataMixin<Memory> + public base::MemoryBase<CoreSegment, Memory>, + public detail::FindInstanceDataMixin<Memory> { using Base = base::MemoryBase<CoreSegment, Memory>; public: - using Base::MemoryBase; - }; -} - +} // namespace armarx::armem::wm diff --git a/source/RobotAPI/libraries/armem/test/ArMemEntityInstanceDataTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemEntityInstanceDataTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..24193227415c833e91251a03208e830738ca1b31 --- /dev/null +++ b/source/RobotAPI/libraries/armem/test/ArMemEntityInstanceDataTest.cpp @@ -0,0 +1,72 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package RobotAPI::ArmarXObjects::armem + * @author Simon Ottenhaus ( simon dot ottenhaus at kit dot edu ) + * @date 2020 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#define BOOST_TEST_MODULE RobotAPI::ArmarXLibraries::armem + +#define ARMARX_BOOST_TEST + +#include <iostream> +#include <set> + +#include <RobotAPI/Test.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/aron/common/aron/Color.aron.generated.h> +#include <RobotAPI/libraries/aron/common/aron/time.aron.generated.h> + +BOOST_AUTO_TEST_CASE(test_EntityInstance_withDataAs_Color) +{ + simox::arondto::Color color; + color.r = 0; + color.g = 100; + color.b = 200; + color.a = 255; + + armarx::armem::wm::EntityInstance instance; + instance.data() = color.toAron(); + + const armarx::armem::wm::EntityInstanceBase<simox::arondto::Color> w = + instance.withDataAs<simox::arondto::Color>(); + const simox::arondto::Color& colorOut = w.data(); + + BOOST_CHECK(colorOut == color); + BOOST_CHECK_EQUAL(colorOut.r, 0); + BOOST_CHECK_EQUAL(colorOut.g, 100); + BOOST_CHECK_EQUAL(colorOut.b, 200); + BOOST_CHECK_EQUAL(colorOut.a, 255); +} + +BOOST_AUTO_TEST_CASE(test_EntityInstance_withDataAs_Time) +{ + armarx::arondto::Duration duration; + duration.microSeconds = 1000; + + armarx::armem::wm::EntityInstance instance; + instance.data() = duration.toAron(); + + const armarx::armem::wm::EntityInstanceBase<armarx::arondto::Duration> w = + instance.withDataAs<armarx::arondto::Duration>(); + const armarx::arondto::Duration& durationOut = w.data(); + + BOOST_CHECK(durationOut == duration); + BOOST_CHECK_EQUAL(durationOut.microSeconds, 1000); + assert(durationOut.microSeconds == 1000); +} diff --git a/source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp index bf97734a52d7d9db9198101307270c23d8b07383..53771403181a1afcba608d94979faa54db61404b 100644 --- a/source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp +++ b/source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp @@ -24,33 +24,30 @@ #define ARMARX_BOOST_TEST -#include <RobotAPI/Test.h> -#include <RobotAPI/libraries/armem/core/Commit.h> -#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> -#include <RobotAPI/libraries/armem/core/operations.h> - #include <iostream> #include <set> +#include <RobotAPI/Test.h> +#include <RobotAPI/libraries/armem/core/Commit.h> +#include <RobotAPI/libraries/armem/core/operations.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> +#include <RobotAPI/libraries/aron/common/aron/time.aron.generated.h> namespace armem = armarx::armem; - template <class ValueT> -static -std::vector<ValueT> toVector(const std::set<ValueT>& set) +static std::vector<ValueT> +toVector(const std::set<ValueT>& set) { return {set.begin(), set.end()}; } - - BOOST_AUTO_TEST_CASE(test_forEach) { using namespace armarx::armem; const MemoryID mid("memory"); - const std::set<MemoryID> emptySet; // For comparison. + const std::set<MemoryID> emptySet; // For comparison. wm::Memory memory(mid); std::set<MemoryID> cids, pids, eids, sids, iids; @@ -101,75 +98,79 @@ BOOST_AUTO_TEST_CASE(test_forEach) BOOST_TEST_MESSAGE("Memory: \n" << armem::print(memory)); - memory.forEachInstance([&](const wm::EntityInstance & i) -> bool - { - BOOST_TEST_CONTEXT(wm::EntityInstance::getLevelName() << " " << i.id()) + memory.forEachInstance( + [&](const wm::EntityInstance& i) -> bool { - BOOST_TEST_INFO(toVector(iids)); - BOOST_CHECK_EQUAL(iids.count(i.id()), 1); - iids.erase(i.id()); - } - return true; - }); + BOOST_TEST_CONTEXT(wm::EntityInstance::getLevelName() << " " << i.id()) + { + BOOST_TEST_INFO(toVector(iids)); + BOOST_CHECK_EQUAL(iids.count(i.id()), 1); + iids.erase(i.id()); + } + return true; + }); BOOST_TEST_CONTEXT(toVector(iids)) { BOOST_CHECK_EQUAL(iids.size(), 0); } - memory.forEachSnapshot([&](const wm::EntitySnapshot & s) -> bool - { - BOOST_TEST_CONTEXT(wm::EntitySnapshot::getLevelName() << " " << s.id()) + memory.forEachSnapshot( + [&](const wm::EntitySnapshot& s) -> bool { - BOOST_TEST_INFO(toVector(sids)); - BOOST_CHECK_EQUAL(sids.count(s.id()), 1); - sids.erase(s.id()); - } - return true; - }); + BOOST_TEST_CONTEXT(wm::EntitySnapshot::getLevelName() << " " << s.id()) + { + BOOST_TEST_INFO(toVector(sids)); + BOOST_CHECK_EQUAL(sids.count(s.id()), 1); + sids.erase(s.id()); + } + return true; + }); BOOST_TEST_INFO(toVector(sids)); BOOST_CHECK_EQUAL(sids.size(), 0); - memory.forEachEntity([&](const wm::Entity & e) -> bool - { - BOOST_TEST_CONTEXT(wm::Entity::getLevelName() << " " << e.id()) + memory.forEachEntity( + [&](const wm::Entity& e) -> bool { - BOOST_TEST_INFO(toVector(eids)); - BOOST_CHECK_EQUAL(eids.count(e.id()), 1); - eids.erase(e.id()); - } - return true; - }); + BOOST_TEST_CONTEXT(wm::Entity::getLevelName() << " " << e.id()) + { + BOOST_TEST_INFO(toVector(eids)); + BOOST_CHECK_EQUAL(eids.count(e.id()), 1); + eids.erase(e.id()); + } + return true; + }); BOOST_TEST_INFO(toVector(eids)); BOOST_CHECK_EQUAL(eids.size(), 0); - memory.forEachProviderSegment([&](const wm::ProviderSegment & p) // -> bool - { - BOOST_TEST_CONTEXT(wm::ProviderSegment::getLevelName() << " " << p.id()) + memory.forEachProviderSegment( + [&](const wm::ProviderSegment& p) // -> bool { - BOOST_TEST_INFO(toVector(pids)); - BOOST_CHECK_EQUAL(pids.count(p.id()), 1); - pids.erase(p.id()); - } - return true; - }); + BOOST_TEST_CONTEXT(wm::ProviderSegment::getLevelName() << " " << p.id()) + { + BOOST_TEST_INFO(toVector(pids)); + BOOST_CHECK_EQUAL(pids.count(p.id()), 1); + pids.erase(p.id()); + } + return true; + }); BOOST_TEST_INFO(toVector(pids)); BOOST_CHECK_EQUAL(pids.size(), 0); - memory.forEachCoreSegment([&](const wm::CoreSegment & c) // -> bool - { - BOOST_TEST_CONTEXT(wm::CoreSegment::getLevelName() << " " << c.id()) + memory.forEachCoreSegment( + [&](const wm::CoreSegment& c) // -> bool { - BOOST_TEST_INFO(toVector(cids)); - BOOST_CHECK_EQUAL(cids.count(c.id()), 1); - cids.erase(c.id()); - } - return true; - }); + BOOST_TEST_CONTEXT(wm::CoreSegment::getLevelName() << " " << c.id()) + { + BOOST_TEST_INFO(toVector(cids)); + BOOST_CHECK_EQUAL(cids.count(c.id()), 1); + cids.erase(c.id()); + } + return true; + }); BOOST_TEST_INFO(toVector(cids)); BOOST_CHECK_EQUAL(cids.size(), 0); } - BOOST_AUTO_TEST_CASE(test_forEach_non_bool_func) { // Check whether this compiles + runs without break. @@ -179,15 +180,10 @@ BOOST_AUTO_TEST_CASE(test_forEach_non_bool_func) entity.addSnapshot(armem::Time(armem::Duration::MicroSeconds(1500))); int i = 0; - entity.forEachSnapshot([&i](const armem::wm::EntitySnapshot&) -> void - { - ++i; - }); + entity.forEachSnapshot([&i](const armem::wm::EntitySnapshot&) -> void { ++i; }); BOOST_CHECK_EQUAL(i, 2); } - - BOOST_AUTO_TEST_CASE(test_forEachInstanceIn) { armem::wm::EntitySnapshot snapshot(armem::Time::Now()); @@ -195,10 +191,7 @@ BOOST_AUTO_TEST_CASE(test_forEachInstanceIn) snapshot.addInstance(); int i = 0; - auto count = [&i](const auto&) -> void - { - ++i; - }; + auto count = [&i](const auto&) -> void { ++i; }; { auto test = [&](auto&& snapshot) @@ -273,9 +266,7 @@ BOOST_AUTO_TEST_CASE(test_forEachInstanceIn) armem::wm::ProviderSegment provSeg("provider"); provSeg.addEntity(entity); - provSeg.addEntity(entity.name() + " 2") - .addSnapshot(armem::Time::Now()) - .addInstance(); + provSeg.addEntity(entity.name() + " 2").addSnapshot(armem::Time::Now()).addInstance(); { auto test = [&](auto&& provSeg) @@ -320,9 +311,9 @@ BOOST_AUTO_TEST_CASE(test_forEachInstanceIn) armem::wm::CoreSegment coreSeg("core"); coreSeg.addProviderSegment(provSeg); coreSeg.addProviderSegment("other prov segment") - .addEntity("other entity") - .addSnapshot(armem::Time::Now()) - .addInstance(); + .addEntity("other entity") + .addSnapshot(armem::Time::Now()) + .addInstance(); { auto test = [&](auto&& coreSeg) @@ -370,10 +361,10 @@ BOOST_AUTO_TEST_CASE(test_forEachInstanceIn) armem::wm::Memory memory("memory"); memory.addCoreSegment(coreSeg); memory.addCoreSegment("other memory") - .addProviderSegment("other provider segment") - .addEntity("other entity") - .addSnapshot(armem::Time::Now()) - .addInstance(); + .addProviderSegment("other provider segment") + .addEntity("other entity") + .addSnapshot(armem::Time::Now()) + .addInstance(); { auto test = [&](auto&& memory) @@ -422,3 +413,212 @@ BOOST_AUTO_TEST_CASE(test_forEachInstanceIn) test(const_cast<const armem::wm::Memory&>(memory)); } } + +namespace forEachInstanceAs +{ + struct Fixture + { + armem::wm::Entity entity; + armem::wm::EntitySnapshot* snapshotA = nullptr; + armem::wm::EntitySnapshot* snapshotB = nullptr; + + armem::wm::EntityInstance* instanceA0 = nullptr; + armem::wm::EntityInstance* instanceA1 = nullptr; + armem::wm::EntityInstance* instanceB0 = nullptr; + armem::wm::EntityInstance* instanceB1 = nullptr; + + Fixture() + { + snapshotA = &entity.addSnapshot(armem::Time(armem::Duration::MicroSeconds(100))); + snapshotB = &entity.addSnapshot(armem::Time(armem::Duration::MicroSeconds(200))); + + BOOST_REQUIRE_EQUAL(entity.size(), 2); + BOOST_REQUIRE_EQUAL(snapshotA->size(), 0); + BOOST_REQUIRE_EQUAL(snapshotB->size(), 0); + + instanceA0 = &snapshotA->addInstance(); + instanceA1 = &snapshotA->addInstance(); + instanceB0 = &snapshotB->addInstance(); + instanceB1 = &snapshotB->addInstance(); + + if (false) + { + BOOST_REQUIRE_EQUAL(snapshotA->findInstance(0), instanceA0); + BOOST_REQUIRE_EQUAL(snapshotA->findInstance(1), instanceA1); + BOOST_REQUIRE_EQUAL(snapshotB->findInstance(0), instanceB0); + BOOST_REQUIRE_EQUAL(snapshotB->findInstance(1), instanceB1); + } + + int i = 0; + + i = 0; + entity.forEachSnapshot( + [&i](const armem::wm::EntitySnapshot& snapshot) + { + BOOST_REQUIRE_EQUAL(snapshot.size(), 2); + ++i; + }); + BOOST_REQUIRE_EQUAL(i, 2); + + i = 0; + entity.forEachInstance( + [&i](armem::wm::EntityInstance& instance) + { + instance.setData(makeDuration(i * 1000).toAron()); + BOOST_REQUIRE(instance.data()); + ++i; + }); + BOOST_REQUIRE_EQUAL(i, 4); + + if (false) + { + instanceA0->setData(makeDuration(1000).toAron()); + instanceA1->setData(makeDuration(2000).toAron()); + instanceB0->setData(makeDuration(3000).toAron()); + instanceB1->setData(makeDuration(4000).toAron()); + + BOOST_REQUIRE(instanceA0->data()); + BOOST_REQUIRE(instanceA1->data()); + BOOST_REQUIRE(instanceB0->data()); + BOOST_REQUIRE(instanceB1->data()); + BOOST_REQUIRE_NO_THROW(armarx::arondto::Duration::FromAron(instanceA0->data())); + BOOST_REQUIRE_NO_THROW(armarx::arondto::Duration::FromAron(instanceA1->data())); + BOOST_REQUIRE_NO_THROW(armarx::arondto::Duration::FromAron(instanceB0->data())); + BOOST_REQUIRE_NO_THROW(armarx::arondto::Duration::FromAron(instanceB1->data())); + } + + i = 0; + entity.forEachInstance( + [&i](const armem::wm::EntityInstance& instance) + { + BOOST_REQUIRE(instance.data()); + ++i; + return true; + }); + BOOST_REQUIRE_EQUAL(i, 4); + } + + static armarx::arondto::Duration + makeDuration(int microSeconds) + { + armarx::arondto::Duration duration; + duration.microSeconds = microSeconds; + return duration; + }; + }; +} // namespace forEachInstanceAs + + +BOOST_FIXTURE_TEST_SUITE(forEachInstanceAs, Fixture) + +BOOST_AUTO_TEST_CASE(test_forEachInstanceAs_const_ref_return_true) +{ + int i = 0; + + i = 0; + entity.forEachInstanceAs( + [&i](const armarx::arondto::Duration& duration) + { + BOOST_CHECK_EQUAL(duration.microSeconds, i * 1000); + ++i; + + return true; + }); + BOOST_CHECK_EQUAL(i, 4); +} + +BOOST_AUTO_TEST_CASE(test_forEachInstanceAs_const_ref) +{ + int i = 0; + entity.forEachInstanceAs( + [&i](const armarx::arondto::Duration& duration) + { + BOOST_CHECK_EQUAL(duration.microSeconds, i * 1000); + ++i; + }); + BOOST_CHECK_EQUAL(i, 4); +} + +BOOST_AUTO_TEST_CASE(test_forEachInstanceAs_value_return_true) +{ + int i = 0; + entity.forEachInstanceAs( + [&i](armarx::arondto::Duration duration) + { + BOOST_CHECK_EQUAL(duration.microSeconds, i * 1000); + ++i; + + return true; + }); + BOOST_CHECK_EQUAL(i, 4); +} + +BOOST_AUTO_TEST_CASE(test_forEachInstanceAs_value) +{ + int i = 0; + entity.forEachInstanceAs( + [&i](armarx::arondto::Duration duration) + { + BOOST_CHECK_EQUAL(duration.microSeconds, i * 1000); + ++i; + }); + BOOST_CHECK_EQUAL(i, 4); +} + +BOOST_AUTO_TEST_CASE(test_forEachInstanceWithDataAs_const_ref_return_true) +{ + int i = 0; + entity.forEachInstanceWithDataAs( + [&i](const armem::wm::EntityInstanceBase<armarx::arondto::Duration>& instance) + { + const armarx::arondto::Duration& duration = instance.data(); + BOOST_CHECK_EQUAL(duration.microSeconds, i * 1000); + ++i; + + return true; + }); + BOOST_CHECK_EQUAL(i, 4); +} + +BOOST_AUTO_TEST_CASE(test_forEachInstanceWithDataAs_const_ref) +{ + int i = 0; + entity.forEachInstanceWithDataAs( + [&i](const armem::wm::EntityInstanceBase<armarx::arondto::Duration>& instance) + { + const armarx::arondto::Duration& duration = instance.data(); + BOOST_CHECK_EQUAL(duration.microSeconds, i * 1000); + ++i; + }); + BOOST_CHECK_EQUAL(i, 4); +} + +BOOST_AUTO_TEST_CASE(test_forEachInstanceWithDataAs_value_return_true) +{ + int i = 0; + entity.forEachInstanceWithDataAs( + [&i](armem::wm::EntityInstanceBase<armarx::arondto::Duration> instance) + { + const armarx::arondto::Duration& duration = instance.data(); + BOOST_CHECK_EQUAL(duration.microSeconds, i * 1000); + ++i; + + return true; + }); + BOOST_CHECK_EQUAL(i, 4); +} + +BOOST_AUTO_TEST_CASE(test_forEachInstanceWithDataAs_value) +{ + int i = 0; + entity.forEachInstanceWithDataAs( + [&i](armem::wm::EntityInstanceBase<armarx::arondto::Duration> instance) + { + const armarx::arondto::Duration& duration = instance.data(); + BOOST_CHECK_EQUAL(duration.microSeconds, i * 1000); + ++i; + }); + BOOST_CHECK_EQUAL(i, 4); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/source/RobotAPI/libraries/armem/test/ArMemGetFindTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemGetFindTest.cpp index f03b02052ef9956aab079dda96677acaf5aca48d..4c133b5ac32e58eaf573e3b26f334b148c6a17cb 100644 --- a/source/RobotAPI/libraries/armem/test/ArMemGetFindTest.cpp +++ b/source/RobotAPI/libraries/armem/test/ArMemGetFindTest.cpp @@ -14,7 +14,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * * @package RobotAPI::ArmarXObjects::armem - * @author Simon Ottenhaus ( simon dot ottenhaus at kit dot edu ) + * @author Rainer Kartmann ( raier dot kartmann at kit dot edu ) * @date 2020 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt * GNU General Public License @@ -24,29 +24,36 @@ #define ARMARX_BOOST_TEST -#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> -#include <RobotAPI/libraries/armem/core/error.h> -#include <RobotAPI/libraries/armem/core/operations.h> +#include <iostream> #include <RobotAPI/Test.h> - -#include <iostream> +#include <RobotAPI/libraries/armem/core/error.h> +#include <RobotAPI/libraries/armem/core/operations.h> +#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h> namespace armem = armarx::armem; namespace wm = armarx::armem::wm; namespace aron = armarx::aron; - namespace ArMemGetFindTest { struct Fixture { wm::EntitySnapshot snapshot; + wm::EntitySnapshot snapshotEmpty; + wm::Entity entity; + wm::Entity entityEmpty; + wm::ProviderSegment provSeg; + wm::ProviderSegment provSegEmpty; + wm::CoreSegment coreSeg; + wm::CoreSegment coreSegEmpty; + wm::Memory memory; + wm::Memory memoryEmpty; armem::MemoryID instanceID; armem::MemoryID snapshotID; @@ -58,24 +65,38 @@ namespace ArMemGetFindTest Fixture() { { + snapshotEmpty.time() = armem::Time(armem::Duration::MicroSeconds(500)); + snapshot.time() = armem::Time(armem::Duration::MicroSeconds(1000)); snapshot.addInstance(); } { + entityEmpty.name() = "entity empty"; + entity.name() = "entity"; entity.addSnapshot(snapshot); + entity.addSnapshot(snapshotEmpty); } { + provSegEmpty.name() = "provider segment empty"; + provSeg.name() = "provider segment"; provSeg.addEntity(entity); + provSeg.addEntity(entityEmpty); } { + coreSegEmpty.name() = "core segment empty"; + coreSeg.name() = "core segment"; coreSeg.addProviderSegment(provSeg); + coreSeg.addProviderSegment(provSegEmpty); } { + memoryEmpty.name() = "memory empty"; + memory.name() = "memory"; memory.addCoreSegment(coreSeg); + memory.addCoreSegment(coreSegEmpty); } memoryID = memory.id(); @@ -85,22 +106,18 @@ namespace ArMemGetFindTest snapshotID = entityID.withTimestamp(snapshot.time()); instanceID = snapshotID.withInstanceIndex(0); } + ~Fixture() { } - template <class ParentT> - void test_get_find_instance_by_id(ParentT&& parent) - { - _test_get_find_instance_by_id(const_cast<const ParentT&>(parent)); - _test_get_find_instance_by_id(const_cast<ParentT&>(parent)); - } - template <class ParentT> - void _test_get_find_instance_by_id(ParentT&& parent) + void + _test_get_find_instance_by_id(ParentT&& parent) { BOOST_TEST_CONTEXT("Parent: " << armem::print(parent)) { + BOOST_CHECK_EQUAL(parent.hasInstances(), true); BOOST_CHECK_EQUAL(parent.hasInstance(snapshotID.withInstanceIndex(0)), true); BOOST_CHECK_EQUAL(parent.hasInstance(snapshotID.withInstanceIndex(1)), false); @@ -108,106 +125,240 @@ namespace ArMemGetFindTest BOOST_CHECK_EQUAL(parent.findInstance(snapshotID.withInstanceIndex(1)), nullptr); BOOST_CHECK_NO_THROW(parent.getInstance(snapshotID.withInstanceIndex(0))); - BOOST_CHECK_THROW(parent.getInstance(snapshotID.withInstanceIndex(1)), armem::error::MissingEntry); + BOOST_CHECK_THROW(parent.getInstance(snapshotID.withInstanceIndex(1)), + armem::error::MissingEntry); } } template <class ParentT> - void test_get_find_snapshot_by_id(ParentT&& parent) + void + test_get_find_instance_by_id(ParentT&& parent) { - _test_get_find_snapshot_by_id(const_cast<const ParentT&>(parent)); - _test_get_find_snapshot_by_id(const_cast<ParentT&>(parent)); + _test_get_find_instance_by_id(const_cast<const ParentT&>(parent)); + _test_get_find_instance_by_id(const_cast<ParentT&>(parent)); } + template <class ParentT> - void _test_get_find_snapshot_by_id(ParentT&& parent) + void + _test_get_find_latest_instance(ParentT&& parent) { BOOST_TEST_CONTEXT("Parent: " << armem::print(parent)) { - BOOST_CHECK_EQUAL(parent.hasSnapshot(entityID.withTimestamp(armem::Time(armem::Duration::MicroSeconds(1000)))), true); - BOOST_CHECK_EQUAL(parent.hasSnapshot(entityID.withTimestamp(armem::Time(armem::Duration::MicroSeconds(2000)))), false); + BOOST_CHECK_EQUAL(parent.hasInstances(), true); + BOOST_CHECK_NE(parent.findLatestInstance(), nullptr); + BOOST_CHECK_NO_THROW(parent.getLatestInstance()); + } + } - BOOST_CHECK_NE(parent.findSnapshot(entityID.withTimestamp(armem::Time(armem::Duration::MicroSeconds(1000)))), nullptr); - BOOST_CHECK_EQUAL(parent.findSnapshot(entityID.withTimestamp(armem::Time(armem::Duration::MicroSeconds(2000)))), nullptr); + template <class ParentT> + void + test_get_find_latest_instance(ParentT&& parent) + { + _test_get_find_latest_instance(const_cast<const ParentT&>(parent)); + _test_get_find_latest_instance(const_cast<ParentT&>(parent)); + } - BOOST_CHECK_NO_THROW(parent.getSnapshot(entityID.withTimestamp(armem::Time(armem::Duration::MicroSeconds(1000))))); - BOOST_CHECK_THROW(parent.getSnapshot(entityID.withTimestamp(armem::Time(armem::Duration::MicroSeconds(2000)))), armem::error::MissingEntry); + template <class ParentT> + void + _test_get_find_latest_instance_when_empty(ParentT&& parent) + { + BOOST_TEST_CONTEXT("Parent: " << armem::print(parent)) + { + BOOST_CHECK_EQUAL(parent.hasInstances(), false); + BOOST_CHECK_EQUAL(parent.findLatestInstance(), nullptr); + BOOST_CHECK_THROW(parent.getLatestInstance(), armem::error::NoSuchEntries); } } + template <class ParentT> + void + test_get_find_latest_instance_when_empty(ParentT&& parent) + { + _test_get_find_latest_instance_when_empty(const_cast<const ParentT&>(parent)); + _test_get_find_latest_instance_when_empty(const_cast<ParentT&>(parent)); + } template <class ParentT> - void test_get_find_entity_by_id(ParentT&& parent) + void + _test_get_find_snapshot_by_id(ParentT&& parent) { - _test_get_find_entity_by_id(const_cast<const ParentT&>(parent)); - _test_get_find_entity_by_id(const_cast<ParentT&>(parent)); + BOOST_TEST_CONTEXT("Parent: " << armem::print(parent)) + { + BOOST_CHECK_EQUAL(parent.hasSnapshots(), true); + + BOOST_CHECK_EQUAL(parent.hasSnapshot(entityID.withTimestamp( + armem::Time(armem::Duration::MicroSeconds(1000)))), + true); + BOOST_CHECK_EQUAL(parent.hasSnapshot(entityID.withTimestamp( + armem::Time(armem::Duration::MicroSeconds(2000)))), + false); + + BOOST_CHECK_NE(parent.findSnapshot(entityID.withTimestamp( + armem::Time(armem::Duration::MicroSeconds(1000)))), + nullptr); + BOOST_CHECK_EQUAL(parent.findSnapshot(entityID.withTimestamp( + armem::Time(armem::Duration::MicroSeconds(2000)))), + nullptr); + + BOOST_CHECK_NO_THROW(parent.getSnapshot( + entityID.withTimestamp(armem::Time(armem::Duration::MicroSeconds(1000))))); + BOOST_CHECK_THROW(parent.getSnapshot(entityID.withTimestamp( + armem::Time(armem::Duration::MicroSeconds(2000)))), + armem::error::MissingEntry); + } + } + + template <class ParentT> + void + test_get_find_snapshot_by_id(ParentT&& parent) + { + _test_get_find_snapshot_by_id(const_cast<const ParentT&>(parent)); + _test_get_find_snapshot_by_id(const_cast<ParentT&>(parent)); } + template <class ParentT> - void _test_get_find_entity_by_id(ParentT&& parent) + void + _test_get_find_entity_by_id(ParentT&& parent) { BOOST_TEST_CONTEXT("Parent: " << armem::print(parent)) { BOOST_CHECK_EQUAL(parent.hasEntity(provSegID.withEntityName("entity")), true); - BOOST_CHECK_EQUAL(parent.hasEntity(provSegID.withEntityName("other entity")), false); + BOOST_CHECK_EQUAL(parent.hasEntity(provSegID.withEntityName("other entity")), + false); BOOST_CHECK_NE(parent.findEntity(provSegID.withEntityName("entity")), nullptr); - BOOST_CHECK_EQUAL(parent.findEntity(provSegID.withEntityName("other entity")), nullptr); + BOOST_CHECK_EQUAL(parent.findEntity(provSegID.withEntityName("other entity")), + nullptr); BOOST_CHECK_NO_THROW(parent.getEntity(provSegID.withEntityName("entity"))); - BOOST_CHECK_THROW(parent.getEntity(provSegID.withEntityName("other entity")), armem::error::MissingEntry); + BOOST_CHECK_THROW(parent.getEntity(provSegID.withEntityName("other entity")), + armem::error::MissingEntry); } } template <class ParentT> - void test_get_find_provider_segment_by_id(ParentT&& parent) + void + _test_get_find_latest_snapshot(ParentT&& parent) { - _test_get_find_provider_segment_by_id(const_cast<const ParentT&>(parent)); - _test_get_find_provider_segment_by_id(const_cast<ParentT&>(parent)); + BOOST_TEST_CONTEXT("Parent: " << armem::print(parent)) + { + BOOST_CHECK_EQUAL(parent.hasSnapshots(), true); + BOOST_CHECK_NE(parent.findLatestSnapshot(), nullptr); + BOOST_CHECK_NO_THROW(parent.getLatestSnapshot()); + } } + template <class ParentT> - void _test_get_find_provider_segment_by_id(ParentT&& parent) + void + test_get_find_latest_snapshot(ParentT&& parent) + { + _test_get_find_latest_snapshot(const_cast<const ParentT&>(parent)); + _test_get_find_latest_snapshot(const_cast<ParentT&>(parent)); + } + + template <class ParentT> + void + _test_get_find_latest_snapshot_when_empty(ParentT&& parent) { BOOST_TEST_CONTEXT("Parent: " << armem::print(parent)) { - BOOST_CHECK_EQUAL(parent.hasProviderSegment(provSegID.withProviderSegmentName("provider segment")), true); - BOOST_CHECK_EQUAL(parent.hasProviderSegment(provSegID.withProviderSegmentName("other provider segment")), false); - - BOOST_CHECK_NE(parent.findProviderSegment(provSegID.withProviderSegmentName("provider segment")), nullptr); - BOOST_CHECK_EQUAL(parent.findProviderSegment(provSegID.withProviderSegmentName("other provider segment")), nullptr); - - BOOST_CHECK_NO_THROW(parent.getProviderSegment(provSegID.withProviderSegmentName("provider segment"))); - BOOST_CHECK_THROW(parent.getProviderSegment(provSegID.withProviderSegmentName("other provider segment")), armem::error::MissingEntry); + BOOST_CHECK_EQUAL(parent.hasSnapshots(), false); + BOOST_CHECK_EQUAL(parent.findLatestSnapshot(), nullptr); + BOOST_CHECK_THROW(parent.getLatestSnapshot(), armem::error::NoSuchEntries); } } template <class ParentT> - void test_get_find_core_segment_by_id(ParentT&& parent) + void + test_get_find_latest_snapshot_when_empty(ParentT&& parent) { - _test_get_find_core_segment_by_id(const_cast<const ParentT&>(parent)); - _test_get_find_core_segment_by_id(const_cast<ParentT&>(parent)); + _test_get_find_latest_snapshot_when_empty(const_cast<const ParentT&>(parent)); + _test_get_find_latest_snapshot_when_empty(const_cast<ParentT&>(parent)); } + template <class ParentT> - void _test_get_find_core_segment_by_id(ParentT&& parent) + void + test_get_find_entity_by_id(ParentT&& parent) + { + _test_get_find_entity_by_id(const_cast<const ParentT&>(parent)); + _test_get_find_entity_by_id(const_cast<ParentT&>(parent)); + } + + template <class ParentT> + void + _test_get_find_provider_segment_by_id(ParentT&& parent) { BOOST_TEST_CONTEXT("Parent: " << armem::print(parent)) { - BOOST_CHECK_EQUAL(parent.hasCoreSegment(provSegID.withCoreSegmentName("core segment")), true); - BOOST_CHECK_EQUAL(parent.hasCoreSegment(provSegID.withCoreSegmentName("other core segment")), false); + BOOST_CHECK_EQUAL(parent.hasProviderSegment( + provSegID.withProviderSegmentName("provider segment")), + true); + BOOST_CHECK_EQUAL(parent.hasProviderSegment( + provSegID.withProviderSegmentName("other provider segment")), + false); + + BOOST_CHECK_NE(parent.findProviderSegment( + provSegID.withProviderSegmentName("provider segment")), + nullptr); + BOOST_CHECK_EQUAL(parent.findProviderSegment( + provSegID.withProviderSegmentName("other provider segment")), + nullptr); + + BOOST_CHECK_NO_THROW(parent.getProviderSegment( + provSegID.withProviderSegmentName("provider segment"))); + BOOST_CHECK_THROW(parent.getProviderSegment( + provSegID.withProviderSegmentName("other provider segment")), + armem::error::MissingEntry); + } + } - BOOST_CHECK_NE(parent.findCoreSegment(provSegID.withCoreSegmentName("core segment")), nullptr); - BOOST_CHECK_EQUAL(parent.findCoreSegment(provSegID.withCoreSegmentName("other core segment")), nullptr); + template <class ParentT> + void + test_get_find_provider_segment_by_id(ParentT&& parent) + { + _test_get_find_provider_segment_by_id(const_cast<const ParentT&>(parent)); + _test_get_find_provider_segment_by_id(const_cast<ParentT&>(parent)); + } - BOOST_CHECK_NO_THROW(parent.getCoreSegment(provSegID.withCoreSegmentName("core segment"))); - BOOST_CHECK_THROW(parent.getCoreSegment(provSegID.withCoreSegmentName("other core segment")), armem::error::MissingEntry); + template <class ParentT> + void + _test_get_find_core_segment_by_id(ParentT&& parent) + { + BOOST_TEST_CONTEXT("Parent: " << armem::print(parent)) + { + BOOST_CHECK_EQUAL( + parent.hasCoreSegment(provSegID.withCoreSegmentName("core segment")), true); + BOOST_CHECK_EQUAL( + parent.hasCoreSegment(provSegID.withCoreSegmentName("other core segment")), + false); + + BOOST_CHECK_NE( + parent.findCoreSegment(provSegID.withCoreSegmentName("core segment")), nullptr); + BOOST_CHECK_EQUAL( + parent.findCoreSegment(provSegID.withCoreSegmentName("other core segment")), + nullptr); + + BOOST_CHECK_NO_THROW( + parent.getCoreSegment(provSegID.withCoreSegmentName("core segment"))); + BOOST_CHECK_THROW( + parent.getCoreSegment(provSegID.withCoreSegmentName("other core segment")), + armem::error::MissingEntry); } } + + template <class ParentT> + void + test_get_find_core_segment_by_id(ParentT&& parent) + { + _test_get_find_core_segment_by_id(const_cast<const ParentT&>(parent)); + _test_get_find_core_segment_by_id(const_cast<ParentT&>(parent)); + } }; -} +} // namespace ArMemGetFindTest BOOST_FIXTURE_TEST_SUITE(ArMemGetFindTest, Fixture) - - BOOST_AUTO_TEST_CASE(test_snapshot_get_find_instance_by_key) { BOOST_CHECK_EQUAL(snapshot.hasInstance(0), true); @@ -220,20 +371,20 @@ BOOST_AUTO_TEST_CASE(test_snapshot_get_find_instance_by_key) BOOST_CHECK_THROW(snapshot.getInstance(1), armem::error::MissingEntry); } - BOOST_AUTO_TEST_CASE(test_entity_get_find_snapshot_by_key) { BOOST_CHECK_EQUAL(entity.hasSnapshot(armem::Time(armem::Duration::MicroSeconds(1000))), true); BOOST_CHECK_EQUAL(entity.hasSnapshot(armem::Time(armem::Duration::MicroSeconds(2000))), false); BOOST_CHECK_NE(entity.findSnapshot(armem::Time(armem::Duration::MicroSeconds(1000))), nullptr); - BOOST_CHECK_EQUAL(entity.findSnapshot(armem::Time(armem::Duration::MicroSeconds(2000))), nullptr); + BOOST_CHECK_EQUAL(entity.findSnapshot(armem::Time(armem::Duration::MicroSeconds(2000))), + nullptr); BOOST_CHECK_NO_THROW(entity.getSnapshot(armem::Time(armem::Duration::MicroSeconds(1000)))); - BOOST_CHECK_THROW(entity.getSnapshot(armem::Time(armem::Duration::MicroSeconds(2000))), armem::error::MissingEntry); + BOOST_CHECK_THROW(entity.getSnapshot(armem::Time(armem::Duration::MicroSeconds(2000))), + armem::error::MissingEntry); } - BOOST_AUTO_TEST_CASE(test_provider_segment_get_find_entity_by_key) { BOOST_CHECK_EQUAL(provSeg.hasEntity("entity"), true); @@ -246,7 +397,6 @@ BOOST_AUTO_TEST_CASE(test_provider_segment_get_find_entity_by_key) BOOST_CHECK_THROW(provSeg.getEntity("other entity"), armem::error::MissingEntry); } - BOOST_AUTO_TEST_CASE(test_core_segment_get_find_provider_segment_by_key) { BOOST_CHECK_EQUAL(coreSeg.hasProviderSegment("provider segment"), true); @@ -256,10 +406,10 @@ BOOST_AUTO_TEST_CASE(test_core_segment_get_find_provider_segment_by_key) BOOST_CHECK_EQUAL(coreSeg.findProviderSegment("other provider segment"), nullptr); BOOST_CHECK_NO_THROW(coreSeg.getProviderSegment("provider segment")); - BOOST_CHECK_THROW(coreSeg.getProviderSegment("other provider segment"), armem::error::MissingEntry); + BOOST_CHECK_THROW(coreSeg.getProviderSegment("other provider segment"), + armem::error::MissingEntry); } - BOOST_AUTO_TEST_CASE(test_memory_get_find_core_segment_by_key) { BOOST_CHECK_EQUAL(memory.hasCoreSegment("core segment"), true); @@ -272,66 +422,119 @@ BOOST_AUTO_TEST_CASE(test_memory_get_find_core_segment_by_key) BOOST_CHECK_THROW(memory.getCoreSegment("other core segment"), armem::error::MissingEntry); } - - BOOST_AUTO_TEST_CASE(test_snapshot_get_find_instance_by_id) { test_get_find_instance_by_id(snapshot); } + BOOST_AUTO_TEST_CASE(test_entity_get_find_instance_by_id) { test_get_find_instance_by_id(entity); } + BOOST_AUTO_TEST_CASE(test_provider_segment_get_find_instance_by_id) { test_get_find_instance_by_id(provSeg); } + BOOST_AUTO_TEST_CASE(test_core_segment_get_find_instance_by_id) { test_get_find_instance_by_id(coreSeg); } + BOOST_AUTO_TEST_CASE(test_memory_get_find_instance_by_id) { test_get_find_instance_by_id(memory); } +BOOST_AUTO_TEST_CASE(test_entity_get_find_latest_instance) +{ + test_get_find_latest_instance(entity); + test_get_find_latest_instance_when_empty(entityEmpty); +} + +BOOST_AUTO_TEST_CASE(test_provider_segment_get_find_latest_instance) +{ + test_get_find_latest_instance(provSeg); + test_get_find_latest_instance_when_empty(provSegEmpty); +} + +BOOST_AUTO_TEST_CASE(test_core_segment_get_find_latest_instance) +{ + test_get_find_latest_instance(coreSeg); + test_get_find_latest_instance_when_empty(coreSegEmpty); +} + +BOOST_AUTO_TEST_CASE(test_memory_get_find_latest_instance) +{ + test_get_find_latest_instance(memory); + test_get_find_latest_instance_when_empty(memoryEmpty); +} BOOST_AUTO_TEST_CASE(test_entity_get_find_snapshot_by_id) { test_get_find_snapshot_by_id(entity); } + BOOST_AUTO_TEST_CASE(test_provider_segment_get_find_snapshot_by_id) { test_get_find_snapshot_by_id(provSeg); } + BOOST_AUTO_TEST_CASE(test_core_segment_get_find_snapshot_by_id) { test_get_find_snapshot_by_id(coreSeg); } + BOOST_AUTO_TEST_CASE(test_memory_get_find_snapshot_by_id) { test_get_find_snapshot_by_id(memory); } +BOOST_AUTO_TEST_CASE(test_entity_get_find_latest_snapshot) +{ + test_get_find_latest_snapshot(entity); + test_get_find_latest_snapshot_when_empty(entityEmpty); +} + +BOOST_AUTO_TEST_CASE(test_provider_segment_get_find_latest_snapshot) +{ + test_get_find_latest_snapshot(provSeg); + test_get_find_latest_snapshot_when_empty(provSegEmpty); +} + +BOOST_AUTO_TEST_CASE(test_core_segment_get_find_latest_snapshot) +{ + test_get_find_latest_snapshot(coreSeg); + test_get_find_latest_snapshot_when_empty(coreSegEmpty); +} + +BOOST_AUTO_TEST_CASE(test_memory_get_find_latest_snapshot) +{ + test_get_find_latest_snapshot(memory); + test_get_find_latest_snapshot_when_empty(memoryEmpty); +} BOOST_AUTO_TEST_CASE(test_provider_segment_get_find_entity_by_id) { test_get_find_entity_by_id(provSeg); } + BOOST_AUTO_TEST_CASE(test_core_segment_get_find_entity_by_id) { test_get_find_entity_by_id(coreSeg); } + BOOST_AUTO_TEST_CASE(test_memory_get_find_entity_by_id) { test_get_find_entity_by_id(memory); } - BOOST_AUTO_TEST_CASE(test_core_segment_get_find_provider_segment_by_id) { test_get_find_provider_segment_by_id(coreSeg); } + BOOST_AUTO_TEST_CASE(test_memory_get_find_provider_segment_by_id) { test_get_find_provider_segment_by_id(memory); @@ -342,6 +545,4 @@ BOOST_AUTO_TEST_CASE(test_memory_get_find_core_segment_by_id) test_get_find_core_segment_by_id(memory); } - - BOOST_AUTO_TEST_SUITE_END() diff --git a/source/RobotAPI/libraries/armem/test/CMakeLists.txt b/source/RobotAPI/libraries/armem/test/CMakeLists.txt index da77a43b82a6174b756ddf1705e8c29ea3acabb2..688f0009e90f7540708e8e02fde2f7336944a471 100644 --- a/source/RobotAPI/libraries/armem/test/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem/test/CMakeLists.txt @@ -2,6 +2,7 @@ # Libs required for the tests SET(LIBS ${LIBS} ArmarXCore ${LIB_NAME}) +armarx_add_test(ArMemEntityInstanceDataTest ArMemEntityInstanceDataTest.cpp "${LIBS}") armarx_add_test(ArMemForEachTest ArMemForEachTest.cpp "${LIBS}") armarx_add_test(ArMemGetFindTest ArMemGetFindTest.cpp "${LIBS}") armarx_add_test(ArMemIceConversionsTest ArMemIceConversionsTest.cpp "${LIBS}")