From 9cb51b58788b1aa48ecbe2dc1a4042db894e146f Mon Sep 17 00:00:00 2001 From: "fabian.peller-konrad@kit.edu" <fabian.peller-konrad@kit.edu> Date: Fri, 23 Apr 2021 16:16:15 +0200 Subject: [PATCH] memory export at file system --- .../armem/core/diskMemory/CoreSegment.cpp | 128 +++++++++++ .../armem/core/diskMemory/CoreSegment.h | 50 +++++ .../armem/core/diskMemory/Entity.cpp | 108 ++++++++++ .../libraries/armem/core/diskMemory/Entity.h | 65 ++++++ .../armem/core/diskMemory/EntityInstance.cpp | 201 ++++++++++++++++++ .../armem/core/diskMemory/EntityInstance.h | 68 ++++++ .../armem/core/diskMemory/EntitySnapshot.cpp | 112 ++++++++++ .../armem/core/diskMemory/EntitySnapshot.h | 50 +++++ .../armem/core/diskMemory/Memory.cpp | 112 ++++++++++ .../libraries/armem/core/diskMemory/Memory.h | 45 ++++ .../armem/core/diskMemory/ProviderSegment.cpp | 135 ++++++++++++ .../armem/core/diskMemory/ProviderSegment.h | 50 +++++ .../diskMemory/detail/TypedEntityContainer.h | 100 +++++++++ .../armem/core/longtermMemory/CoreSegment.h | 4 +- .../armem/core/longtermMemory/Entity.h | 4 +- .../core/longtermMemory/EntityInstance.cpp | 1 - .../core/longtermMemory/EntitySnapshot.h | 4 +- .../armem/core/longtermMemory/Memory.h | 5 +- .../core/longtermMemory/ProviderSegment.h | 4 +- .../longtermMemory/detail/EntityContainer.cpp | 10 - .../longtermMemory/detail/EntityContainer.h | 32 --- .../longtermMemory/detail/MemoryContainer.cpp | 7 - .../longtermMemory/detail/MemoryContainer.h | 28 --- .../detail/TypedEntityContainer.h | 26 --- .../libraries/armem_gui/MemoryViewer.cpp | 26 ++- 25 files changed, 1250 insertions(+), 125 deletions(-) create mode 100644 source/RobotAPI/libraries/armem/core/diskMemory/CoreSegment.cpp create mode 100644 source/RobotAPI/libraries/armem/core/diskMemory/CoreSegment.h create mode 100644 source/RobotAPI/libraries/armem/core/diskMemory/Entity.cpp create mode 100644 source/RobotAPI/libraries/armem/core/diskMemory/Entity.h create mode 100644 source/RobotAPI/libraries/armem/core/diskMemory/EntityInstance.cpp create mode 100644 source/RobotAPI/libraries/armem/core/diskMemory/EntityInstance.h create mode 100644 source/RobotAPI/libraries/armem/core/diskMemory/EntitySnapshot.cpp create mode 100644 source/RobotAPI/libraries/armem/core/diskMemory/EntitySnapshot.h create mode 100644 source/RobotAPI/libraries/armem/core/diskMemory/Memory.cpp create mode 100644 source/RobotAPI/libraries/armem/core/diskMemory/Memory.h create mode 100644 source/RobotAPI/libraries/armem/core/diskMemory/ProviderSegment.cpp create mode 100644 source/RobotAPI/libraries/armem/core/diskMemory/ProviderSegment.h create mode 100644 source/RobotAPI/libraries/armem/core/diskMemory/detail/TypedEntityContainer.h delete mode 100644 source/RobotAPI/libraries/armem/core/longtermMemory/detail/EntityContainer.cpp delete mode 100644 source/RobotAPI/libraries/armem/core/longtermMemory/detail/EntityContainer.h delete mode 100644 source/RobotAPI/libraries/armem/core/longtermMemory/detail/MemoryContainer.cpp delete mode 100644 source/RobotAPI/libraries/armem/core/longtermMemory/detail/MemoryContainer.h delete mode 100644 source/RobotAPI/libraries/armem/core/longtermMemory/detail/TypedEntityContainer.h diff --git a/source/RobotAPI/libraries/armem/core/diskMemory/CoreSegment.cpp b/source/RobotAPI/libraries/armem/core/diskMemory/CoreSegment.cpp new file mode 100644 index 000000000..e8be60e6c --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/diskMemory/CoreSegment.cpp @@ -0,0 +1,128 @@ +#include "CoreSegment.h" + +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include "error.h" + + +namespace armarx::armem::diskMemory +{ + + CoreSegment::CoreSegment() + { + } + + CoreSegment::CoreSegment(const std::string& name, aron::typenavigator::ObjectNavigatorPtr aronType) : + armarx::armem::detail::MemoryItem(MemoryID().withCoreSegmentName(name)), + armarx::armem::detail::TypedEntityContainerBase<ProviderSegment, Entity, CoreSegment>(MemoryID().withCoreSegmentName(name), aronType) + { + } + + CoreSegment::CoreSegment(const std::string& name, const MemoryID& parentID, aron::typenavigator::ObjectNavigatorPtr aronType) : + armarx::armem::detail::MemoryItem(MemoryID().withCoreSegmentName(name)), + armarx::armem::detail::TypedEntityContainerBase<ProviderSegment, Entity, CoreSegment>(parentID.withCoreSegmentName(name), aronType) + { + } + + CoreSegment::CoreSegment(const MemoryID& id, aron::typenavigator::ObjectNavigatorPtr aronType) : + armarx::armem::detail::MemoryItem(id), + armarx::armem::detail::TypedEntityContainerBase<ProviderSegment, Entity, CoreSegment>(id, aronType) + { + } + + CoreSegment::CoreSegment(const CoreSegment& other) : + armarx::armem::detail::MemoryItem(other), + MemoryContainerBase<std::map<std::string, ProviderSegment>, CoreSegment>(other), + armarx::armem::detail::TypedEntityContainerBase<ProviderSegment, Entity, CoreSegment>(other) + { + } + + CoreSegment& CoreSegment::operator=(const CoreSegment& other) + { + other._copySelf(*this); + return *this; + } + + std::filesystem::path CoreSegment::_fullPath() const + { + if(path) + { + return _fullPath(*path); + } + return std::filesystem::path(); + } + + std::filesystem::path CoreSegment::_fullPath(const std::filesystem::path& path) const + { + return path / id.memoryName / id.coreSegmentName; + } + + workingmemory::CoreSegment CoreSegment::convert() const + { + workingmemory::CoreSegment m; + for (const auto& [_, s] : container) + { + m.addProviderSegment(s.convert(aronType)); + } + return m; + } + + void CoreSegment::reload(const std::shared_ptr<std::filesystem::path>& p_ptr) + { + if(!p_ptr) + { + ARMARX_WARNING << "The entered is NULL."; + } + std::filesystem::path p = _fullPath(*p_ptr); + if(std::filesystem::is_regular_file(p)) + { + ARMARX_ERROR << "The entered path is leading to a file! Abort due to error."; + } + + container.clear(); + path = p_ptr; + + if(!std::filesystem::exists(p)) + { + ARMARX_INFO << "The entered path does not exist. Assuming an empty container."; + } + else + { + for (const auto& d : std::filesystem::directory_iterator(p)) + { + if(d.is_directory()) + { + std::string k = d.path().filename(); + auto wms = container.emplace(std::make_pair(k, id.withProviderSegmentName(k))); + wms.first->second.reload(p_ptr); + } + + if(d.is_regular_file()) + { + readAronType(d.path()); + } + } + } + } + + void CoreSegment::append(const workingmemory::CoreSegment& m) + { + std::filesystem::create_directories(_fullPath()); + writeAronType(_fullPath()); + + for (const auto& [k, s] : m.container) + { + if (const auto& it = container.find(k); it != container.end()) + { + it->second.append(s); + } + else + { + std::filesystem::create_directory(_fullPath() / k); + auto wms = container.emplace(std::make_pair(k, id.withProviderSegmentName(k))); + wms.first->second.path = path; + wms.first->second.append(s); + } + } + } +} diff --git a/source/RobotAPI/libraries/armem/core/diskMemory/CoreSegment.h b/source/RobotAPI/libraries/armem/core/diskMemory/CoreSegment.h new file mode 100644 index 000000000..d5a8314d2 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/diskMemory/CoreSegment.h @@ -0,0 +1,50 @@ +#pragma once + +#include <filesystem> + +#include "../base/CoreSegment.h" +#include "detail/TypedEntityContainer.h" + +#include "ProviderSegment.h" + +#include "../workingMemory/CoreSegment.h" + + +namespace armarx::armem::diskMemory +{ + + /** + * @brief Data of a core segment containing multiple provider segments. + */ + class CoreSegment : + virtual public CoreSegmentBase<ProviderSegment, CoreSegment>, + virtual public detail::TypedEntityContainer<ProviderSegment, CoreSegment> + { + public: + using Base = CoreSegmentBase<ProviderSegment, CoreSegment>; + using ProviderSegmentT = ProviderSegment; + + CoreSegment(); + CoreSegment(const std::string& name, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr); + CoreSegment(const std::string& name, const MemoryID& parentID, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr); + CoreSegment(const MemoryID& id, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr); + + CoreSegment(const CoreSegment& other); + CoreSegment& operator=(const CoreSegment& other); + + // Conversion + workingmemory::CoreSegment convert() const; + + // Filesystem connection + void reload(const std::shared_ptr<std::filesystem::path>&); + void append(const workingmemory::CoreSegment&); + + private: + std::filesystem::path _fullPath() const; + std::filesystem::path _fullPath(const std::filesystem::path&) const; + + public: + std::shared_ptr<std::filesystem::path> path; + }; + +} diff --git a/source/RobotAPI/libraries/armem/core/diskMemory/Entity.cpp b/source/RobotAPI/libraries/armem/core/diskMemory/Entity.cpp new file mode 100644 index 000000000..c2c8982a8 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/diskMemory/Entity.cpp @@ -0,0 +1,108 @@ +#include "Entity.h" + +namespace armarx::armem::diskMemory +{ + + Entity::Entity() + { + } + + Entity::Entity(const std::string& name, const MemoryID& parentID) : + armarx::armem::detail::MemoryItem(parentID.withEntityName(name)) + { + } + + Entity::Entity(const MemoryID& id) : + armarx::armem::detail::MemoryItem(id) + { + } + + Entity::Entity(const Entity& other) : + armarx::armem::detail::MemoryItem(other), + armarx::armem::detail::MemoryContainerBase<std::map<Time, EntitySnapshot>, Entity>(other) + { + } + + Entity& Entity::operator=(const Entity& other) + { + other._copySelf(*this); + return *this; + } + + std::filesystem::path Entity::_fullPath() const + { + if(path) + { + return _fullPath(*path); + } + return std::filesystem::path(); + } + + std::filesystem::path Entity::_fullPath(const std::filesystem::path& path) const + { + return path / id.memoryName / id.coreSegmentName / id.providerSegmentName / id.entityName; + } + + workingmemory::Entity Entity::convert(const aron::typenavigator::NavigatorPtr& expectedStructure) const + { + workingmemory::Entity m; + for (const auto& [_, s] : container) + { + m.addSnapshot(s.convert(expectedStructure)); + } + return m; + } + + void Entity::reload(const std::shared_ptr<std::filesystem::path>& p_ptr) + { + if(!p_ptr) + { + ARMARX_WARNING << "The entered is NULL."; + } + std::filesystem::path p = _fullPath(*p_ptr); + if(std::filesystem::is_regular_file(p)) + { + ARMARX_ERROR << "The entered path is leading to a file! Abort due to error."; + } + + container.clear(); + path = p_ptr; + + if(!std::filesystem::exists(p)) + { + ARMARX_INFO << "The entered path does not exist. Assuming an empty container."; + } + else + { + for (const auto& d : std::filesystem::directory_iterator(p)) + { + if(d.is_directory()) + { + std::string k = d.path().filename(); + armem::Time t = armem::Time::microSeconds(std::stol(k)); + auto wms = container.emplace(std::make_pair(t, id.withTimestamp(t))); + wms.first->second.reload(p_ptr); + } + } + } + } + + void Entity::append(const workingmemory::Entity& m) + { + std::filesystem::create_directories(_fullPath()); + for (const auto& [k, s] : m.container) + { + if (const auto& it = container.find(k); it != container.end()) + { + it->second.setTo(s); + } + else + { + std::filesystem::create_directory(_fullPath() / std::to_string(k.toMicroSeconds())); + auto wms = container.emplace(std::make_pair(k, id.withTimestamp(k))); + wms.first->second.path = path; + wms.first->second.setTo(s); + } + } + } +} diff --git a/source/RobotAPI/libraries/armem/core/diskMemory/Entity.h b/source/RobotAPI/libraries/armem/core/diskMemory/Entity.h new file mode 100644 index 000000000..391eefb05 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/diskMemory/Entity.h @@ -0,0 +1,65 @@ +#pragma once + +#include <filesystem> + +#include "../base/Entity.h" + +#include "EntitySnapshot.h" + +#include "../workingMemory/Entity.h" + + +namespace armarx::armem::diskMemory +{ + /** + * @brief An entity over a period of time. + * + * An entity should be a physical thing or abstract concept existing + * (and potentially evolving) over some time. + * + * Examples are: + * - objects (the green box) + * - agents (robot, human) + * - locations (frige, sink) + * - grasp affordances (general, or for a specific object) + * - images + * - point clouds + * - other sensory values + * + * At each point in time (`EntitySnapshot`), the entity can have a + * (potentially variable) number of instances (`EntityInstance`), + * each containing a single `AronData` object of a specific `AronType`. + */ + class Entity : + virtual public EntityBase<EntitySnapshot, Entity> + { + + public: + using Base = EntityBase<EntitySnapshot, Entity>; + using EntitySnapshotT = EntitySnapshot; + + Entity(); + Entity(const std::string& name, const MemoryID& parentID = {}); + Entity(const MemoryID& id); + + /// Copy the history from `other` to this. + Entity(const Entity& other); + /// Copy the history from `other` to this. + Entity& operator=(const Entity& other); + + // Conversion + workingmemory::Entity convert(const aron::typenavigator::NavigatorPtr& expectedStructure) const; + + // Filesystem connection + void reload(const std::shared_ptr<std::filesystem::path>&); + void append(const workingmemory::Entity&); + + private: + std::filesystem::path _fullPath() const; + std::filesystem::path _fullPath(const std::filesystem::path&) const; + + public: + std::shared_ptr<std::filesystem::path> path; + }; + +} diff --git a/source/RobotAPI/libraries/armem/core/diskMemory/EntityInstance.cpp b/source/RobotAPI/libraries/armem/core/diskMemory/EntityInstance.cpp new file mode 100644 index 000000000..dc131b44b --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/diskMemory/EntityInstance.cpp @@ -0,0 +1,201 @@ +#include "EntityInstance.h" + +#include <iostream> +#include <fstream> + +#include "../../core/error.h" + +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <RobotAPI/libraries/aron/core/io/dataIO/converter/Converter.h> +#include <RobotAPI/libraries/aron/core/io/dataIO/visitor/Visitor.h> +#include <RobotAPI/libraries/aron/core/io/dataIO/reader/nlohmannJSON/NlohmannJSONReader.h> +#include <RobotAPI/libraries/aron/core/io/dataIO/writer/nlohmannJSON/NlohmannJSONWriter.h> + +namespace armarx::armem::diskMemory +{ + EntityInstance::EntityInstance() + { + } + + EntityInstance::EntityInstance(const EntityInstance& other) : + MemoryItem(other.id) + { + } + + EntityInstance::EntityInstance(int index, const MemoryID& parentID) : + EntityInstance(parentID.withInstanceIndex(index)) + { + } + + EntityInstance::EntityInstance(const MemoryID& id) : + MemoryItem(id) + { + } + + EntityInstance& EntityInstance::operator=(const EntityInstance& other) + { + other._copySelf(*this); + return *this; + } + + bool EntityInstance::equalsDeep(const EntityInstance& other) const + { + return id == other.id; + } + + void EntityInstance::update(const EntityUpdate& update, int index) + { + ARMARX_CHECK_FITS_SIZE(index, update.instancesData.size()); + + this->index() = index; + } + + EntityInstance EntityInstance::copy() const + { + EntityInstance d; + this->_copySelf(d); + return d; + } + + void EntityInstance::_copySelf(EntityInstance& other) const + { + EntityInstanceBase<EntityInstance>::_copySelf(other); + } + + std::filesystem::path EntityInstance::_fullPath() const + { + if(path) + { + return _fullPath(*path); + } + return std::filesystem::path(); + } + + std::filesystem::path EntityInstance::_fullPath(const std::filesystem::path& path) const + { + return path / id.memoryName / id.coreSegmentName / id.providerSegmentName / id.entityName / std::to_string(id.timestamp.toMicroSeconds()) / std::to_string(id.instanceIndex); + } + + workingmemory::EntityInstance EntityInstance::convert(const aron::typenavigator::NavigatorPtr& expectedStructure) const + { + std::filesystem::path p = _fullPath(); + std::filesystem::path d = p / (std::string(DATA_FILENAME) + ".json"); + + if(std::filesystem::is_regular_file(d)) + { + std::ifstream ifs(d); + std::string file_content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>())); + aron::dataIO::reader::NlohmannJSONReader dataReader(file_content); + aron::dataIO::writer::NavigatorWriter navWriter; + + aron::dataIO::Converter::ReadAndConvert(dataReader, navWriter, expectedStructure); + + aron::datanavigator::DictNavigatorPtr aron = aron::datanavigator::DictNavigator::DynamicCastAndCheck(navWriter.getResult()); + return unwrapData(aron); + } + else + { + throw error::ArMemError("An diskMemory EntityInstance is not leading to a regular file."); + } + } + + void EntityInstance::reload(const std::shared_ptr<std::filesystem::path>& p_ptr) + { + if(!p_ptr) + { + ARMARX_WARNING << "The entered is NULL."; + } + std::filesystem::path p = _fullPath(*p_ptr); + if(!std::filesystem::is_directory(p)) + { + ARMARX_ERROR << "The entered path is not leading to a file! This is an error since if the folder for an EntityInstance exists there must be a data file in it (containing at least the metadata)."; + } + else + { + path = p_ptr; + } + } + + void EntityInstance::setTo(const workingmemory::EntityInstance& m) + { + std::filesystem::path p = _fullPath(); + std::filesystem::create_directories(p); + + std::filesystem::path d = p / (std::string(DATA_FILENAME) + ".json"); + + if(std::filesystem::is_regular_file(d)) + { + std::filesystem::remove(d); + } + + std::ofstream ofs; + ofs.open(d); + + aron::datanavigator::DictNavigatorPtr aron = wrapData(m); + aron::dataIO::writer::NlohmannJSONWriter dataWriter; + aron::dataIO::Visitor::VisitAndSetup(dataWriter, aron); + std::string new_file_full_content = dataWriter.getResult().dump(2); + + ofs << new_file_full_content; + ofs.close(); + } + + + workingmemory::EntityInstance EntityInstance::unwrapData(const aron::datanavigator::DictNavigatorPtr& dataWrapped) const + { + workingmemory::EntityInstance e(id); + workingmemory::EntityInstanceMetadata& metadata = e.metadata(); + + if (dataWrapped->hasElement(DATA_WRAPPER_DATA_FIELD)) + { + aron::datanavigator::DictNavigatorPtr data = aron::datanavigator::DictNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_DATA_FIELD)); + e.setData(data); + } + + auto timeCreated = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_CREATED_FIELD)); + metadata.timeCreated = Time::microSeconds(timeCreated->toAronLongPtr()->value); + + auto timeSent = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_SENT_FIELD)); + metadata.timeSent = Time::microSeconds(timeSent->toAronLongPtr()->value); + + auto timeArrived = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_ARRIVED_FIELD)); + metadata.timeArrived = Time::microSeconds(timeArrived->toAronLongPtr()->value); + + auto confidence = aron::datanavigator::DoubleNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_CONFIDENCE_FIELD)); + metadata.confidence = static_cast<float>(confidence->toAronDoublePtr()->value); + + return e; + } + + aron::datanavigator::DictNavigatorPtr EntityInstance::wrapData(const workingmemory::EntityInstance& e) const + { + auto dataWrapped = std::make_shared<aron::datanavigator::DictNavigator>(); + if(e.data()) + { + dataWrapped->addElement(DATA_WRAPPER_DATA_FIELD, e.data()); + } + + auto timeWrapped = std::make_shared<aron::datanavigator::LongNavigator>(); + timeWrapped->setValue(Time::now().toMicroSeconds()); + dataWrapped->addElement(DATA_WRAPPER_TIME_STORED_FIELD, timeWrapped); + + const workingmemory::EntityInstanceMetadata& metadata = e.metadata(); + auto timeCreated = std::make_shared<aron::datanavigator::LongNavigator>(); + timeCreated->setValue(metadata.timeCreated.toMicroSeconds()); + dataWrapped->addElement(DATA_WRAPPER_TIME_CREATED_FIELD, timeCreated); + + auto timeSent = std::make_shared<aron::datanavigator::LongNavigator>(); + timeSent->setValue(metadata.timeSent.toMicroSeconds()); + dataWrapped->addElement(DATA_WRAPPER_TIME_SENT_FIELD, timeSent); + + auto timeArrived = std::make_shared<aron::datanavigator::LongNavigator>(); + timeArrived->setValue(metadata.timeArrived.toMicroSeconds()); + dataWrapped->addElement(DATA_WRAPPER_TIME_ARRIVED_FIELD, timeArrived); + + auto confidence = std::make_shared<aron::datanavigator::DoubleNavigator>(); + confidence->setValue(metadata.confidence); + dataWrapped->addElement(DATA_WRAPPER_CONFIDENCE_FIELD, confidence); + + return dataWrapped; + } +} diff --git a/source/RobotAPI/libraries/armem/core/diskMemory/EntityInstance.h b/source/RobotAPI/libraries/armem/core/diskMemory/EntityInstance.h new file mode 100644 index 000000000..6eb97bd13 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/diskMemory/EntityInstance.h @@ -0,0 +1,68 @@ +#pragma once + +#include <filesystem> + +#include "../base/EntityInstance.h" + +#include "../workingMemory/EntityInstance.h" + +namespace armarx::armem::diskMemory +{ + /** + * @brief Data of a single entity instance. + */ + class EntityInstance : + virtual public EntityInstanceBase<EntityInstance> + { + + public: + using Base = EntityInstanceBase<EntityInstance>; + + EntityInstance(); + EntityInstance(const EntityInstance&); + EntityInstance(int index, const MemoryID& parentID = {}); + EntityInstance(const MemoryID& id); + + EntityInstance& operator=(const EntityInstance& other); + + /** + * @brief Fill `*this` with the update's values. + * @param update The update. + * @param index The instances index. + */ + virtual void update(const EntityUpdate& update, int index) override; + + virtual bool equalsDeep(const EntityInstance& other) const override; + + virtual EntityInstance copy() const override; + + // Conversion + workingmemory::EntityInstance convert(const aron::typenavigator::NavigatorPtr& expectedStructure) const; + + // Filesystem connection + void reload(const std::shared_ptr<std::filesystem::path>&); + void setTo(const workingmemory::EntityInstance&); + + protected: + virtual void _copySelf(EntityInstance& other) const override; + + private: + std::filesystem::path _fullPath() const; + std::filesystem::path _fullPath(const std::filesystem::path&) const; + + workingmemory::EntityInstance unwrapData(const aron::datanavigator::DictNavigatorPtr&) const; + aron::datanavigator::DictNavigatorPtr wrapData(const workingmemory::EntityInstance&) const; + + public: + std::shared_ptr<std::filesystem::path> path; + + private: + static const constexpr char* DATA_FILENAME = "data"; + static constexpr const char* DATA_WRAPPER_DATA_FIELD = "__ARON_DATA"; + static constexpr const char* DATA_WRAPPER_TIME_STORED_FIELD = "__WRITER_METADATA__TIME_STORED"; + static constexpr const char* DATA_WRAPPER_TIME_CREATED_FIELD = "__ENTITY_METADATA__TIME_CREATED"; + static constexpr const char* DATA_WRAPPER_TIME_SENT_FIELD = "__ENTITY_METADATA__TIME_SENT"; + static constexpr const char* DATA_WRAPPER_TIME_ARRIVED_FIELD = "__ENTITY_METADATA__TIME_ARRIVED"; + static constexpr const char* DATA_WRAPPER_CONFIDENCE_FIELD = "__ENTITY_METADATA__CONFIDENCE"; + }; +} diff --git a/source/RobotAPI/libraries/armem/core/diskMemory/EntitySnapshot.cpp b/source/RobotAPI/libraries/armem/core/diskMemory/EntitySnapshot.cpp new file mode 100644 index 000000000..05e4bd68c --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/diskMemory/EntitySnapshot.cpp @@ -0,0 +1,112 @@ +#include "EntitySnapshot.h" + +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include "error.h" + + +namespace armarx::armem::diskMemory +{ + + + EntitySnapshot::EntitySnapshot() + { + } + + EntitySnapshot::EntitySnapshot(Time time, const MemoryID& parentID) : + EntitySnapshot(parentID.withTimestamp(time)) + { + } + + EntitySnapshot::EntitySnapshot(const MemoryID& id) : + MemoryItem(id) + { + } + + EntitySnapshot::EntitySnapshot(const EntitySnapshot& other) : + armarx::armem::detail::MemoryItem(other), + armarx::armem::detail::MemoryContainerBase<std::vector<EntityInstance>, EntitySnapshot>(other) + { + } + + EntitySnapshot& EntitySnapshot::operator=(const EntitySnapshot& other) + { + other._copySelf(*this); + return *this; + } + + std::filesystem::path EntitySnapshot::_fullPath() const + { + if(path) + { + return _fullPath(*path); + } + return std::filesystem::path(); + } + + std::filesystem::path EntitySnapshot::_fullPath(const std::filesystem::path& path) const + { + return path / id.memoryName / id.coreSegmentName / id.providerSegmentName / id.entityName / std::to_string(id.timestamp.toMicroSeconds()); + } + + workingmemory::EntitySnapshot EntitySnapshot::convert(const aron::typenavigator::NavigatorPtr& expectedStructure) const + { + workingmemory::EntitySnapshot m; + for (const auto& s : container) + { + m.addInstance(s.convert(expectedStructure)); + } + return m; + } + + void EntitySnapshot::reload(const std::shared_ptr<std::filesystem::path>& p_ptr) + { + if(!p_ptr) + { + ARMARX_WARNING << "The entered is NULL."; + } + std::filesystem::path p = _fullPath(*p_ptr); + if(!std::filesystem::is_directory(p)) + { + ARMARX_ERROR << "The entered path is not leading to a directory! Every EntitySnapshot must at least contain one EntityInstance."; + } + else + { + container.clear(); + path = p_ptr; + + // todo + for (int i = 0; i < 1000; ++i) + { + std::filesystem::path d = p / std::to_string(i); + if(std::filesystem::is_directory(d)) + { + auto wms = container.emplace_back(id.withInstanceIndex(i)); + wms.reload(p_ptr); + } + else + { + break; + } + } + } + } + + void EntitySnapshot::setTo(const workingmemory::EntitySnapshot& m) + { + std::filesystem::create_directories(_fullPath()); + + // We remove the contente here and reset it with new values + container.clear(); + + unsigned int i = 0; + for (const auto& s : m.container) + { + std::filesystem::create_directory(_fullPath() / std::to_string(i)); + + auto wms = container.emplace_back(id.withInstanceIndex(i++)); + wms.path = path; + wms.setTo(s); + } + } +} diff --git a/source/RobotAPI/libraries/armem/core/diskMemory/EntitySnapshot.h b/source/RobotAPI/libraries/armem/core/diskMemory/EntitySnapshot.h new file mode 100644 index 000000000..d286ce8f5 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/diskMemory/EntitySnapshot.h @@ -0,0 +1,50 @@ +#pragma once + +#include <filesystem> + +#include "../base/EntitySnapshot.h" + +#include "EntityInstance.h" + +#include "../workingMemory/EntitySnapshot.h" + + +namespace armarx::armem::diskMemory +{ + + /** + * @brief Data of an entity at one point in time. + */ + class EntitySnapshot : + virtual public EntitySnapshotBase<EntityInstance, EntitySnapshot> + { + + public: + using Base = EntitySnapshotBase<EntityInstance, EntitySnapshot>; + using EntityInstanceT = EntityInstance; + + EntitySnapshot(); + EntitySnapshot(Time time, const MemoryID& parentID = {}); + EntitySnapshot(const MemoryID& id); + + /// Copy the instances from `other` to this. + EntitySnapshot(const EntitySnapshot& other); + + /// Copy the instances from `other` to this. + EntitySnapshot& operator=(const EntitySnapshot& other); + + // Conversion + void reload(const std::shared_ptr<std::filesystem::path>&); + workingmemory::EntitySnapshot convert(const aron::typenavigator::NavigatorPtr& expectedStructure) const; + + // MongoDB connection + void setTo(const workingmemory::EntitySnapshot&); + + private: + std::filesystem::path _fullPath() const; + std::filesystem::path _fullPath(const std::filesystem::path&) const; + + public: + std::shared_ptr<std::filesystem::path> path; + }; +} diff --git a/source/RobotAPI/libraries/armem/core/diskMemory/Memory.cpp b/source/RobotAPI/libraries/armem/core/diskMemory/Memory.cpp new file mode 100644 index 000000000..0b99f1460 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/diskMemory/Memory.cpp @@ -0,0 +1,112 @@ +#include "Memory.h" + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include "error.h" + + +namespace armarx::armem::diskMemory +{ + + Memory::Memory() + { + } + + Memory::Memory(const std::string& name) : + armarx::armem::detail::MemoryItem(MemoryID().withMemoryName(name)) + { + } + + Memory::Memory(const MemoryID& id) : + MemoryItem(id) + { + } + + Memory::Memory(const Memory& other) : + armarx::armem::detail::MemoryItem(other), + MemoryContainerBase<std::map<std::string, CoreSegment>, Memory>(other) + { + *this = other; + } + + Memory& Memory::operator=(const Memory& other) + { + other._copySelf(*this); + return *this; + } + + std::filesystem::path Memory::_fullPath() const + { + if(path) + { + return _fullPath(*path); + } + return std::filesystem::path(); + } + + std::filesystem::path Memory::_fullPath(const std::filesystem::path& path) const + { + return path / id.memoryName; + } + + workingmemory::Memory Memory::convert() const + { + workingmemory::Memory m; + for (const auto& [_, s] : container) + { + m.addCoreSegment(s.convert()); + } + return m; + } + + void Memory::reload(const std::filesystem::path& p) + { + if(std::filesystem::is_regular_file(p)) + { + ARMARX_ERROR << "The entered path is leading to a file! Abort due to error."; + } + + container.clear(); + path = std::make_shared<std::filesystem::path>(p.parent_path()); + + if(!std::filesystem::exists(p)) + { + ARMARX_INFO << "The entered path does not exist. Assuming an empty container."; + } + else + { + id = MemoryID().withMemoryName(p.filename()); + + for (const auto& d : std::filesystem::directory_iterator(p)) + { + if(d.is_directory()) + { + std::string k = d.path().filename(); + auto wms = container.emplace(std::make_pair(k, id.withCoreSegmentName(k))); + wms.first->second.reload(path); + } + } + } + } + + void Memory::append(const workingmemory::Memory& m) + { + std::filesystem::create_directories(_fullPath()); + for (const auto& [k, s] : m.container) + { + if (const auto& it = container.find(k); it != container.end()) + { + it->second.append(s); + } + else + { + std::filesystem::create_directory(_fullPath() / k); + + auto wms = container.emplace(std::make_pair(k, id.withCoreSegmentName(k))); + wms.first->second.path = path; + wms.first->second.append(s); + } + } + } +} diff --git a/source/RobotAPI/libraries/armem/core/diskMemory/Memory.h b/source/RobotAPI/libraries/armem/core/diskMemory/Memory.h new file mode 100644 index 000000000..a32b1dcc1 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/diskMemory/Memory.h @@ -0,0 +1,45 @@ +#pragma once + +#include <filesystem> + +#include "../base/Memory.h" + +#include "CoreSegment.h" + +#include "../workingMemory/Memory.h" + +namespace armarx::armem::diskMemory +{ + + /** + * @brief Data of a memory consisting of multiple core segments. + */ + class Memory : + virtual public MemoryBase<CoreSegment, Memory> + { + public: + using Base = MemoryBase<CoreSegment, Memory>; + using CoreSegmentT = CoreSegment; + + Memory(); + Memory(const std::string& name); + Memory(const MemoryID& id); + + Memory(const Memory& other); + Memory& operator=(const Memory& other); + + // Conversion + workingmemory::Memory convert() const; + + // Filesystem connection + void reload(const std::filesystem::path&); + void append(const workingmemory::Memory&); + + private: + std::filesystem::path _fullPath() const; + std::filesystem::path _fullPath(const std::filesystem::path&) const; + + public: + std::shared_ptr<std::filesystem::path> path; + }; +} diff --git a/source/RobotAPI/libraries/armem/core/diskMemory/ProviderSegment.cpp b/source/RobotAPI/libraries/armem/core/diskMemory/ProviderSegment.cpp new file mode 100644 index 000000000..0afa005a8 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/diskMemory/ProviderSegment.cpp @@ -0,0 +1,135 @@ +#include "ProviderSegment.h" + +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include "error.h" + + +namespace armarx::armem::diskMemory +{ + + ProviderSegment::ProviderSegment() + { + } + + ProviderSegment::ProviderSegment(const std::string& name, aron::typenavigator::ObjectNavigatorPtr aronType) : + armarx::armem::detail::MemoryItem(MemoryID().withProviderSegmentName(name)), + armarx::armem::detail::TypedEntityContainerBase<Entity, Entity, ProviderSegment>(MemoryID().withProviderSegmentName(name), aronType) + { + } + + ProviderSegment::ProviderSegment(const std::string& name, const MemoryID parentID, aron::typenavigator::ObjectNavigatorPtr aronType) : + armarx::armem::detail::MemoryItem(parentID.withProviderSegmentName(name)), + armarx::armem::detail::TypedEntityContainerBase<Entity, Entity, ProviderSegment>(parentID.withProviderSegmentName(name), aronType) + { + } + + ProviderSegment::ProviderSegment(const MemoryID id, aron::typenavigator::ObjectNavigatorPtr aronType) : + armarx::armem::detail::MemoryItem(id), + armarx::armem::detail::TypedEntityContainerBase<Entity, Entity, ProviderSegment>(id, aronType) + { + } + + ProviderSegment::ProviderSegment(const ProviderSegment& other) : + armarx::armem::detail::MemoryItem(other), + MemoryContainerBase<std::map<std::string, Entity>, ProviderSegment>(other), + armarx::armem::detail::TypedEntityContainerBase<Entity, Entity, ProviderSegment>(other) + { + } + + ProviderSegment& ProviderSegment::operator=(const ProviderSegment& other) + { + other._copySelf(*this); + return *this; + } + + std::filesystem::path ProviderSegment::_fullPath() const + { + if(path) + { + return _fullPath(*path); + } + return std::filesystem::path(); + } + + std::filesystem::path ProviderSegment::_fullPath(const std::filesystem::path& path) const + { + return path / id.memoryName / id.coreSegmentName / id.providerSegmentName; + } + + workingmemory::ProviderSegment ProviderSegment::convert(const aron::typenavigator::NavigatorPtr& expectedStructure) const + { + workingmemory::ProviderSegment m; + for (const auto& [_, s] : container) + { + if(hasAronType()) + { + m.addEntity(s.convert(aronType)); + } + else + { + m.addEntity(s.convert(expectedStructure)); + } + } + return m; + } + + void ProviderSegment::reload(const std::shared_ptr<std::filesystem::path>& p_ptr) + { + if(!p_ptr) + { + ARMARX_WARNING << "The entered is NULL."; + } + std::filesystem::path p = _fullPath(*p_ptr); + if(std::filesystem::is_regular_file(p)) + { + ARMARX_ERROR << "The entered path is leading to a file! Abort due to error."; + } + + container.clear(); + path = p_ptr; + + if(!std::filesystem::exists(p)) + { + ARMARX_INFO << "The entered path does not exist. Assuming an empty container."; + } + else + { + for (const auto& d : std::filesystem::directory_iterator(p)) + { + if(d.is_directory()) + { + std::string k = d.path().filename(); + auto wms = container.emplace(std::make_pair(k, id.withEntityName(k))); + wms.first->second.reload(p_ptr); + } + + if(d.is_regular_file()) + { + readAronType(d.path()); + } + } + } + } + + void ProviderSegment::append(const workingmemory::ProviderSegment& m) + { + std::filesystem::create_directories(_fullPath()); + writeAronType(_fullPath()); + + for (const auto& [k, s] : m.container) + { + if (const auto& it = container.find(k); it != container.end()) + { + it->second.append(s); + } + else + { + std::filesystem::create_directory(_fullPath() / k); + auto wms = container.emplace(std::make_pair(k, id.withEntityName(k))); + wms.first->second.path = path; + wms.first->second.append(s); + } + } + } +} diff --git a/source/RobotAPI/libraries/armem/core/diskMemory/ProviderSegment.h b/source/RobotAPI/libraries/armem/core/diskMemory/ProviderSegment.h new file mode 100644 index 000000000..2a2033d74 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/diskMemory/ProviderSegment.h @@ -0,0 +1,50 @@ +#pragma once + +#include <filesystem> + +#include "../base/ProviderSegment.h" +#include "detail/TypedEntityContainer.h" + +#include "Entity.h" + +#include "../workingMemory/ProviderSegment.h" + + +namespace armarx::armem::diskMemory +{ + + /** + * @brief Data of a provider segment containing multiple entities. + */ + class ProviderSegment : + virtual public ProviderSegmentBase<Entity, ProviderSegment>, + virtual public detail::TypedEntityContainer<Entity, ProviderSegment> + { + public: + using Base = ProviderSegmentBase<Entity, ProviderSegment>; + using EntityT = Entity; + + ProviderSegment(); + ProviderSegment(const std::string& name, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr); + ProviderSegment(const std::string& name, const MemoryID parentID, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr); + ProviderSegment(const MemoryID id, aron::typenavigator::ObjectNavigatorPtr aronType = nullptr); + + ProviderSegment(const ProviderSegment& other); + ProviderSegment& operator=(const ProviderSegment& other); + + // Conversion + workingmemory::ProviderSegment convert(const aron::typenavigator::NavigatorPtr& expectedStructure) const; + + // Filesystem connection + void reload(const std::shared_ptr<std::filesystem::path>&); + void append(const workingmemory::ProviderSegment&); + + private: + std::filesystem::path _fullPath() const; + std::filesystem::path _fullPath(const std::filesystem::path&) const; + + public: + std::shared_ptr<std::filesystem::path> path; + }; + +} diff --git a/source/RobotAPI/libraries/armem/core/diskMemory/detail/TypedEntityContainer.h b/source/RobotAPI/libraries/armem/core/diskMemory/detail/TypedEntityContainer.h new file mode 100644 index 000000000..205cffa96 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/diskMemory/detail/TypedEntityContainer.h @@ -0,0 +1,100 @@ +#pragma once + +#include <iostream> +#include <fstream> + +#include "../../base/detail/TypedEntityContainer.h" +#include "../Entity.h" + +#include <RobotAPI/libraries/aron/core/navigator/type/container/Object.h> +#include <RobotAPI/libraries/aron/core/io/typeIO/visitor/Visitor.h> +#include <RobotAPI/libraries/aron/core/io/typeIO/converter/Converter.h> +#include <RobotAPI/libraries/aron/core/io/typeIO/reader/nlohmannJSON/NlohmannJSONReader.h> +#include <RobotAPI/libraries/aron/core/io/typeIO/writer/navigator/NavigatorWriter.h> +#include <RobotAPI/libraries/aron/core/io/typeIO/writer/nlohmannJSON/NlohmannJSONWriter.h> + +namespace armarx::armem::diskMemory::detail +{ + + /** + * @brief An entity container with a specific (Aron) type. + */ + template <class _ValueT, class Derived> + class TypedEntityContainer : + virtual public armarx::armem::detail::TypedEntityContainerBase<_ValueT, Entity, Derived> + { + using Base = armarx::armem::detail::TypedEntityContainerBase<_ValueT, Entity, Derived>; + + public: + TypedEntityContainer& operator=(const TypedEntityContainer& other) + { + other._copySelf(*this); + return *this; + } + + protected: + aron::typenavigator::ObjectNavigatorPtr unwrapType(const aron::typenavigator::ObjectNavigatorPtr& t) const + { + return aron::typenavigator::ObjectNavigator::DynamicCastAndCheck(t->getMemberType(TYPE_WRAPPER_DATA_FIELD)); + } + + aron::typenavigator::ObjectNavigatorPtr wrapType(const aron::typenavigator::ObjectNavigatorPtr& t) const + { + aron::typenavigator::ObjectNavigatorPtr typeWrapped(new aron::typenavigator::ObjectNavigator()); + typeWrapped->setObjectName(t->getObjectName() + "__ltm_type_export"); + typeWrapped->addMemberType(TYPE_WRAPPER_DATA_FIELD, t); + + typeWrapped->addMemberType(TYPE_WRAPPER_TIME_STORED_FIELD, std::make_shared<aron::typenavigator::LongNavigator>()); + typeWrapped->addMemberType(TYPE_WRAPPER_TIME_CREATED_FIELD, std::make_shared<aron::typenavigator::LongNavigator>()); + typeWrapped->addMemberType(TYPE_WRAPPER_TIME_SENT_FIELD, std::make_shared<aron::typenavigator::LongNavigator>()); + typeWrapped->addMemberType(TYPE_WRAPPER_TIME_ARRIVED_FIELD, std::make_shared<aron::typenavigator::LongNavigator>()); + typeWrapped->addMemberType(TYPE_WRAPPER_CONFIDENCE_FIELD, std::make_shared<aron::typenavigator::DoubleNavigator>()); + + return typeWrapped; + } + + using Base::aronType; + void readAronType(const std::filesystem::path& d) + { + if(std::filesystem::is_regular_file(d)) + { + if(d.filename() == (std::string(TYPE_FILENAME) + ".json")) + { + std::ifstream ifs(d); + std::string file_content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>())); + + aron::typeIO::reader::NlohmannJSONReader typeReader(file_content); + aron::typeIO::writer::NavigatorWriter navWriter; + aron::typeIO::Converter::ReadAndConvert(typeReader, navWriter); + aronType = aron::typenavigator::ObjectNavigator::DynamicCastAndCheck(navWriter.getResult()); + } + } + } + + using Base::hasAronType; + void writeAronType(const std::filesystem::path& d) + { + if(hasAronType()) + { + std::ofstream ofs; + ofs.open(d); + + aron::typeIO::writer::NlohmannJSONWriter typeWriter; + aron::typeIO::Visitor::VisitAndSetup(typeWriter, aronType); + std::string new_file_full_content = typeWriter.getResult().dump(2); + + ofs << new_file_full_content; + ofs.close(); + } + } + + private: + static const constexpr char* TYPE_FILENAME = "type"; + static constexpr const char* TYPE_WRAPPER_DATA_FIELD = "__ARON_DATA"; + static constexpr const char* TYPE_WRAPPER_TIME_STORED_FIELD = "__WRITER_METADATA__TIME_STORED"; + static constexpr const char* TYPE_WRAPPER_TIME_CREATED_FIELD = "__ENTITY_METADATA__TIME_CREATED"; + static constexpr const char* TYPE_WRAPPER_TIME_SENT_FIELD = "__ENTITY_METADATA__TIME_SENT"; + static constexpr const char* TYPE_WRAPPER_TIME_ARRIVED_FIELD = "__ENTITY_METADATA__TIME_ARRIVED"; + static constexpr const char* TYPE_WRAPPER_CONFIDENCE_FIELD = "__ENTITY_METADATA__CONFIDENCE"; + }; +} diff --git a/source/RobotAPI/libraries/armem/core/longtermMemory/CoreSegment.h b/source/RobotAPI/libraries/armem/core/longtermMemory/CoreSegment.h index ec710907f..ed8b60c67 100644 --- a/source/RobotAPI/libraries/armem/core/longtermMemory/CoreSegment.h +++ b/source/RobotAPI/libraries/armem/core/longtermMemory/CoreSegment.h @@ -3,7 +3,6 @@ #include "../base/CoreSegment.h" #include "ProviderSegment.h" -#include "detail/TypedEntityContainer.h" #include "../workingMemory/CoreSegment.h" @@ -15,8 +14,7 @@ namespace armarx::armem::longtermmemory * @brief Data of a core segment containing multiple provider segments. */ class CoreSegment : - virtual public CoreSegmentBase<ProviderSegment, CoreSegment>, - virtual public detail::TypedEntityContainer<ProviderSegment, CoreSegment> + virtual public CoreSegmentBase<ProviderSegment, CoreSegment> { public: using Base = CoreSegmentBase<ProviderSegment, CoreSegment>; diff --git a/source/RobotAPI/libraries/armem/core/longtermMemory/Entity.h b/source/RobotAPI/libraries/armem/core/longtermMemory/Entity.h index 967fa2b76..edc46900e 100644 --- a/source/RobotAPI/libraries/armem/core/longtermMemory/Entity.h +++ b/source/RobotAPI/libraries/armem/core/longtermMemory/Entity.h @@ -3,7 +3,6 @@ #include "../base/Entity.h" #include "EntitySnapshot.h" -#include "detail/MemoryContainer.h" #include "../workingMemory/Entity.h" @@ -30,8 +29,7 @@ namespace armarx::armem::longtermmemory * each containing a single `AronData` object of a specific `AronType`. */ class Entity : - virtual public EntityBase<EntitySnapshot, Entity>, - virtual public detail::MemoryContainer<std::map<Time, EntitySnapshot>, Entity> + virtual public EntityBase<EntitySnapshot, Entity> { public: diff --git a/source/RobotAPI/libraries/armem/core/longtermMemory/EntityInstance.cpp b/source/RobotAPI/libraries/armem/core/longtermMemory/EntityInstance.cpp index 696b5c5c5..d4770ded9 100644 --- a/source/RobotAPI/libraries/armem/core/longtermMemory/EntityInstance.cpp +++ b/source/RobotAPI/libraries/armem/core/longtermMemory/EntityInstance.cpp @@ -2,7 +2,6 @@ #include <ArmarXCore/core/exceptions/local/ExpressionException.h> - namespace armarx::armem::longtermmemory { diff --git a/source/RobotAPI/libraries/armem/core/longtermMemory/EntitySnapshot.h b/source/RobotAPI/libraries/armem/core/longtermMemory/EntitySnapshot.h index 6f2b9c74c..16dc077f3 100644 --- a/source/RobotAPI/libraries/armem/core/longtermMemory/EntitySnapshot.h +++ b/source/RobotAPI/libraries/armem/core/longtermMemory/EntitySnapshot.h @@ -3,7 +3,6 @@ #include "../base/EntitySnapshot.h" #include "EntityInstance.h" -#include "detail/MemoryContainer.h" #include "../workingMemory/EntitySnapshot.h" @@ -15,8 +14,7 @@ namespace armarx::armem::longtermmemory * @brief Data of an entity at one point in time. */ class EntitySnapshot : - virtual public EntitySnapshotBase<EntityInstance, EntitySnapshot>, - virtual public detail::MemoryContainer<std::vector<EntityInstance>, EntitySnapshot> + virtual public EntitySnapshotBase<EntityInstance, EntitySnapshot> { public: diff --git a/source/RobotAPI/libraries/armem/core/longtermMemory/Memory.h b/source/RobotAPI/libraries/armem/core/longtermMemory/Memory.h index 85137aaf4..ab7c8b90f 100644 --- a/source/RobotAPI/libraries/armem/core/longtermMemory/Memory.h +++ b/source/RobotAPI/libraries/armem/core/longtermMemory/Memory.h @@ -3,20 +3,17 @@ #include "../base/Memory.h" #include "CoreSegment.h" -#include "detail/EntityContainer.h" #include "../workingMemory/Memory.h" #include "mongodb/MongoDBConnectionManager.h" namespace armarx::armem::longtermmemory { - /** * @brief Data of a memory consisting of multiple core segments. */ class Memory : - virtual public MemoryBase<CoreSegment, Memory>, - virtual public detail::EntityContainer<CoreSegment, Memory> + virtual public MemoryBase<CoreSegment, Memory> { public: using Base = MemoryBase<CoreSegment, Memory>; diff --git a/source/RobotAPI/libraries/armem/core/longtermMemory/ProviderSegment.h b/source/RobotAPI/libraries/armem/core/longtermMemory/ProviderSegment.h index 0c43e80e1..0ccff9600 100644 --- a/source/RobotAPI/libraries/armem/core/longtermMemory/ProviderSegment.h +++ b/source/RobotAPI/libraries/armem/core/longtermMemory/ProviderSegment.h @@ -3,7 +3,6 @@ #include "../base/ProviderSegment.h" #include "Entity.h" -#include "detail/TypedEntityContainer.h" #include "../workingMemory/ProviderSegment.h" @@ -15,8 +14,7 @@ namespace armarx::armem::longtermmemory * @brief Data of a provider segment containing multiple entities. */ class ProviderSegment : - virtual public ProviderSegmentBase<Entity, ProviderSegment>, - virtual public detail::TypedEntityContainer<Entity, ProviderSegment> + virtual public ProviderSegmentBase<Entity, ProviderSegment> { public: using Base = ProviderSegmentBase<Entity, ProviderSegment>; diff --git a/source/RobotAPI/libraries/armem/core/longtermMemory/detail/EntityContainer.cpp b/source/RobotAPI/libraries/armem/core/longtermMemory/detail/EntityContainer.cpp deleted file mode 100644 index 43ade411e..000000000 --- a/source/RobotAPI/libraries/armem/core/longtermMemory/detail/EntityContainer.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "EntityContainer.h" - -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> - - -namespace armarx::armem::detail -{ - - -} diff --git a/source/RobotAPI/libraries/armem/core/longtermMemory/detail/EntityContainer.h b/source/RobotAPI/libraries/armem/core/longtermMemory/detail/EntityContainer.h deleted file mode 100644 index 73e5ea68e..000000000 --- a/source/RobotAPI/libraries/armem/core/longtermMemory/detail/EntityContainer.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "../../base/detail/EntityContainer.h" -#include "MemoryContainer.h" - -#include "../Entity.h" -#include "../EntitySnapshot.h" -#include "../EntityInstance.h" - - -namespace armarx::armem::longtermmemory::detail -{ - - /** - * @brief A container of entities at some point in the hierarchy. - * - * Can be updated by multiple entity updates. - */ - template <class _ValueT, class Derived> - class EntityContainer : - virtual public armarx::armem::detail::EntityContainerBase<_ValueT, Entity, Derived>, - virtual public MemoryContainer<std::map<std::string, _ValueT>, Derived> - { - public: - EntityContainer& operator=(const EntityContainer& other) - { - other._copySelf(*this); - return *this; - } - }; - -} diff --git a/source/RobotAPI/libraries/armem/core/longtermMemory/detail/MemoryContainer.cpp b/source/RobotAPI/libraries/armem/core/longtermMemory/detail/MemoryContainer.cpp deleted file mode 100644 index 9fd73048f..000000000 --- a/source/RobotAPI/libraries/armem/core/longtermMemory/detail/MemoryContainer.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "MemoryContainer.h" - - -namespace armarx::armem::detail -{ - -} diff --git a/source/RobotAPI/libraries/armem/core/longtermMemory/detail/MemoryContainer.h b/source/RobotAPI/libraries/armem/core/longtermMemory/detail/MemoryContainer.h deleted file mode 100644 index 5913d50db..000000000 --- a/source/RobotAPI/libraries/armem/core/longtermMemory/detail/MemoryContainer.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include <ArmarXCore/core/exceptions/local/ExpressionException.h> - -#include "../../error.h" - -#include "../../base/detail/MemoryContainer.h" - - -namespace armarx::armem::longtermmemory::detail -{ - - /** - * @class Provides default implmentations of `MemoryContainer`, as well as - * iterators (which requires a template). - */ - template <class _ContainerT, class Derived> - class MemoryContainer : - virtual public armarx::armem::detail::MemoryContainerBase<_ContainerT, Derived> - { - public: - MemoryContainer& operator=(const MemoryContainer& other) - { - other._copySelf(*this); - return *this; - } - }; -} diff --git a/source/RobotAPI/libraries/armem/core/longtermMemory/detail/TypedEntityContainer.h b/source/RobotAPI/libraries/armem/core/longtermMemory/detail/TypedEntityContainer.h deleted file mode 100644 index ea826343e..000000000 --- a/source/RobotAPI/libraries/armem/core/longtermMemory/detail/TypedEntityContainer.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "../../base/detail/TypedEntityContainer.h" -#include "EntityContainer.h" - -#include <RobotAPI/libraries/aron/core/navigator/type/container/Object.h> - -namespace armarx::armem::longtermmemory::detail -{ - - /** - * @brief An entity container with a specific (Aron) type. - */ - template <class _ValueT, class Derived> - class TypedEntityContainer : - virtual public armarx::armem::detail::TypedEntityContainerBase<_ValueT, Entity, Derived>, - virtual public EntityContainer<_ValueT, Derived> - { - public: - TypedEntityContainer& operator=(const TypedEntityContainer& other) - { - other._copySelf(*this); - return *this; - } - }; -} diff --git a/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp b/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp index 564984f22..698b1ced4 100644 --- a/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp +++ b/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp @@ -3,7 +3,7 @@ #include <RobotAPI/libraries/armem/core/ice_conversions.h> #include <RobotAPI/libraries/armem_gui/gui_utils.h> -//#include <RobotAPI/libraries/armem/core/io/diskWriter/NlohmannJSON/NlohmannJSONDiskWriter.h> +#include <RobotAPI/libraries/armem/core/diskMemory/Memory.h> #include <ArmarXGui/libraries/SimpleConfigDialog/SimpleConfigDialog.h> @@ -140,7 +140,27 @@ namespace armarx::armem::gui QString qs = ltmControlWidget->getEnteredPath(); std::string utf8_text = qs.toUtf8().constData(); + ARMARX_IMPORTANT << "Exporting all memories at '" << utf8_text << "'."; + std::filesystem::path p(utf8_text); + if (std::filesystem::is_regular_file(p)) + { + ARMARX_WARNING << "Could not export a memory at '" << utf8_text << "'. Skipping export."; + return; + } + + std::filesystem::create_directories(p); + for (auto& [name, reader] : memoryReaders) + { + armem::client::QueryInput input = memoryGroup->queryWidget()->queryInput(); + armem::client::QueryResult result = reader.query(input); + + armem::diskMemory::Memory dMem(name); + ARMARX_IMPORTANT << "RELOAD"; + dMem.reload(p / name); + ARMARX_IMPORTANT << "APPEND"; + dMem.append(result.memory); + } TIMING_END_STREAM(MemoryExport, ARMARX_VERBOSE); } @@ -271,10 +291,6 @@ namespace armarx::armem::gui { convMap[name] = &data.value(); } - /*if (data.second.has_value()) - { - convMap[name].second = &data.second.value(); - }*/ } if (convMap.empty()) -- GitLab