diff --git a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h index 1cc0a66fdd4f296771b67d8bb558adf5d1cad9a1..aa3a1c903433d233747287cf9218e5a8b70d2e35 100644 --- a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h +++ b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h @@ -272,27 +272,28 @@ namespace armarx::armem::base ProviderSegmentT& addProviderSegment(const std::string& name, aron::typenavigator::ObjectNavigatorPtr providerSegmentType = nullptr) { aron::typenavigator::ObjectNavigatorPtr type = providerSegmentType ? providerSegmentType : this->aronType(); - return addProviderSegment(ProviderSegmentT(name, this->id(), type)); + return this->_derived().addProviderSegment(name, name, type); } /// Copy and insert a provider segment. ProviderSegmentT& addProviderSegment(const ProviderSegmentT& providerSegment) { - return addProviderSegment(ProviderSegmentT(providerSegment)); + return this->_derived().addProviderSegment(providerSegment.name(), ProviderSegmentT(providerSegment)); } /// Move and insert a provider segment. ProviderSegmentT& addProviderSegment(ProviderSegmentT&& providerSegment) { - if (hasProviderSegment(providerSegment.name())) - { - throw armem::error::ContainerEntryAlreadyExists( - ProviderSegmentT::getLevelName(), providerSegment.name(), getLevelName(), this->getKeyString()); - } + return this->_derived().addProviderSegment(providerSegment.name(), std::move(providerSegment)); + } - auto it = this->_container.emplace(providerSegment.name(), std::move(providerSegment)).first; - it->second.id().setCoreSegmentID(this->id()); - return it->second; + /// Insert a provider segment in-place. + template <class ...Args> + ProviderSegmentT& addProviderSegment(const std::string& name, Args... args) + { + ChildT& child = this->template _addChild<ChildT>(name, args...); + child.id() = this->id().withProviderSegmentName(name); + return child; } diff --git a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h index dc1ced89727c29b73fbe1da9db30c9a0df711f9b..e73db7d84b1b09c12ff435d727aea49d780c5ef3 100644 --- a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h +++ b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h @@ -211,17 +211,28 @@ namespace armarx::armem::base CoreSegmentT& addCoreSegment( const std::string& name, aron::typenavigator::ObjectNavigatorPtr coreSegmentType = nullptr) { - return _addCoreSegment(name, name, this->id(), coreSegmentType); + return this->_derived().addCoreSegment(name, name, coreSegmentType); } + /// Copy and insert a core segment. CoreSegmentT& addCoreSegment(const CoreSegmentT& coreSegment) { - return _addCoreSegment(coreSegment.name(), CoreSegmentT(coreSegment)); + return this->_derived().addCoreSegment(coreSegment.name(), CoreSegmentT(coreSegment)); } + /// Move and insert a core segment. CoreSegmentT& addCoreSegment(CoreSegmentT&& coreSegment) { - return _addCoreSegment(coreSegment.name(), coreSegment); + return this->_derived().addCoreSegment(coreSegment.name(), std::move(coreSegment)); + } + + /// Move and insert a core segment. + template <class ...Args> + CoreSegmentT& addCoreSegment(const std::string& name, Args... args) + { + CoreSegmentT& child = this->template _addChild<ChildT>(name, args...); + child.id() = this->id().withCoreSegmentName(name); + return child; } @@ -317,31 +328,7 @@ namespace armarx::armem::base } - private: - - /** - * This function allows to emplace a CoreSegment directly in the - * container from its constructor arguments, instead of constructing - * it outside and moving it. - * This is necessary if CoreSegmentT is not movable. - */ - template <class ...Args> - CoreSegmentT& _addCoreSegment(const std::string& name, Args... args) - { - auto [it, inserted] = this->_container.try_emplace(name, args...); - if (not inserted) - { - throw armem::error::ContainerEntryAlreadyExists( - CoreSegmentT::getLevelName(), name, DerivedT::getLevelName(), this->name()); - } - else - { - it->second.id().setMemoryID(this->id()); - it->second.id().coreSegmentName = name; - return it->second; - } - } - + protected: std::pair<bool, CoreSegmentT*> _addCoreSegmentIfMissing(const std::string& coreSegmentName) { diff --git a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h index 27dae3122cb2e4a642013386532681901e3c978d..ba9b091a3c00653c2a80298461e58bdd2e39d998 100644 --- a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h +++ b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h @@ -229,7 +229,7 @@ namespace armarx::armem::base return ret; } - void append(const _Derived& m) + void append(const DerivedT& m) { // ARMARX_INFO << "ProviderSegment: Merge name '" << m.name() << "' into '" << name() << "'"; @@ -245,22 +245,32 @@ namespace armarx::armem::base }); } + /// Add an empty entity with the given name. EntityT& addEntity(const std::string& name) { - return addEntity(EntityT(name, this->id())); + return this->_derived().addEntity(name, name); } + /// Copy and insert an entity. EntityT& addEntity(const EntityT& entity) { - return addEntity(EntityT(entity)); + return this->_derived().addEntity(entity.name(), EntityT(entity)); } + /// Move and insert an entity. EntityT& addEntity(EntityT&& entity) { - auto it = this->_container.emplace(entity.name(), std::move(entity)).first; - it->second.id().setProviderSegmentID(this->id()); - return it->second; + return this->_derived().addEntity(entity.name(), std::move(entity)); + } + + /// Insert an entity in-place. + 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; } diff --git a/source/RobotAPI/libraries/armem/core/base/detail/MemoryContainerBase.h b/source/RobotAPI/libraries/armem/core/base/detail/MemoryContainerBase.h index 4d7cbec1877176f511e854eeefa60a9d6159aded..3e22caa31456c6a2afab30a721d064bb661427f5 100644 --- a/source/RobotAPI/libraries/armem/core/base/detail/MemoryContainerBase.h +++ b/source/RobotAPI/libraries/armem/core/base/detail/MemoryContainerBase.h @@ -108,6 +108,15 @@ namespace armarx::armem::base::detail return _container; } + DerivedT& _derived() + { + return static_cast<DerivedT&>(*this); + } + const DerivedT& _derived() const + { + return static_cast<DerivedT&>(*this); + } + /** * @throw `armem::error::ContainerNameMismatch` if `gottenName` does not match `actualName`. @@ -123,6 +132,19 @@ namespace armarx::armem::base::detail } + template <class ChildT, class KeyT, class ...ChildArgs> + ChildT& _addChild(const KeyT& key, ChildArgs... childArgs) + { + auto [it, inserted] = this->_container.try_emplace(key, childArgs...); + if (not inserted) + { + throw armem::error::ContainerEntryAlreadyExists( + ChildT::getLevelName(), key, DerivedT::getLevelName(), this->_derived().name()); + } + return it->second; + } + + protected: mutable ContainerT _container; diff --git a/source/RobotAPI/libraries/armem/server/wm/detail/MaxHistorySize.h b/source/RobotAPI/libraries/armem/server/wm/detail/MaxHistorySize.h index e2f2d498c2945f4456c281abafe0f1ad66074e72..962179a68aeb601dc261eb6d496389295597a2ea 100644 --- a/source/RobotAPI/libraries/armem/server/wm/detail/MaxHistorySize.h +++ b/source/RobotAPI/libraries/armem/server/wm/detail/MaxHistorySize.h @@ -1,6 +1,5 @@ #pragma once - namespace armarx::armem::server::detail { // TODO: Replace by ConstrainedHistorySize (not only max entries, e.g. delete oldest / delete least accessed / ...) @@ -50,7 +49,6 @@ namespace armarx::armem::server::detail static_cast<DerivedT&>(*this).forEachChild([maxSize](auto & child) { child.setMaxHistorySize(maxSize); - return true; }); } diff --git a/source/RobotAPI/libraries/armem/server/wm/memory_definitions.h b/source/RobotAPI/libraries/armem/server/wm/memory_definitions.h index 4eb6fdbb3105b0ae2ce3148c8457b915040a170a..0849a9b582e44b7f7c1e20942232a323fa1b4012 100644 --- a/source/RobotAPI/libraries/armem/server/wm/memory_definitions.h +++ b/source/RobotAPI/libraries/armem/server/wm/memory_definitions.h @@ -26,8 +26,8 @@ namespace armarx::armem::server::wm /// @see base::EntityBase class Entity : - public base::EntityBase<EntitySnapshot, Entity>, - public detail::MaxHistorySize + public base::EntityBase<EntitySnapshot, Entity> + , public detail::MaxHistorySize { public: @@ -64,7 +64,14 @@ namespace armarx::armem::server::wm using ProviderSegmentBase::addEntity; - EntityT& addEntity(EntityT&& entity); + + template <class ...Args> + Entity& addEntity(const std::string& name, Args... args) + { + Entity& added = ProviderSegmentBase::addEntity(name, args...); + added.setMaxHistorySize(this->getMaxHistorySize()); + return added; + } }; @@ -115,7 +122,13 @@ namespace armarx::armem::server::wm /// @see base::CoreSegmentBase::addProviderSegment() using CoreSegmentBase::addProviderSegment; - ProviderSegment& addProviderSegment(ProviderSegment&& providerSegment); + template <class ...Args> + ProviderSegment& addProviderSegment(const std::string& name, Args... args) + { + ProviderSegmentT& added = CoreSegmentBase::addProviderSegment(name, args...); + added.setMaxHistorySize(this->getMaxHistorySize()); + return added; + } // Locking interface diff --git a/source/RobotAPI/libraries/armem/test/ArMemMemoryTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemMemoryTest.cpp index 376f2ec680f92e64a5c72b496543749a303e8cc1..143577fc3303aec2e73c5e7bd6f2c2d7226bc3fd 100644 --- a/source/RobotAPI/libraries/armem/test/ArMemMemoryTest.cpp +++ b/source/RobotAPI/libraries/armem/test/ArMemMemoryTest.cpp @@ -753,7 +753,7 @@ BOOST_AUTO_TEST_CASE(test_history_size_in_provider_segment) std::vector<std::string> entityNames = { "A", "B" }; // Fill entities and histories with unlimited size. - for (const auto& name : entityNames) + for (const std::string& name : entityNames) { update.entityID.entityName = name; @@ -805,11 +805,12 @@ BOOST_AUTO_TEST_CASE(test_history_size_in_provider_segment) providerSegment.setMaxHistorySize(-1); entityNames.push_back("C"); - for (const auto& name : entityNames) + for (const std::string& name : entityNames) { update.entityID.entityName = name; update.timeCreated = armem::Time::milliSeconds(5000); providerSegment.update(update); + BOOST_CHECK_EQUAL(providerSegment.getEntity(name).getMaxHistorySize(), -1); BOOST_CHECK_EQUAL(providerSegment.getEntity(name).size(), 3); } }