From 293afef54060ca0c082f750d7b561e2a74a3108a Mon Sep 17 00:00:00 2001
From: Rainer Kartmann <rainer.kartmann@kit.edu>
Date: Wed, 4 Aug 2021 18:24:09 +0200
Subject: [PATCH] Fix bugs, depr. warnings, tests, etc

---
 .../armem/core/base/CoreSegmentBase.h         |   8 +-
 .../libraries/armem/core/base/EntityBase.h    | 130 +++++---------
 .../armem/core/base/EntityInstanceBase.h      |   2 +-
 .../armem/core/base/EntitySnapshotBase.h      |  48 +++--
 .../libraries/armem/core/base/MemoryBase.h    |  30 ++--
 .../armem/core/base/ProviderSegmentBase.h     |   5 +-
 .../armem/core/diskmemory/CoreSegment.cpp     |  13 +-
 .../armem/core/diskmemory/Entity.cpp          |  11 +-
 .../armem/core/diskmemory/EntityInstance.cpp  |   6 +-
 .../armem/core/diskmemory/EntityInstance.h    |   2 +-
 .../armem/core/diskmemory/Memory.cpp          |  14 +-
 .../armem/core/diskmemory/ProviderSegment.cpp |  14 +-
 .../armem/core/longtermmemory/Entity.cpp      |  24 +--
 .../core/longtermmemory/EntityInstance.cpp    |   6 +-
 .../core/longtermmemory/EntityInstance.h      |   2 +-
 .../core/longtermmemory/EntitySnapshot.cpp    |   8 +-
 .../armem/core/longtermmemory/Memory.cpp      |  12 +-
 .../core/longtermmemory/ProviderSegment.cpp   |  16 +-
 .../core/workingmemory/EntityInstance.cpp     |   8 +-
 .../armem/core/workingmemory/EntityInstance.h |   2 +-
 .../armem/core/workingmemory/EntitySnapshot.h |   9 +-
 .../core/workingmemory/visitor/Visitor.cpp    | 110 ++++--------
 .../base/CoreSegmentQueryProcessorBase.h      |  11 +-
 .../base/EntityQueryProcessorBase.h           |  32 ++--
 .../libraries/armem/test/ArMemForEachTest.cpp | 170 ++++++++++++++++++
 .../armem/test/ArMemIceConversionsTest.cpp    |   4 +-
 .../libraries/armem/test/ArMemMemoryTest.cpp  |  46 +++--
 .../libraries/armem/test/ArMemQueryTest.cpp   |  59 +++---
 .../libraries/armem/test/CMakeLists.txt       |   1 +
 .../libraries/armem_gui/test/ArMemGuiTest.cpp |  12 +-
 30 files changed, 476 insertions(+), 339 deletions(-)
 create mode 100644 source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp

diff --git a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h
index bdde3f1c8..4ec1df3d1 100644
--- a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h
@@ -61,11 +61,11 @@ namespace armarx::armem::base
         {
         }
         explicit CoreSegmentBase(const std::string& name, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) :
-            CoreSegmentBase(MemoryID().withCoreSegmentName(name), aronType)
+            CoreSegmentBase(name, MemoryID(), aronType)
         {
         }
         explicit CoreSegmentBase(const std::string& name, const MemoryID& parentID, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) :
-            CoreSegmentBase(parentID.withProviderSegmentName(name), aronType)
+            CoreSegmentBase(parentID.withCoreSegmentName(name), aronType)
         {
         }
         explicit CoreSegmentBase(const MemoryID& id, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) :
@@ -221,7 +221,7 @@ namespace armarx::armem::base
                 }
                 else
                 {
-                    throw error::MissingEntry::create<EntitySnapshotT>(providerSegmentName, *this);
+                    throw error::MissingEntry::create<ProviderSegmentT>(providerSegmentName, *this);
                 }
             }
             else
@@ -256,7 +256,7 @@ 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, type));
+            return addProviderSegment(ProviderSegmentT(name, this->id(), type));
         }
 
         /// Copy and insert a provider segment.
diff --git a/source/RobotAPI/libraries/armem/core/base/EntityBase.h b/source/RobotAPI/libraries/armem/core/base/EntityBase.h
index 715696465..64b13c7e4 100644
--- a/source/RobotAPI/libraries/armem/core/base/EntityBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/EntityBase.h
@@ -98,7 +98,7 @@ namespace armarx::armem::base
         /**
          * @brief Indicates whether a history entry for the given time exists.
          */
-        virtual bool hasSnapshot(const Time& time)
+        bool hasSnapshot(const Time& time)
         {
             return const_cast<const EntityBase*>(this)->hasSnapshot(time);
         }
@@ -125,11 +125,6 @@ namespace armarx::armem::base
         /**
          * @brief Get all timestamps in the history.
          */
-        virtual std::vector<Time> getTimestamps()
-        {
-            return const_cast<const EntityBase*>(this)->getTimestamps();
-        }
-
         virtual std::vector<Time> getTimestamps() const
         {
             return simox::alg::get_keys(this->_container);
@@ -143,7 +138,7 @@ namespace armarx::armem::base
          *
          * @throws `armem::error::MissingEntry` If there is no such entry.
          */
-        virtual EntitySnapshotT& getSnapshot(const Time& time)
+        EntitySnapshotT& getSnapshot(const Time& time)
         {
             return const_cast<EntitySnapshotT&>(const_cast<const EntityBase*>(this)->getSnapshot(time));
         }
@@ -194,30 +189,9 @@ namespace armarx::armem::base
          * @throw `armem::error::EntityHistoryEmpty` If the history is empty.
          * @throw `armem::error::MissingEntry` If no such snapshot
          */
-        virtual const EntitySnapshotT& getLatestSnapshotBeforeOrAt(const Time& time) const
+        const EntitySnapshotT& getLatestSnapshotBeforeOrAt(const Time& time) const
         {
-            // first element equal or greater
-            typename ContainerT::const_iterator refIt = this->_container.upper_bound(time);
-
-            if (refIt == this->_container.begin())
-            {
-                if (refIt->first == time)
-                {
-                    return refIt->second;
-                }
-                throw error::MissingEntry::create<EntitySnapshotT>(toDateTimeMilliSeconds(time), *this);
-            }
-
-            // last element less than
-            typename ContainerT::const_iterator refItPrev = std::prev(refIt);
-
-            // ... or we return the element before if possible
-            if (refItPrev != this->_container.begin())
-            {
-                return refItPrev->second;
-            }
-
-            throw error::MissingEntry::create<EntitySnapshotT>(toDateTimeMilliSeconds(time), *this);
+            return getLatestSnapshotBefore(time + Time::microSeconds(1));
         }
 
         /**
@@ -227,51 +201,65 @@ namespace armarx::armem::base
          * @throw `armem::error::EntityHistoryEmpty` If the history is empty.
          * @throw `armem::error::MissingEntry` If no such snapshot
          */
-        virtual const EntitySnapshotT& getLatestSnapshotBefore(const Time& time) const
+        const EntitySnapshotT& getLatestSnapshotBefore(const Time& time) const
         {
-            // first element equal or greater
-            typename ContainerT::const_iterator refIt = this->_container.upper_bound(time);
+            if (this->empty())
+            {
+                throw error::EntityHistoryEmpty(this->name());
+            }
 
-            if (refIt == this->_container.begin())
+            // We want the rightmost element < time
+            // lower_bound() gives us the the leftmost >= time, which is probably the right neighbour
+            typename ContainerT::const_iterator greaterEq = this->_container.lower_bound(time);
+            // Special cases:
+            // refIt = begin() => no element < time
+            if (greaterEq == this->_container.begin())
             {
                 throw error::MissingEntry::create<EntitySnapshotT>(toDateTimeMilliSeconds(time), *this);
             }
 
-            // last element less than
-            typename ContainerT::const_iterator refItPrev = std::prev(refIt);
+            // end(): No element >= time, we can still have one < time (rbegin()) => std::prev(end())
+            // empty has been checked above
 
-            // we return the element before if possible
-            if (refItPrev != this->_container.begin())
-            {
-                return refItPrev->second;
-            }
+            // std::prev of end() is ok
+            typename ContainerT::const_iterator less = std::prev(greaterEq);
 
-            throw error::MissingEntry::create<EntitySnapshotT>(toDateTimeMilliSeconds(time), *this);
+            // we return the element before if possible
+            return less->second;
         }
 
         /**
-         * @brief Return all snapshots before or at time.
+         * @brief Return all snapshots before (excluding) time.
          * @param time The time.
          * @return The latest snapshots.
-         * @throw `armem::error::EntityHistoryEmpty` If the history is empty.
-         * @throw `armem::error::MissingEntry` If no such snapshots
          */
-        virtual const std::vector<std::reference_wrapper<const EntitySnapshotT>> getSnapshotsBefore(const Time& time) const
+        std::vector<std::reference_wrapper<const EntitySnapshotT>>
+                getSnapshotsBefore(const Time& time) const
         {
             std::vector<std::reference_wrapper<const EntitySnapshotT>> ret;
-            const EntitySnapshotT& latest = getLatestSnapshotBefore(time);
-
             for (const auto& [timestamp, snapshot] : this->_container)
             {
-                ret.emplace_back(snapshot);
-                if (timestamp == latest.id().timestamp)
+                if (timestamp >= time)
                 {
                     break;
                 }
+                ret.emplace_back(snapshot);
             }
             return ret;
         }
 
+        /**
+         * @brief Return all snapshots before or at time.
+         * @param time The time.
+         * @return The latest snapshots.
+         */
+        std::vector<std::reference_wrapper<const EntitySnapshotT>>
+                getSnapshotsBeforeOrAt(const Time& time) const
+        {
+            return getSnapshotsBefore(time + Time::microSeconds(1));
+        }
+
+
         /**
          * @brief Return first snapshot after or at time.
          * @param time The time.
@@ -279,16 +267,17 @@ namespace armarx::armem::base
          * @throw `armem::error::EntityHistoryEmpty` If the history is empty.
          * @throw `armem::error::MissingEntry` If no such snapshot
          */
-        virtual const EntitySnapshotT& getFirstSnapshotAfterOrAt(const Time& time) const
+        const EntitySnapshotT& getFirstSnapshotAfterOrAt(const Time& time) const
         {
-            // first element equal or greater
-            typename ContainerT::const_iterator refIt = this->_container.upper_bound(time);
+            // We want the leftmost element >= time.
+            // That's lower bound.
+            typename ContainerT::const_iterator greaterEq = this->_container.lower_bound(time);
 
-            if (refIt == this->_container.end())
+            if (greaterEq == this->_container.end())
             {
                 throw error::MissingEntry::create<EntitySnapshotT>(toDateTimeMilliSeconds(time), *this);
             }
-            return refIt->second;
+            return greaterEq->second;
         }
 
         /**
@@ -298,30 +287,9 @@ namespace armarx::armem::base
          * @throw `armem::error::EntityHistoryEmpty` If the history is empty.
          * @throw `armem::error::MissingEntry` If no such snapshot
          */
-        virtual const EntitySnapshotT& getFirstSnapshotAfter(const Time& time) const
+        const EntitySnapshotT& getFirstSnapshotAfter(const Time& time) const
         {
-            // first element equal or greater
-            typename ContainerT::const_iterator refIt = this->_container.upper_bound(time);
-
-            if (refIt == this->_container.end())
-            {
-                throw error::MissingEntry::create<EntitySnapshotT>(toDateTimeMilliSeconds(time), *this);
-            }
-
-            if (refIt->first > time)
-            {
-                return refIt->second;
-            }
-
-            // first element greater than
-            typename ContainerT::const_iterator refItNext = std::next(refIt);
-
-            if (refItNext != this->_container.end())
-            {
-                return refItNext->second;
-            }
-
-            throw error::MissingEntry::create<EntitySnapshotT>(toDateTimeMilliSeconds(time), *this);
+            return getFirstSnapshotAfter(time - Time::microSeconds(1));
         }
 
 
@@ -386,7 +354,7 @@ namespace armarx::armem::base
                 ret.entityUpdateType = UpdateType::UpdatedExisting;
             }
             // Update entry.
-            snapshot->update(update, this->id());
+            snapshot->update(update);
             ret.id = snapshot->id();
 
             return ret;
@@ -431,7 +399,7 @@ namespace armarx::armem::base
 
         EntitySnapshotT& addSnapshot(const Time& timestamp)
         {
-            return addSnapshot(EntitySnapshotT(timestamp));
+            return addSnapshot(EntitySnapshotT(timestamp, this->id()));
         }
 
 
@@ -449,7 +417,7 @@ namespace armarx::armem::base
 
         // MISC
 
-        virtual bool equalsDeep(const EntityBase& other) const
+        bool equalsDeep(const EntityBase& other) const
         {
             //std::cout << "Entity::equalsDeep" << std::endl;
             if (this->size() != other.size())
diff --git a/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h b/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h
index 4d92dffc0..c9689c182 100644
--- a/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/EntityInstanceBase.h
@@ -50,7 +50,7 @@ namespace armarx::armem::base
          * @param update The update.
          * @param index The instances index.
          */
-        virtual void update(const EntityUpdate& update, int index) = 0;
+        virtual void update(const EntityUpdate& update) = 0;
 
         virtual bool equalsDeep(const DerivedT& other) const = 0;
 
diff --git a/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h b/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h
index 00f996ca4..17c3eb576 100644
--- a/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/EntitySnapshotBase.h
@@ -94,6 +94,23 @@ namespace armarx::armem::base
             }
         }
 
+        EntityInstanceT* findInstance(int index)
+        {
+            return const_cast<EntityInstanceT*>(const_cast<const EntitySnapshotBase*>(this)->findInstance(index));
+        }
+        const EntityInstanceT* findInstance(int index) const
+        {
+            if (hasInstance(index))
+            {
+                return &this->_container[static_cast<size_t>(index)];
+            }
+            else
+            {
+                return nullptr;
+            }
+        }
+
+
         /**
          * @brief Get the given instance.
          * @param index The instance's index.
@@ -149,19 +166,15 @@ namespace armarx::armem::base
 
         // MODIFICATION
 
-        void update(const EntityUpdate& update, std::optional<MemoryID> parentID = std::nullopt)
+        void update(const EntityUpdate& update)
         {
-            if (parentID)
-            {
-                this->id() = *parentID;
-            }
-            time() = update.timeCreated;
+            detail::throwIfNotEqual(time(), update.timeCreated);
 
             this->_container.clear();
-            for (int i = 0; i < int(update.instancesData.size()); ++i)
+            for (int index = 0; index < int(update.instancesData.size()); ++index)
             {
-                EntityInstanceT& data = this->_container.emplace_back(i, this->id());
-                data.update(update, i);
+                EntityInstanceT& data = this->_container.emplace_back(index, this->id());
+                data.update(update);
             }
         }
 
@@ -189,19 +202,18 @@ namespace armarx::armem::base
                                              "Cannot add an EntityInstance because its index is too big.");
             }
 
-            int new_index = this->_container.size();
-            auto& it = this->_container.emplace_back(std::move(instance));
-            it.index() = new_index;
-            return it;
+            int index = static_cast<int>(this->_container.size());
+            EntityInstanceT& added = this->_container.emplace_back(std::move(instance));
+            added.id() = this->id().withInstanceIndex(index);
+            return added;
         }
 
         EntityInstanceT& addInstance()
         {
-            int new_index = this->_container.size();
-            auto& it = this->_container.emplace_back(EntityInstanceT());;
-            it.index() = new_index;
-            it.id() = this->id().withInstanceIndex(new_index);
-            return it;
+            int index = static_cast<int>(this->size());
+            EntityInstanceT& added = this->_container.emplace_back(EntityInstanceT());
+            added.id() = this->id().withInstanceIndex(index);
+            return added;
         }
 
 
diff --git a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
index 339022c01..c5cf1fb2f 100644
--- a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
@@ -212,7 +212,7 @@ namespace armarx::armem::base
          */
         CoreSegmentT& addCoreSegment(const std::string& name, aron::typenavigator::ObjectNavigatorPtr coreSegmentType = nullptr)
         {
-            return addCoreSegment(CoreSegmentT(name, coreSegmentType));
+            return addCoreSegment(CoreSegmentT(name, this->id(), coreSegmentType));
         }
         /// Copy and insert a core segment.
         CoreSegmentT& addCoreSegment(const CoreSegmentT& coreSegment)
@@ -263,7 +263,7 @@ namespace armarx::armem::base
         virtual std::vector<UpdateResult> update(const Commit& commit)
         {
             std::vector<UpdateResult> results;
-            for (const auto& update : commit.updates)
+            for (const EntityUpdate& update : commit.updates)
             {
                 results.push_back(this->update(update));
             }
@@ -309,7 +309,7 @@ namespace armarx::armem::base
                 }
                 else
                 {
-                    throw error::MissingEntry::create<EntitySnapshotT>(coreSegmentName, *this);
+                    throw error::MissingEntry::create<CoreSegmentT>(coreSegmentName, *this);
                 }
             }
             else
@@ -335,7 +335,6 @@ namespace armarx::armem::base
                     it = this->_container.emplace(coreSeg.name(), this->id().withCoreSegmentName(coreSeg.name())).first;
                 }
                 it->second.append(coreSeg);
-
                 return true;
             });
         }
@@ -374,19 +373,22 @@ namespace armarx::armem::base
         std::string dump() const
         {
             std::stringstream ss;
-            ss << "Memory: " << this->name() << "\n";
-            for (const auto& [ckey, cseg] : this->container())
+            ss << "Memory '" << this->name() << "': \n";
+            forEachCoreSegment([&ss](const CoreSegmentT & cseg)
             {
-                ss << " |- Found core seg: " << ckey << "\n";
-                for (const auto& [pkey, pseg] : cseg)
+                ss << "+- Core segment '" << cseg.name() << "' (" << cseg.size() << "): \n";
+                cseg.forEachProviderSegment([&ss](const ProviderSegmentT & pseg)
                 {
-                    ss << " |   |- Found prov seg: " << pkey << "\n";
-                    for (const auto& [ekey, eseg] : pseg)
+                    ss << "|  +- Provider segment '" << pseg.name() << "' (" << pseg.size() << "): \n";
+                    pseg.forEachEntity([&ss](const EntityT & entity)
                     {
-                        ss << " |   |   |- Found entity: " << ekey << "\n";
-                    }
-                }
-            }
+                        ss << "|  |  +- Entity '" << entity.name() << "' (" << entity.size() << "): \n";
+                        return true;
+                    });
+                    return true;
+                });
+                return true;
+            });
             return ss.str();
         }
 
diff --git a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h
index d5d2d4bf2..41d25fb28 100644
--- a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h
@@ -57,7 +57,7 @@ namespace armarx::armem::base
         }
 
         explicit ProviderSegmentBase(const std::string& name, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) :
-            ProviderSegmentBase(MemoryID().withProviderSegmentName(name), aronType)
+            ProviderSegmentBase(name, MemoryID(), aronType)
         {
         }
         explicit ProviderSegmentBase(const std::string& name, const MemoryID parentID, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr) :
@@ -215,13 +215,14 @@ namespace armarx::armem::base
                     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)
         {
-            return addEntity(EntityT(name));
+            return addEntity(EntityT(name, this->id()));
         }
         /// Copy and insert an entity.
         EntityT& addEntity(const EntityT& entity)
diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/CoreSegment.cpp b/source/RobotAPI/libraries/armem/core/diskmemory/CoreSegment.cpp
index b3fb28a54..204aa8f86 100644
--- a/source/RobotAPI/libraries/armem/core/diskmemory/CoreSegment.cpp
+++ b/source/RobotAPI/libraries/armem/core/diskmemory/CoreSegment.cpp
@@ -78,9 +78,9 @@ namespace armarx::armem::d_ltm
         std::filesystem::create_directories(_fullPath());
         TypeIO::writeAronType(_aronType, _fullPath());
 
-        for (const auto& [k, s] : m)
+        m.forEachProviderSegment([this](const wm::ProviderSegment & s)
         {
-            if (auto it = _container.find(k); it != _container.end())
+            if (auto it = _container.find(s.name()); it != _container.end())
             {
                 it->second.append(s);
             }
@@ -88,18 +88,19 @@ namespace armarx::armem::d_ltm
             {
                 try
                 {
-                    std::filesystem::create_directory(_fullPath() / k);
+                    std::filesystem::create_directory(_fullPath() / s.name());
                 }
                 catch (...)
                 {
                     ARMARX_WARNING << GetHandledExceptionString();
-                    return;
+                    return false;
                 }
 
-                auto wms = _container.emplace(k, id().withProviderSegmentName(k));
+                auto wms = _container.emplace(s.name(), id().withProviderSegmentName(s.name()));
                 wms.first->second.path = path;
                 wms.first->second.append(s);
             }
-        }
+            return true;
+        });
     }
 }
diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/Entity.cpp b/source/RobotAPI/libraries/armem/core/diskmemory/Entity.cpp
index daa61bc4a..c2e91a823 100644
--- a/source/RobotAPI/libraries/armem/core/diskmemory/Entity.cpp
+++ b/source/RobotAPI/libraries/armem/core/diskmemory/Entity.cpp
@@ -63,20 +63,21 @@ namespace armarx::armem::d_ltm
     void Entity::append(const wm::Entity& m)
     {
         std::filesystem::create_directories(_fullPath());
-        for (const auto& [k, s] : m)
+        m.forEachEntitySnapshot([this](const wm::EntitySnapshot & s)
         {
-            if (auto it = _container.find(k); it != _container.end())
+            if (auto it = _container.find(s.time()); it != _container.end())
             {
                 // timestamp already exists
                 // We assume that a snapshot does not change, so ignore
             }
             else
             {
-                std::filesystem::create_directory(_fullPath() / std::to_string(k.toMicroSeconds()));
-                auto wms = _container.emplace(std::make_pair(k, id().withTimestamp(k)));
+                std::filesystem::create_directory(_fullPath() / std::to_string(s.time().toMicroSeconds()));
+                auto wms = _container.emplace(std::make_pair(s.time(), id().withTimestamp(s.time())));
                 wms.first->second.path = path;
                 wms.first->second.setTo(s);
             }
-        }
+            return true;
+        });
     }
 }
diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.cpp b/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.cpp
index 5fbfa91d5..d22310fb2 100644
--- a/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.cpp
+++ b/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.cpp
@@ -28,11 +28,9 @@ namespace armarx::armem::d_ltm
 
 
 
-    void EntityInstance::update(const EntityUpdate& update, int index)
+    void EntityInstance::update(const EntityUpdate& update)
     {
-        ARMARX_CHECK_FITS_SIZE(index, update.instancesData.size());
-
-        this->index() = index;
+        ARMARX_CHECK_FITS_SIZE(this->index(), update.instancesData.size());
     }
 
 
diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.h b/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.h
index 54d3c4cb8..f8c14159e 100644
--- a/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.h
+++ b/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.h
@@ -33,7 +33,7 @@ namespace armarx::armem::d_ltm
          * @param update The update.
          * @param index The instances index.
          */
-        virtual void update(const EntityUpdate& update, int index) override;
+        virtual void update(const EntityUpdate& update) override;
 
         virtual bool equalsDeep(const EntityInstance& other) const override;
 
diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/Memory.cpp b/source/RobotAPI/libraries/armem/core/diskmemory/Memory.cpp
index 97871505a..3fc60e049 100644
--- a/source/RobotAPI/libraries/armem/core/diskmemory/Memory.cpp
+++ b/source/RobotAPI/libraries/armem/core/diskmemory/Memory.cpp
@@ -65,9 +65,9 @@ namespace armarx::armem::d_ltm
     void Memory::append(const wm::Memory& m)
     {
         std::filesystem::create_directories(_fullPath());
-        for (const auto& [k, s] : m)
+        m.forEachCoreSegment([this](const wm::CoreSegment & s) -> bool
         {
-            if (auto it = _container.find(k); it != _container.end())
+            if (auto it = _container.find(s.name()); it != _container.end())
             {
                 it->second.append(s);
             }
@@ -75,18 +75,20 @@ namespace armarx::armem::d_ltm
             {
                 try
                 {
-                    std::filesystem::create_directory(_fullPath() / k);
+                    std::filesystem::create_directory(_fullPath() / s.name());
                 }
                 catch (...)
                 {
                     ARMARX_WARNING << GetHandledExceptionString();
-                    return;
+                    return false;
                 }
 
-                auto wms = _container.emplace(k, id().withCoreSegmentName(k));
+                auto wms = _container.emplace(s.name(), id().withCoreSegmentName(s.name()));
                 wms.first->second.path = path;
                 wms.first->second.append(s);
             }
-        }
+
+            return true;
+        });
     }
 }
diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/ProviderSegment.cpp b/source/RobotAPI/libraries/armem/core/diskmemory/ProviderSegment.cpp
index 577417542..08ed0c2b0 100644
--- a/source/RobotAPI/libraries/armem/core/diskmemory/ProviderSegment.cpp
+++ b/source/RobotAPI/libraries/armem/core/diskmemory/ProviderSegment.cpp
@@ -95,9 +95,9 @@ namespace armarx::armem::d_ltm
 
         TypeIO::writeAronType(_aronType, _fullPath());
 
-        for (const auto& [k, s] : m)
+        m.forEachEntity([this](const wm::Entity & s)
         {
-            if (auto it = _container.find(k); it != _container.end())
+            if (auto it = _container.find(s.name()); it != _container.end())
             {
                 it->second.append(s);
             }
@@ -106,18 +106,20 @@ namespace armarx::armem::d_ltm
 
                 try
                 {
-                    std::filesystem::create_directory(_fullPath() / k);
+                    std::filesystem::create_directory(_fullPath() / s.name());
                 }
                 catch (...)
                 {
                     ARMARX_WARNING << GetHandledExceptionString();
-                    return;
+                    return false;
                 }
 
-                auto wms = _container.emplace(k, id().withEntityName(k));
+                auto wms = _container.emplace(s.name(), id().withEntityName(s.name()));
                 wms.first->second.path = path;
                 wms.first->second.append(s);
             }
-        }
+
+            return true;
+        });
     }
 }
diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.cpp
index 4e92467af..b4ece9ec4 100644
--- a/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.cpp
+++ b/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.cpp
@@ -60,21 +60,22 @@ namespace armarx::armem::ltm
         mongocxx::database db = client[dbsettings.database];
         mongocxx::collection coll = db[id().str()];
 
-        for (const auto& [k, s] : m)
+        m.forEachEntitySnapshot([this](const wm::EntitySnapshot & snapshot)
         {
-            if (auto it = _container.find(k); it != _container.end())
+            if (auto it = _container.find(snapshot.time()); it != _container.end())
             {
                 // timestamp already exists
                 // We assume that a snapshot does not change, so ignore
             }
             else
             {
-                auto wms = _container.emplace(std::make_pair(k, id().withTimestamp(k)));
+                auto wms = _container.emplace(std::make_pair(snapshot.time(), id().withTimestamp(snapshot.time())));
                 wms.first->second.dbsettings = dbsettings;
-                wms.first->second.setTo(s, k);
+                wms.first->second.setTo(snapshot, snapshot.time());
                 //truncateHistoryToSize();
             }
-        }
+            return true;
+        });
     }
 
     bool Entity::hasSnapshot(const Time& time) const
@@ -89,21 +90,22 @@ namespace armarx::armem::ltm
         mongocxx::database db = client[dbsettings.database];
         mongocxx::collection coll = db[id().str()];
 
-        bsoncxx::stdx::optional<bsoncxx::document::value> maybe_result = coll.find_one(document{} << "timestamp" << time.toMicroSeconds() << finalize);
+        bsoncxx::stdx::optional<bsoncxx::document::value> maybe_result =
+            coll.find_one(document{} << "timestamp" << time.toMicroSeconds() << finalize);
         if (!maybe_result)
         {
             return false;
         }
 
-        auto json = nlohmann::json::parse(bsoncxx::to_json(*maybe_result));
-        auto id = MemoryID::fromString(json["id"].get<std::string>());
-        auto instances = json["instances"];
+        nlohmann::json json = nlohmann::json::parse(bsoncxx::to_json(*maybe_result));
+        MemoryID id = MemoryID::fromString(json["id"].get<std::string>());
+        nlohmann::json instances = json["instances"];
         EntitySnapshot snapshot(id);
         snapshot.dbsettings = dbsettings;
 
-        for (unsigned int i = 0; i < instances.size(); ++i)
+        for (size_t i = 0; i < instances.size(); ++i)
         {
-            EntityInstance instance(id.withInstanceIndex(i));
+            EntityInstance instance(id.withInstanceIndex(static_cast<int>(i)));
             snapshot.addInstance(instance);
         }
 
diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.cpp
index 30297767a..f0afc6a70 100644
--- a/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.cpp
+++ b/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.cpp
@@ -19,11 +19,9 @@ namespace armarx::armem::ltm
         return id() == other.id() && _metadata == other.metadata();
     }
 
-    void EntityInstance::update(const EntityUpdate& update, int index)
+    void EntityInstance::update(const EntityUpdate& update)
     {
-        ARMARX_CHECK_FITS_SIZE(index, update.instancesData.size());
-
-        this->index() = index;
+        ARMARX_CHECK_FITS_SIZE(this->index(), update.instancesData.size());
 
         this->_metadata.confidence = update.confidence;
         this->_metadata.timeCreated = update.timeCreated;
diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.h b/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.h
index 81bd70fd3..5fa23431b 100644
--- a/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.h
+++ b/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.h
@@ -62,7 +62,7 @@ namespace armarx::armem::ltm
          * @param update The update.
          * @param index The instances index.
          */
-        virtual void update(const EntityUpdate& update, int index) override;
+        virtual void update(const EntityUpdate& update) override;
 
         virtual bool equalsDeep(const EntityInstance& other) const override;
 
diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.cpp
index f3dd8a595..313d6901d 100644
--- a/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.cpp
+++ b/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.cpp
@@ -85,18 +85,20 @@ namespace armarx::armem::ltm
         auto array_builder = bsoncxx::builder::basic::array{};
 
         int i = 0;
-        for (const auto& s : m)
+        m.forEachEntityInstance([this, &array_builder, &i](const wm::EntityInstance & instance)
         {
             auto wms = _container.emplace_back(id().withInstanceIndex(i++));
 
             auto aron = std::make_shared<aron::datanavigator::DictNavigator>();
-            to_aron(aron, s);
+            to_aron(aron, instance);
             nlohmann::json j;
             from_aron(aron, j);
 
             auto doc_value = bsoncxx::from_json(j.dump(2));
             array_builder.append(doc_value);
-        }
+
+            return true;
+        });
 
         auto after_array = in_array << array_builder;
         bsoncxx::document::value doc = after_array << bsoncxx::builder::stream::finalize;
diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.cpp
index 9b81f00a8..ecefdc468 100644
--- a/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.cpp
+++ b/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.cpp
@@ -202,9 +202,9 @@ namespace armarx::armem::ltm
         mongocxx::database db = client[dbsettings.database];
         mongocxx::collection coll = db[id().str()];
 
-        for (const auto& [k, s] : m)
+        m.forEachCoreSegment([this, &coll](const wm::CoreSegment & s)
         {
-            if (auto it = _container.find(k); it != _container.end())
+            if (auto it = _container.find(s.name()); it != _container.end())
             {
                 // TODO check if foreign key exists
                 it->second.append(s);
@@ -213,15 +213,17 @@ namespace armarx::armem::ltm
             {
                 auto builder = bsoncxx::builder::stream::document{};
                 bsoncxx::document::value foreign_key = builder
-                                                       << "foreign_key" << s.id().withCoreSegmentName(k).str()
+                                                       << "foreign_key" << s.id().withCoreSegmentName(s.name()).str()
                                                        << bsoncxx::builder::stream::finalize;
                 coll.insert_one(foreign_key.view());
 
-                auto wms = _container.emplace(k, id().withCoreSegmentName(k));
+                auto wms = _container.emplace(s.name(), id().withCoreSegmentName(s.name()));
                 wms.first->second.dbsettings = dbsettings;
                 wms.first->second.append(s);
             }
-        }
+
+            return true;
+        });
 
         TIMING_END(LTM_Append);
     }
diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.cpp
index 878adc8d7..8126867e4 100644
--- a/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.cpp
+++ b/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.cpp
@@ -1,8 +1,10 @@
 #include "ProviderSegment.h"
 
+#include "error.h"
+
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 
-#include "error.h"
+#include <SimoxUtility/json/json.hpp>
 
 
 namespace armarx::armem::ltm
@@ -60,9 +62,9 @@ namespace armarx::armem::ltm
         mongocxx::database db = client[dbsettings.database];
         mongocxx::collection coll = db[id().str()];
 
-        for (const auto& [k, s] : m)
+        m.forEachEntity([this, &coll](const wm::Entity & s)
         {
-            if (auto it = _container.find(k); it != _container.end())
+            if (auto it = _container.find(s.name()); it != _container.end())
             {
                 it->second.append(s);
             }
@@ -70,14 +72,16 @@ namespace armarx::armem::ltm
             {
                 auto builder = bsoncxx::builder::stream::document{};
                 bsoncxx::document::value foreign_key = builder
-                                                       << "foreign_key" << s.id().withEntityName(k).str()
+                                                       << "foreign_key" << s.id().withEntityName(s.name()).str()
                                                        << bsoncxx::builder::stream::finalize;
                 coll.insert_one(foreign_key.view());
 
-                auto wms = _container.emplace(k, id().withEntityName(k));
+                auto wms = _container.emplace(s.name(), id().withEntityName(s.name()));
                 wms.first->second.dbsettings = dbsettings;
                 wms.first->second.append(s);
             }
-        }
+
+            return true;
+        });
     }
 }
diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/EntityInstance.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/EntityInstance.cpp
index 9158bd7e3..0962f86fb 100644
--- a/source/RobotAPI/libraries/armem/core/workingmemory/EntityInstance.cpp
+++ b/source/RobotAPI/libraries/armem/core/workingmemory/EntityInstance.cpp
@@ -43,12 +43,12 @@ namespace armarx::armem::wm
         return id() == other.id() && _metadata == other.metadata();
     }
 
-    void EntityInstance::update(const EntityUpdate& update, int index)
+
+    void EntityInstance::update(const EntityUpdate& update)
     {
-        ARMARX_CHECK_FITS_SIZE(index, update.instancesData.size());
+        ARMARX_CHECK_FITS_SIZE(this->index(), update.instancesData.size());
 
-        this->index() = index;
-        setData(update.instancesData.at(size_t(index)));
+        setData(update.instancesData.at(size_t(this->index())));
 
         this->_metadata.confidence = update.confidence;
 
diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/EntityInstance.h b/source/RobotAPI/libraries/armem/core/workingmemory/EntityInstance.h
index ef516e630..06389c366 100644
--- a/source/RobotAPI/libraries/armem/core/workingmemory/EntityInstance.h
+++ b/source/RobotAPI/libraries/armem/core/workingmemory/EntityInstance.h
@@ -82,7 +82,7 @@ namespace armarx::armem::wm
          * @param update The update.
          * @param index The instances index.
          */
-        virtual void update(const EntityUpdate& update, int index) override;
+        virtual void update(const EntityUpdate& update) override;
 
         virtual bool equalsDeep(const EntityInstance& other) const override;
 
diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/EntitySnapshot.h b/source/RobotAPI/libraries/armem/core/workingmemory/EntitySnapshot.h
index fb3123eb7..226fefd83 100644
--- a/source/RobotAPI/libraries/armem/core/workingmemory/EntitySnapshot.h
+++ b/source/RobotAPI/libraries/armem/core/workingmemory/EntitySnapshot.h
@@ -21,10 +21,17 @@ namespace armarx::armem::wm
     public:
 
         using Base::EntitySnapshotBase;
-        using Base::operator=;
+        // using Base::operator=;
+
+        EntitySnapshot(const EntitySnapshot& other) = default;
+        EntitySnapshot(EntitySnapshot&& other) = default;
+        EntitySnapshot& operator=(const EntitySnapshot& other) = default;
+        EntitySnapshot& operator=(EntitySnapshot&& other) = default;
+
 
         std::vector<aron::datanavigator::DictNavigatorPtr> getAronData() const;
 
+
     protected:
 
         virtual void _copySelfWithoutData(EntitySnapshot& other) const override;
diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/visitor/Visitor.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/visitor/Visitor.cpp
index ede63a494..e9b42d775 100644
--- a/source/RobotAPI/libraries/armem/core/workingmemory/visitor/Visitor.cpp
+++ b/source/RobotAPI/libraries/armem/core/workingmemory/visitor/Visitor.cpp
@@ -19,80 +19,55 @@ namespace armarx::armem::wm
 
     bool Visitor::applyTo(Memory& memory)
     {
-        bool cont = true;
         visitEnter(memory);
-        for (auto& [_, coreSeg] : memory)
+        bool cont = memory.forEachCoreSegment([this](CoreSegment & coreSeg)
         {
-            if (!applyTo(coreSeg))
-            {
-                cont = false;
-                break;
-            }
-        }
+            return applyTo(coreSeg);
+        });
         visitExit(memory);
         return cont;
     }
 
     bool Visitor::applyTo(CoreSegment& coreSegment)
     {
-        bool cont = true;
         visitEnter(coreSegment);
-        for (auto& [_, provSeg] : coreSegment)
+        bool cont = coreSegment.forEachProviderSegment([this](ProviderSegment & provSeg)
         {
-            if (!applyTo(provSeg))
-            {
-                cont = false;
-                break;
-            }
-        }
+            return applyTo(provSeg);
+        });
         visitExit(coreSegment);
         return cont;
     }
 
     bool Visitor::applyTo(ProviderSegment& providerSegment)
     {
-        bool cont = true;
         visitEnter(providerSegment);
-        for (auto& [_, entity] : providerSegment)
+        bool cont = providerSegment.forEachEntity([this](Entity & entity)
         {
-            if (!applyTo(entity))
-            {
-                cont = false;
-                break;
-            }
-        }
+            return applyTo(entity);
+        });
         visitExit(providerSegment);
         return cont;
     }
 
     bool Visitor::applyTo(Entity& entity)
     {
-        bool cont = true;
         visitEnter(entity);
-        for (auto& [_, snapshot] : entity)
+        bool cont = entity.forEachEntitySnapshot([this](EntitySnapshot & snapshot)
         {
-            if (!applyTo(snapshot))
-            {
-                cont = false;
-                break;
-            }
-        }
+            return applyTo(snapshot);
+        });
         visitExit(entity);
         return cont;
     }
 
     bool Visitor::applyTo(EntitySnapshot& snapshot)
     {
-        bool cont = true;
         visitEnter(snapshot);
-        for (auto& instance : snapshot)
+        bool cont = snapshot.forEachEntityInstance([this](EntityInstance & instance)
         {
-            if (!applyTo(instance))
-            {
-                cont = false;
-                break;
-            }
-        }
+            return applyTo(instance);
+        });
         visitExit(snapshot);
         return cont;
     }
@@ -105,80 +80,55 @@ namespace armarx::armem::wm
 
     bool Visitor::applyTo(const Memory& memory)
     {
-        bool cont = true;
         visitEnter(memory);
-        for (const auto& [_, coreSeg] : memory)
+        bool cont = memory.forEachCoreSegment([this](const CoreSegment & coreSeg)
         {
-            if (!applyTo(coreSeg))
-            {
-                cont = false;
-                break;
-            }
-        }
+            return applyTo(coreSeg);
+        });
         visitExit(memory);
         return cont;
     }
 
     bool Visitor::applyTo(const CoreSegment& coreSegment)
     {
-        bool cont = true;
         visitEnter(coreSegment);
-        for (const auto& [_, provSeg] : coreSegment)
+        bool cont = coreSegment.forEachProviderSegment([this](const ProviderSegment & provSeg)
         {
-            if (!applyTo(provSeg))
-            {
-                cont = false;
-                break;
-            }
-        }
+            return applyTo(provSeg);
+        });
         visitExit(coreSegment);
         return cont;
     }
 
     bool Visitor::applyTo(const ProviderSegment& providerSegment)
     {
-        bool cont = true;
         visitEnter(providerSegment);
-        for (const auto& [_, entity] : providerSegment)
+        bool cont = providerSegment.forEachEntity([this](const Entity & entity)
         {
-            if (!applyTo(entity))
-            {
-                cont = false;
-                break;
-            }
-        }
+            return applyTo(entity);
+        });
         visitExit(providerSegment);
         return cont;
     }
 
     bool Visitor::applyTo(const Entity& entity)
     {
-        bool cont = true;
         visitEnter(entity);
-        for (const auto& [_, snapshot] : entity)
+        bool cont = entity.forEachEntitySnapshot([this](const EntitySnapshot & snapshot)
         {
-            if (!applyTo(snapshot))
-            {
-                cont = false;
-                break;
-            }
-        }
+            return applyTo(snapshot);
+        });
         visitExit(entity);
         return cont;
     }
 
     bool Visitor::applyTo(const EntitySnapshot& snapshot)
     {
-        bool cont = true;
         visitEnter(snapshot);
-        for (const auto& instance : snapshot)
+        bool cont = snapshot.forEachEntityInstance([this](const EntityInstance & instance)
         {
-            if (!applyTo(instance))
-            {
-                cont = false;
-                break;
-            }
-        }
+            return applyTo(instance);
+        });
         visitExit(snapshot);
         return cont;
     }
diff --git a/source/RobotAPI/libraries/armem/server/query_proc/base/CoreSegmentQueryProcessorBase.h b/source/RobotAPI/libraries/armem/server/query_proc/base/CoreSegmentQueryProcessorBase.h
index 9d7b25182..bb0c5072e 100644
--- a/source/RobotAPI/libraries/armem/server/query_proc/base/CoreSegmentQueryProcessorBase.h
+++ b/source/RobotAPI/libraries/armem/server/query_proc/base/CoreSegmentQueryProcessorBase.h
@@ -57,10 +57,11 @@ namespace armarx::armem::base::query_proc
                      const armem::query::data::core::All& query,
                      const _CoreSegmentT& coreSegment) const
         {
-            for (const auto& [name, providerSegment] : coreSegment.providerSegments())
+            coreSegment.forEachProviderSegment([this, &query, &result](const ProviderSegmentT & providerSegment)
             {
                 result.addProviderSegment(providerSegmentProcessorProcess(query.providerSegmentQueries, providerSegment));
-            }
+                return true;
+            });
         }
 
         void process(_CoreSegmentT& result,
@@ -83,13 +84,15 @@ namespace armarx::armem::base::query_proc
                      const _CoreSegmentT& coreSegment) const
         {
             std::regex regex(query.providerSegmentNameRegex);
-            for (const auto& [name, providerSegment] : coreSegment.providerSegments())
+            coreSegment.forEachProviderSegment(
+                [this, &result, &query, &regex](const ProviderSegmentT & providerSegment)
             {
                 if (std::regex_search(providerSegment.name(), regex))
                 {
                     result.addProviderSegment(providerSegmentProcessorProcess(query.providerSegmentQueries, providerSegment));
                 }
-            }
+                return true;
+            });
         }
 
     protected:
diff --git a/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.h b/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.h
index 40113207f..009683a32 100644
--- a/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.h
+++ b/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.h
@@ -78,10 +78,11 @@ namespace armarx::armem::base::query_proc
             (void) query;
             // Copy this entitiy and its contents.
 
-            for (const auto& [time, snapshot] : entity)
+            entity.forEachEntitySnapshot([this, &result](const EntitySnapshotT & snapshot)
             {
                 addResultSnapshot(result, snapshot);
-            }
+                return true;
+            });
         }
 
         void process(_EntityT& result,
@@ -211,24 +212,27 @@ namespace armarx::armem::base::query_proc
                      const armem::query::data::entity::BeforeTime& query,
                      const _EntityT& entity) const
         {
-            const auto referenceTimestamp = fromIce<Time>(query.timestamp);
+            const armem::Time referenceTimestamp = fromIce<Time>(query.timestamp);
             ARMARX_CHECK(referenceTimestamp.toMicroSeconds() >= 0) << "Reference timestamp is negative!";
 
-            const auto maxEntries = fromIce<std::int64_t>(query.maxEntries);
-
             try
             {
-                const auto before = entity.getSnapshotsBefore(referenceTimestamp);
+                const auto& befores = entity.getSnapshotsBefore(referenceTimestamp);
 
-                int i = 0;
-                for (const auto& snapshot : before)
+                size_t num = 0;
+                if (query.maxEntries < 0)
                 {
-                    if (maxEntries >= 0 && i >= maxEntries)
-                    {
-                        break;
-                    }
-                    addResultSnapshot(result, snapshot);
-                    ++i;
+                    num = befores.size();
+                }
+                else
+                {
+                    num = std::min(befores.size(), static_cast<size_t>(query.maxEntries));
+                }
+
+                for (size_t r = 0; r < num; ++r)
+                {
+                    size_t i = befores.size() - 1 - r;
+                    addResultSnapshot(result, befores[i]);
                 }
             }
             catch (const  error::MissingEntry&)
diff --git a/source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp
new file mode 100644
index 000000000..013fae19b
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp
@@ -0,0 +1,170 @@
+/*
+ * 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 <RobotAPI/Test.h>
+#include <RobotAPI/libraries/armem/core/Commit.h>
+#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h>
+
+#include <iostream>
+#include <set>
+
+
+namespace armem = armarx::armem;
+
+
+template <class ValueT>
+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.
+
+    wm::Memory memory(mid);
+    std::set<MemoryID> cids, pids, eids, sids, iids;
+
+    for (size_t c = 0; c <= 2; ++c)
+    {
+        const MemoryID cid = mid.withCoreSegmentName("core_" + std::to_string(c));
+        cids.insert(cid);
+        wm::CoreSegment& coreSeg = memory.addCoreSegment(cid.coreSegmentName);
+        for (size_t p = 0; p <= c; ++p)
+        {
+            const MemoryID pid = cid.withProviderSegmentName("prov_" + std::to_string(p));
+            pids.insert(pid);
+            for (size_t e = 0; e <= p; ++e)
+            {
+                const MemoryID eid = pid.withEntityName("entity_" + std::to_string(e));
+                eids.insert(eid);
+                for (size_t s = 0; s <= e; ++s)
+                {
+                    const MemoryID sid = eid.withTimestamp(Time::microSeconds(int(s)));
+                    sids.insert(sid);
+
+                    EntityUpdate update;
+                    update.entityID = eid;
+                    update.timeCreated = sid.timestamp;
+                    for (size_t i = 0; i <= s; ++i)
+                    {
+                        const MemoryID iid = sid.withInstanceIndex(int(i));
+                        iids.insert(iid);
+                        update.instancesData.emplace_back();
+                    }
+                    auto r = memory.update(update);
+
+                    BOOST_CHECK(coreSeg.hasProviderSegment(pid.providerSegmentName));
+                }
+            }
+
+            BOOST_CHECK_EQUAL(coreSeg.size(), p + 1);
+        }
+        BOOST_CHECK_EQUAL(memory.size(), c + 1);
+    }
+
+    BOOST_CHECK_GT(iids.size(), 0);
+    BOOST_CHECK_GT(sids.size(), 0);
+    BOOST_CHECK_GT(eids.size(), 0);
+    BOOST_CHECK_GT(pids.size(), 0);
+    BOOST_CHECK_GT(cids.size(), 0);
+
+    BOOST_TEST_MESSAGE("Memory: \n" << memory.dump());
+
+    memory.forEachEntityInstance([&](const wm::EntityInstance & i) -> bool
+    {
+        BOOST_TEST_CONTEXT(i.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.forEachEntitySnapshot([&](const wm::EntitySnapshot & s) -> bool
+    {
+        BOOST_TEST_CONTEXT(s.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(e.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(p.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(c.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);
+
+}
diff --git a/source/RobotAPI/libraries/armem/test/ArMemIceConversionsTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemIceConversionsTest.cpp
index a835f39be..52530a7c5 100644
--- a/source/RobotAPI/libraries/armem/test/ArMemIceConversionsTest.cpp
+++ b/source/RobotAPI/libraries/armem/test/ArMemIceConversionsTest.cpp
@@ -59,12 +59,12 @@ BOOST_AUTO_TEST_CASE(test_entity)
     BOOST_CHECK_EQUAL(ice->id.providerSegmentName, entity.id().providerSegmentName);
     BOOST_CHECK_EQUAL(ice->id.entityName, entity.id().entityName);
 
-    BOOST_CHECK_EQUAL(ice->history.size(), entity.history().size());
+    BOOST_CHECK_EQUAL(ice->history.size(), entity.size());
 
     armem::wm::Entity entityOut;
     armem::fromIce(ice, entityOut);
 
-    BOOST_CHECK_EQUAL(entityOut.history().size(), entity.history().size());
+    BOOST_CHECK_EQUAL(entityOut.size(), entity.size());
 
     std::vector<armem::Time> timestamps = entityOut.getTimestamps();
     BOOST_CHECK_EQUAL_COLLECTIONS(timestamps.begin(), timestamps.end(), expectedTimestamps.begin(), expectedTimestamps.end());
diff --git a/source/RobotAPI/libraries/armem/test/ArMemMemoryTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemMemoryTest.cpp
index d30c49232..f7aebf000 100644
--- a/source/RobotAPI/libraries/armem/test/ArMemMemoryTest.cpp
+++ b/source/RobotAPI/libraries/armem/test/ArMemMemoryTest.cpp
@@ -170,8 +170,8 @@ namespace ArMemMemoryTest
     };
     struct MemoryContainerCtorOpTestFixture
     {
-        const armem::MemoryID id {"A/B/C/123/1"};
-        const armem::MemoryID moved {"////1"};  // int is not moved
+        const armem::MemoryID id {"M/C/P/E/123/1"};
+        const armem::MemoryID moved {"////123/1"};  // Time and int are just copied, not moved
         TestMemoryContainer cont {id};
 
         MemoryContainerCtorOpTestFixture()
@@ -364,14 +364,17 @@ struct CustomChecks<armem::d_ltm::Memory>
 
 struct CopyMoveCtorsOpsTestBase
 {
-    const armem::MemoryID id {"A/B/C/123000"};  // int index would not be moved
-    const armem::MemoryID idMoved;
+    const armem::MemoryID id {"M", "C", "P", "E", armem::Time::microSeconds(123000), 1};
+    //const armem::MemoryID idMoved {"", "", "", "", armem::Time::microSeconds(123000), 1};
+    armem::MemoryID idMoved = id;
 
     std::string typeName;
 
     CopyMoveCtorsOpsTestBase(const std::string& typeName) :
         typeName(typeName)
     {
+        armem::MemoryID copy = std::move(idMoved);
+        (void) copy;
     }
     virtual ~CopyMoveCtorsOpsTestBase()
     {
@@ -490,10 +493,17 @@ struct CopyMoveCtorsOpsTest : public CopyMoveCtorsOpsTestBase
     void reset() override
     {
         in = T {id};
+        if constexpr(std::is_same_v<T, armem::wm::Memory>
+                     || std::is_same_v<T, armem::ltm::Memory>
+                     || std::is_same_v<T, armem::d_ltm::Memory>)
+        {
+            in._addMissingCoreSegmentDuringUpdate = true;
+        }
         {
             armem::EntityUpdate update;
-            update.entityID = armem::MemoryID("A", "B", "C", "D", armem::Time::seconds(1), 0);
+            update.entityID = armem::MemoryID("M", "C", "P", "E", armem::Time::microSeconds(123000), 0);
             update.timeCreated = update.entityID.timestamp;
+            update.instancesData.emplace_back();
             in.update(update);
         }
 
@@ -662,9 +672,9 @@ BOOST_AUTO_TEST_CASE(test_segment_setup)
     armem::wm::Entity& entity = providerSegment.getEntity("image");
     BOOST_CHECK_EQUAL(entity.name(), "image");
     BOOST_CHECK_EQUAL(entity.size(), 1);
-    BOOST_CHECK_EQUAL(entity.history().count(update.timeCreated), 1);
+    BOOST_CHECK(entity.hasSnapshot(update.timeCreated));
 
-    armem::wm::EntitySnapshot& entitySnapshot = entity.history().at(update.timeCreated);
+    armem::wm::EntitySnapshot& entitySnapshot = entity.getSnapshot(update.timeCreated);
     BOOST_CHECK_EQUAL(entitySnapshot.size(), update.instancesData.size());
 
 
@@ -674,8 +684,8 @@ BOOST_AUTO_TEST_CASE(test_segment_setup)
     update.timeCreated = armem::Time::milliSeconds(2000);
     memory.update(update);
     BOOST_CHECK_EQUAL(entity.size(), 2);
-    BOOST_CHECK_EQUAL(entity.history().count(update.timeCreated), 1);
-    BOOST_CHECK_EQUAL(entity.history().at(update.timeCreated).size(), update.instancesData.size());
+    BOOST_CHECK(entity.hasSnapshot(update.timeCreated));
+    BOOST_CHECK_EQUAL(entity.getSnapshot(update.timeCreated).size(), update.instancesData.size());
 
 
     // A third update (on entity).
@@ -707,17 +717,17 @@ BOOST_AUTO_TEST_CASE(test_history_size_in_entity)
     // Now with maximum history size.
     entity.setMaxHistorySize(2);
     BOOST_CHECK_EQUAL(entity.size(), 2);
-    BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(1000)), 0);
-    BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(2000)), 1);
-    BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(3000)), 1);
+    BOOST_CHECK(not entity.hasSnapshot(armem::Time::milliSeconds(1000)));
+    BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(2000)));
+    BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(3000)));
 
 
     update.timeCreated = armem::Time::milliSeconds(4000);
     entity.update(update);
     BOOST_CHECK_EQUAL(entity.size(), 2);
-    BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(2000)), 0);
-    BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(3000)), 1);
-    BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(4000)), 1);
+    BOOST_CHECK(not entity.hasSnapshot(armem::Time::milliSeconds(2000)));
+    BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(3000)));
+    BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(4000)));
 
     // Disable maximum history size.
     entity.setMaxHistorySize(-1);
@@ -725,9 +735,9 @@ BOOST_AUTO_TEST_CASE(test_history_size_in_entity)
     update.timeCreated = armem::Time::milliSeconds(5000);
     entity.update(update);
     BOOST_CHECK_EQUAL(entity.size(), 3);
-    BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(3000)), 1);
-    BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(4000)), 1);
-    BOOST_CHECK_EQUAL(entity.history().count(armem::Time::milliSeconds(5000)), 1);
+    BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(3000)));
+    BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(4000)));
+    BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(5000)));
 }
 
 
diff --git a/source/RobotAPI/libraries/armem/test/ArMemQueryTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemQueryTest.cpp
index 4b83fd432..a674ef503 100644
--- a/source/RobotAPI/libraries/armem/test/ArMemQueryTest.cpp
+++ b/source/RobotAPI/libraries/armem/test/ArMemQueryTest.cpp
@@ -56,7 +56,6 @@ namespace ArMemQueryTest
         armem::wm::Entity entity;
 
         armem::wm::query_proc::EntityQueryProcessor processor;
-        query::EntityQueryPtr entityQuery;
 
         std::vector<armem::wm::Entity> results;
 
@@ -85,10 +84,10 @@ namespace ArMemQueryTest
         template <class QueryT>
         void addResults(QueryT query = {})
         {
-            entityQuery = new QueryT(query);
-
+            // Test whether we get the same result when we pass the concrete type
+            // (static resolution) and when we pass the base type (dynamic resolution).
             results.emplace_back(processor.process(query, entity));
-            results.emplace_back(processor.process(*entityQuery, entity));
+            results.emplace_back(processor.process(static_cast<query::EntityQuery const&>(query), entity));
         }
     };
 
@@ -126,8 +125,8 @@ BOOST_AUTO_TEST_CASE(test_entity_Single_latest)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
         BOOST_CHECK_EQUAL(result.size(), 1);
-        BOOST_CHECK_EQUAL(result.history().begin()->second.time(), entity.getLatestSnapshot().time());
-        BOOST_CHECK_NE(&result.history().begin()->second, &entity.history().rbegin()->second);
+        const armem::wm::EntitySnapshot& first = result.getFirstSnapshotAfterOrAt(armem::Time::microSeconds(0));
+        BOOST_CHECK_EQUAL(first.time(), armem::Time::microSeconds(5000));
     }
 }
 
@@ -191,7 +190,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_slice)
 
         BOOST_CHECK_EQUAL(result.size(), 2);
 
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         std::vector<armem::Time> expected
         {
             armem::Time::microSeconds(2000), armem::Time::microSeconds(3000)
@@ -212,7 +211,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_exact)
 
         BOOST_CHECK_EQUAL(result.size(), 3);
 
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         std::vector<armem::Time> expected
         {
             armem::Time::microSeconds(2000), armem::Time::microSeconds(3000), armem::Time::microSeconds(4000)
@@ -233,8 +232,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_all)
 
         BOOST_CHECK_EQUAL(result.size(), entity.size());
 
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
-        std::vector<armem::Time> expected = simox::alg::get_keys(entity.history());
+        const std::vector<armem::Time> times = result.getTimestamps();
+        const std::vector<armem::Time> expected = entity.getTimestamps();
         BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end());
     }
 }
@@ -266,7 +265,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_from_start)
 
         BOOST_CHECK_EQUAL(result.size(), 2);
 
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        const std::vector<armem::Time> times = result.getTimestamps();
         std::vector<armem::Time> expected
         {
             armem::Time::microSeconds(1000), armem::Time::microSeconds(2000)
@@ -284,10 +283,9 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_to_end)
     for (const armem::wm::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
-
         BOOST_CHECK_EQUAL(result.size(), 3);
 
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        const std::vector<armem::Time> times = result.getTimestamps();
         std::vector<armem::Time> expected
         {
             armem::Time::microSeconds(3000), armem::Time::microSeconds(4000), armem::Time::microSeconds(5000)
@@ -307,12 +305,11 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeTime_1)
 
     for (const auto& result : results)
     {
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        const std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE_EQUAL(times.size(), 1);
 
-        BOOST_REQUIRE_EQUAL(times.front(),  armem::Time::microSeconds(3000));
+        BOOST_CHECK_EQUAL(times.front(), armem::Time::microSeconds(3000));
     }
-
 }
 
 BOOST_AUTO_TEST_CASE(test_entity_BeforeTime_2)
@@ -323,7 +320,7 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeTime_2)
 
     for (const auto& result : results)
     {
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        const std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE_EQUAL(times.size(), 2);
 
         std::vector<armem::Time> expected
@@ -348,7 +345,7 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeOrAtTime_before)
 
     for (const auto& result : results)
     {
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE_EQUAL(times.size(), 1);
 
         BOOST_REQUIRE_EQUAL(times.front(),  armem::Time::microSeconds(3000));
@@ -363,7 +360,7 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeOrAtTime_at)
 
     for (const auto& result : results)
     {
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE_EQUAL(times.size(), 1);
 
         BOOST_REQUIRE_EQUAL(times.front(),  armem::Time::microSeconds(3000));
@@ -378,7 +375,7 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeOrAtTime_lookup_past)
 
     for (const auto& result : results)
     {
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE(times.empty());
     }
 }
@@ -398,7 +395,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_no_limit)
 
     for (const auto& result : results)
     {
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE_EQUAL(times.size(), 2);
 
         std::vector<armem::Time> expected
@@ -424,7 +421,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_600)
 
     for (const auto& result : results)
     {
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE_EQUAL(times.size(), 2);
 
         std::vector<armem::Time> expected
@@ -450,7 +447,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_too_small)
 
     for (const auto& result : results)
     {
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE_EQUAL(times.size(), 0);
     }
 
@@ -469,7 +466,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_only_next)
 
     for (const auto& result : results)
     {
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE_EQUAL(times.size(), 1);
 
         std::vector<armem::Time> expected
@@ -494,7 +491,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_only_previous)
 
     for (const auto& result : results)
     {
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE_EQUAL(times.size(), 1);
 
         std::vector<armem::Time> expected
@@ -519,7 +516,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_perfect_match)
 
     for (const auto& result : results)
     {
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE_EQUAL(times.size(), 1);
 
         std::vector<armem::Time> expected
@@ -544,7 +541,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_past)
 
     for (const auto& result : results)
     {
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE(times.empty());
     }
 }
@@ -562,7 +559,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_future)
 
     for (const auto& result : results)
     {
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE(times.empty());
     }
 }
@@ -580,7 +577,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_future_valid)
 
     for (const auto& result : results)
     {
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE_EQUAL(times.size(), 1);
 
         std::vector<armem::Time> expected
@@ -643,7 +640,7 @@ BOOST_AUTO_TEST_CASE(test_entity_IndexRange_all_default)
 
         BOOST_CHECK_EQUAL(result.size(), entity.size());
 
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         std::vector<armem::Time> expected = simox::alg::get_keys(entity.history());
         BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end());
     }
@@ -666,7 +663,7 @@ BOOST_AUTO_TEST_CASE(test_entity_IndexRange_slice)
 
         BOOST_CHECK_EQUAL(result.size(), 3);
 
-        std::vector<armem::Time> times = simox::alg::get_keys(result.history());
+        std::vector<armem::Time> times = result.getTimestamps();
         std::vector<armem::Time> expected
         {
             armem::Time::microSeconds(2000), armem::Time::microSeconds(3000), armem::Time::microSeconds(4000)
diff --git a/source/RobotAPI/libraries/armem/test/CMakeLists.txt b/source/RobotAPI/libraries/armem/test/CMakeLists.txt
index e7fa876c1..b10935f95 100644
--- a/source/RobotAPI/libraries/armem/test/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem/test/CMakeLists.txt
@@ -8,3 +8,4 @@ armarx_add_test(ArMemMemoryIDTest ArMemMemoryIDTest.cpp "${LIBS}")
 armarx_add_test(ArMemQueryTest ArMemQueryTest.cpp "${LIBS}")
 armarx_add_test(ArMemLTMTest ArMemLTMTest.cpp "${LIBS}")
 armarx_add_test(ArMemQueryBuilderTest ArMemQueryBuilderTest.cpp "${LIBS}")
+armarx_add_test(ArMemForEachTest ArMemForEachTest.cpp "${LIBS}")
diff --git a/source/RobotAPI/libraries/armem_gui/test/ArMemGuiTest.cpp b/source/RobotAPI/libraries/armem_gui/test/ArMemGuiTest.cpp
index 4f259c7af..303a319bc 100644
--- a/source/RobotAPI/libraries/armem_gui/test/ArMemGuiTest.cpp
+++ b/source/RobotAPI/libraries/armem_gui/test/ArMemGuiTest.cpp
@@ -44,13 +44,13 @@ BOOST_AUTO_TEST_CASE(test_sanitizeTypeName)
         BOOST_CHECK_EQUAL(sanitizeTypeName(dict.getName()), "Dict<Float>");
     }
     {
-        ListNavigator dict;
-        dict.setAcceptedType(std::make_shared<LongNavigator>());
-        BOOST_CHECK_EQUAL(sanitizeTypeName(dict.getName()), "Dict<Long>");
+        ListNavigator list;
+        list.setAcceptedType(std::make_shared<LongNavigator>());
+        BOOST_CHECK_EQUAL(sanitizeTypeName(list.getName()), "List<Long>");
     }
     {
-        ObjectNavigator dict;
-        dict.setObjectName("namespace::MyObjectName");
-        BOOST_CHECK_EQUAL(sanitizeTypeName(dict.getName()), "namespace::MyObjectName");
+        ObjectNavigator obj;
+        obj.setObjectName("namespace::MyObjectName");
+        BOOST_CHECK_EQUAL(sanitizeTypeName(obj.getName()), "MyObjectName    (namespace)");
     }
 }
-- 
GitLab