diff --git a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h index bdde3f1c81b6f853c36390c30e8bea994258d9bb..4ec1df3d12777dff6bdaf05667abb2dc7eb1007f 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 7156964655a85c17df9e7d3e5e54242ff735f1cf..64b13c7e4d17975756986fee743ed5afadcab72e 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 4d92dffc09c088f6ea26ceee53fa7147f88c669d..c9689c1822154c17d906132fbe95b46c9e214ed7 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 00f996ca4c9b3d7002f3e252c2de4bce9f0440fd..17c3eb5760663699c97fd526c3469a781e531512 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 339022c016cc91969cf9e6acf875efb77f509829..c5cf1fb2f7a0f505280835bee092ccb562ac84fb 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 d5d2d4bf29746b9c9027db1b643519307b9851cd..41d25fb28102f484511b3bd09043c7d96048ba5a 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 b3fb28a54ba7bc034019e65303cab3534ea199a0..204aa8f86e20d99df852abbdc79be3d1a07ef39f 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 daa61bc4a43376b93be40cd7d203c63b80e7f1ef..c2e91a823dd14f2aa52ec4b93b5240d6c57f928e 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 5fbfa91d5a749f37d40eda2698787908ff61e8f3..d22310fb2385d223439a4c563e526549c818234a 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 54d3c4cb8d1be247887d8463eb1d37f00c7bd6c3..f8c14159eb488b5e80e25e868b2f9d700cb3572f 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 97871505a80cf4d91bbe88f0eea0c3da27c5c8d5..3fc60e0496aa21c441cf5e8a60443e43ef741a46 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 577417542795ec2edfdbccdf9f5e52d98e0cf976..08ed0c2b07edc156764f02dc88c5f76160f9d355 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 4e92467af23d5a9a96c70b84fb6bdf4394ca5030..b4ece9ec457d234ad9218b1b5cc8c5d1417e2926 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 30297767adbd92646a2f505299aac353f3ea07a5..f0afc6a703c1ac7d8fda6b8127c1ad4692ffb946 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 81bd70fd31fbd8ce9b89678646cc76f082282e6e..5fa23431ba399a1850158496415a8bd21d4eab6a 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 f3dd8a59507d361eb22309c665e07c089255fa3c..313d6901d154740f041b89508778fc2799ff55fb 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 9b81f00a8679735d3ded28a1f2799027331a544e..ecefdc46837818a8649e204efedf52cc05489494 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 878adc8d76c0685753a4409b6ac0229e22b303a0..8126867e4db4be01c91dfb582b67c94303751927 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 9158bd7e33565ed62f9c24f5bbbe0d15450ee9e0..0962f86fb946eb3cc6a48fddc4a4568a936f1362 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 ef516e630fcabc7e54f5ac316c884433ad2d6833..06389c3664542e13195083df8f9513047b4f169a 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 fb3123eb75a9dfccc8ceb86389a134745f7ffd90..226fefd83e6cce5e18233bd8b5bf6c58ca16fcc5 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 ede63a494a7aff26c54ba1d7149200c91be7d987..e9b42d775d847a98734a311494746954d41b969a 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 9d7b2518227e4ddf0c5d759963af193656e39894..bb0c5072ebab28eb03cdb15fa3eab9ef315b783c 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, ®ex](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 40113207f194c76301fbe8768a6d42c22f8b01db..009683a32779d5e6728c1c86387ab0631c9193b2 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 0000000000000000000000000000000000000000..013fae19b7bdffd234e1db83e17d518c9e33ccfb --- /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 a835f39bef74f745b22c4ee167e4755a031fec50..52530a7c59accf71b5b24bd9a6c179dc01ed389d 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 d30c49232cf84ec9d192d23c4fcaa041df8f2e57..f7aebf000b77c500cd22f757425eb853d3798b44 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 4b83fd43261e1d97da45495f5da94279931e606f..a674ef5033a0a86f19b3d755c5b2db90780dd8ea 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 e7fa876c119596f5c49352cfd0dca757ab01019c..b10935f95fedd6a1309248007422c53783d2c9e4 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 4f259c7af5a50ff198b139084eb604bfd06fead5..303a319bcd30566b8000e1d10cc6ab3ef812093d 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)"); } }