config_parser: Split up sections

We can't always combine sections together in network files as sections
like

[Address]
Address=::1/128
Peer=fe80::1
[Address]
Address=::2/128
Peer=fe80::2

Require that they are grouped accordingly. Rewrite the storage logic of
the config parser to support this logical organization.

Change-Id: I34ae1523202f8770fe3dcac010fb6226dd28b9ec
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/config_parser.hpp b/src/config_parser.hpp
index 7ff20ba..9b203c2 100644
--- a/src/config_parser.hpp
+++ b/src/config_parser.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <filesystem>
+#include <functional>
 #include <optional>
 #include <string>
 #include <string_view>
@@ -35,8 +36,41 @@
 using ValueList = std::vector<Value>;
 using KeyValuesMap =
     std::unordered_map<Key, ValueList, string_hash, std::equal_to<>>;
-using SectionMap =
-    std::unordered_map<Section, KeyValuesMap, string_hash, std::equal_to<>>;
+using KeyValuesMapList = std::vector<KeyValuesMap>;
+using SectionMapInt =
+    std::unordered_map<Section, KeyValuesMapList, string_hash, std::equal_to<>>;
+
+class SectionMap : public SectionMapInt
+{
+  public:
+    const std::string* getLastValueString(std::string_view section,
+                                          std::string_view key) const noexcept;
+    inline auto getValues(std::string_view section, std::string_view key,
+                          auto&& conv) const
+    {
+        std::vector<std::invoke_result_t<decltype(conv), const Value&>> values;
+        auto sit = find(section);
+        if (sit == end())
+        {
+            return values;
+        }
+        for (const auto& secv : sit->second)
+        {
+            auto kit = secv.find(key);
+            if (kit == secv.end())
+            {
+                continue;
+            }
+            for (auto v : kit->second)
+            {
+                values.push_back(conv(v));
+            }
+        }
+        return values;
+    }
+    std::vector<std::string> getValueStrings(std::string_view section,
+                                             std::string_view key) const;
+};
 
 class Parser
 {
@@ -48,13 +82,11 @@
      */
     Parser(const fs::path& filename);
 
-    /** @brief Get the values of the given key and section.
-     *  @param[in] section - section name.
-     *  @param[in] key - key to look for.
-     *  @returns   The ValueList or nullptr if no key + section exists.
-     */
-    const ValueList& getValues(std::string_view section,
-                               std::string_view key) const noexcept;
+    /** @brief Retrieve the map of all values in the file */
+    inline const SectionMap& getMap() const noexcept
+    {
+        return sections;
+    }
 
     /** @brief Determine if there were warnings parsing the file
      *  @return The number of parsing issues in the file