diff --git a/source/RobotAPI/components/ArMemGlobalStorage/ArMemGlobalStorage.cpp b/source/RobotAPI/components/ArMemGlobalStorage/ArMemGlobalStorage.cpp deleted file mode 100644 index 802aea2a766fcbdb39ab77c8ffeb924f5c797c3a..0000000000000000000000000000000000000000 --- a/source/RobotAPI/components/ArMemGlobalStorage/ArMemGlobalStorage.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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::ArMemGlobalStorage - * @author fabian.peller-konrad@kit.edu ( fabian dot peller-konrad at kit dot edu ) - * @date 2020 - * @copyright http://www.gnu.org/licenses/gpl-2.0.txt - * GNU General Public License - */ - -#include "ArMemGlobalStorage.h" - -// STD/STL -#include <algorithm> - -// Boost -#include <boost/asio.hpp> - -// Simox -#include <SimoxUtility/algorithm/string.h> - -// ArmarX -#include <RobotAPI/interface/armem/legacy.h> - -namespace armarx -{ - namespace armem - { - - armarx::PropertyDefinitionsPtr ArMemGlobalStorage::createPropertyDefinitions() - { - PropertyDefinitionsPtr defs{new ComponentPropertyDefinitions{getConfigIdentifier()}}; - - defs->optional(local_memory_names, "LocalMemoryNames", "The objectnames of the local memories, comma separated"); - return defs; - } - - ArMemGlobalStorage::ArMemGlobalStorage(): - armarx::Component(), - armarx::armem::ArMemBase(), - armarx::armem::ArMemGlobalMemoryResolver() - { - } - - std::string ArMemGlobalStorage::getDefaultName() const - { - return "ArMemGlobalStorage"; - } - - - void ArMemGlobalStorage::onInitComponent() - { - for (const std::string& name : simox::alg::split(local_memory_names, ",")) - { - usingProxy(GenerateLocalMemoryObjectNameFromHostname(name)); - } - } - - - void ArMemGlobalStorage::onConnectComponent() - { - for (const std::string& hostname : simox::alg::split(local_memory_names, ",")) - { - ArMemLocalMemoryInterfacePrx localMemoryPrx = getProxy<ArMemLocalMemoryInterfacePrx>(GenerateLocalMemoryObjectNameFromHostname(hostname)); - local_memories[hostname] = localMemoryPrx; - } - } - - - void ArMemGlobalStorage::onDisconnectComponent() - { - - } - - - void ArMemGlobalStorage::onExitComponent() - { - - } - - std::string ArMemGlobalStorage::getHostnameOfCurrentMachine(const Ice::Current&) - { - return getMyHostname(); - } - - ArMemLocalMemoryInterfacePrx ArMemGlobalStorage::getMemoryOfCurrentMachine(const Ice::Current& c) - { - return getMemoryForHostname(getMyHostname(), c); - } - - ArMemLocalMemoryInterfacePrx ArMemGlobalStorage::getMemoryForHostname(const std::string& hostname, const Ice::Current&) - { - if (local_memories.find(hostname) == local_memories.end()) - { - throw LocalException("The local memory of host '" + hostname + "' does not exist!. Could not return proxy!"); - } - return local_memories[hostname]; - } - - void ArMemGlobalStorage::dynamicallyRegisterNewLocalMemory(const std::string& hostname, const Ice::Current&) - { - if (local_memories.find(hostname) == local_memories.end()) - { - ArMemLocalMemoryInterfacePrx localMemoryPrx = getProxy<ArMemLocalMemoryInterfacePrx>(GenerateLocalMemoryObjectNameFromHostname(hostname)); - local_memories[hostname] = localMemoryPrx; - } - } - - void ArMemGlobalStorage::exportDataOfAllMemoriesToLocation(const std::string&, const Ice::Current&) - { - // TODO!! Needs Aron-JSON Export? - } - } -} diff --git a/source/RobotAPI/components/ArMemGlobalStorage/ArMemGlobalStorage.h b/source/RobotAPI/components/ArMemGlobalStorage/ArMemGlobalStorage.h deleted file mode 100644 index 9c9b47801f70c58712d73c68e564ecbd05ba9876..0000000000000000000000000000000000000000 --- a/source/RobotAPI/components/ArMemGlobalStorage/ArMemGlobalStorage.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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::ArMemGlobalStorage - * @author fabian.peller-konrad@kit.edu ( fabian dot peller-konrad at kit dot edu ) - * @date 2020 - * @copyright http://www.gnu.org/licenses/gpl-2.0.txt - * GNU General Public License - */ - -#pragma once - -// STD/STL -#include <map> - -// Aron -#include <RobotAPI/interface/aron.h> -#include <RobotAPI/interface/armem/legacy.h> - -// ArmarX -#include <ArmarXCore/core/Component.h> -#include <RobotAPI/libraries/armem/legacy/ArMemBase.h> - -namespace armarx -{ - namespace armem - { - class ArMemGlobalStorage : - virtual public armarx::Component, - virtual public armarx::armem::ArMemBase, - virtual public armarx::armem::ArMemGlobalMemoryResolver - { - public: - ArMemGlobalStorage(); - - std::string getDefaultName() const override; - - std::string getHostnameOfCurrentMachine(const Ice::Current& = Ice::Current()); - ArMemLocalMemoryInterfacePrx getMemoryOfCurrentMachine(const Ice::Current& = Ice::Current()); - ArMemLocalMemoryInterfacePrx getMemoryForHostname(const std::string&, const Ice::Current& = Ice::Current()); - - void dynamicallyRegisterNewLocalMemory(const std::string&, const Ice::Current& = Ice::Current()); - - void exportDataOfAllMemoriesToLocation(const std::string&, const Ice::Current& = Ice::Current()); - - protected: - void onInitComponent() override; - void onConnectComponent() override; - void onDisconnectComponent() override; - void onExitComponent() override; - armarx::PropertyDefinitionsPtr createPropertyDefinitions() override; - - private: - std::string local_memory_names; - std::map<std::string, ArMemLocalMemoryInterfacePrx> local_memories; - }; - } -} diff --git a/source/RobotAPI/components/ArMemGlobalStorage/CMakeLists.txt b/source/RobotAPI/components/ArMemGlobalStorage/CMakeLists.txt deleted file mode 100644 index df827fa04cd4f34d7c42c861581f12034698a157..0000000000000000000000000000000000000000 --- a/source/RobotAPI/components/ArMemGlobalStorage/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -armarx_component_set_name("ArMemGlobalStorage") - -set(COMPONENT_LIBS - ArmarXCore - ArmarXCoreInterfaces - RobotAPICore - RobotAPIInterfaces - armem -) - -set(SOURCES ArMemGlobalStorage.cpp) -set(HEADERS ArMemGlobalStorage.h) - -armarx_add_component("${SOURCES}" "${HEADERS}") - -# add unit tests -add_subdirectory(test) - -armarx_generate_and_add_component_executable(COMPONENT_NAMESPACE "armarx::armem" APPLICATION_APP_SUFFIX) diff --git a/source/RobotAPI/components/ArMemGlobalStorage/test/ArMemGlobalStorageTest.cpp b/source/RobotAPI/components/ArMemGlobalStorage/test/ArMemGlobalStorageTest.cpp deleted file mode 100644 index f5451b02e484b0fde7ce24805beb9b46cc5c2b60..0000000000000000000000000000000000000000 --- a/source/RobotAPI/components/ArMemGlobalStorage/test/ArMemGlobalStorageTest.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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::ArMemGlobalStorage - * @author fabian.peller-konrad@kit.edu ( fabian dot peller-konrad 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::ArmarXObjects::ArMemGlobalStorage - -#define ARMARX_BOOST_TEST - -#include <RobotAPI/Test.h> -#include <RobotAPI/components/ArMemGlobalStorage/ArMemGlobalStorage.h> - -#include <iostream> - -BOOST_AUTO_TEST_CASE(testExample) -{ - armarx::armem::ArMemGlobalStorage instance; - - BOOST_CHECK_EQUAL(true, true); -} diff --git a/source/RobotAPI/components/ArMemGlobalStorage/test/CMakeLists.txt b/source/RobotAPI/components/ArMemGlobalStorage/test/CMakeLists.txt deleted file mode 100644 index c7cc9e00f7900fb219e4c2b5a089d832c027d1ef..0000000000000000000000000000000000000000 --- a/source/RobotAPI/components/ArMemGlobalStorage/test/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ - -# Libs required for the tests -SET(LIBS ${LIBS} ArmarXCore ArMemGlobalStorage) - -armarx_add_test(ArMemGlobalStorageTest ArMemGlobalStorageTest.cpp "${LIBS}") diff --git a/source/RobotAPI/components/ArMemLocalStorage/ArMemLocalStorage.cpp b/source/RobotAPI/components/ArMemLocalStorage/ArMemLocalStorage.cpp deleted file mode 100644 index 7474703e6289bf2dfbf7aa8c5234307c42e3486c..0000000000000000000000000000000000000000 --- a/source/RobotAPI/components/ArMemLocalStorage/ArMemLocalStorage.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* - * 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::ArMemLocalStorage - * @author fabian.peller-konrad@kit.edu ( fabian dot peller-konrad at kit dot edu ) - * @date 2020 - * @copyright http://www.gnu.org/licenses/gpl-2.0.txt - * GNU General Public License - */ - -// Header -#include "ArMemLocalStorage.h" - -// Boost -#include <boost/asio.hpp> - -namespace armarx -{ - - namespace armem - { - armarx::PropertyDefinitionsPtr ArMemLocalStorage::createPropertyDefinitions() - { - PropertyDefinitionsPtr defs(new ComponentPropertyDefinitions(getConfigIdentifier())); - defs->optional(maximum_segments, "MaximumNumberOfSegments", "Maximum number of segments (<0 means infinite)"); - defs->optional(maximum_entries_per_segment, "MaximumEntriesPerSegment", "Maximum number of accepted datatypes per segment (<0 means infinite)"); - return defs; - } - - std::string ArMemLocalStorage::getDefaultName() const - { - return GenerateLocalMemoryObjectNameFromHostname(getMyHostname()); - } - - ArMemLocalStorage::ArMemLocalStorage() : - armarx::Component(), - armarx::armem::ArMemBase(), - num_segments(0), - num_entries_per_segment(), - maximum_segments(-1), - maximum_entries_per_segment(-1) - { - - } - - void ArMemLocalStorage::onInitComponent() - { - - } - - void ArMemLocalStorage::onConnectComponent() - { - - } - - void ArMemLocalStorage::onDisconnectComponent() - { - - } - - void ArMemLocalStorage::onExitComponent() - { - - } - - ArMemLocalStorage::HasSegmentReturnType ArMemLocalStorage::hasSegment(const std::string& segment) const - { - auto index_pos = indexed_storage.find(segment); - auto timestamped_pos = timestamped_storage.find(segment); - auto hashed_pos = hashed_storage.find(segment); - - if (index_pos == indexed_storage.end() && timestamped_pos == timestamped_storage.end() && hashed_pos == hashed_storage.end()) - { - return HasSegmentReturnType::No; - } - - if (index_pos != indexed_storage.end() && timestamped_pos != timestamped_storage.end() && hashed_pos != hashed_storage.end()) - { - return HasSegmentReturnType::Yes; - } - - bool index_pos_end = (index_pos == indexed_storage.end()); - bool timestamped_pos_end = (timestamped_pos == timestamped_storage.end()); - bool hashed_pos_end = (hashed_pos == hashed_storage.end()); - ARMARX_ERROR << "The memory is in an inconsistent state. A segment was found in some containers but not in all! Resetting segment!\n" - << "The indexed storage " << (index_pos_end ? "does not contain " : "contains ") << " the segment, \n" - << "The timestamped storage " << (timestamped_pos_end ? "does not contain " : "contains ") << " the segment, \n" - << "The hashed storage " << (hashed_pos_end ? "does not contain " : "contains ") << " the segment, \n"; - return HasSegmentReturnType::InvalidState; - } - - - std::string ArMemLocalStorage::commit(const std::string& segment, long sentAt, const std::vector<aron::data::AronDataPtr>& data, const Ice::Current&) - { - // Check if segment already exists - HasSegmentReturnType has_segment = hasSegment(segment); - if (has_segment != HasSegmentReturnType::Yes) - { - // Need to allocate a new storage for a new segment - ARMARX_WARNING << "A new segment '" + segment + "' registered to the memory. Allocating space for its members..."; - indexed_storage[segment] = IndexedDatatypeStorage(); - timestamped_storage[segment] = TimestampedDataTypeStorage(); - hashed_storage[segment] = HashedDataTypeStorage(); - - if (has_segment != HasSegmentReturnType::InvalidState) - { - // Otherwise we reassign the segment again. - num_segments++; - } - } - - IndexedDatatypeStorage& indexed_segment_storage = indexed_storage[segment]; - TimestampedDataTypeStorage& timestamped_segment_storage = timestamped_storage[segment]; - HashedDataTypeStorage& hashed_segment_storage = hashed_storage[segment]; - - long now = IceUtil::Time::now().toMilliSeconds(); - if (sentAt > now) - { - ARMARX_WARNING << "Received an invalid timestamp. The timestamp when sending data to the segment '" + segment + "' is greater than the storage timestamp (The transmitted time needs to be in milliseconds [ms]). Please check!" ; - } - - // Create new memory entry and save result - ArMemCommitPtr entryPtr = ArMemCommitPtr(new ArMemCommit()); - entryPtr->producer = "TODO"; - entryPtr->stored_in_segment = segment; - entryPtr->produce_timestamp_ms = sentAt; - entryPtr->stored_in_segment = IceUtil::Time::now().toMilliSeconds(); - entryPtr->data = data; - - ARMARX_INFO << "Saving a new commit to segment '" + segment + "'"; - std::string string_to_hash = segment + "__" + std::to_string(now); - size_t hash = std::hash<std::string> {}(string_to_hash); - - if (timestamped_segment_storage.find(now) != timestamped_segment_storage.end()) - { - ARMARX_WARNING << "The segment '" + segment + "' already contains a value at timestamp " + std::to_string(now) + ". Overwriting value!"; - } - if (hashed_segment_storage.find(hash) != hashed_segment_storage.end()) - { - ARMARX_WARNING << "The segment '" + segment + "' already contains data at the commit hash " + std::to_string(hash) + ". Overwriting value!"; - } - - std::string hash_as_string = std::to_string(hash); - ARMARX_DEBUG << "Storing new data with hash: " << hash_as_string; - indexed_segment_storage.push_back(entryPtr); - timestamped_segment_storage[now] = entryPtr; - hashed_segment_storage[hash] = entryPtr; - ARMARX_DEBUG << "Stored new data with hash: " << hash_as_string; - ARMARX_DEBUG << "The current segment " << segment << " now contains " << indexed_segment_storage.size() << " elements!"; - return std::to_string(hash); - } - - std::string ArMemLocalStorage::commit_single(const std::string& segment, long generatedTS, const aron::data::AronDataPtr& x, const Ice::Current& c) - { - return commit(segment, generatedTS, {x}, c); - } - - void ArMemLocalStorage::checkStorageIntegrity() const - { - if (indexed_storage.size() != timestamped_storage.size() || - indexed_storage.size() != hashed_storage.size() || - timestamped_storage.size() != hashed_storage.size()) - { - throw LocalException("The memory is in an invalid state. The storages have different sizes! Please Check!"); - } - for (const auto& [segment, datatypeStorage] : indexed_storage) - { - checkStorageIntegrityForSegment(segment); - } - } - - void ArMemLocalStorage::checkStorageIntegrityForSegment(const std::string& segment) const - { - HasSegmentReturnType has_segment = hasSegment(segment); - if (has_segment != HasSegmentReturnType::Yes) - { - throw LocalException("The memory is in an invalid state. Not all storages contain the segment '" + segment + "'! Please Check!"); - } - } - - - ArMemCommitPtr ArMemLocalStorage::getLatestCommitFromSegment(const std::string& segment, const Ice::Current&) - { - HasSegmentReturnType has_segment = hasSegment(segment); - if (has_segment != HasSegmentReturnType::Yes) - { - return nullptr; - } - - int index = indexed_storage[segment].size() - 1; - if (index >= 0) - { - return indexed_storage[segment][index]; - } - return nullptr; - } - - ArMemCommitPtr ArMemLocalStorage::getNextCommitFromSegmentForTimestamp(const std::string&, Ice::Long, const Ice::Current&) - { - return nullptr; - } - - TimestampedArMemCommitList ArMemLocalStorage::getAllCommitsBetweenTimestampsFromSegment(const std::string&, Ice::Long, Ice::Long, const Ice::Current&) - { - return {}; - } - - TimestampedArMemCommitList ArMemLocalStorage::getAllCommitsFromSegment(const std::string&, const Ice::Current&) - { - return {}; - } - } -} diff --git a/source/RobotAPI/components/ArMemLocalStorage/ArMemLocalStorage.h b/source/RobotAPI/components/ArMemLocalStorage/ArMemLocalStorage.h deleted file mode 100644 index ef5622cd60b7f86fdd5096c62fde3e52ee42805d..0000000000000000000000000000000000000000 --- a/source/RobotAPI/components/ArMemLocalStorage/ArMemLocalStorage.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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::ArMemLocalStorage - * @author fabian.peller-konrad@kit.edu ( fabian dot peller-konrad at kit dot edu ) - * @date 2020 - * @copyright http://www.gnu.org/licenses/gpl-2.0.txt - * GNU General Public License - */ - -#pragma once - -// STD/STL -#include <map> - -// Aron -#include <RobotAPI/interface/aron.h> -#include <RobotAPI/interface/armem/legacy.h> - -// ArmarX -#include <ArmarXCore/core/Component.h> -#include <RobotAPI/libraries/armem/legacy/ArMemBase.h> - -namespace armarx -{ - - namespace armem - { - class ArMemLocalStorage : - virtual public armarx::Component, - virtual public armarx::armem::ArMemBase, - virtual public armarx::armem::ArMemLocalMemoryInterface - { - public: - enum HasSegmentReturnType - { - Yes, - No, - InvalidState - }; - - typedef std::vector<ArMemCommitPtr> IndexedDatatypeStorage; - typedef std::map<long, ArMemCommitPtr> TimestampedDataTypeStorage; - typedef std::map<std::size_t, ArMemCommitPtr> HashedDataTypeStorage; - - ArMemLocalStorage(); - - std::string getDefaultName() const override; - - HasSegmentReturnType hasSegment(const std::string&) const; - long size(const std::string&) const; - - ArMemCommitPtr getLatestCommitFromSegment(const std::string&, const Ice::Current& = Ice::Current()); - ArMemCommitPtr getNextCommitFromSegmentForTimestamp(const std::string&, long, const Ice::Current& = Ice::Current()); - TimestampedArMemCommitList getAllCommitsBetweenTimestampsFromSegment(const std::string&, Ice::Long, Ice::Long, const Ice::Current& = Ice::Current()); - TimestampedArMemCommitList getAllCommitsFromSegment(const std::string&, const Ice::Current& = Ice::Current()); - - std::string commit(const std::string& segment, long generatedTS, const std::vector<aron::data::AronDataPtr>&, const Ice::Current& = Ice::Current()); - std::string commit_single(const std::string& segment, long generatedTS, const aron::data::AronDataPtr&, const Ice::Current& = Ice::Current()); - - protected: - void onInitComponent() override; - void onConnectComponent() override; - void onDisconnectComponent() override; - void onExitComponent() override; - - armarx::PropertyDefinitionsPtr createPropertyDefinitions() override; - - private: - - void checkStorageIntegrity() const; - void checkStorageIntegrityForSegment(const std::string&) const; - - private: - std::map<std::string, IndexedDatatypeStorage> indexed_storage; - std::map<std::string, TimestampedDataTypeStorage> timestamped_storage; - std::map<std::string, HashedDataTypeStorage> hashed_storage; - - long num_segments; - std::map<std::string, long> num_entries_per_segment; - - long maximum_segments; - long maximum_entries_per_segment; - }; - } -} diff --git a/source/RobotAPI/components/ArMemLocalStorage/CMakeLists.txt b/source/RobotAPI/components/ArMemLocalStorage/CMakeLists.txt deleted file mode 100644 index 38cac48d2c54abd4d58c5a64ea5fe6b178a1b79a..0000000000000000000000000000000000000000 --- a/source/RobotAPI/components/ArMemLocalStorage/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -armarx_component_set_name("ArMemLocalStorage") - - -set(COMPONENT_LIBS - ArmarXCore - ArmarXCoreInterfaces - RobotAPICore - RobotAPIInterfaces - armem -) - -set(SOURCES - ./ArMemLocalStorage.cpp -) -set(HEADERS - ./ArMemLocalStorage.h -) - - -armarx_add_component("${SOURCES}" "${HEADERS}") - -#find_package(MyLib QUIET) -#armarx_build_if(MyLib_FOUND "MyLib not available") -# all target_include_directories must be guarded by if(Xyz_FOUND) -# for multiple libraries write: if(X_FOUND AND Y_FOUND).... -#if(MyLib_FOUND) -# target_include_directories(ArMemLocalStorage PUBLIC ${MyLib_INCLUDE_DIRS}) -#endif() - -# add unit tests -add_subdirectory(test) - -#generate the application -armarx_generate_and_add_component_executable(COMPONENT_NAMESPACE "armarx::armem" APPLICATION_APP_SUFFIX) diff --git a/source/RobotAPI/components/ArMemLocalStorage/test/ArMemLocalStorageTest.cpp b/source/RobotAPI/components/ArMemLocalStorage/test/ArMemLocalStorageTest.cpp deleted file mode 100644 index 48a74567fdd35708d0d6e30ee8b25f67f4381be3..0000000000000000000000000000000000000000 --- a/source/RobotAPI/components/ArMemLocalStorage/test/ArMemLocalStorageTest.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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::ArMemLocalStorage - * @author fabian.peller-konrad@kit.edu ( fabian dot peller-konrad 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::ArmarXObjects::ArMemLocalStorage - -#define ARMARX_BOOST_TEST - -#include <RobotAPI/Test.h> -#include <RobotAPI/components/ArMemLocalStorage/ArMemLocalStorage.h> - -#include <iostream> - -BOOST_AUTO_TEST_CASE(testExample) -{ - armarx::armem::ArMemLocalStorage instance; - - BOOST_CHECK_EQUAL(true, true); -} diff --git a/source/RobotAPI/components/ArMemLocalStorage/test/CMakeLists.txt b/source/RobotAPI/components/ArMemLocalStorage/test/CMakeLists.txt deleted file mode 100644 index f72cfa041acff0351e753c642b077c34b3e807b8..0000000000000000000000000000000000000000 --- a/source/RobotAPI/components/ArMemLocalStorage/test/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ - -# Libs required for the tests -SET(LIBS ${LIBS} ArmarXCore ArMemLocalStorage) - -armarx_add_test(ArMemLocalStorageTest ArMemLocalStorageTest.cpp "${LIBS}") diff --git a/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.cpp b/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.cpp index 92429966c7a66dbf2411c38ce8cea7ce0328ee16..b0fdb1f3a5622f37bbd0fcd4cfdaa79513e4cc5b 100644 --- a/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.cpp +++ b/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.cpp @@ -27,8 +27,9 @@ #include <RobotAPI/interface/aron.h> -#include <RobotAPI/libraries/armem/core/ice_conversions.h> +#include <RobotAPI/libraries/armem/component/MemoryRemoteGui.h> #include <RobotAPI/libraries/armem/client/MemoryWriter.h> +#include <RobotAPI/libraries/armem/memory/ice_conversions.h> namespace armarx @@ -64,6 +65,9 @@ namespace armarx void ArMemExampleClient::onConnectComponent() { + createRemoteGuiTab(); + RemoteGui_startRunningTask(); + { ARMARX_IMPORTANT << "Waiting for memory '" << memoryName << "'."; armem::Time start = armem::Time::now(); @@ -194,6 +198,68 @@ namespace armarx << "\n- error message: \t" << result.errorMessage ; } + + + if (true) + { + ARMARX_IMPORTANT + << "Querying latest snapshot:" + << "\n- entityID: \t'" << snapshotID << "'" + // << "\n" << *memoryQuery + ; + + armem::query::EntityQueryPtr entityQuery = + // new armem::query::entity::Single(); + new armem::query::entity::All(); + armem::query::ProviderSegmentQueryPtr providerQuery = + new armem::query::provider::Single({entityQuery}, snapshotID.entityName); + // new armem::query::provider::All({entityQuery}); + armem::query::CoreSegmentQueryPtr coreQuery = + new armem::query::core::Single({providerQuery}, snapshotID.providerSegmentName); + armem::query::MemoryQueryPtr memoryQuery = + new armem::query::memory::Single({coreQuery}, snapshotID.coreSegmentName); + + + + armem::data::MemoryPtr iceResult = memory->query({memoryQuery}); + armem::MemoryPtr result = armem::fromIce<armem::MemoryPtr>(iceResult); + + ARMARX_CHECK_EQUAL(result->coreSegments.size(), 1); + + armem::CoreSegmentPtr& coreSeg = result->coreSegments.begin()->second; + ARMARX_CHECK_EQUAL(coreSeg->providerSegments.size(), 1); + + armem::ProviderSegmentPtr& provSeg = coreSeg->providerSegments.begin()->second; + ARMARX_CHECK_EQUAL(provSeg->entities.size(), 1); + + armem::EntityPtr& entity = provSeg->entities.begin()->second; + ARMARX_CHECK_GREATER_EQUAL(entity->history.size(), 1); + + armem::EntitySnapshotPtr& snapshot = entity->history.begin()->second; + + ARMARX_INFO << "Result: " + << "\n- memory: \t" << result->name + << "\n- core segment: \t" << coreSeg->name + << "\n- prov segment: \t" << provSeg->name + << "\n- entity: \t" << entity->name + << "\n- snapshot: \t" << snapshot->time + << "\n- #instances: \t" << snapshot->instances.size() + ; + + + ARMARX_IMPORTANT << "Getting entity from snapshot ID"; + const armem::Entity& e = result->getEntity(snapshotID); + ARMARX_INFO << "Result: " + << "\n- entity: \t" << e.name + << "\n- snapshot: \t" << e.getLatestSnapshot().time + << "\n- #instances: \t" << e.getLatestSnapshot().instances.size() + ; + + + tab.queryResult = std::move(result); + tab.rebuild = true; + } + } @@ -207,9 +273,26 @@ namespace armarx } - void ArMemExampleClient::RemoteGui_update() + void ArMemExampleClient::createRemoteGuiTab() { + using namespace armarx::RemoteGui::Client; + if (tab.queryResult) + { + armem::MemoryRemoteGui mrg; + tab.queryResultGroup = mrg.makeGroupBox(*tab.queryResult); + } + + VBoxLayout root = {tab.queryResultGroup, VSpacer()}; + RemoteGui_createTab(getName(), root, &tab); + } + + void ArMemExampleClient::RemoteGui_update() + { + if (tab.rebuild.exchange(false)) + { + createRemoteGuiTab(); + } } } diff --git a/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.h b/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.h index 9fd9033b2d1e2a97a6ca3ef8db6a13034cf06997..c1f6b4b010acb94c0373fafdb0a8e3d8262e0171 100644 --- a/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.h +++ b/source/RobotAPI/components/armem/ArMemExampleClient/ArMemExampleClient.h @@ -35,6 +35,7 @@ #include <RobotAPI/interface/armem/MemoryNameSystemInterface.h> #include <RobotAPI/libraries/armem/client/MemoryClientComponentPlugin.h> +#include <RobotAPI/libraries/armem/memory/Memory.h> namespace armarx @@ -76,6 +77,7 @@ namespace armarx // LightweightRemoteGuiComponentPluginUser interface public: + void createRemoteGuiTab(); void RemoteGui_update() override; @@ -104,5 +106,15 @@ namespace armarx std::string memoryName = "Example"; armem::MemoryInterfacePrx memory; + + struct RemoteGuiTab : RemoteGui::Client::Tab + { + std::atomic_bool rebuild = false; + + armem::MemoryPtr queryResult; + RemoteGui::Client::GroupBox queryResultGroup; + }; + RemoteGuiTab tab; + }; } diff --git a/source/RobotAPI/interface/CMakeLists.txt b/source/RobotAPI/interface/CMakeLists.txt index 3e693d83079b81a535b6b7abdafa47ee7a3e82ad..ac8108e7589ebfbd6179e61ac64ed5ce3bdb1e1f 100644 --- a/source/RobotAPI/interface/CMakeLists.txt +++ b/source/RobotAPI/interface/CMakeLists.txt @@ -106,8 +106,9 @@ set(SLICE_FILES armem/WritingInterface.ice armem/MemoryInterface.ice armem/MemoryNameSystemInterface.ice - armem/GlobalMemoryResolver.ice - armem/legacy.ice + + armem/query.ice + armem/memory.ice components/ObstacleAvoidance/ObstacleAvoidanceInterface.ice components/ObstacleAvoidance/ObstacleDetectionInterface.ice diff --git a/source/RobotAPI/interface/armem.ice b/source/RobotAPI/interface/armem.ice index b52a5794c64124c0c76583b7587132046ef0db62..6fa4705257ad47e82ec53d8804f9e5d5cadce39c 100644 --- a/source/RobotAPI/interface/armem.ice +++ b/source/RobotAPI/interface/armem.ice @@ -3,8 +3,6 @@ #include <RobotAPI/interface/armem/ReadingInterface.ice> #include <RobotAPI/interface/armem/WritingInterface.ice> #include <RobotAPI/interface/armem/MemoryInterface.ice> -#include <RobotAPI/interface/armem/GlobalMemoryResolver.ice> -#include <RobotAPI/interface/armem/legacy.ice> module armarx diff --git a/source/RobotAPI/interface/armem/GlobalMemoryResolver.ice b/source/RobotAPI/interface/armem/GlobalMemoryResolver.ice deleted file mode 100644 index 2007f49b2e2ddee2ded87a49d6e79c1b205e13f7..0000000000000000000000000000000000000000 --- a/source/RobotAPI/interface/armem/GlobalMemoryResolver.ice +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include <RobotAPI/interface/armem/MemoryInterface.ice> - - -module armarx -{ - module armem - { - - interface GlobalMemoryResolver - { - string getHostnameOfCurrentMachine(); - MemoryInterface* getMemoryOfCurrentMachine(); - MemoryInterface* getMemoryForHostname(string hostname); - - void dynamicallyRegisterNewLocalMemory(string hostname); - - void exportDataOfAllMemoriesToLocation(string location); - } - - }; -}; diff --git a/source/RobotAPI/interface/armem/ReadingInterface.ice b/source/RobotAPI/interface/armem/ReadingInterface.ice index a803ae44bda9ddb716bcb6c487020f7c44f6b840..a85c5d90c0adfb786f7c53d0ec356c7fe250fab3 100644 --- a/source/RobotAPI/interface/armem/ReadingInterface.ice +++ b/source/RobotAPI/interface/armem/ReadingInterface.ice @@ -2,13 +2,14 @@ #include <RobotAPI/interface/aron.ice> +#include <RobotAPI/interface/armem/query.ice> +#include <RobotAPI/interface/armem/memory.ice> + module armarx { module armem { - // WIP - module data { struct EntitySnapshotQuery @@ -35,6 +36,8 @@ module armarx interface ReadingInterface { data::EntitySnapshotQueryResultList getEntitySnapshots(data::EntitySnapshotQueryList queries); + + data::Memory query(query::MemoryQuerySeq queries); }; }; diff --git a/source/RobotAPI/interface/armem/legacy.ice b/source/RobotAPI/interface/armem/legacy.ice deleted file mode 100644 index d40c24027b70f045bf69685793f52ca29536042e..0000000000000000000000000000000000000000 --- a/source/RobotAPI/interface/armem/legacy.ice +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include <RobotAPI/interface/aron.ice> - - -module armarx -{ - module armem - { - // data in a commit - class ArMemCommit - { - string producer; - string stored_in_segment; - long produce_timestamp_ms; - long storage_timestamp_ms; - int priority; - aron::data::AronDataList data; // Dict?!? - }; - - // map storageTS to commit - dictionary<long, ArMemCommit> TimestampedArMemCommitList; - - - interface ArMemReceiverInterface - { - ArMemCommit getLatestCommitFromSegment(string segment); - ArMemCommit getNextCommitFromSegmentForTimestamp(string segment, long timestamp); - TimestampedArMemCommitList getAllCommitsBetweenTimestampsFromSegment(string segment, long timestamp1, long timestamp2); - TimestampedArMemCommitList getAllCommitsFromSegment(string segment); - }; - - interface ArMemProducerInterface - { - string commit(string segment, long produceTimestamp, aron::data::AronDataList values); - string commit_single(string segment, long produceTimestamp, aron::data::AronData value); - }; - - interface ArMemLocalMemoryInterface - extends ArMemReceiverInterface, ArMemProducerInterface - { - - }; - - interface ArMemGlobalMemoryResolver - { - string getHostnameOfCurrentMachine(); - ArMemLocalMemoryInterface* getMemoryOfCurrentMachine(); - ArMemLocalMemoryInterface* getMemoryForHostname(string hostname); - - void dynamicallyRegisterNewLocalMemory(string hostname); - - void exportDataOfAllMemoriesToLocation(string location); - } - - }; -}; diff --git a/source/RobotAPI/interface/armem/memory.ice b/source/RobotAPI/interface/armem/memory.ice new file mode 100644 index 0000000000000000000000000000000000000000..68d25c0e32bd4dd8d4eabc366bc961bf18079338 --- /dev/null +++ b/source/RobotAPI/interface/armem/memory.ice @@ -0,0 +1,83 @@ +#pragma once + +#include <RobotAPI/interface/aron.ice> + + +module armarx +{ + module armem + { + // WIP + + module data + { + /// Ice Twin of `armarx::armem::EntityMetadata`. + class EntityMetadata + { + long timeCreatedMicroSeconds; + long timeSentMicroSeconds; + long timeArrivedMicroSeconds; + + float confidence = 1.0; + }; + /// Ice Twin of `armarx::armem::EntityData`. + class EntityData + { + int index; + aron::data::AronData data; + + EntityMetadata metadata; + }; + sequence<EntityData> EntityDataSeq; + + + /// Ice Twin of `armarx::armem::EntitySnapshot`. + class EntitySnapshot + { + long timeMicroSeconds; + EntityDataSeq instances; + }; + dictionary<long, EntitySnapshot> EntityHistory; + + + /// Ice Twin of `armarx::armem::Entity`. + class Entity + { + string name; + EntityHistory history; + }; + dictionary<string, Entity> EntityDict; + + + /// Ice Twin of `armarx::armem::ProviderSegment`. + class ProviderSegment + { + string name; + EntityDict entities; + }; + dictionary<string, ProviderSegment> ProviderSegmentDict; + + + /// Ice Twin of `armarx::armem::CoreSegment`. + class CoreSegment + { + string name; + // aron::type::AronType type; + ProviderSegmentDict providerSegments; + }; + dictionary<string, CoreSegment> CoreSegmentDict; + + + /// Ice Twin of `armarx::armem::Memory`. + class Memory + { + string name; + // aron::type::AronType type; + CoreSegmentDict coreSegments; + }; + dictionary<string, Memory> MemoryDict; + + } + + }; +}; diff --git a/source/RobotAPI/interface/armem/query.ice b/source/RobotAPI/interface/armem/query.ice new file mode 100644 index 0000000000000000000000000000000000000000..87cd1b1e5787f00d9fedebb9aa23601276ff48af --- /dev/null +++ b/source/RobotAPI/interface/armem/query.ice @@ -0,0 +1,110 @@ +#pragma once + +#include <RobotAPI/interface/aron.ice> + + +module armarx +{ + module armem + { + module query + { + + /// Which entity snapshots to get from an entity? + class EntityQuery + { + }; + sequence<EntityQuery> EntityQuerySeq; + + module entity + { + class All extends EntityQuery + { + }; + class Single extends EntityQuery + { + long timestamp = -1; // -1 for latest + }; + class Range extends EntityQuery + { + long minTimestamp = -1; // -1 for oldest + long maxTimestamp = -1; // -1 for latest + }; + } + + + /// Which entities to get from a provider segment? + class ProviderSegmentQuery + { + EntityQuerySeq entityQueries; + }; + sequence<ProviderSegmentQuery> ProviderSegmentQuerySeq; + module provider + { + class All extends ProviderSegmentQuery + { + }; + class Single extends ProviderSegmentQuery + { + string entityName; + }; + class Regex extends ProviderSegmentQuery + { + string entityNameRegex; + }; + } + + + /// Which provider segments to get from a core segment? + class CoreSegmentQuery + { + ProviderSegmentQuerySeq providerSegmentQueries; + }; + sequence<CoreSegmentQuery> CoreSegmentQuerySeq; + + module core + { + class All extends CoreSegmentQuery + { + }; + class Single extends CoreSegmentQuery + { + string providerSegmentName; + }; + class Regex extends CoreSegmentQuery + { + string providerSegmentNameRegex; + }; + } + + + /// Which core segments to get from a memory? + class MemoryQuery + { + CoreSegmentQuerySeq coreSegmentQueries; + }; + sequence<MemoryQuery> MemoryQuerySeq; + + module memory + { + class All extends MemoryQuery + { + }; + class Single extends MemoryQuery + { + string coreSegmentName; + }; + class Regex extends MemoryQuery + { + string coreSegmentNameRegex; + }; + } + } + + interface someReadingInterface + { + // data::EntitySnapshotQueryResultList getEntitySnapshots(data::EntitySnapshotQueryList queries); + }; + + }; +}; diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt index 080a8124129ca9996024e5595d2c478ed53bd257..8d3ab648046b4322c0dd12753d9465296ddbacc9 100644 --- a/source/RobotAPI/libraries/armem/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem/CMakeLists.txt @@ -40,6 +40,12 @@ set(LIB_FILES component/MemoryComponentPlugin.cpp component/MemoryRemoteGui.cpp + query/BaseQueryProcessor.cpp + query/EntityQueryProcessor.cpp + query/ProviderSegmentQueryProcessor.cpp + query/CoreSegmentQueryProcessor.cpp + query/MemoryQueryProcessor.cpp + legacy/ArMemBase.cpp ) set(LIB_HEADERS @@ -73,6 +79,13 @@ set(LIB_HEADERS component/MemoryComponentPlugin.h component/MemoryRemoteGui.h + query.h + query/BaseQueryProcessor.h + query/EntityQueryProcessor.h + query/ProviderSegmentQueryProcessor.h + query/CoreSegmentQueryProcessor.h + query/MemoryQueryProcessor.h + legacy/ArMemBase.h ) diff --git a/source/RobotAPI/libraries/armem/component/IceMemory.cpp b/source/RobotAPI/libraries/armem/component/IceMemory.cpp index c446b8e95746f8956aa8ae60cdb4a16b1adc31e8..936818e1656e87e4f65715e90af7ccd65ad6de79 100644 --- a/source/RobotAPI/libraries/armem/component/IceMemory.cpp +++ b/source/RobotAPI/libraries/armem/component/IceMemory.cpp @@ -4,6 +4,7 @@ #include "../error.h" #include "../memory/ice_conversions.h" +#include "../query/MemoryQueryProcessor.h" namespace armarx::armem @@ -14,6 +15,8 @@ namespace armarx::armem } + // WRITING + armem::data::AddSegmentResult IceMemory::addSegment(const armem::data::AddSegmentInput& input, bool addCoreSegments) { ARMARX_DEBUG << "Adding segment '" << input.coreSegmentName << "/" << input.providerSegmentName << "'."; @@ -122,4 +125,15 @@ namespace armarx::armem return commitResult; } + + // READING + + armem::data::MemoryPtr IceMemory::query(const armem::query::MemoryQuerySeq& queries) + { + ARMARX_CHECK_NOT_NULL(memory); + + armem::MemoryQueryProcessor processor; + return processor.processToIce(queries, *memory); + } + } diff --git a/source/RobotAPI/libraries/armem/component/IceMemory.h b/source/RobotAPI/libraries/armem/component/IceMemory.h index 1be749224a800fc4e9f3e5ac1fd474ec95f3fcd0..641b679a666d1b96b42e8c8f0b6e8317128c4ea3 100644 --- a/source/RobotAPI/libraries/armem/component/IceMemory.h +++ b/source/RobotAPI/libraries/armem/component/IceMemory.h @@ -23,6 +23,8 @@ namespace armarx::armem IceMemory(Memory* memory = nullptr); + // WRITING + armem::data::AddSegmentResult addSegment( const armem::data::AddSegmentInput& input, bool addCoreSegments = false); @@ -34,6 +36,11 @@ namespace armarx::armem armem::CommitResult commit(const armem::InternalCommit& commit); + // READING + + armem::data::MemoryPtr query(const armem::query::MemoryQuerySeq& queries); + + public: Memory* memory; diff --git a/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.cpp b/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.cpp index fad77819edd1d3702b0d2b2bfb31a034cd29f0f5..151e908967016117635b555506a2365174713116 100644 --- a/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.cpp +++ b/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.cpp @@ -150,5 +150,10 @@ namespace armarx::armem return results; } + armem::data::MemoryPtr MemoryComponentPluginUser::query(const armem::query::MemoryQuerySeq& queries, const Ice::Current&) + { + std::scoped_lock lock(memoryMutex); + return iceMemory.query(queries); + } } diff --git a/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.h b/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.h index 39a26a3bfb0b0ec0e04d4883961555cba0106f17..a1e0bd423dff46d6ae9914917d85013bd7a01c7e 100644 --- a/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.h +++ b/source/RobotAPI/libraries/armem/component/MemoryComponentPlugin.h @@ -75,6 +75,7 @@ namespace armarx::armem // ReadingInterface interface virtual armem::data::EntitySnapshotQueryResultList getEntitySnapshots(const armem::data::EntitySnapshotQueryList&, const Ice::Current& = Ice::emptyCurrent) override; + virtual armem::data::MemoryPtr query(const armem::query::MemoryQuerySeq& queries, const Ice::Current& = Ice::emptyCurrent) override; public: diff --git a/source/RobotAPI/libraries/armem/core/ice_conversions.cpp b/source/RobotAPI/libraries/armem/core/ice_conversions.cpp index cc046eed9aaed88f84215b316e0ebcaf380a6286..03d26fb5d7bead2123f2d02577140c773fc045f5 100644 --- a/source/RobotAPI/libraries/armem/core/ice_conversions.cpp +++ b/source/RobotAPI/libraries/armem/core/ice_conversions.cpp @@ -4,6 +4,19 @@ namespace armarx { +/* + void armem::fromIce(long ice, Time& time) + { + time = Time::microSeconds(ice); + } + + void armem::toIce(long& ice, const Time& time) + { + ice = time.toMicroSeconds(); + } +*/ + + void armem::fromIce(const data::Commit& ice, Commit& commit) { commit.updates.clear(); @@ -86,3 +99,5 @@ namespace armarx } + + diff --git a/source/RobotAPI/libraries/armem/core/ice_conversions.h b/source/RobotAPI/libraries/armem/core/ice_conversions.h index e29b0edcf1f616577dc4d497518979cc4d4362f2..9b7550f683c1f1ead59f6ee40717eb744545e6d3 100644 --- a/source/RobotAPI/libraries/armem/core/ice_conversions.h +++ b/source/RobotAPI/libraries/armem/core/ice_conversions.h @@ -1,14 +1,33 @@ #pragma once +#include <memory> #include <RobotAPI/interface/armem/MemoryInterface.h> #include "Commit.h" +namespace IceUtil +{ + // Define in original namespace to allow ADL. + inline void fromIce(long ice, Time& time) + { + time = Time::microSeconds(ice); + } + inline void toIce(long& ice, const Time& time) + { + ice = time.toMicroSeconds(); + } +} + + namespace armarx::armem { + // void fromIce(long ice, Time& time); + // void toIce(long& ice, const Time& time); + + void fromIce(const data::Commit& ice, Commit& commit); void toIce(data::Commit& ice, const Commit& commit); @@ -22,4 +41,128 @@ namespace armarx::armem void fromIce(const data::EntityUpdateResult& ice, EntityUpdateResult& result); void toIce(data::EntityUpdateResult& ice, const EntityUpdateResult& result); + + template <class T> + void toIce(T& ice, const T& cpp) + { + ice = cpp; + } + template <class T> + void fromIce(const T& ice, T& cpp) + { + cpp = ice; + } + + template <class IceT, class CppT> + IceT toIce(const CppT& cpp) + { + IceT ice; + toIce(ice, cpp); + return ice; + } + template <class CppT, class IceT> + CppT fromIce(const IceT& ice) + { + CppT cpp; + fromIce(ice, cpp); + return cpp; + } + + template <class IceT, class CppT> + void toIce(IceT& ice, const std::unique_ptr<CppT>& cppPointer) + { + toIce(ice, *cppPointer); + } + template <class IceT, class CppT> + void fromIce(const IceT& ice, std::unique_ptr<CppT>& cppPointer) + { + cppPointer = std::make_unique<CppT>(); + fromIce(ice, *cppPointer); + } + + template <class IceT, class CppT> + void toIce(::IceInternal::Handle<IceT>& ice, const CppT& cpp) + { + ice = new IceT(); + toIce(*ice, cpp); + } + template <class IceT, class CppT> + void fromIce(const ::IceInternal::Handle<IceT>& ice, CppT& cpp) + { + fromIce(*ice, cpp); + } + + template <class IceT, class CppT> + void toIce(::IceInternal::Handle<IceT>& ice, const std::unique_ptr<CppT>& cppPointer) + { + ice = new IceT(); + toIce(*ice, *cppPointer); + } + template <class IceT, class CppT> + void fromIce(const ::IceInternal::Handle<IceT>& ice, std::unique_ptr<CppT>& cppPointer) + { + cppPointer = std::make_unique<CppT>(); + fromIce(*ice, *cppPointer); + } + + template <class IceT, class CppT> + void toIce(std::vector<IceT>& ices, const std::vector<CppT>& cpps) + { + ices.clear(); + ices.reserve(cpps.size()); + for (const auto& cpp : cpps) + { + toIce(ices.emplace_back(), cpp); + } + } + template <class IceT, class CppT> + void fromIce(const std::vector<IceT>& ices, std::vector<CppT>& cpps) + { + cpps.clear(); + cpps.reserve(ices.size()); + for (const auto& ice : ices) + { + fromIce(ice, cpps.emplace_back()); + } + } + + template <class IceT, class CppT> + std::vector<IceT> toIce(const std::vector<CppT>& cpps) + { + std::vector<IceT> ices; + toIce(ices, cpps); + return ices; + } + + + template <class IceKeyT, class IceValueT, class CppKeyT, class CppValueT> + void toIce(std::map<IceKeyT, IceValueT>& iceMap, + const std::map<CppKeyT, CppValueT>& cppMap) + { + iceMap.clear(); + for (const auto& [key, value] : cppMap) + { + iceMap.emplace(toIce<IceKeyT>(key), toIce<IceValueT>(value)); + } + } + template <class IceKeyT, class IceValueT, class CppKeyT, class CppValueT> + void fromIce(const std::map<IceKeyT, IceValueT>& iceMap, + std::map<CppKeyT, CppValueT>& cppMap) + { + cppMap.clear(); + for (const auto& [key, value] : iceMap) + { + cppMap.emplace(fromIce<CppKeyT>(key), fromIce<CppValueT>(value)); + } + } + + template <class IceKeyT, class IceValueT, class CppKeyT, class CppValueT> + std::map<IceKeyT, IceValueT> toIce(const std::map<CppKeyT, CppValueT>& cppMap) + { + std::map<IceKeyT, IceValueT> iceMap; + toIce(iceMap, cppMap); + return iceMap; + } + + } diff --git a/source/RobotAPI/libraries/armem/error/ArMemError.cpp b/source/RobotAPI/libraries/armem/error/ArMemError.cpp index 3ba1c5d840964bf8c6fe30016f47f6e139e8d47f..249d7588c285307114385a49046dd9aba5e97617 100644 --- a/source/RobotAPI/libraries/armem/error/ArMemError.cpp +++ b/source/RobotAPI/libraries/armem/error/ArMemError.cpp @@ -117,4 +117,18 @@ namespace armarx::armem::error return ss.str(); } + + + UnknownQueryType::UnknownQueryType(const std::string& term, const std::string& typeName) : + ArMemError(makeMsg(term, typeName)) + { + } + + std::string UnknownQueryType::makeMsg(const std::string& term, const std::string& typeName) + { + std::stringstream ss; + ss << "Unknown " << term << " query type '" << typeName << "'."; + return ss.str(); + } + } diff --git a/source/RobotAPI/libraries/armem/error/ArMemError.h b/source/RobotAPI/libraries/armem/error/ArMemError.h index b529ffc4bfd6b1222e335f7cd1842954bd036210..5dd1a9118fb11a1b66405d15fd41b544955c2bdb 100644 --- a/source/RobotAPI/libraries/armem/error/ArMemError.h +++ b/source/RobotAPI/libraries/armem/error/ArMemError.h @@ -1,6 +1,7 @@ #pragma once #include <stdexcept> +#include <SimoxUtility/meta/type_name.h> #include "../core/MemoryID.h" @@ -107,5 +108,24 @@ namespace armarx::armem::error }; + /** + * @brief Indicates that an entity's history was queried, but is empty. + */ + class UnknownQueryType : public ArMemError + { + public: + + template <class QueryType> + UnknownQueryType(const std::string& term, const QueryType& query) : + UnknownQueryType(term, simox::meta::get_type_name(query)) + { + } + UnknownQueryType(const std::string& term, const std::string& typeName); + + static std::string makeMsg(const std::string& term, const std::string& typeName); + + }; + + } diff --git a/source/RobotAPI/libraries/armem/memory/CoreSegment.cpp b/source/RobotAPI/libraries/armem/memory/CoreSegment.cpp index c2b4814416960e55accdf151a6e127ab358391e0..bf3c6e2894721818c8124d6acbcd1a4752bd10d0 100644 --- a/source/RobotAPI/libraries/armem/memory/CoreSegment.cpp +++ b/source/RobotAPI/libraries/armem/memory/CoreSegment.cpp @@ -8,6 +8,34 @@ namespace armarx::armem { + CoreSegment::CoreSegment(const CoreSegment& other) : EntityStorage (other) + { + *this = other; + } + + CoreSegment& CoreSegment::operator=(const CoreSegment& other) + { + this->name = other.name; + + this->providerSegments.clear(); + for (const auto& [name, entity] : other.providerSegments) + { + this->providerSegments.emplace(name, std::make_unique<ProviderSegment>(*entity)); + } + + return *this; + } + + CoreSegment::~CoreSegment() + { + } + + CoreSegmentPtr CoreSegment::getEmptyCopy() const + { + CoreSegmentPtr other = std::make_unique<CoreSegment>(); + other->name = this->name; + return other; + } bool CoreSegment::hasProviderSegment(const std::string& name) const { @@ -15,6 +43,11 @@ namespace armarx::armem } ProviderSegment& CoreSegment::getProviderSegment(const std::string& name) + { + return const_cast<ProviderSegment&>(const_cast<const CoreSegment*>(this)->getProviderSegment(name)); + } + + const ProviderSegment& CoreSegment::getProviderSegment(const std::string& name) const { auto it = this->providerSegments.find(name); if (it != providerSegments.end()) @@ -28,7 +61,7 @@ namespace armarx::armem } } - Entity& CoreSegment::getEntity(const MemoryID& id) + const Entity& CoreSegment::getEntity(const MemoryID& id) const { checkStorageName(id.coreSegmentName, this->name, "core segment"); return getProviderSegment(id.providerSegmentName).getEntity(id); @@ -46,6 +79,17 @@ namespace armarx::armem return *it->second; } + ProviderSegment& CoreSegment::addProviderSegment(const ProviderSegment& providerSegment) + { + return addProviderSegment(std::make_unique<ProviderSegment>(providerSegment)); + } + + ProviderSegment& CoreSegment::addProviderSegment(ProviderSegmentPtr&& providerSegment) + { + auto it = providerSegments.emplace(providerSegment->name, std::move(providerSegment)).first; + return *it->second; + } + MemoryID CoreSegment::update(const InternalEntityUpdate& update) { diff --git a/source/RobotAPI/libraries/armem/memory/CoreSegment.h b/source/RobotAPI/libraries/armem/memory/CoreSegment.h index fecf5168bdfdc64616d01eec1ad4751116b27ada..5436b03eb665744d24d6f99bc3537c435c63d5d1 100644 --- a/source/RobotAPI/libraries/armem/memory/CoreSegment.h +++ b/source/RobotAPI/libraries/armem/memory/CoreSegment.h @@ -11,6 +11,9 @@ namespace armarx::armem { + class CoreSegment; + using CoreSegmentPtr = std::unique_ptr<CoreSegment>; + /** * @brief Data of a core segment containing multiple provider segments. */ @@ -20,27 +23,39 @@ namespace armarx::armem using EntityStorage::EntityStorage; + CoreSegment(const CoreSegment& other); + CoreSegment& operator=(const CoreSegment& other); + + ~CoreSegment() override; + + + CoreSegmentPtr getEmptyCopy() const; + bool hasProviderSegment(const std::string& name) const; - ProviderSegment& getProviderSegment(const std::string& name); - Entity& getEntity(const MemoryID& id) override; + ProviderSegment& getProviderSegment(const std::string& name); + const ProviderSegment& getProviderSegment(const std::string& name) const; + const Entity& getEntity(const MemoryID& id) const override; - ProviderSegment& addProviderSegment(const std::string& name); virtual MemoryID update(const InternalEntityUpdate& update) override; using EntityStorage::update; + ProviderSegment& addProviderSegment(const std::string& name); + ProviderSegment& addProviderSegment(const ProviderSegment& providerSegment); + ProviderSegment& addProviderSegment(ProviderSegmentPtr&& providerSegment); + + void clear() override; public: + aron::type::AronTypePtr type; std::map<std::string, ProviderSegmentPtr> providerSegments; }; - using CoreSegmentPtr = std::unique_ptr<CoreSegment>; - } diff --git a/source/RobotAPI/libraries/armem/memory/Entity.cpp b/source/RobotAPI/libraries/armem/memory/Entity.cpp index 502c29fb5868690c7630b7649aad794acb61222f..e961eee5166795c3e641ac045743e74e6b9d43d5 100644 --- a/source/RobotAPI/libraries/armem/memory/Entity.cpp +++ b/source/RobotAPI/libraries/armem/memory/Entity.cpp @@ -16,12 +16,44 @@ namespace armarx::armem { } + Entity::Entity(const Entity& other) + { + *this = other; + } + + Entity& Entity::operator=(const Entity& other) + { + this->name = other.name; + this->maxHistorySize = other.maxHistorySize; + + this->history.clear(); + for (const auto& [time, snapshot] : other.history) + { + this->addSnapshot(*snapshot); + } + + return *this; + } + + EntityPtr Entity::getEmptyCopy() const + { + EntityPtr other = std::make_unique<Entity>(); + other->name = this->name; + other->maxHistorySize = this->maxHistorySize; + return other; + } + bool Entity::hasSnapshot(Time time) const { return history.count(time) > 0; } EntitySnapshot& Entity::getSnapshot(Time time) + { + return const_cast<EntitySnapshot&>(const_cast<const Entity*>(this)->getSnapshot(time)); + } + + const EntitySnapshot&Entity::getSnapshot(Time time) const { auto it = history.find(time); if (it != history.end()) @@ -37,12 +69,22 @@ namespace armarx::armem } EntitySnapshot& Entity::getSnapshot(const MemoryID& id) + { + return const_cast<EntitySnapshot&>(const_cast<const Entity*>(this)->getSnapshot(id)); + } + + const EntitySnapshot&Entity::getSnapshot(const MemoryID& id) const { checkEntityName(id.entityName); return getSnapshot(id.timestamp); } EntitySnapshot& Entity::getLatestSnapshot() + { + return const_cast<EntitySnapshot&>(const_cast<const Entity*>(this)->getLatestSnapshot()); + } + + const EntitySnapshot& Entity::getLatestSnapshot() const { if (history.empty()) { @@ -53,6 +95,18 @@ namespace armarx::armem } + EntitySnapshot& Entity::addSnapshot(const EntitySnapshot& snapshot) + { + return addSnapshot(std::make_unique<EntitySnapshot>(snapshot)); + } + + EntitySnapshot&Entity::addSnapshot(EntitySnapshotPtr&& snapshot) + { + auto it = history.emplace(snapshot->time, std::move(snapshot)).first; + return *it->second; + } + + MemoryID Entity::update(const InternalEntityUpdate& update) { checkEntityName(update.entityID.entityName); diff --git a/source/RobotAPI/libraries/armem/memory/Entity.h b/source/RobotAPI/libraries/armem/memory/Entity.h index 53a1d21830376dfe1e2fb59411a3f90423916c8b..7c2e590a1c1d2717d80c1b53f17c4cb303d4f710 100644 --- a/source/RobotAPI/libraries/armem/memory/Entity.h +++ b/source/RobotAPI/libraries/armem/memory/Entity.h @@ -12,6 +12,9 @@ namespace armarx::armem { + class Entity; + using EntityPtr = std::unique_ptr<Entity>; + /** * @brief Data of an entity over a period of time. */ @@ -22,15 +25,30 @@ namespace armarx::armem Entity(); Entity(const std::string& name); + /// Copy the history from `other` to this. + Entity(const Entity& other); + /// Copy the history from `other` to this. + Entity& operator=(const Entity& other); + + + /// Get an empty copy of `*this`. + EntityPtr getEmptyCopy() const; + + bool hasSnapshot(Time time) const; + EntitySnapshot& getSnapshot(Time time); + const EntitySnapshot& getSnapshot(Time time) const; + EntitySnapshot& getSnapshot(const MemoryID& id); + const EntitySnapshot& getSnapshot(const MemoryID& id) const; /** * @brief Return the snapshot with the most recent timestamp. * @return The latest snapshot. */ EntitySnapshot& getLatestSnapshot(); + const EntitySnapshot& getLatestSnapshot() const; /** @@ -40,6 +58,10 @@ namespace armarx::armem */ MemoryID update(const InternalEntityUpdate& update); + /// Add a single snapshot. + EntitySnapshot& addSnapshot(const EntitySnapshot& snapshot); + EntitySnapshot& addSnapshot(EntitySnapshotPtr&& snapshot); + /** * @brief Sets the maximum history size. * @@ -71,6 +93,4 @@ namespace armarx::armem }; - using EntityPtr = std::unique_ptr<Entity>; - } diff --git a/source/RobotAPI/libraries/armem/memory/EntityData.cpp b/source/RobotAPI/libraries/armem/memory/EntityData.cpp index 957157f3523c1511c0ceafab370cdb46a514c097..670b8b3ae8afaf0a0bdf36d1ff2e2b85fe49503d 100644 --- a/source/RobotAPI/libraries/armem/memory/EntityData.cpp +++ b/source/RobotAPI/libraries/armem/memory/EntityData.cpp @@ -12,6 +12,15 @@ namespace armarx::armem this->index = index; this->data = update.instancesData.at(size_t(index)); + try + { + this->dataNavigator = aron::datanavigator::AronDataNavigator::FromAronData(this->data); + } + catch (const armarx::LocalException&) + { + this->dataNavigator = nullptr; + } + this->metadata.confidence = update.confidence; diff --git a/source/RobotAPI/libraries/armem/memory/EntityData.h b/source/RobotAPI/libraries/armem/memory/EntityData.h index 113ab78077b270541640c6e577f542d34ba94127..0d8abf52098e715bc8a383d40bc8e6e84340cad7 100644 --- a/source/RobotAPI/libraries/armem/memory/EntityData.h +++ b/source/RobotAPI/libraries/armem/memory/EntityData.h @@ -3,6 +3,7 @@ #include <memory> #include <RobotAPI/interface/aron.h> +#include <RobotAPI/libraries/aron/aroncore/navigators/datanavigator/AronDataNavigator.h> #include "../core/Time.h" @@ -36,7 +37,11 @@ namespace armarx::armem { int index; + /// The actual data. aron::data::AronDataPtr data; + /// Allows investigating `data`'s structure. + aron::datanavigator::AronDataNavigatorPtr dataNavigator; + EntityMetadata metadata; /** diff --git a/source/RobotAPI/libraries/armem/memory/EntitySnapshot.cpp b/source/RobotAPI/libraries/armem/memory/EntitySnapshot.cpp index b55c477c5480966908a929c5c99388e1fc671c17..077b208b9794df9987e3466b0b4ed0d7eec243b4 100644 --- a/source/RobotAPI/libraries/armem/memory/EntitySnapshot.cpp +++ b/source/RobotAPI/libraries/armem/memory/EntitySnapshot.cpp @@ -9,6 +9,24 @@ namespace armarx::armem { + EntitySnapshot::EntitySnapshot(const EntitySnapshot& other) + { + *this = other; + } + + EntitySnapshot& EntitySnapshot::operator=(const EntitySnapshot& other) + { + this->time = other.time; + this->instances.clear(); + this->instances.reserve(other.instances.size()); + for (const auto& data : other.instances) + { + this->instances.emplace_back(std::make_unique<EntityData>(*data)); + } + + return *this; + } + void EntitySnapshot::update(const InternalEntityUpdate& update) { time = update.timeCreated; diff --git a/source/RobotAPI/libraries/armem/memory/EntitySnapshot.h b/source/RobotAPI/libraries/armem/memory/EntitySnapshot.h index 78c5f9e61e4709d827afe6d1a7a484512ca90b81..b6ae2d0ca0bc0d7ce99b1ad86eed3fe9957b67a3 100644 --- a/source/RobotAPI/libraries/armem/memory/EntitySnapshot.h +++ b/source/RobotAPI/libraries/armem/memory/EntitySnapshot.h @@ -21,6 +21,11 @@ namespace armarx::armem EntitySnapshot() = default; + /// Copy the instances from `other` to this. + EntitySnapshot(const EntitySnapshot& other); + /// Copy the instances from `other` to this. + EntitySnapshot& operator=(const EntitySnapshot& other); + void update(const InternalEntityUpdate& update); diff --git a/source/RobotAPI/libraries/armem/memory/EntityStorage.cpp b/source/RobotAPI/libraries/armem/memory/EntityStorage.cpp index ccae15c3ff29f6554953fcc717140fbcee337b95..742d4f027f4cfeb89ab004a88597c74d8a38ef02 100644 --- a/source/RobotAPI/libraries/armem/memory/EntityStorage.cpp +++ b/source/RobotAPI/libraries/armem/memory/EntityStorage.cpp @@ -26,9 +26,19 @@ namespace armarx::armem return ids; } + Entity& EntityStorage::getEntity(const MemoryID& id) + { + return const_cast<Entity&>(const_cast<const EntityStorage*>(this)->getEntity(id)); + } + EntitySnapshot& EntityStorage::getEntitySnapshot(const MemoryID& id) { - Entity& entity = getEntity(id); + return const_cast<EntitySnapshot&>(const_cast<const EntityStorage*>(this)->getEntitySnapshot(id)); + } + + const EntitySnapshot&EntityStorage::getEntitySnapshot(const MemoryID& id) const + { + const Entity& entity = getEntity(id); if (id.hasTimestamp()) { diff --git a/source/RobotAPI/libraries/armem/memory/EntityStorage.h b/source/RobotAPI/libraries/armem/memory/EntityStorage.h index 43ad2f6b589e54ef04989a5028bc4e7cbd1113fa..75ba385a3012fa50e1911b3cfb8298b628a35f42 100644 --- a/source/RobotAPI/libraries/armem/memory/EntityStorage.h +++ b/source/RobotAPI/libraries/armem/memory/EntityStorage.h @@ -47,7 +47,8 @@ namespace armarx::armem * @return The entity. * @throw An exception deriving from `armem::error::ArMemError` if the entity is missing. */ - virtual Entity& getEntity(const MemoryID& id) = 0; + virtual Entity& getEntity(const MemoryID& id); + virtual const Entity& getEntity(const MemoryID& id) const = 0; /** * @brief Retrieve an entity snapshot. @@ -59,6 +60,8 @@ namespace armarx::armem * @throw An exception deriving from `armem::error::ArMemError` if the snapshot is missing. */ virtual EntitySnapshot& getEntitySnapshot(const MemoryID& id); + virtual const EntitySnapshot& getEntitySnapshot(const MemoryID& id) const; + protected: diff --git a/source/RobotAPI/libraries/armem/memory/Memory.cpp b/source/RobotAPI/libraries/armem/memory/Memory.cpp index c96f6fe48a2c50c8ed8ffc17b96a6eca29ebb653..c42de46863a196c083bf2f1fb7113ce8684fa37a 100644 --- a/source/RobotAPI/libraries/armem/memory/Memory.cpp +++ b/source/RobotAPI/libraries/armem/memory/Memory.cpp @@ -9,12 +9,45 @@ namespace armarx::armem { + Memory::Memory(const Memory& other) : EntityStorage (other) + { + *this = other; + } + + Memory& Memory::operator=(const Memory& other) + { + this->name = other.name; + + this->coreSegments.clear(); + for (const auto& [name, coreSegment] : other.coreSegments) + { + this->coreSegments.emplace(name, std::make_unique<CoreSegment>(*coreSegment)); + } + + return *this; + } + + Memory::~Memory() + { + } + + MemoryPtr Memory::getEmptyCopy() const + { + MemoryPtr other = std::make_unique<Memory>(); + other->name = this->name; + return other; + } + bool Memory::hasCoreSegment(const std::__cxx11::string& name) const { return coreSegments.count(name) > 0; } CoreSegment& Memory::getCoreSegment(const std::string& name) + { + return const_cast<CoreSegment&>(const_cast<const Memory*>(this)->getCoreSegment(name)); + } + const CoreSegment& Memory::getCoreSegment(const std::string& name) const { auto it = this->coreSegments.find(name); if (it != coreSegments.end()) @@ -29,7 +62,7 @@ namespace armarx::armem } - Entity& Memory::getEntity(const MemoryID& id) + const Entity& Memory::getEntity(const MemoryID& id) const { checkStorageName(id.memoryName, this->name, "memory"); return getCoreSegment(id.coreSegmentName).getEntity(id); @@ -47,6 +80,17 @@ namespace armarx::armem return *it->second; } + CoreSegment& Memory::addCoreSegment(const CoreSegment& coreSegment) + { + return addCoreSegment(std::make_unique<CoreSegment>(coreSegment)); + } + + CoreSegment& Memory::addCoreSegment(CoreSegmentPtr&& coreSegment) + { + auto it = coreSegments.emplace(coreSegment->name, std::move(coreSegment)).first; + return *it->second; + } + std::vector<CoreSegment*> Memory::addCoreSegments(const std::vector<std::string>& names) { std::vector<CoreSegment*> segments; diff --git a/source/RobotAPI/libraries/armem/memory/Memory.h b/source/RobotAPI/libraries/armem/memory/Memory.h index 242f2743a931883d13e1f85df9aeefd2fec87e00..e83555c83fcbf3254acc15d0bdf7258c2e103d29 100644 --- a/source/RobotAPI/libraries/armem/memory/Memory.h +++ b/source/RobotAPI/libraries/armem/memory/Memory.h @@ -11,6 +11,10 @@ namespace armarx::armem { + class Memory; + using MemoryPtr = std::unique_ptr<Memory>; + + /** * @brief Data of a memory consisting of multiple core segments. */ @@ -20,14 +24,28 @@ namespace armarx::armem using EntityStorage::EntityStorage; + Memory(const Memory& other); + Memory& operator=(const Memory& other); + + ~Memory() override; + + + MemoryPtr getEmptyCopy() const; + bool hasCoreSegment(const std::string& name) const; CoreSegment& getCoreSegment(const std::string& name); + const CoreSegment& getCoreSegment(const std::string& name) const; - Entity& getEntity(const MemoryID& id) override; + const Entity& getEntity(const MemoryID& id) const override; + // CoreSegment& addCoreSegment(const std::string& name, aron::type::AronTypePtr type); CoreSegment& addCoreSegment(const std::string& name); + CoreSegment& addCoreSegment(const CoreSegment& coreSegment); + CoreSegment& addCoreSegment(CoreSegmentPtr&& coreSegment); + + /** * @brief Add multiple core segments. * @param The core segment names. @@ -48,7 +66,6 @@ namespace armarx::armem }; - using MemoryPtr = std::unique_ptr<Memory>; } diff --git a/source/RobotAPI/libraries/armem/memory/ProviderSegment.cpp b/source/RobotAPI/libraries/armem/memory/ProviderSegment.cpp index 9b7bbbd94587bad5baca12cadfdbfb96637e4500..991999ea59fdc487824cc92f5dee866f3adc2c71 100644 --- a/source/RobotAPI/libraries/armem/memory/ProviderSegment.cpp +++ b/source/RobotAPI/libraries/armem/memory/ProviderSegment.cpp @@ -8,7 +8,42 @@ namespace armarx::armem { - Entity& ProviderSegment::getEntity(const std::string& name) + ProviderSegment::ProviderSegment(const ProviderSegment& other) : EntityStorage (other) + { + *this = other; + } + + ProviderSegment& ProviderSegment::operator=(const ProviderSegment& other) + { + this->name = other.name; + + this->entities.clear(); + for (const auto& [name, entity] : other.entities) + { + this->entities.emplace(name, std::make_unique<Entity>(*entity)); + } + + return *this; + } + + ProviderSegment::~ProviderSegment() + { + } + + ProviderSegmentPtr ProviderSegment::getEmptyCopy() const + { + ProviderSegmentPtr other = std::make_unique<ProviderSegment>(); + other->name = this->name; + other->maxHistorySize = this->maxHistorySize; + return other; + } + + Entity& ProviderSegment::getEntity(const string& name) + { + return const_cast<Entity&>(const_cast<const ProviderSegment*>(this)->getEntity(name)); + } + + const Entity& ProviderSegment::getEntity(const std::string& name) const { auto it = this->entities.find(name); if (it != entities.end()) @@ -22,7 +57,7 @@ namespace armarx::armem } } - Entity& ProviderSegment::getEntity(const MemoryID& id) + const Entity& ProviderSegment::getEntity(const MemoryID& id) const { checkStorageName(id.providerSegmentName, this->name, "provider segment"); return getEntity(id.entityName); @@ -44,6 +79,17 @@ namespace armarx::armem return it->second->update(update); } + Entity& ProviderSegment::addEntity(const Entity& entity) + { + return addEntity(std::make_unique<Entity>(entity)); + } + + Entity& ProviderSegment::addEntity(EntityPtr&& entity) + { + auto it = entities.emplace(entity->name, std::move(entity)).first; + return *it->second; + } + void ProviderSegment::clear() { entities.clear(); diff --git a/source/RobotAPI/libraries/armem/memory/ProviderSegment.h b/source/RobotAPI/libraries/armem/memory/ProviderSegment.h index 83c0c783337cb6120c1511a7d9c0392adefd9bc1..c27eb5ca7393c64ee4233fcbb35290edeca524f3 100644 --- a/source/RobotAPI/libraries/armem/memory/ProviderSegment.h +++ b/source/RobotAPI/libraries/armem/memory/ProviderSegment.h @@ -11,6 +11,9 @@ namespace armarx::armem { + class ProviderSegment; + using ProviderSegmentPtr = std::unique_ptr<ProviderSegment>; + /** * @brief Data of a provider segment containing multiple entities. */ @@ -20,13 +23,26 @@ namespace armarx::armem using EntityStorage::EntityStorage; + ProviderSegment(const ProviderSegment& other); + ProviderSegment& operator=(const ProviderSegment& other); + + ~ProviderSegment() override; + + + ProviderSegmentPtr getEmptyCopy() const; + bool hasEntity(const std::string& name) const { return entities.count(name) > 0; } + + using EntityStorage::getEntity; + const Entity& getEntity(const MemoryID& id) const override; + Entity& getEntity(const std::string& name); - Entity& getEntity(const MemoryID& id) override; + const Entity& getEntity(const std::string& name) const; + /** * @brief Updates an entity's history. @@ -36,6 +52,9 @@ namespace armarx::armem virtual MemoryID update(const InternalEntityUpdate& update) override; using EntityStorage::update; + Entity& addEntity(const Entity& entity); + Entity& addEntity(EntityPtr&& entity); + virtual void clear() override; @@ -59,6 +78,4 @@ namespace armarx::armem }; - using ProviderSegmentPtr = std::unique_ptr<ProviderSegment>; - } diff --git a/source/RobotAPI/libraries/armem/memory/ice_conversions.cpp b/source/RobotAPI/libraries/armem/memory/ice_conversions.cpp index dba3703d7d121d25a22cba733ef5a0cfa2c311b6..cf98b613838d990ebdc39e7cdba8da3b51dd5353 100644 --- a/source/RobotAPI/libraries/armem/memory/ice_conversions.cpp +++ b/source/RobotAPI/libraries/armem/memory/ice_conversions.cpp @@ -21,6 +21,90 @@ namespace armarx update.timeArrived = timeArrived; } + void armem::toIce(data::EntityMetadata& ice, const EntityMetadata& metadata) + { + ice.confidence = metadata.confidence; + toIce(ice.timeArrivedMicroSeconds, metadata.timeArrived); + toIce(ice.timeCreatedMicroSeconds, metadata.timeCreated); + toIce(ice.timeSentMicroSeconds, metadata.timeSent); + } + void armem::fromIce(const data::EntityMetadata& ice, EntityMetadata& metadata) + { + metadata.confidence = ice.confidence; + fromIce(ice.timeArrivedMicroSeconds, metadata.timeArrived); + fromIce(ice.timeCreatedMicroSeconds, metadata.timeCreated); + fromIce(ice.timeSentMicroSeconds, metadata.timeSent); + } + + void armem::toIce(data::EntityData& ice, const EntityData& data) + { + ice.data = data.data; + ice.index = data.index; + toIce(ice.metadata, data.metadata); + } + void armem::fromIce(const data::EntityData& ice, EntityData& data) + { + data.data = ice.data; + data.index = ice.index; + fromIce(ice.metadata, data.metadata); + } + + + void armem::toIce(data::EntitySnapshot& ice, const EntitySnapshot& snapshot) + { + toIce(ice.timeMicroSeconds, snapshot.time); + toIce(ice.instances, snapshot.instances); + } + void armem::fromIce(const data::EntitySnapshot& ice, EntitySnapshot& snapshot) + { + fromIce(ice.timeMicroSeconds, snapshot.time); + fromIce(ice.instances, snapshot.instances); + } + + void armem::toIce(data::Entity& ice, const Entity& entity) + { + ice.name = entity.name; + toIce(ice.history, entity.history); + } + void armem::fromIce(const data::Entity& ice, Entity& entity) + { + entity.name = ice.name; + fromIce(ice.history, entity.history); + } + + + void armem::toIce(data::ProviderSegment& ice, const ProviderSegment& providerSegment) + { + ice.name = providerSegment.name; + toIce(ice.entities, providerSegment.entities); + } + void armem::fromIce(const data::ProviderSegment& ice, ProviderSegment& providerSegment) + { + providerSegment.name = ice.name; + fromIce(ice.entities, providerSegment.entities); + } + + void armem::toIce(data::CoreSegment& ice, const CoreSegment& coreSegment) + { + ice.name = coreSegment.name; + toIce(ice.providerSegments, coreSegment.providerSegments); + } + void armem::fromIce(const data::CoreSegment& ice, CoreSegment& coreSegment) + { + coreSegment.name = ice.name; + fromIce(ice.providerSegments, coreSegment.providerSegments); + } + + void armem::toIce(data::Memory& ice, const Memory& memory) + { + ice.name = memory.name; + toIce(ice.coreSegments, memory.coreSegments); + } + void armem::fromIce(const data::Memory& ice, Memory& memory) + { + memory.name = ice.name; + fromIce(ice.coreSegments, memory.coreSegments); + } } diff --git a/source/RobotAPI/libraries/armem/memory/ice_conversions.h b/source/RobotAPI/libraries/armem/memory/ice_conversions.h index aefefc6523f6b14752d016f34f06143212d1a9c0..4fad4a8b4c9590426e251978ce0d3812eb412dd5 100644 --- a/source/RobotAPI/libraries/armem/memory/ice_conversions.h +++ b/source/RobotAPI/libraries/armem/memory/ice_conversions.h @@ -1,17 +1,43 @@ #pragma once +#include <RobotAPI/interface/armem/memory.h> #include "../core/ice_conversions.h" #include "InternalCommit.h" +#include "Memory.h" namespace armarx::armem { void fromIce(const data::Commit& ice, InternalCommit& commit, Time timeArrived); - void fromIce(const data::EntityUpdate& ice, InternalEntityUpdate& update, Time timeArrived); + void toIce(data::EntityMetadata& ice, const EntityMetadata& metadata); + void fromIce(const data::EntityMetadata& ice, EntityMetadata& metadata); + + void toIce(data::EntityData& ice, const EntityData& data); + void fromIce(const data::EntityData& ice, EntityData& data); + + + void toIce(data::EntitySnapshot& ice, const EntitySnapshot& snapshot); + void fromIce(const data::EntitySnapshot& ice, EntitySnapshot& snapshot); + + void toIce(data::Entity& ice, const Entity& entity); + void fromIce(const data::Entity& ice, Entity& entity); + + + void toIce(data::ProviderSegment& ice, const ProviderSegment& providerSegment); + void fromIce(const data::ProviderSegment& ice, ProviderSegment& providerSegment); + + void toIce(data::CoreSegment& ice, const CoreSegment& coreSegment); + void fromIce(const data::CoreSegment& ice, CoreSegment& coreSegment); + + void toIce(data::Memory& ice, const Memory& memory); + void fromIce(const data::Memory& ice, Memory& memory); + + + } diff --git a/source/RobotAPI/libraries/armem/query.h b/source/RobotAPI/libraries/armem/query.h new file mode 100644 index 0000000000000000000000000000000000000000..8bf723f3a38cc329e8c3c977f0f43f12fd0cf14f --- /dev/null +++ b/source/RobotAPI/libraries/armem/query.h @@ -0,0 +1,5 @@ +#pragma once + +#include "query/EntityQueryProcessor.h" +#include "query/ice_conversions.h" + diff --git a/source/RobotAPI/libraries/armem/query/BaseQueryProcessor.cpp b/source/RobotAPI/libraries/armem/query/BaseQueryProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa818cca129e6114a54bb5fc5ec9496f53af4920 --- /dev/null +++ b/source/RobotAPI/libraries/armem/query/BaseQueryProcessor.cpp @@ -0,0 +1,14 @@ +#include "BaseQueryProcessor.h" + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include "../error/ArMemError.h" + +#include "../core/ice_conversions.h" + + +namespace armarx::armem +{ + +} diff --git a/source/RobotAPI/libraries/armem/query/BaseQueryProcessor.h b/source/RobotAPI/libraries/armem/query/BaseQueryProcessor.h new file mode 100644 index 0000000000000000000000000000000000000000..2397b40cc66012b6c1cfae129967247be07ef973 --- /dev/null +++ b/source/RobotAPI/libraries/armem/query/BaseQueryProcessor.h @@ -0,0 +1,62 @@ +#pragma once + +#include <RobotAPI/interface/armem/query.h> + +#include "../memory/Memory.h" + + +namespace armarx::armem +{ + + /** + * @brief Base class for memory query processors. + */ + template <class DataT, class QueryT> + class BaseQueryProcessor + { + public: + + using DataPtrT = std::unique_ptr<DataT>; + using QueryPtrT = ::IceInternal::Handle<QueryT>; + using QuerySeqT = std::vector<QueryPtrT>; + + + public: + + + virtual ~BaseQueryProcessor() + {} + + + DataPtrT process(const QueryT& query, const DataT& data) const + { + DataPtrT result = data.getEmptyCopy(); + this->process(*result, query, data); + return result; + } + DataPtrT process(const QueryPtrT& query, const DataPtrT& data) const + { + return this->process(*query, *data); + } + + DataPtrT process(const QuerySeqT& queries, const DataT& data) const + { + DataPtrT result = data.getEmptyCopy(); + this->process(*result, queries, data); + return result; + } + + + void process(DataT& result, const QuerySeqT& queries, const DataT& data) const + { + for (const auto& query : queries) + { + this->process(result, *query, data); + } + } + + virtual void process(DataT& result, const QueryT& query, const DataT& data) const = 0; + + }; + +} diff --git a/source/RobotAPI/libraries/armem/query/CoreSegmentQueryProcessor.cpp b/source/RobotAPI/libraries/armem/query/CoreSegmentQueryProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c7ed8bec453ab1b981100ec0930a11599aab0e48 --- /dev/null +++ b/source/RobotAPI/libraries/armem/query/CoreSegmentQueryProcessor.cpp @@ -0,0 +1,80 @@ +#include "CoreSegmentQueryProcessor.h" + +#include <regex> + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include "../error/ArMemError.h" + +#include "../core/ice_conversions.h" + + +namespace armarx::armem +{ + + void CoreSegmentQueryProcessor::process(CoreSegment& result, const query::CoreSegmentQuery& query, const CoreSegment& coreSegment) const + { + if (auto q = dynamic_cast<const query::core::All*>(&query)) + { + process(result, *q, coreSegment); + } + else if (auto q = dynamic_cast<const query::core::Single*>(&query)) + { + process(result, *q, coreSegment); + } + else if (auto q = dynamic_cast<const query::core::Regex*>(&query)) + { + process(result, *q, coreSegment); + } + else + { + throw armem::error::UnknownQueryType("core segment", query); + } + } + + + void CoreSegmentQueryProcessor::process(CoreSegment& result, + const query::core::All& query, const CoreSegment& coreSegment) const + { + for (const auto& [name, providerSegment] : coreSegment.providerSegments) + { + result.addProviderSegment(providerSegmentProcessor.process(query.providerSegmentQueries, *providerSegment)); + } + } + + void CoreSegmentQueryProcessor::process(CoreSegment& result, + const query::core::Single& query, const CoreSegment& coreSegment) const + { + try + { + const ProviderSegment& providerSegment = coreSegment.getProviderSegment(query.providerSegmentName); + result.addProviderSegment(providerSegmentProcessor.process(query.providerSegmentQueries, providerSegment)); + } + catch (const error::MissingEntry&) + { + // Leave empty. + } + } + + void CoreSegmentQueryProcessor::process(CoreSegment& result, + const query::core::Regex& query, const CoreSegment& coreSegment) const + { + std::regex regex(query.providerSegmentNameRegex); + for (const auto& [name, providerSegment] : coreSegment.providerSegments) + { + if (std::regex_search(providerSegment->name, regex)) + { + result.addProviderSegment(providerSegmentProcessor.process(query.providerSegmentQueries, *providerSegment)); + } + } + } + + + data::CoreSegmentPtr CoreSegmentQueryProcessor::processToIce( + const query::CoreSegmentQuery& query, const CoreSegment& coreSegment) const + { + return toIce<data::CoreSegmentPtr>(process(query, coreSegment)); + } + +} diff --git a/source/RobotAPI/libraries/armem/query/CoreSegmentQueryProcessor.h b/source/RobotAPI/libraries/armem/query/CoreSegmentQueryProcessor.h new file mode 100644 index 0000000000000000000000000000000000000000..a25810750ed2e9fb0e4e46ebb8447c97f9f35bcd --- /dev/null +++ b/source/RobotAPI/libraries/armem/query/CoreSegmentQueryProcessor.h @@ -0,0 +1,41 @@ +#pragma once + +#include <RobotAPI/interface/armem/query.h> + +#include "../memory/Memory.h" +#include "../memory/ice_conversions.h" + +#include "BaseQueryProcessor.h" +#include "ProviderSegmentQueryProcessor.h" + + + +namespace armarx::armem +{ + + /** + * @brief Handles memory queries. + */ + class CoreSegmentQueryProcessor : public BaseQueryProcessor<CoreSegment, query::CoreSegmentQuery> + { + public: + + using BaseQueryProcessor::process; + + void process(CoreSegment& result, const query::CoreSegmentQuery& query, const CoreSegment& coreSegment) const; + + void process(CoreSegment& result, const query::core::All& query, const CoreSegment& coreSegment) const; + void process(CoreSegment& result, const query::core::Single& query, const CoreSegment& coreSegment) const; + void process(CoreSegment& result, const query::core::Regex& query, const CoreSegment& coreSegment) const; + + + data::CoreSegmentPtr processToIce(const query::CoreSegmentQuery& query, const CoreSegment& coreSegment) const; + + + private: + + ProviderSegmentQueryProcessor providerSegmentProcessor; + + }; + +} diff --git a/source/RobotAPI/libraries/armem/query/EntityQueryProcessor.cpp b/source/RobotAPI/libraries/armem/query/EntityQueryProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5ac1e3fbf2d50d53be353eaf6bb895c58c87f4aa --- /dev/null +++ b/source/RobotAPI/libraries/armem/query/EntityQueryProcessor.cpp @@ -0,0 +1,89 @@ +#include "EntityQueryProcessor.h" + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include "../error/ArMemError.h" + +#include "../core/ice_conversions.h" + + +namespace armarx::armem +{ + + void EntityQueryProcessor::process(Entity& result, const query::EntityQuery& query, const Entity& entity) const + { + if (auto q = dynamic_cast<const query::entity::All*>(&query)) + { + process(result, *q, entity); + } + else if (auto q = dynamic_cast<const query::entity::Single*>(&query)) + { + process(result, *q, entity); + } + else if (auto q = dynamic_cast<const query::entity::Range*>(&query)) + { + process(result, *q, entity); + } + else + { + throw armem::error::UnknownQueryType("entity snapshot", query); + } + } + + void EntityQueryProcessor::process(Entity& result, const query::entity::All& query, const Entity& entity) const + { + (void) query; + // Copy this entitiy and its contents. + result = entity; + } + + void EntityQueryProcessor::process(Entity& result, const query::entity::Single& query, const Entity& entity) const + { + (void) query; + if (query.timestamp < 0) + { + result.addSnapshot(entity.getLatestSnapshot()); + } + else + { + Time time = fromIce<Time>(query.timestamp); + try + { + result.addSnapshot(entity.getSnapshot(time)); + } + catch (const armem::error::MissingEntry&) + { + // Leave empty. + } + } + } + + void EntityQueryProcessor::process(Entity& result, const query::entity::Range& query, const Entity& entity) const + { + if (query.minTimestamp <= query.maxTimestamp || query.minTimestamp < 0 || query.maxTimestamp < 0) + { + Time min = fromIce<Time>(query.minTimestamp); + Time max = fromIce<Time>(query.maxTimestamp); + process(result, min, max, entity); + } + } + + void EntityQueryProcessor::process(Entity& result, const Time& min, const Time& max, const Entity& entity) const + { + // Returns an iterator pointing to the first element that is not less than (i.e. greater or equal to) key. + auto begin = min.toMicroSeconds() > 0 ? entity.history.lower_bound(min) : entity.history.begin(); + // Returns an iterator pointing to the first element that is *greater than* key. + auto end = max.toMicroSeconds() > 0 ? entity.history.upper_bound(max) : entity.history.end(); + + for (auto it = begin; it != end && it != entity.history.end(); ++it) + { + result.addSnapshot(*it->second); + } + } + + data::EntityPtr EntityQueryProcessor::processToIce(const query::EntityQuery& query, const Entity& entity) const + { + return toIce<data::EntityPtr>(process(query, entity)); + } +} diff --git a/source/RobotAPI/libraries/armem/query/EntityQueryProcessor.h b/source/RobotAPI/libraries/armem/query/EntityQueryProcessor.h new file mode 100644 index 0000000000000000000000000000000000000000..64235ff2844cb14e5fa1a367c3782bbe5f37962e --- /dev/null +++ b/source/RobotAPI/libraries/armem/query/EntityQueryProcessor.h @@ -0,0 +1,36 @@ +#pragma once + +#include <RobotAPI/interface/armem/query.h> + +#include "../memory/Memory.h" +#include "../memory/ice_conversions.h" + +#include "BaseQueryProcessor.h" + + +namespace armarx::armem +{ + + /** + * @brief Handles memory queries. + */ + class EntityQueryProcessor : public BaseQueryProcessor<Entity, query::EntityQuery> + { + public: + + using BaseQueryProcessor::process; + + void process(Entity& result, const query::EntityQuery& query, const Entity& entity) const override; + + void process(Entity& result, const query::entity::All& query, const Entity& entity) const; + void process(Entity& result, const query::entity::Single& query, const Entity& entity) const; + void process(Entity& result, const query::entity::Range& query, const Entity& entity) const; + + void process(Entity& result, const Time& min, const Time& max, const Entity& entity) const; + + + data::EntityPtr processToIce(const query::EntityQuery& query, const Entity& entity) const; + + }; + +} diff --git a/source/RobotAPI/libraries/armem/query/MemoryQueryProcessor.cpp b/source/RobotAPI/libraries/armem/query/MemoryQueryProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..390f0c507c62566e1b7e9eb401dc26c65ba9126e --- /dev/null +++ b/source/RobotAPI/libraries/armem/query/MemoryQueryProcessor.cpp @@ -0,0 +1,85 @@ +#include "MemoryQueryProcessor.h" + +#include <regex> + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include "../error/ArMemError.h" + +#include "../memory/ice_conversions.h" + + +namespace armarx::armem +{ + + void MemoryQueryProcessor::process(Memory& result, const query::MemoryQuery& query, const Memory& memory) const + { + if (auto q = dynamic_cast<const query::memory::All*>(&query)) + { + process(result, *q, memory); + } + else if (auto q = dynamic_cast<const query::memory::Single*>(&query)) + { + process(result, *q, memory); + } + else if (auto q = dynamic_cast<const query::memory::Regex*>(&query)) + { + process(result, *q, memory); + } + else + { + throw armem::error::UnknownQueryType("memory segment", query); + } + } + + + void MemoryQueryProcessor::process(Memory& result, + const query::memory::All& query, const Memory& memory) const + { + for (const auto& [name, coreSegment] : memory.coreSegments) + { + result.addCoreSegment(coreSegmentProcessor.process(query.coreSegmentQueries, *coreSegment)); + } + } + + void MemoryQueryProcessor::process(Memory& result, + const query::memory::Single& query, const Memory& memory) const + { + try + { + const CoreSegment& coreSegment = memory.getCoreSegment(query.coreSegmentName); + result.addCoreSegment(coreSegmentProcessor.process(query.coreSegmentQueries, coreSegment)); + } + catch (const error::MissingEntry&) + { + // Leave empty. + } + } + + void MemoryQueryProcessor::process(Memory& result, + const query::memory::Regex& query, const Memory& memory) const + { + std::regex regex(query.coreSegmentNameRegex); + for (const auto& [name, coreSegment] : memory.coreSegments) + { + if (std::regex_search(coreSegment->name, regex)) + { + result.addCoreSegment(coreSegmentProcessor.process(query.coreSegmentQueries, *coreSegment)); + } + } + } + + + data::MemoryPtr MemoryQueryProcessor::processToIce( + const query::MemoryQuery& query, const Memory& memory) const + { + return toIce<data::MemoryPtr>(process(query, memory)); + } + + data::MemoryPtr MemoryQueryProcessor::processToIce(const query::MemoryQuerySeq& queries, const Memory& memory) const + { + return toIce<data::MemoryPtr>(process(queries, memory)); + } + +} diff --git a/source/RobotAPI/libraries/armem/query/MemoryQueryProcessor.h b/source/RobotAPI/libraries/armem/query/MemoryQueryProcessor.h new file mode 100644 index 0000000000000000000000000000000000000000..ebbfa1a1ad910b707882e67f427c0e1ed2e9ff4b --- /dev/null +++ b/source/RobotAPI/libraries/armem/query/MemoryQueryProcessor.h @@ -0,0 +1,42 @@ +#pragma once + +#include <RobotAPI/interface/armem/query.h> + +#include "../memory/Memory.h" +#include "../memory/ice_conversions.h" + +#include "BaseQueryProcessor.h" +#include "CoreSegmentQueryProcessor.h" + + + +namespace armarx::armem +{ + + /** + * @brief Handles memory queries. + */ + class MemoryQueryProcessor : public BaseQueryProcessor<Memory, query::MemoryQuery> + { + public: + + using BaseQueryProcessor::process; + + void process(Memory& result, const query::MemoryQuery& query, const Memory& memory) const; + + void process(Memory& result, const query::memory::All& query, const Memory& memory) const; + void process(Memory& result, const query::memory::Single& query, const Memory& memory) const; + void process(Memory& result, const query::memory::Regex& query, const Memory& memory) const; + + + data::MemoryPtr processToIce(const query::MemoryQuery& query, const Memory& memory) const; + data::MemoryPtr processToIce(const query::MemoryQuerySeq& query, const Memory& memory) const; + + + private: + + CoreSegmentQueryProcessor coreSegmentProcessor; + + }; + +} diff --git a/source/RobotAPI/libraries/armem/query/ProviderSegmentQueryProcessor.cpp b/source/RobotAPI/libraries/armem/query/ProviderSegmentQueryProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6e5db59e17c74e3a88dc460e543d8f4b7cc2e496 --- /dev/null +++ b/source/RobotAPI/libraries/armem/query/ProviderSegmentQueryProcessor.cpp @@ -0,0 +1,80 @@ +#include "ProviderSegmentQueryProcessor.h" + +#include <regex> + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include "../error/ArMemError.h" + +#include "../core/ice_conversions.h" + + +namespace armarx::armem +{ + + void ProviderSegmentQueryProcessor::process(ProviderSegment& result, const query::ProviderSegmentQuery& query, const ProviderSegment& providerSegment) const + { + if (auto q = dynamic_cast<const query::provider::All*>(&query)) + { + process(result, *q, providerSegment); + } + else if (auto q = dynamic_cast<const query::provider::Single*>(&query)) + { + process(result, *q, providerSegment); + } + else if (auto q = dynamic_cast<const query::provider::Regex*>(&query)) + { + process(result, *q, providerSegment); + } + else + { + throw armem::error::UnknownQueryType("provider segment", query); + } + } + + + void ProviderSegmentQueryProcessor::process(ProviderSegment& result, + const query::provider::All& query, const ProviderSegment& providerSegment) const + { + for (const auto& [name, entity] : providerSegment.entities) + { + result.addEntity(std::move(*entityProcessor.process(query.entityQueries, *entity))); + } + } + + void ProviderSegmentQueryProcessor::process(ProviderSegment& result, + const query::provider::Single& query, const ProviderSegment& providerSegment) const + { + try + { + const Entity& entity = providerSegment.getEntity(query.entityName); + result.addEntity(std::move(*entityProcessor.process(query.entityQueries, entity))); + } + catch (const error::MissingEntry&) + { + // Leave empty. + } + } + + void ProviderSegmentQueryProcessor::process(ProviderSegment& result, + const query::provider::Regex& query, const ProviderSegment& providerSegment) const + { + std::regex regex(query.entityNameRegex); + for (const auto& [name, entity] : providerSegment.entities) + { + if (std::regex_search(entity->name, regex)) + { + result.addEntity(std::move(*entityProcessor.process(query.entityQueries, *entity))); + } + } + } + + + data::ProviderSegmentPtr ProviderSegmentQueryProcessor::processToIce( + const query::ProviderSegmentQuery& query, const ProviderSegment& providerSegment) const + { + return toIce<data::ProviderSegmentPtr>(process(query, providerSegment)); + } + +} diff --git a/source/RobotAPI/libraries/armem/query/ProviderSegmentQueryProcessor.h b/source/RobotAPI/libraries/armem/query/ProviderSegmentQueryProcessor.h new file mode 100644 index 0000000000000000000000000000000000000000..f0d2a14e18e4e9c71f470ce24a7abab3c66bcf92 --- /dev/null +++ b/source/RobotAPI/libraries/armem/query/ProviderSegmentQueryProcessor.h @@ -0,0 +1,41 @@ +#pragma once + +#include <RobotAPI/interface/armem/query.h> + +#include "../memory/Memory.h" +#include "../memory/ice_conversions.h" + +#include "BaseQueryProcessor.h" +#include "EntityQueryProcessor.h" + + + +namespace armarx::armem +{ + + /** + * @brief Handles memory queries. + */ + class ProviderSegmentQueryProcessor : public BaseQueryProcessor<ProviderSegment, query::ProviderSegmentQuery> + { + public: + + using BaseQueryProcessor::process; + + void process(ProviderSegment& result, const query::ProviderSegmentQuery& query, const ProviderSegment& providerSegment) const; + + void process(ProviderSegment& result, const query::provider::All& query, const ProviderSegment& providerSegment) const; + void process(ProviderSegment& result, const query::provider::Single& query, const ProviderSegment& providerSegment) const; + void process(ProviderSegment& result, const query::provider::Regex& query, const ProviderSegment& providerSegment) const; + + + data::ProviderSegmentPtr processToIce(const query::ProviderSegmentQuery& query, const ProviderSegment& providerSegment) const; + + + private: + + EntityQueryProcessor entityProcessor; + + }; + +} diff --git a/source/RobotAPI/libraries/armem/test/ArmemQueryTest.cpp b/source/RobotAPI/libraries/armem/test/ArmemQueryTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..421e672e5fccf4038404e1a3fa52948c4247ad77 --- /dev/null +++ b/source/RobotAPI/libraries/armem/test/ArmemQueryTest.cpp @@ -0,0 +1,281 @@ +/* + * 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 "../query/EntityQueryProcessor.h" +#include "../error.h" + + +#include <iostream> + +#include <SimoxUtility/algorithm/get_map_keys_values.h> +#include <SimoxUtility/algorithm/string.h> + + +namespace armem = armarx::armem; +namespace aron = armarx::aron; + + +namespace ArMemQueryTest +{ + + class UnknownEntityQuery : public armem::query::EntityQuery + { + }; + + struct Fixture + { + armem::EntityPtr entity; + + armem::EntityQueryProcessor processor; + armem::query::EntityQueryPtr entityQuery; + + std::vector<armem::EntityPtr> results; + + Fixture() + { + entity = std::make_unique<armem::Entity>("entity"); + + armem::EntitySnapshot snapshot; + snapshot.time = armem::Time::microSeconds(1000); + entity->addSnapshot(snapshot); + snapshot.time = armem::Time::microSeconds(2000); + entity->addSnapshot(snapshot); + snapshot.time = armem::Time::microSeconds(3000); + entity->addSnapshot(snapshot); + snapshot.time = armem::Time::microSeconds(4000); + entity->addSnapshot(snapshot); + snapshot.time = armem::Time::microSeconds(5000); + entity->addSnapshot(snapshot); + } + ~Fixture() + { + + } + + template <class QueryT> + void addResults(QueryT query = {}) + { + entityQuery = new QueryT(query); + + results.emplace_back(processor.process(query, *entity)); + results.emplace_back(processor.process(*entityQuery, *entity)); + } + }; + +} + + +BOOST_FIXTURE_TEST_SUITE(ArMemQueryTest, ArMemQueryTest::Fixture) + + +BOOST_AUTO_TEST_CASE(test_entity_Single_latest) +{ + addResults(armem::query::entity::Single()); + BOOST_REQUIRE_GT(results.size(), 0); + + for (const auto& result : results) + { + BOOST_CHECK_EQUAL(result->name, entity->name); + BOOST_CHECK_EQUAL(result->history.size(), 1); + BOOST_CHECK_EQUAL(result->history.begin()->second->time, entity->getLatestSnapshot().time); + BOOST_CHECK_NE(result->history.begin()->second.get(), entity->history.rbegin()->second.get()); + } +} + + +BOOST_AUTO_TEST_CASE(test_entity_Single_existing) +{ + addResults(armem::query::entity::Single { 3000 }); + BOOST_REQUIRE_GT(results.size(), 0); + + for (const auto& result : results) + { + BOOST_CHECK_EQUAL(result->name, entity->name); + BOOST_CHECK_EQUAL(result->history.size(), 1); + BOOST_CHECK_EQUAL(result->history.begin()->second->time, armem::Time::microSeconds(3000)); + } +} + + +BOOST_AUTO_TEST_CASE(test_entity_Single_non_existing) +{ + addResults(armem::query::entity::Single { 3500 }); + BOOST_REQUIRE_GT(results.size(), 0); + + for (const auto& result : results) + { + BOOST_CHECK_EQUAL(result->name, entity->name); + BOOST_CHECK_EQUAL(result->history.size(), 0); + } +} + + +BOOST_AUTO_TEST_CASE(test_entity_All) +{ + addResults(armem::query::entity::All()); + BOOST_REQUIRE_GT(results.size(), 0); + + for (const auto& result : results) + { + BOOST_CHECK_EQUAL(result->name, entity->name); + BOOST_CHECK_EQUAL(result->history.size(), entity->history.size()); + for (auto it = result->history.begin(), jt = entity->history.begin(); + it != result->history.end(); ++it, ++jt) + { + BOOST_CHECK_EQUAL(it->first, jt->first); + BOOST_CHECK_EQUAL(it->second->time, jt->second->time); + BOOST_CHECK_NE(it->second.get(), jt->second.get()); + } + } +} + + +BOOST_AUTO_TEST_CASE(test_entity_Range_slice) +{ + addResults(armem::query::entity::Range{ 1500, 3500 }); + BOOST_REQUIRE_GT(results.size(), 0); + + for (const auto& result : results) + { + BOOST_CHECK_EQUAL(result->name, entity->name); + BOOST_CHECK_EQUAL(result->history.size(), 2); + + std::vector<armem::Time> times = simox::get_keys(result->history); + std::vector<armem::Time> expected { + armem::Time::microSeconds(2000), armem::Time::microSeconds(3000) + }; + BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end()); + } +} + + +BOOST_AUTO_TEST_CASE(test_entity_Range_exact) +{ + addResults(armem::query::entity::Range{ 2000, 4000 }); + BOOST_REQUIRE_GT(results.size(), 0); + + for (const auto& result : results) + { + BOOST_CHECK_EQUAL(result->name, entity->name); + BOOST_CHECK_EQUAL(result->history.size(), 3); + + std::vector<armem::Time> times = simox::get_keys(result->history); + std::vector<armem::Time> expected { + armem::Time::microSeconds(2000), armem::Time::microSeconds(3000), armem::Time::microSeconds(4000) + }; + BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end()); + } +} + +BOOST_AUTO_TEST_CASE(test_entity_Range_all) +{ + addResults(armem::query::entity::Range{ 0, 10000 }); + addResults(armem::query::entity::Range{ -1, -1 }); + BOOST_REQUIRE_GT(results.size(), 0); + + for (const auto& result : results) + { + BOOST_CHECK_EQUAL(result->name, entity->name); + BOOST_CHECK_EQUAL(result->history.size(), entity->history.size()); + + std::vector<armem::Time> times = simox::get_keys(result->history); + std::vector<armem::Time> expected = simox::get_keys(entity->history); + BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end()); + } +} + + +BOOST_AUTO_TEST_CASE(test_entity_Range_empty) +{ + addResults(armem::query::entity::Range{ 2400, 2600 }); + addResults(armem::query::entity::Range{ 6000, 1000 }); + BOOST_REQUIRE_GT(results.size(), 0); + + for (const auto& result : results) + { + BOOST_CHECK_EQUAL(result->name, entity->name); + BOOST_CHECK_EQUAL(result->history.size(), 0); + } +} + + +BOOST_AUTO_TEST_CASE(test_entity_Range_from_start) +{ + addResults(armem::query::entity::Range{ -1, 2500 }); + BOOST_REQUIRE_GT(results.size(), 0); + + for (const auto& result : results) + { + BOOST_CHECK_EQUAL(result->name, entity->name); + BOOST_CHECK_EQUAL(result->history.size(), 2); + + std::vector<armem::Time> times = simox::get_keys(result->history); + std::vector<armem::Time> expected { + armem::Time::microSeconds(1000), armem::Time::microSeconds(2000) + }; + BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end()); + } +} + + +BOOST_AUTO_TEST_CASE(test_entity_Range_to_end) +{ + addResults(armem::query::entity::Range{ 2500, -1 }); + BOOST_REQUIRE_GT(results.size(), 0); + + for (const auto& result : results) + { + BOOST_CHECK_EQUAL(result->name, entity->name); + BOOST_CHECK_EQUAL(result->history.size(), 3); + + std::vector<armem::Time> times = simox::get_keys(result->history); + std::vector<armem::Time> expected { + armem::Time::microSeconds(3000), armem::Time::microSeconds(4000), armem::Time::microSeconds(5000) + }; + BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end()); + } +} + + +BOOST_AUTO_TEST_CASE(test_entity_UnknownQueryType) +{ + BOOST_CHECK_THROW(processor.process(UnknownEntityQuery(), *entity), armem::error::UnknownQueryType); + std::string msg; + try + { + processor.process(UnknownEntityQuery(), *entity); + } + catch (const armem::error::UnknownQueryType& e) + { + msg = e.what(); + } + BOOST_TEST_MESSAGE(msg); + BOOST_CHECK(simox::alg::contains(msg, "UnknownEntityQuery")); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/source/RobotAPI/libraries/armem/test/CMakeLists.txt b/source/RobotAPI/libraries/armem/test/CMakeLists.txt index 1b2d707ae12a621b80a6909264b941aad0baf5e1..ea0aec9604371b9efd745d85c607f0d23162b78a 100644 --- a/source/RobotAPI/libraries/armem/test/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem/test/CMakeLists.txt @@ -2,5 +2,5 @@ # Libs required for the tests SET(LIBS ${LIBS} ArmarXCore ${LIB_NAME}) -# armarx_add_test(armemTest armemTest.cpp "${LIBS}") armarx_add_test(ArmemMemoryTest ArmemMemoryTest.cpp "${LIBS}") +armarx_add_test(ArmemQueryTest ArmemQueryTest.cpp "${LIBS}") diff --git a/source/RobotAPI/libraries/armem/test/armemTest.cpp b/source/RobotAPI/libraries/armem/test/armemTest.cpp deleted file mode 100644 index 2b4b2de157192afd4b7a7346dfb316d8bfce5c04..0000000000000000000000000000000000000000 --- a/source/RobotAPI/libraries/armem/test/armemTest.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 "../armem.h" - -#include <iostream> - -BOOST_AUTO_TEST_CASE(testExample) -{ - BOOST_CHECK_EQUAL(true, true); -}