From 11298761662869197868a1ae0bfe3074de40df9d Mon Sep 17 00:00:00 2001 From: Rainer Kartmann <rainer.kartmann@kit.edu> Date: Wed, 11 Aug 2021 16:22:20 +0200 Subject: [PATCH] Fix max history size inheritance on adding children --- .../armem/core/base/CoreSegmentBase.h | 21 ++++----- .../libraries/armem/core/base/MemoryBase.h | 43 +++++++------------ .../armem/core/base/ProviderSegmentBase.h | 22 +++++++--- .../core/base/detail/MemoryContainerBase.h | 22 ++++++++++ .../armem/server/wm/detail/MaxHistorySize.h | 2 - .../armem/server/wm/memory_definitions.h | 21 +++++++-- .../libraries/armem/test/ArMemMemoryTest.cpp | 5 ++- 7 files changed, 84 insertions(+), 52 deletions(-) diff --git a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h index 1cc0a66fd..aa3a1c903 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 dc1ced897..e73db7d84 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 27dae3122..ba9b091a3 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 4d7cbec18..3e22caa31 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 e2f2d498c..962179a68 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 4eb6fdbb3..0849a9b58 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 376f2ec68..143577fc3 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); } } -- GitLab