diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt index ef5f227686bf252f3f7941fd3f0d96aed72442d1..565b2c951353fcecee34fcc20a98cd50d333c018 100644 --- a/source/RobotAPI/libraries/armem/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem/CMakeLists.txt @@ -36,6 +36,7 @@ set(LIB_FILES core/base/detail/MemoryContainerBase.cpp core/base/detail/EntityContainerBase.cpp core/base/detail/AronTyped.cpp + core/base/detail/iteration_mixins.cpp core/base/CoreSegmentBase.cpp core/base/EntityBase.cpp @@ -154,6 +155,7 @@ set(LIB_HEADERS core/base/detail/MemoryContainerBase.h core/base/detail/EntityContainerBase.h core/base/detail/AronTyped.h + core/base/detail/iteration_mixins.h core/base/CoreSegmentBase.h core/base/EntityBase.h diff --git a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h index 1f4e285c88080d9c7191cda2b9790397ebeee8b6..61b227c3c0da4fde7bd307bfa827edea0438765b 100644 --- a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h +++ b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h @@ -7,6 +7,7 @@ #include "detail/AronTyped.h" #include "detail/EntityContainerBase.h" #include "detail/MaxHistorySize.h" +#include "detail/iteration_mixins.h" namespace armarx::armem::base @@ -19,7 +20,10 @@ namespace armarx::armem::base class CoreSegmentBase : public detail::EntityContainerBase<_ProviderSegmentT, typename _ProviderSegmentT::EntityT, _Derived>, public detail::MaxHistorySize, - public detail::AronTyped + public detail::AronTyped, + public detail::ForEachEntityInstanceMixin<_Derived>, + public detail::ForEachEntitySnapshotMixin<_Derived>, + public detail::ForEachEntityMixin<_Derived> { using Base = detail::EntityContainerBase<_ProviderSegmentT, typename _ProviderSegmentT::EntityT, _Derived>; @@ -50,6 +54,7 @@ namespace armarx::armem::base {} }; + public: CoreSegmentBase() @@ -75,6 +80,8 @@ namespace armarx::armem::base CoreSegmentBase& operator=(CoreSegmentBase&& other) = default; + // READ ACCESS + inline const std::string& name() const { return this->id().coreSegmentName; @@ -85,16 +92,6 @@ namespace armarx::armem::base } - inline const auto& providerSegments() const - { - return this->_container; - } - inline auto& providerSegments() - { - return this->_container; - } - - bool hasProviderSegment(const std::string& name) const { return this->_container.count(name) > 0; @@ -145,6 +142,43 @@ namespace armarx::armem::base } } + + // ITERATION + + /** + * @param func Function like: bool process(ProviderSegmentT& provSeg) + */ + template <class ProviderSegmentFunctionT> + bool forEachProviderSegment(ProviderSegmentFunctionT&& func) + { + return base::detail::forEachChildPair(this->_container, func); + } + /** + * @param func Function like: bool process(const ProviderSegmentT& provSeg) + */ + template <class ProviderSegmentFunctionT> + bool forEachProviderSegment(ProviderSegmentFunctionT&& func) const + { + return base::detail::forEachChildPair(this->_container, func); + } + + // forEachEntity() is provided by ForEachEntityMixin. + // forEachEntitySnapshot() is provided by ForEachEntitySnapshotMixin. + // forEachEntityInstance() is provided by ForEachEntityInstanceMixin. + + + inline const auto& providerSegments() const + { + return this->_container; + } + inline auto& providerSegments() + { + return this->_container; + } + + + // MODIFICATION + /** * @brief Updates an entity's history. * @@ -262,6 +296,9 @@ namespace armarx::armem::base } } + + // MISC + virtual bool equalsDeep(const CoreSegmentBase& other) const { //std::cout << "CoreSegment::equalsDeep" << std::endl; diff --git a/source/RobotAPI/libraries/armem/core/base/EntityBase.h b/source/RobotAPI/libraries/armem/core/base/EntityBase.h index 5ebb9844ec2110ef26b4901679a7542add16c103..4fe586cc309520494fd8443ef1f28f1cfe010229 100644 --- a/source/RobotAPI/libraries/armem/core/base/EntityBase.h +++ b/source/RobotAPI/libraries/armem/core/base/EntityBase.h @@ -13,6 +13,7 @@ #include "EntitySnapshotBase.h" #include "detail/MaxHistorySize.h" #include "detail/MemoryContainerBase.h" +#include "detail/iteration_mixins.h" namespace armarx::armem::base @@ -40,7 +41,8 @@ namespace armarx::armem::base template <class _EntitySnapshotT, class _Derived> class EntityBase : public detail::MemoryContainerBase<std::map<Time, _EntitySnapshotT>, _Derived>, - public detail::MaxHistorySize + public detail::MaxHistorySize, + public detail::ForEachEntityInstanceMixin<_Derived> { using Base = detail::MemoryContainerBase<std::map<Time, _EntitySnapshotT>, _Derived>; @@ -82,27 +84,7 @@ namespace armarx::armem::base EntityBase& operator=(EntityBase&& other) = default; - virtual bool equalsDeep(const EntityBase& other) const - { - //std::cout << "Entity::equalsDeep" << std::endl; - if (this->size() != other.size()) - { - return false; - } - for (const auto& [key, snapshot] : this->_container) - { - if (not other.hasSnapshot(key)) - { - return false; - } - if (not snapshot.equalsDeep(other.getSnapshot(key))) - { - return false; - } - } - return true; - } - + // READING inline const std::string& name() const { @@ -113,17 +95,6 @@ namespace armarx::armem::base return const_cast<std::string&>(const_cast<const EntityBase*>(this)->name()); } - - inline const ContainerT& history() const - { - return this->_container; - } - inline ContainerT& history() - { - return const_cast<ContainerT&>(const_cast<const EntityBase*>(this)->history()); - } - - /** * @brief Indicates whether a history entry for the given time exists. */ @@ -354,6 +325,39 @@ namespace armarx::armem::base } + // ITERATION + + /** + * @param func Function like: bool process(EntitySnapshotT& snapshot) + */ + template <class SnapshotFunctionT> + bool forEachEntitySnapshot(SnapshotFunctionT&& func) + { + return base::detail::forEachChildPair(this->_container, func); + } + /** + * @param func Function like void process(const EntitySnapshotT& snapshot) + */ + template <class SnapshotFunctionT> + bool forEachEntitySnapshot(SnapshotFunctionT&& func) const + { + return base::detail::forEachChildPair(this->_container, func); + } + // forEachEntityInstance() is provided by ForEachEntityInstanceMixin. + + + inline const ContainerT& history() const + { + return this->_container; + } + inline ContainerT& history() + { + return const_cast<ContainerT&>(const_cast<const EntityBase*>(this)->history()); + } + + + // MODIFICATION + /** * @brief Add the given update to this entity's history. * @param update The update. @@ -440,6 +444,30 @@ namespace armarx::armem::base truncate(); } + + // MISC + + virtual bool equalsDeep(const EntityBase& other) const + { + //std::cout << "Entity::equalsDeep" << std::endl; + if (this->size() != other.size()) + { + return false; + } + for (const auto& [key, snapshot] : this->_container) + { + if (not other.hasSnapshot(key)) + { + return false; + } + if (not snapshot.equalsDeep(other.getSnapshot(key))) + { + return false; + } + } + return true; + } + std::string getKeyString() const { return this->id().entityName; diff --git a/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h b/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h index eaa9ca810e46d2cbf5ccb1912b8954a8ebfc7c37..0d9a6ffdca8e15c3164797be76087cb5cae0052f 100644 --- a/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h +++ b/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h @@ -8,6 +8,7 @@ #include "EntityInstanceBase.h" #include "detail/MemoryContainerBase.h" +#include "detail/iteration_mixins.h" namespace armarx::armem::base @@ -49,24 +50,7 @@ namespace armarx::armem::base EntitySnapshotBase& operator=(EntitySnapshotBase&& other) = default; - bool equalsDeep(const EntitySnapshotBase& other) const - { - //std::cout << "EntitySnapshot::equalsDeep" << std::endl; - if (this->size() != other.size()) - { - return false; - } - int i = 0; - for (const auto& instance : this->_container) - { - if (not instance.equalsDeep(other.getInstance(i))) - { - return false; - } - i++; - } - return true; - } + // READING inline Time& time() { @@ -78,34 +62,6 @@ namespace armarx::armem::base return this->id().timestamp; } - - inline const std::vector<EntityInstanceT>& instances() const - { - return this->_container; - } - inline std::vector<EntityInstanceT>& instances() - { - return const_cast<std::vector<EntityInstanceT>&>(const_cast<const EntitySnapshotBase*>(this)->instances()); - } - - - void update(const EntityUpdate& update, std::optional<MemoryID> parentID = std::nullopt) - { - if (parentID) - { - this->id() = *parentID; - } - time() = update.timeCreated; - - this->_container.clear(); - for (int i = 0; i < int(update.instancesData.size()); ++i) - { - EntityInstanceT& data = this->_container.emplace_back(i, this->id()); - data.update(update, i); - } - } - - bool hasInstance(int index) const { size_t si = size_t(index); @@ -157,6 +113,53 @@ namespace armarx::armem::base } + // ITERATION + + /** + * @param func Function like void process(EntityInstanceT& instance)> + */ + template <class InstanceFunctionT> + bool forEachEntityInstance(InstanceFunctionT&& func) + { + return base::detail::forEachChildSingle(this->_container, func); + } + /** + * @param func Function like void process (const EntityInstanceT& instance) + */ + template <class InstanceFunctionT> + bool forEachEntityInstance(InstanceFunctionT&& func) const + { + return base::detail::forEachChildSingle(this->_container, func); + } + + inline const std::vector<EntityInstanceT>& instances() const + { + return this->_container; + } + inline std::vector<EntityInstanceT>& instances() + { + return const_cast<std::vector<EntityInstanceT>&>(const_cast<const EntitySnapshotBase*>(this)->instances()); + } + + + // MODIFICATION + + void update(const EntityUpdate& update, std::optional<MemoryID> parentID = std::nullopt) + { + if (parentID) + { + this->id() = *parentID; + } + time() = update.timeCreated; + + this->_container.clear(); + for (int i = 0; i < int(update.instancesData.size()); ++i) + { + EntityInstanceT& data = this->_container.emplace_back(i, this->id()); + data.update(update, i); + } + } + /** * @brief Add a single instance with data. * @param instance The instance. @@ -196,6 +199,29 @@ namespace armarx::armem::base return it; } + + // MISC + + bool equalsDeep(const EntitySnapshotBase& other) const + { + //std::cout << "EntitySnapshot::equalsDeep" << std::endl; + if (this->size() != other.size()) + { + return false; + } + int i = 0; + for (const auto& instance : this->_container) + { + if (not instance.equalsDeep(other.getInstance(i))) + { + return false; + } + i++; + } + return true; + } + + std::string getKeyString() const { return toDateTimeMilliSeconds(this->time()); diff --git a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h index 7c00ec9a3fe3d51ef3fff1aec3973b0ce25934f2..271f2bf9f5b0ef44b69c062a7bdbb0e826b8bd2c 100644 --- a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h +++ b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h @@ -7,6 +7,7 @@ #include "CoreSegmentBase.h" #include "detail/EntityContainerBase.h" +#include "detail/iteration_mixins.h" namespace armarx::armem::base @@ -17,7 +18,11 @@ namespace armarx::armem::base */ template <class _CoreSegmentT, class _Derived> class MemoryBase : - public detail::EntityContainerBase<_CoreSegmentT, typename _CoreSegmentT::ProviderSegmentT::EntityT, _Derived> + public detail::EntityContainerBase<_CoreSegmentT, typename _CoreSegmentT::ProviderSegmentT::EntityT, _Derived>, + public detail::ForEachEntityInstanceMixin<_Derived>, + public detail::ForEachEntitySnapshotMixin<_Derived>, + public detail::ForEachEntityMixin<_Derived>, + public detail::ForEachProviderSegmentMixin<_Derived> { using Base = detail::EntityContainerBase<_CoreSegmentT, typename _CoreSegmentT::ProviderSegmentT::EntityT, _Derived>; @@ -72,6 +77,8 @@ namespace armarx::armem::base MemoryBase& operator=(MemoryBase&& other) = default; + // READ ACCESS + inline const std::string& name() const { return this->id().memoryName; @@ -82,16 +89,6 @@ namespace armarx::armem::base } - inline auto& coreSegments() const - { - return this->_container; - } - inline auto& coreSegments() - { - return this->_container; - } - - bool hasCoreSegment(const std::string& name) const { return this->_container.count(name) > 0; @@ -167,6 +164,44 @@ namespace armarx::armem::base } } + + // ITERATION + + /** + * @param func Function like: bool process(CoreSegmentT& provSeg) + */ + template <class CoreSegmentFunctionT> + bool forEachCoreSegment(CoreSegmentFunctionT&& func) + { + return base::detail::forEachChildPair(this->_container, func); + } + /** + * @param func Function like: bool process(const CoreSegmentT& provSeg) + */ + template <class CoreSegmentFunctionT> + bool forEachCoreSegment(CoreSegmentFunctionT&& func) const + { + return base::detail::forEachChildPair(this->_container, func); + } + + // forEachProviderSegment() is provided by ForEachProviderSegmentMixin. + // forEachEntity() is provided by ForEachEntityMixin. + // forEachEntitySnapshot() is provided by ForEachEntitySnapshotMixin. + // forEachEntityInstance() is provided by ForEachEntityInstanceMixin. + + + inline auto& coreSegments() const + { + return this->_container; + } + inline auto& coreSegments() + { + return this->_container; + } + + + // MODIFICATION + /** * @brief Add an empty core segment with the given name. * @param name The core segment name. diff --git a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h index 62777c78d0711f2540978fb7a01e1ce17eaefca8..a09fda41f17e345e1842cc991717c40e2e8bc731 100644 --- a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h +++ b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h @@ -7,6 +7,7 @@ #include "detail/AronTyped.h" #include "detail/EntityContainerBase.h" #include "detail/MaxHistorySize.h" +#include "detail/iteration_mixins.h" namespace armarx::armem::base @@ -19,7 +20,9 @@ namespace armarx::armem::base class ProviderSegmentBase : public detail::EntityContainerBase<_EntityT, _EntityT, _Derived>, public detail::MaxHistorySize, - public detail::AronTyped + public detail::AronTyped, + public detail::ForEachEntityInstanceMixin<_Derived>, + public detail::ForEachEntitySnapshotMixin<_Derived> { using Base = detail::EntityContainerBase<_EntityT, _EntityT, _Derived>; @@ -73,6 +76,8 @@ namespace armarx::armem::base ProviderSegmentBase& operator=(ProviderSegmentBase&& other) = default; + // READ ACCESS + inline const std::string& name() const { return this->id().providerSegmentName; @@ -83,16 +88,6 @@ namespace armarx::armem::base } - inline const auto& entities() const - { - return this->_container; - } - inline auto& entities() - { - return this->_container; - } - - bool hasEntity(const std::string& name) const { return this->_container.count(name) > 0; @@ -137,6 +132,44 @@ namespace armarx::armem::base } } + + // ITERATION + + // All functors are taken as universal reference (F&&). + + /** + * @param func Function like: bool process(EntityT& entity) + */ + template <class EntityFunctionT> + bool forEachEntity(EntityFunctionT&& func) + { + return base::detail::forEachChildPair(this->_container, func); + } + /** + * @param func Function like: bool process(const EntityT& entity) + */ + template <class EntityFunctionT> + bool forEachEntity(EntityFunctionT&& func) const + { + return base::detail::forEachChildPair(this->_container, func); + } + + // forEachEntitySnapshot() is provided by ForEachEntitySnapshotMixin. + // forEachEntityInstance() is provided by ForEachEntityInstanceMixin. + + + inline const ContainerT& entities() const + { + return this->_container; + } + inline ContainerT& entities() + { + return this->_container; + } + + + // MODIFICATION + /** * @brief Updates an entity's history. * @@ -221,6 +254,8 @@ namespace armarx::armem::base } + // MISC + virtual bool equalsDeep(const ProviderSegmentBase& other) const { //std::cout << "ProviderSegment::equalsDeep" << std::endl;