From e48d66440ed61928c9d71408d0d15ff814f7d3e2 Mon Sep 17 00:00:00 2001
From: phesch <ulila@student.kit.edu>
Date: Tue, 17 May 2022 21:42:00 +0200
Subject: [PATCH] Rename map prefix functions for semantics

Also move generic templates into detail namespace.
---
 .../RobotAPI/libraries/armem/CMakeLists.txt   |   2 +-
 .../libraries/armem/core/container_maps.h     | 209 ++++++++++++++++++
 .../RobotAPI/libraries/armem/core/prefixes.h  | 203 -----------------
 .../armem/test/ArMemPrefixesTest.cpp          |  32 +--
 4 files changed, 226 insertions(+), 220 deletions(-)
 create mode 100644 source/RobotAPI/libraries/armem/core/container_maps.h
 delete mode 100644 source/RobotAPI/libraries/armem/core/prefixes.h

diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt
index 8183a5501..cff3ea8a1 100644
--- a/source/RobotAPI/libraries/armem/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem/CMakeLists.txt
@@ -86,7 +86,7 @@ set(LIB_HEADERS
     core/MemoryID.h
     core/MemoryID_operators.h
     core/operations.h
-    core/prefixes.h
+    core/container_maps.h
     core/SuccessHeader.h
     core/Time.h
     core/aron_conversions.h
diff --git a/source/RobotAPI/libraries/armem/core/container_maps.h b/source/RobotAPI/libraries/armem/core/container_maps.h
new file mode 100644
index 000000000..9c5b26f52
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/core/container_maps.h
@@ -0,0 +1,209 @@
+/*
+ * 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/>.
+ *
+ * @author     phesch ( ulila at student dot kit dot edu )
+ * @date       2022
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <map>
+#include <optional>
+#include <tuple>
+
+#include <RobotAPI/libraries/armem/core/MemoryID.h>
+
+namespace armarx::armem
+{
+
+    namespace detail
+    {
+
+        /**
+        * @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.
+        *
+        * `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
+        * prefix of the given key (for strings, this would be the case when passed the empty string).
+        *
+        * @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
+        */
+        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)
+        {
+            std::optional<KeyT> curKey = key;
+            std::optional<ValueT> value;
+            do
+            {
+                auto iterator = keyValMap.find(curKey.value());
+                if (iterator != keyValMap.end())
+                {
+                    value = iterator->second;
+                }
+                else
+                {
+                    curKey = prefixFunc(curKey.value());
+                }
+            } while (!value.has_value() && curKey.has_value());
+
+            if (value.has_value())
+            {
+                return {{curKey.value(), value.value()}};
+            }
+            return {};
+        }
+
+        /**
+        * @brief Accumulate all the values in a map for which the keys are prefixes of the given key.
+        *
+        * `AccumulateT` is a type that the values will be accumulated into using `accumulateFunc`.
+        * `accumulateFunc` is a function that modifies the given accumulator
+        * (by, e.g., adding the given value to it).
+        *
+        * The values are accumulated in order from the longest key to the shortest. 
+        *
+        * @see `getWithLongestPrefix` for a description of `prefixFunc`
+        * @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 accumulateFunc the function that accumulates the values in the accumulator
+        * @param key the key to calculate the prefixes of
+        */
+        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 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())
+                {
+                    curKey = prefixFunc(nextPair.value().first);
+                    accumulateFunc(values, nextPair.value().second);
+                }
+                else
+                {
+                    curKey.reset();
+                }
+            } while (curKey.has_value());
+
+            return values;
+        }
+
+        /**
+        * @brief Collect all the values in a map for which the keys are prefixes of the given key.
+        *
+        * This is a specialization of the general `accumulateFromPrefixes`
+        * for collecting single values into a vector.
+        *
+        * @see `accumulateFromPrefixes` for a detailed description
+        * @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
+        */
+        template <typename KeyT, typename ValueT>
+        std::vector<ValueT>
+        accumulateFromPrefixes(const std::map<KeyT, ValueT>& keyValMap,
+                               const std::function<std::optional<KeyT>(KeyT&)>& prefixFunc,
+                               const KeyT& key)
+        {
+            return accumulateFromPrefixes<KeyT, ValueT, std::vector<ValueT>>(
+                keyValMap,
+                prefixFunc,
+                [](std::vector<ValueT>& values, ValueT& val) { values.push_back(val); },
+                key);
+        }
+
+        /**
+        * @brief Collect all the values in a map for which the keys are prefixes of the given key.
+        *
+        * This is a specialization of the general `accumulateFromPrefixes`
+        * for appending vector values into a single vector.
+        *
+        * @see `accumulateFromPrefixes` for a detailed description
+        * @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
+        */
+        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 KeyT& key)
+        {
+            return accumulateFromPrefixes<KeyT, std::vector<ValueT>, std::vector<ValueT>>(
+                keyValMap,
+                prefixFunc,
+                [](std::vector<ValueT>& values, std::vector<ValueT>& val)
+                { values.insert(values.end(), val.begin(), val.end()); },
+                key);
+        }
+
+    } // namespace detail
+
+    std::optional<MemoryID> inline getMemoryIDParent(MemoryID& memID)
+    {
+        if (!memID.hasMemoryName())
+        {
+            return {};
+        }
+        MemoryID parent = memID.removeLeafItem();
+        return {parent};
+    }
+
+    /**
+     * @see `getWithLongestPrefix`
+     */
+    template <typename ValueT>
+    std::optional<std::pair<MemoryID, ValueT>>
+    getWithMostSpecificContainer(const std::map<MemoryID, ValueT>& idMap, const MemoryID& key)
+    {
+        return detail::getWithLongestPrefix<MemoryID, ValueT>(idMap, &getMemoryIDParent, key);
+    }
+
+    /**
+     * @see `accumulateFromPrefixes`
+     */
+    template <typename ValueT>
+    std::vector<ValueT>
+    accumulateFromContainers(const std::map<MemoryID, ValueT>& idMap, const MemoryID& key)
+    {
+        return detail::accumulateFromPrefixes<MemoryID, ValueT>(idMap, &getMemoryIDParent, key);
+    }
+
+    /**
+     * @see `accumulateFromPrefixes`
+     */
+    template <typename ValueT>
+    std::vector<ValueT>
+    accumulateFromContainers(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/core/prefixes.h b/source/RobotAPI/libraries/armem/core/prefixes.h
deleted file mode 100644
index 0435c42de..000000000
--- a/source/RobotAPI/libraries/armem/core/prefixes.h
+++ /dev/null
@@ -1,203 +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/>.
- *
- * @author     phesch ( ulila at student dot kit dot edu )
- * @date       2022
- * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
- *             GNU General Public License
- */
-
-#pragma once
-
-#include <map>
-#include <optional>
-#include <tuple>
-
-#include <RobotAPI/libraries/armem/core/MemoryID.h>
-
-namespace armarx::armem
-{
-    /**
-     * @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.
-     *
-     * `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
-     * prefix of the given key (for strings, this would be the case when passed the empty string).
-     *
-     * @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
-     */
-    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)
-    {
-        std::optional<KeyT> curKey = key;
-        std::optional<ValueT> value;
-        do
-        {
-            auto iterator = keyValMap.find(curKey.value());
-            if (iterator != keyValMap.end())
-            {
-                value = iterator->second;
-            }
-            else
-            {
-                curKey = prefixFunc(curKey.value());
-            }
-        } while (!value.has_value() && curKey.has_value());
-
-        if (value.has_value())
-        {
-            return {{curKey.value(), value.value()}};
-        }
-        return {};
-    }
-
-    /**
-     * @brief Accumulate all the values in a map for which the keys are prefixes of the given key.
-     *
-     * `AccumulateT` is a type that the values will be accumulated into using `accumulateFunc`.
-     * `accumulateFunc` is a function that modifies the given accumulator
-     * (by, e.g., adding the given value to it).
-     *
-     * The values are accumulated in order from the longest key to the shortest. 
-     *
-     * @see `getWithLongestPrefix` for a description of `prefixFunc`
-     * @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 accumulateFunc the function that accumulates the values in the accumulator
-     * @param key the key to calculate the prefixes of
-     */
-    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 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())
-            {
-                curKey = prefixFunc(nextPair.value().first);
-                accumulateFunc(values, nextPair.value().second);
-            }
-            else
-            {
-                curKey.reset();
-            }
-        } while (curKey.has_value());
-
-        return values;
-    }
-
-    /**
-     * @brief Collect all the values in a map for which the keys are prefixes of the given key.
-     *
-     * This is a specialization of the general `accumulateFromPrefixes`
-     * for collecting single values into a vector.
-     *
-     * @see `accumulateFromPrefixes` for a detailed description
-     * @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
-     */
-    template <typename KeyT, typename ValueT>
-    std::vector<ValueT>
-    accumulateFromPrefixes(const std::map<KeyT, ValueT>& keyValMap,
-                           const std::function<std::optional<KeyT>(KeyT&)>& prefixFunc,
-                           const KeyT& key)
-    {
-        return accumulateFromPrefixes<KeyT, ValueT, std::vector<ValueT>>(
-            keyValMap,
-            prefixFunc,
-            [](std::vector<ValueT>& values, ValueT& val) { values.push_back(val); },
-            key);
-    }
-
-    /**
-     * @brief Collect all the values in a map for which the keys are prefixes of the given key.
-     *
-     * This is a specialization of the general `accumulateFromPrefixes`
-     * for appending vector values into a single vector.
-     *
-     * @see `accumulateFromPrefixes` for a detailed description
-     * @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
-     */
-    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 KeyT& key)
-    {
-        return accumulateFromPrefixes<KeyT, std::vector<ValueT>, std::vector<ValueT>>(
-            keyValMap,
-            prefixFunc,
-            [](std::vector<ValueT>& values, std::vector<ValueT>& val)
-            { values.insert(values.end(), val.begin(), val.end()); },
-            key);
-    }
-
-    std::optional<MemoryID> inline getMemoryIDParent(MemoryID& memID)
-    {
-        if (!memID.hasMemoryName())
-        {
-            return {};
-        }
-        MemoryID parent = memID.removeLeafItem();
-        return {parent};
-    }
-
-    /**
-     * @see `getWithLongestPrefix`
-     */
-    template <typename ValueT>
-    std::optional<std::pair<MemoryID, ValueT>>
-    getWithLongestPrefix(const std::map<MemoryID, ValueT>& idMap, const MemoryID& key)
-    {
-        return getWithLongestPrefix<MemoryID, ValueT>(idMap, &getMemoryIDParent, key);
-    }
-
-    /**
-     * @see `accumulateFromPrefixes`
-     */
-    template <typename ValueT>
-    std::vector<ValueT>
-    accumulateFromPrefixes(const std::map<MemoryID, ValueT>& idMap, const MemoryID& key)
-    {
-        return accumulateFromPrefixes<MemoryID, ValueT>(idMap, &getMemoryIDParent, key);
-    }
-
-    /**
-     * @see `accumulateFromPrefixes`
-     */
-    template <typename ValueT>
-    std::vector<ValueT>
-    accumulateFromPrefixes(const std::map<MemoryID, std::vector<ValueT>>& idMap,
-                           const MemoryID& key)
-    {
-        return 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 877b83daa..eb75fb840 100644
--- a/source/RobotAPI/libraries/armem/test/ArMemPrefixesTest.cpp
+++ b/source/RobotAPI/libraries/armem/test/ArMemPrefixesTest.cpp
@@ -28,7 +28,7 @@
 
 #include <RobotAPI/Test.h>
 #include <RobotAPI/libraries/armem/core/error.h>
-#include <RobotAPI/libraries/armem/core/prefixes.h>
+#include <RobotAPI/libraries/armem/core/container_maps.h>
 
 
 namespace armem = armarx::armem;
@@ -42,14 +42,14 @@ BOOST_AUTO_TEST_CASE(test_MemoryID_prefixes)
 
     BOOST_TEST_CONTEXT(VAROUT(idMap))
     {
-        BOOST_CHECK(not armem::getWithLongestPrefix(idMap, empty).has_value());
-        BOOST_CHECK(not armem::getWithLongestPrefix(idMap, complete).has_value());
-        BOOST_CHECK(armem::accumulateFromPrefixes(idMap, empty).empty());
-        BOOST_CHECK(armem::accumulateFromPrefixes(idMap, complete).empty());
+        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::accumulateFromPrefixes(idListMap, empty).empty());
-        BOOST_CHECK(armem::accumulateFromPrefixes(idListMap, complete).empty());
+        BOOST_CHECK(armem::accumulateFromContainers(idListMap, empty).empty());
+        BOOST_CHECK(armem::accumulateFromContainers(idListMap, complete).empty());
     }
 
     idMap[armem::MemoryID()] = 0;
@@ -60,21 +60,21 @@ BOOST_AUTO_TEST_CASE(test_MemoryID_prefixes)
 
     BOOST_TEST_CONTEXT(VAROUT(idMap))
     {
-        BOOST_CHECK(armem::getWithLongestPrefix(idMap, empty)
+        BOOST_CHECK(armem::getWithMostSpecificContainer(idMap, empty)
                         .value_or(std::make_pair(armem::MemoryID("inv"), -1))
                         .second == 0);
-        BOOST_CHECK(armem::getWithLongestPrefix(idMap, complete.getCoreSegmentID())
+        BOOST_CHECK(armem::getWithMostSpecificContainer(idMap, complete.getCoreSegmentID())
                         .value_or(std::make_pair(armem::MemoryID("inv"), -1))
                         .second == 2);
-        BOOST_CHECK(armem::getWithLongestPrefix(idMap, complete)
+        BOOST_CHECK(armem::getWithMostSpecificContainer(idMap, complete)
                         .value_or(std::make_pair(armem::MemoryID("inv"), -1))
                         .second == 3);
 
-        BOOST_CHECK((armem::accumulateFromPrefixes(idMap, empty) == std::vector<int>{0}));
-        BOOST_CHECK((armem::accumulateFromPrefixes(idMap, complete.getCoreSegmentID()) ==
+        BOOST_CHECK((armem::accumulateFromContainers(idMap, empty) == std::vector<int>{0}));
+        BOOST_CHECK((armem::accumulateFromContainers(idMap, complete.getCoreSegmentID()) ==
                      std::vector<int>{2, 1, 0}));
         BOOST_CHECK(
-            (armem::accumulateFromPrefixes(idMap, complete) == std::vector<int>{3, 2, 1, 0}));
+            (armem::accumulateFromContainers(idMap, complete) == std::vector<int>{3, 2, 1, 0}));
     }
 
     idListMap.emplace("mem", std::vector<int>{1, 2});
@@ -84,10 +84,10 @@ BOOST_AUTO_TEST_CASE(test_MemoryID_prefixes)
 
     BOOST_TEST_CONTEXT(VAROUT(idListMap))
     {
-        BOOST_CHECK((armem::accumulateFromPrefixes(idListMap, empty).empty()));
-        BOOST_CHECK((armem::accumulateFromPrefixes(idListMap, complete.getCoreSegmentID()) ==
+        BOOST_CHECK((armem::accumulateFromContainers(idListMap, empty).empty()));
+        BOOST_CHECK((armem::accumulateFromContainers(idListMap, complete.getCoreSegmentID()) ==
                      std::vector<int>{3, 4, 5, 1, 2}));
-        BOOST_CHECK((armem::accumulateFromPrefixes(idListMap, complete) ==
+        BOOST_CHECK((armem::accumulateFromContainers(idListMap, complete) ==
                      std::vector<int>{6, 7, 8, 3, 4, 5, 1, 2}));
     }
 }
-- 
GitLab