From 2548003a63af1bfce8a694e1001de4b2c53c4f11 Mon Sep 17 00:00:00 2001 From: Rainer Kartmann <rainer.kartmann@kit.edu> Date: Thu, 19 May 2022 10:47:55 +0200 Subject: [PATCH] Revise interface of memory id lookups --- .../libraries/armem/core/container_maps.h | 99 ++++++++++++------- .../armem/test/ArMemPrefixesTest.cpp | 47 ++++----- 2 files changed, 85 insertions(+), 61 deletions(-) diff --git a/source/RobotAPI/libraries/armem/core/container_maps.h b/source/RobotAPI/libraries/armem/core/container_maps.h index 9c5b26f52..625c92bb0 100644 --- a/source/RobotAPI/libraries/armem/core/container_maps.h +++ b/source/RobotAPI/libraries/armem/core/container_maps.h @@ -32,10 +32,18 @@ namespace armarx::armem namespace detail { + template <class KeyT, class ValueT> + struct MapRef + { + KeyT* key; + ValueT* value; + }; + + /** - * @brief Get the key-value pair from the map for which the returned key - * is the longest prefix of the given key among the keys in the map. + * @brief Get the entry in the map for which the returned key is the longest prefix + * of the given key among the keys in the map. * * `prefixFunc` is used to successively calculate the prefixes of the given key. * It must be pure and return an empty optional when there is no shorter @@ -44,35 +52,36 @@ namespace armarx::armem * @param keyValMap the map that contains the key-value-pairs to search * @param prefixFunc the function that returns the longest non-identical prefix of the key * @param key the key to calculate the prefixes of + * + * @return The iterator pointing to the found entry, or `keyValMap.end()`. */ template <typename KeyT, typename ValueT> - std::optional<std::pair<KeyT, ValueT>> - getWithLongestPrefix(const std::map<KeyT, ValueT>& keyValMap, - const std::function<std::optional<KeyT>(KeyT&)>& prefixFunc, - const KeyT& key) + typename std::map<KeyT, ValueT>::const_iterator + findEntryWithLongestPrefix(const std::map<KeyT, ValueT>& keyValMap, + const std::function<std::optional<KeyT>(KeyT&)>& prefixFunc, + const KeyT& key) { std::optional<KeyT> curKey = key; - std::optional<ValueT> value; + + typename std::map<KeyT, ValueT>::const_iterator result = keyValMap.end(); do { auto iterator = keyValMap.find(curKey.value()); if (iterator != keyValMap.end()) { - value = iterator->second; + result = iterator; } else { curKey = prefixFunc(curKey.value()); } - } while (!value.has_value() && curKey.has_value()); - - if (value.has_value()) - { - return {{curKey.value(), value.value()}}; } - return {}; + while (result == keyValMap.end() and curKey.has_value()); + + return result; } + /** * @brief Accumulate all the values in a map for which the keys are prefixes of the given key. * @@ -91,26 +100,27 @@ namespace armarx::armem template <typename KeyT, typename ValueT, typename AccumulateT> AccumulateT accumulateFromPrefixes(const std::map<KeyT, ValueT>& keyValMap, - const std::function<std::optional<KeyT>(KeyT&)>& prefixFunc, - const std::function<void(AccumulateT&, ValueT&)> accumulateFunc, + const std::function<std::optional<KeyT>(const KeyT&)>& prefixFunc, + const std::function<void(AccumulateT&, const ValueT&)> accumulateFunc, const KeyT& key) { std::optional<KeyT> curKey = key; AccumulateT values; do { - std::optional<std::pair<KeyT, ValueT>> nextPair = - getWithLongestPrefix<KeyT, ValueT>(keyValMap, prefixFunc, curKey.value()); - if (nextPair.has_value()) + const auto nextEntry = + findEntryWithLongestPrefix<KeyT, ValueT>(keyValMap, prefixFunc, curKey.value()); + if (nextEntry != keyValMap.end()) { - curKey = prefixFunc(nextPair.value().first); - accumulateFunc(values, nextPair.value().second); + curKey = prefixFunc(nextEntry->first); + accumulateFunc(values, nextEntry->second); } else { curKey.reset(); } - } while (curKey.has_value()); + } + while (curKey.has_value()); return values; } @@ -129,13 +139,13 @@ namespace armarx::armem template <typename KeyT, typename ValueT> std::vector<ValueT> accumulateFromPrefixes(const std::map<KeyT, ValueT>& keyValMap, - const std::function<std::optional<KeyT>(KeyT&)>& prefixFunc, + const std::function<std::optional<KeyT>(const KeyT&)>& prefixFunc, const KeyT& key) { return accumulateFromPrefixes<KeyT, ValueT, std::vector<ValueT>>( keyValMap, prefixFunc, - [](std::vector<ValueT>& values, ValueT& val) { values.push_back(val); }, + [](std::vector<ValueT>& values, const ValueT& val) { values.push_back(val); }, key); } @@ -153,57 +163,70 @@ namespace armarx::armem template <typename KeyT, typename ValueT> std::vector<ValueT> accumulateFromPrefixes(const std::map<KeyT, std::vector<ValueT>>& keyValMap, - const std::function<std::optional<KeyT>(KeyT&)>& prefixFunc, + const std::function<std::optional<KeyT>(const KeyT&)>& prefixFunc, const KeyT& key) { return accumulateFromPrefixes<KeyT, std::vector<ValueT>, std::vector<ValueT>>( keyValMap, prefixFunc, - [](std::vector<ValueT>& values, std::vector<ValueT>& val) + [](std::vector<ValueT>& values, const std::vector<ValueT>& val) { values.insert(values.end(), val.begin(), val.end()); }, key); } } // namespace detail - std::optional<MemoryID> inline getMemoryIDParent(MemoryID& memID) + + std::optional<MemoryID> inline getMemoryIDParent(const MemoryID& memID) { if (!memID.hasMemoryName()) { - return {}; + return std::nullopt; } MemoryID parent = memID.removeLeafItem(); return {parent}; } + /** - * @see `getWithLongestPrefix` + * @brief Find the entry with the most specific key that contains the given ID, + * or `idMap.end()` if no key contains the ID. + * + * @see `detail::findEntryWithLongestPrefix()` */ template <typename ValueT> - std::optional<std::pair<MemoryID, ValueT>> - getWithMostSpecificContainer(const std::map<MemoryID, ValueT>& idMap, const MemoryID& key) + typename std::map<MemoryID, ValueT>::const_iterator + findMostSpecificEntryContainingID(const std::map<MemoryID, ValueT>& idMap, const MemoryID& id) { - return detail::getWithLongestPrefix<MemoryID, ValueT>(idMap, &getMemoryIDParent, key); + return detail::findEntryWithLongestPrefix<MemoryID, ValueT>(idMap, &getMemoryIDParent, id); } + /** - * @see `accumulateFromPrefixes` + * @brief Return all values of keys containing the given ID. + * + * @see `detail::accumulateFromPrefixes()` */ template <typename ValueT> std::vector<ValueT> - accumulateFromContainers(const std::map<MemoryID, ValueT>& idMap, const MemoryID& key) + accumulateEntriesContainingID(const std::map<MemoryID, ValueT>& idMap, const MemoryID& id) { - return detail::accumulateFromPrefixes<MemoryID, ValueT>(idMap, &getMemoryIDParent, key); + return detail::accumulateFromPrefixes<MemoryID, ValueT>(idMap, &getMemoryIDParent, id); } + /** - * @see `accumulateFromPrefixes` + * @brief Return all values of keys containing the given ID in a flattened vector. + * + * @see `detail::accumulateFromPrefixes()` */ template <typename ValueT> std::vector<ValueT> - accumulateFromContainers(const std::map<MemoryID, std::vector<ValueT>>& idMap, - const MemoryID& key) + accumulateEntriesContainingID(const std::map<MemoryID, std::vector<ValueT>>& idMap, + const MemoryID& key) { return detail::accumulateFromPrefixes<MemoryID, ValueT>(idMap, &getMemoryIDParent, key); } + + } // namespace armarx::armem diff --git a/source/RobotAPI/libraries/armem/test/ArMemPrefixesTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemPrefixesTest.cpp index eb75fb840..4efc40432 100644 --- a/source/RobotAPI/libraries/armem/test/ArMemPrefixesTest.cpp +++ b/source/RobotAPI/libraries/armem/test/ArMemPrefixesTest.cpp @@ -42,14 +42,13 @@ BOOST_AUTO_TEST_CASE(test_MemoryID_prefixes) BOOST_TEST_CONTEXT(VAROUT(idMap)) { - BOOST_CHECK(not armem::getWithMostSpecificContainer(idMap, empty).has_value()); - BOOST_CHECK(not armem::getWithMostSpecificContainer(idMap, complete).has_value()); - BOOST_CHECK(armem::accumulateFromContainers(idMap, empty).empty()); - BOOST_CHECK(armem::accumulateFromContainers(idMap, complete).empty()); + BOOST_CHECK(armem::findMostSpecificEntryContainingID(idMap, empty) == idMap.end()); + BOOST_CHECK(armem::findMostSpecificEntryContainingID(idMap, complete) == idMap.end()); + BOOST_CHECK(armem::accumulateEntriesContainingID(idMap, empty).empty()); + BOOST_CHECK(armem::accumulateEntriesContainingID(idMap, complete).empty()); - - BOOST_CHECK(armem::accumulateFromContainers(idListMap, empty).empty()); - BOOST_CHECK(armem::accumulateFromContainers(idListMap, complete).empty()); + BOOST_CHECK(armem::accumulateEntriesContainingID(idListMap, empty).empty()); + BOOST_CHECK(armem::accumulateEntriesContainingID(idListMap, complete).empty()); } idMap[armem::MemoryID()] = 0; @@ -60,21 +59,23 @@ BOOST_AUTO_TEST_CASE(test_MemoryID_prefixes) BOOST_TEST_CONTEXT(VAROUT(idMap)) { - BOOST_CHECK(armem::getWithMostSpecificContainer(idMap, empty) - .value_or(std::make_pair(armem::MemoryID("inv"), -1)) - .second == 0); - BOOST_CHECK(armem::getWithMostSpecificContainer(idMap, complete.getCoreSegmentID()) - .value_or(std::make_pair(armem::MemoryID("inv"), -1)) - .second == 2); - BOOST_CHECK(armem::getWithMostSpecificContainer(idMap, complete) - .value_or(std::make_pair(armem::MemoryID("inv"), -1)) - .second == 3); - - BOOST_CHECK((armem::accumulateFromContainers(idMap, empty) == std::vector<int>{0})); - BOOST_CHECK((armem::accumulateFromContainers(idMap, complete.getCoreSegmentID()) == + auto it = armem::findMostSpecificEntryContainingID(idMap, empty); + BOOST_CHECK(it != idMap.end()); + BOOST_CHECK_EQUAL(it->second, 0); + + it = armem::findMostSpecificEntryContainingID(idMap, complete.getCoreSegmentID()); + BOOST_CHECK(it != idMap.end()); + BOOST_CHECK_EQUAL(it->second, 2); + + it = armem::findMostSpecificEntryContainingID(idMap, complete); + BOOST_CHECK(it != idMap.end()); + BOOST_CHECK_EQUAL(it->second, 3); + + BOOST_CHECK((armem::accumulateEntriesContainingID(idMap, empty) == std::vector<int>{0})); + BOOST_CHECK((armem::accumulateEntriesContainingID(idMap, complete.getCoreSegmentID()) == std::vector<int>{2, 1, 0})); BOOST_CHECK( - (armem::accumulateFromContainers(idMap, complete) == std::vector<int>{3, 2, 1, 0})); + (armem::accumulateEntriesContainingID(idMap, complete) == std::vector<int>{3, 2, 1, 0})); } idListMap.emplace("mem", std::vector<int>{1, 2}); @@ -84,10 +85,10 @@ BOOST_AUTO_TEST_CASE(test_MemoryID_prefixes) BOOST_TEST_CONTEXT(VAROUT(idListMap)) { - BOOST_CHECK((armem::accumulateFromContainers(idListMap, empty).empty())); - BOOST_CHECK((armem::accumulateFromContainers(idListMap, complete.getCoreSegmentID()) == + BOOST_CHECK((armem::accumulateEntriesContainingID(idListMap, empty).empty())); + BOOST_CHECK((armem::accumulateEntriesContainingID(idListMap, complete.getCoreSegmentID()) == std::vector<int>{3, 4, 5, 1, 2})); - BOOST_CHECK((armem::accumulateFromContainers(idListMap, complete) == + BOOST_CHECK((armem::accumulateEntriesContainingID(idListMap, complete) == std::vector<int>{6, 7, 8, 3, 4, 5, 1, 2})); } } -- GitLab