diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt index ee5a16f2563ac08d997f1273035a16085ab1919c..b8442bdf0f1403caf899757976a230aa6a97e235 100644 --- a/source/RobotAPI/libraries/armem/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem/CMakeLists.txt @@ -85,6 +85,7 @@ set(LIB_FILES client/Writer.cpp client/WriterComponentPlugin.cpp + client/util/MemoryListener.cpp client/util/SimpleReaderBase.cpp client/util/SimpleWriterBase.cpp @@ -199,6 +200,7 @@ set(LIB_HEADERS client/query/detail/NameSelectorOps.h client/query/detail/SelectorOps.h + client/util/MemoryListener.h client/util/SimpleReaderBase.h client/util/SimpleWriterBase.h diff --git a/source/RobotAPI/libraries/armem/client/Reader.cpp b/source/RobotAPI/libraries/armem/client/Reader.cpp index 2efc1d41ff87836042522cf9ed166fda974537a8..b548e7aabf3c7f010b09b96c79a2446a4848e82c 100644 --- a/source/RobotAPI/libraries/armem/client/Reader.cpp +++ b/source/RobotAPI/libraries/armem/client/Reader.cpp @@ -108,48 +108,6 @@ namespace armarx::armem::client } - void - Reader::updated(const std::vector<MemoryID>& updatedSnapshotIDs) const - { - std::stringstream error; - - for (const auto& [subscription, callbacks] : this->callbacks) - { - std::vector<MemoryID> matchingSnapshotIDs; - - for (const MemoryID& updatedSnapshotID : updatedSnapshotIDs) - { - try - { - if (contains(subscription, updatedSnapshotID)) - { - matchingSnapshotIDs.push_back(updatedSnapshotID); - } - } - catch (const armem::error::InvalidMemoryID& e) - { - // Log to debug, but ignore otherwise - error << "Error when comparing subscribed ID " << subscription - << " with updated ID " << updatedSnapshotID << ":\n" - << e.what() << "\n\n"; - } - } - - if (not matchingSnapshotIDs.empty()) - { - for (auto& callback : callbacks) - { - callback(subscription, matchingSnapshotIDs); - } - } - } - if (error.str().size() > 0) - { - ARMARX_VERBOSE << "The following issues were encountered during Reader::" << __FUNCTION__ << "(): \n\n" - << error.str(); - } - } - data::StoreResult Reader::readAndStore(const data::StoreInput& input) const { @@ -166,21 +124,6 @@ namespace armarx::armem::client } - void - Reader::subscribe(const MemoryID& id, callback callback) - { - callbacks[id].push_back(callback); - } - - void Reader::subscribe(const MemoryID& subscriptionID, callback_updated_only callback) - { - subscribe(subscriptionID, [callback](const MemoryID&, const std::vector<MemoryID>& updatedSnapshotIDs) - { - callback(updatedSnapshotIDs); - }); - } - - void Reader::setReadingMemory(server::ReadingMemoryInterfacePrx memory) { diff --git a/source/RobotAPI/libraries/armem/client/Reader.h b/source/RobotAPI/libraries/armem/client/Reader.h index ae2548f29c93e4a9ad2ad8bef0079861c87fb8fa..3a1726a548fb4d392eda273ef3228eaeccefb265 100644 --- a/source/RobotAPI/libraries/armem/client/Reader.h +++ b/source/RobotAPI/libraries/armem/client/Reader.h @@ -2,8 +2,6 @@ // STD/STL -#include <functional> -#include <unordered_map> #include <vector> // RobotAPI @@ -13,6 +11,7 @@ #include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h> #include <RobotAPI/libraries/armem/core/workingmemory/Memory.h> #include <RobotAPI/libraries/armem/core/longtermmemory/Memory.h> +#include <RobotAPI/libraries/armem/client/util/MemoryListener.h> #include "Query.h" @@ -23,18 +22,9 @@ namespace armarx::armem::client /** * @brief Reads data from a memory server. */ - class Reader + class Reader : public util::MemoryListener { - using callback = std::function<void(const MemoryID& subscriptionID, const std::vector<MemoryID>& updatedSnapshotIDs)>; - using callback_updated_only = std::function<void(const std::vector<MemoryID>& updatedSnapshotIDs)>; - - template <class CalleeT> - using member_callback = void(CalleeT::*)(const MemoryID& subscriptionID, const std::vector<MemoryID>& updatedSnapshotIDs); - template <class CalleeT> - using member_callback_updated_only = void(CalleeT::*)(const std::vector<MemoryID>& updatedSnapshotIDs); - - public: /** @@ -78,36 +68,6 @@ namespace armarx::armem::client data::StoreResult readAndStore(const data::StoreInput& input) const; - void subscribe(const MemoryID& subscriptionID, callback callback); - void subscribe(const MemoryID& subscriptionID, callback_updated_only callback); - /** - * Subscribe with a class member function: - * @code - * reader.subscribe(entityID, this, &This::myCallback); - * @endcode - */ - template <class CalleeT> - void subscribe(const MemoryID& subscriptionID, CalleeT* callee, member_callback<CalleeT> callback) - { - auto cb = [callee, callback](const MemoryID & subscriptionID, const std::vector<MemoryID>& updatedSnapshotIDs) - { - (callee->*callback)(subscriptionID, updatedSnapshotIDs); - }; - subscribe(subscriptionID, cb); - } - template <class CalleeT> - void subscribe(const MemoryID& subscriptionID, CalleeT* callee, member_callback_updated_only<CalleeT> callback) - { - auto cb = [callee, callback](const MemoryID&, const std::vector<MemoryID>& updatedSnapshotIDs) - { - (callee->*callback)(updatedSnapshotIDs); - }; - subscribe(subscriptionID, cb); - } - /// Function handling updates from the MemoryListener ice topic. - void updated(const std::vector<MemoryID>& updatedIDs) const; - - inline operator bool() const { return bool(memoryPrx); @@ -117,10 +77,6 @@ namespace armarx::armem::client server::ReadingMemoryInterfacePrx memoryPrx; - private: - - std::unordered_map<MemoryID, std::vector<callback>> callbacks; - }; } diff --git a/source/RobotAPI/libraries/armem/client/util/MemoryListener.cpp b/source/RobotAPI/libraries/armem/client/util/MemoryListener.cpp new file mode 100644 index 0000000000000000000000000000000000000000..318d1294eea4f7d5fd0926c4b9d0475b831e60b6 --- /dev/null +++ b/source/RobotAPI/libraries/armem/client/util/MemoryListener.cpp @@ -0,0 +1,76 @@ +#include "MemoryListener.h" + +#include <sstream> + +#include <ArmarXCore/core/logging/Logging.h> +#include <RobotAPI/libraries/armem/core/error.h> + + +namespace armarx::armem::client::util +{ + + MemoryListener::MemoryListener() + { + } + + + void + MemoryListener::updated(const std::vector<MemoryID>& updatedSnapshotIDs) const + { + std::stringstream error; + + for (const auto& [subscription, callbacks] : this->callbacks) + { + std::vector<MemoryID> matchingSnapshotIDs; + + for (const MemoryID& updatedSnapshotID : updatedSnapshotIDs) + { + try + { + if (contains(subscription, updatedSnapshotID)) + { + matchingSnapshotIDs.push_back(updatedSnapshotID); + } + } + catch (const armem::error::InvalidMemoryID& e) + { + // Log to debug, but ignore otherwise + error << "Error when comparing subscribed ID " << subscription + << " with updated ID " << updatedSnapshotID << ":\n" + << e.what() << "\n\n"; + } + } + + if (not matchingSnapshotIDs.empty()) + { + for (auto& callback : callbacks) + { + callback(subscription, matchingSnapshotIDs); + } + } + } + if (error.str().size() > 0) + { + ARMARX_VERBOSE << "The following issues were encountered during MemoryListener::" << __FUNCTION__ << "(): \n\n" + << error.str(); + } + } + + + void + MemoryListener::subscribe(const MemoryID& id, callback callback) + { + callbacks[id].push_back(callback); + } + + + void MemoryListener::subscribe(const MemoryID& subscriptionID, callback_updated_only callback) + { + subscribe(subscriptionID, [callback](const MemoryID&, const std::vector<MemoryID>& updatedSnapshotIDs) + { + callback(updatedSnapshotIDs); + }); + } + + +} diff --git a/source/RobotAPI/libraries/armem/client/util/MemoryListener.h b/source/RobotAPI/libraries/armem/client/util/MemoryListener.h new file mode 100644 index 0000000000000000000000000000000000000000..33e1e104294fd829c45a8362f2e1652cc3962d1e --- /dev/null +++ b/source/RobotAPI/libraries/armem/client/util/MemoryListener.h @@ -0,0 +1,77 @@ +#pragma once + + +// STD/STL +#include <functional> +#include <unordered_map> +#include <vector> + +// RobotAPI +#include <RobotAPI/interface/armem/client/MemoryListenerInterface.h> +#include <RobotAPI/libraries/armem/core/MemoryID.h> + + +namespace armarx::armem::client::util +{ + + /** + * @brief Handles update signals from the memory system and distributes it + * to its subsribers. + */ + class MemoryListener + { + + using callback = std::function<void(const MemoryID& subscriptionID, const std::vector<MemoryID>& updatedSnapshotIDs)>; + using callback_updated_only = std::function<void(const std::vector<MemoryID>& updatedSnapshotIDs)>; + + template <class CalleeT> + using member_callback = void(CalleeT::*)(const MemoryID& subscriptionID, const std::vector<MemoryID>& updatedSnapshotIDs); + template <class CalleeT> + using member_callback_updated_only = void(CalleeT::*)(const std::vector<MemoryID>& updatedSnapshotIDs); + + + public: + + MemoryListener(); + + + void subscribe(const MemoryID& subscriptionID, callback callback); + void subscribe(const MemoryID& subscriptionID, callback_updated_only callback); + + /** + * Subscribe with a class member function: + * @code + * reader.subscribe(entityID, this, &This::myCallback); + * @endcode + */ + template <class CalleeT> + void subscribe(const MemoryID& subscriptionID, CalleeT* callee, member_callback<CalleeT> callback) + { + auto cb = [callee, callback](const MemoryID & subscriptionID, const std::vector<MemoryID>& updatedSnapshotIDs) + { + (callee->*callback)(subscriptionID, updatedSnapshotIDs); + }; + subscribe(subscriptionID, cb); + } + template <class CalleeT> + void subscribe(const MemoryID& subscriptionID, CalleeT* callee, member_callback_updated_only<CalleeT> callback) + { + auto cb = [callee, callback](const MemoryID&, const std::vector<MemoryID>& updatedSnapshotIDs) + { + (callee->*callback)(updatedSnapshotIDs); + }; + subscribe(subscriptionID, cb); + } + + + /// Function handling updates from the MemoryListener ice topic. + void updated(const std::vector<MemoryID>& updatedIDs) const; + + + protected: + + std::unordered_map<MemoryID, std::vector<callback>> callbacks; + + }; + +}