diff --git a/libs/base/internal/message.hpp b/libs/base/internal/message.hpp index 5c820f5cb..a43bafa9e 100644 --- a/libs/base/internal/message.hpp +++ b/libs/base/internal/message.hpp @@ -47,6 +47,8 @@ std::string DebugPrint(char32_t * t) = delete; template inline std::string DebugPrint(std::pair const & p); +template +inline std::string DebugPrint(std::tuple const & p); template inline std::string DebugPrint(std::list const & v); template @@ -136,6 +138,14 @@ std::string DebugPrint(std::pair const & p) return out.str(); } +template +std::string DebugPrint(std::tuple const & p) +{ + std::ostringstream out; + out << "(" << DebugPrint(get<0>(p)) << ", " << DebugPrint(get<1>(p)) << ", " << DebugPrint(get<2>(p)) << ")"; + return out.str(); +} + template std::string DebugPrintSequence(IterT beg, IterT end) { diff --git a/libs/indexer/feature_charge_sockets.cpp b/libs/indexer/feature_charge_sockets.cpp index 7f7486f65..56a6e25c1 100644 --- a/libs/indexer/feature_charge_sockets.cpp +++ b/libs/indexer/feature_charge_sockets.cpp @@ -395,6 +395,35 @@ OSMKeyValues ChargeSocketsHelper::GetOSMKeyValues() return result; } +KeyValueDiffSet ChargeSocketsHelper::Diff(ChargeSocketDescriptors const & oldSockets) +{ + KeyValueDiffSet result; + + auto oldKeys = ChargeSocketsHelper(oldSockets).GetOSMKeyValues(); + auto newKeys = GetOSMKeyValues(); + + std::unordered_map oldMap, newMap; + + for (auto && [k, v] : oldKeys) + oldMap.emplace(k, v); + for (auto && [k, v] : newKeys) + newMap.emplace(k, v); + + // Handle keys that exist in old + for (auto && [k, oldVal] : oldMap) + if (auto it = newMap.find(k); it == newMap.end()) + result.insert({k, oldVal, ""}); // deleted + else if (it->second != oldVal) + result.insert({k, oldVal, it->second}); // updated + + // Handle keys that are only new + for (auto && [k, newVal] : newMap) + if (!oldMap.contains(k)) + result.insert({k, "", newVal}); // created + + return result; +} + void ChargeSocketsHelper::Sort() { size_t const unknownTypeOrder = SUPPORTED_TYPES.size(); diff --git a/libs/indexer/feature_charge_sockets.hpp b/libs/indexer/feature_charge_sockets.hpp index 9404aa249..6a84c8d73 100644 --- a/libs/indexer/feature_charge_sockets.hpp +++ b/libs/indexer/feature_charge_sockets.hpp @@ -1,7 +1,9 @@ #pragma once #include +#include #include +#include #include // for std::pair #include @@ -19,11 +21,15 @@ typedef std::vector ChargeSocketDescriptors; typedef std::vector> OSMKeyValues; +typedef std::set> KeyValueDiffSet; + class ChargeSocketsHelper { public: ChargeSocketsHelper() : m_dirty(false) {} + ChargeSocketsHelper(ChargeSocketDescriptors const & sockets) : m_chargeSockets(sockets), m_dirty(true) {} + /** Create a ChareSocketsHelper instance from an existing list of sockets * stored as "||[];..." * @@ -91,6 +97,19 @@ public: "mcs", "type2_combo", "chademo", "nacs", "type1", "gb_dc", "chaoji", "type3c", "type2_cable", "type2", "gb_ac", "type3a"}; + /** Return a list of OSM attributes that have changed between the current + * list of sockets and the provided old list. + * + * Returns a set of (key, old_value, new_value) tuples. + * + * If old_value="", the attribute is new (ie has been created) + * If new_value="", the attribute has been deleted + * + * Note that this method is not const as it may trigger a re-ordering of the + * internal list of sockets. + */ + KeyValueDiffSet Diff(ChargeSocketDescriptors const & oldSockets); + protected: ChargeSocketDescriptors m_chargeSockets; diff --git a/libs/indexer/indexer_tests/feature_charge_sockets_test.cpp b/libs/indexer/indexer_tests/feature_charge_sockets_test.cpp index ad73d0092..fd87d2436 100644 --- a/libs/indexer/indexer_tests/feature_charge_sockets_test.cpp +++ b/libs/indexer/indexer_tests/feature_charge_sockets_test.cpp @@ -203,6 +203,52 @@ UNIT_TEST(ChargeSockets_Processing) TEST_EQUAL( ChargeSocketsHelper("type2|3|43;type2|5|7.4;type2_combo|10|250;type2|2|50;type2_combo|2|100").GetOSMKeyValues(), kvs, ()); + + /////////////////////////////////////////////////////////// + // OSM attribute diff + OSMKeyValues kvs_old, kvs_new; + KeyValueDiffSet diff; + + kvs_old = {{"socket:type2", "2"}}; + kvs_new = {{"socket:type2", "2"}}; + diff = {}; + TEST_EQUAL(FromKVs(kvs_new).Diff(FromKVs(kvs_old).GetSockets()), diff, ()); + + kvs_old = {{"socket:type2", "3"}}; + kvs_new = {{"socket:type2", "2"}}; + diff = {{"socket:type2", "3", "2"}}; + TEST_EQUAL(FromKVs(kvs_new).Diff(FromKVs(kvs_old).GetSockets()), diff, ()); + + kvs_old = {{"socket:type2", "2"}}; + kvs_new = {{"socket:type2", "3"}}; + diff = {{"socket:type2", "2", "3"}}; + TEST_EQUAL(FromKVs(kvs_new).Diff(FromKVs(kvs_old).GetSockets()), diff, ()); + + kvs_old = {}; + kvs_new = {{"socket:type2", "2"}}; + diff = {{"socket:type2", "", "2"}}; + TEST_EQUAL(FromKVs(kvs_new).Diff(FromKVs(kvs_old).GetSockets()), diff, ()); + + kvs_old = {{"socket:type2", "2"}}; + kvs_new = {}; + diff = {{"socket:type2", "2", ""}}; + TEST_EQUAL(FromKVs(kvs_new).Diff(FromKVs(kvs_old).GetSockets()), diff, ()); + + kvs_old = {{"socket:type2_combo", "10;2"}, + {"socket:type2_combo:output", "250;100"}, + {"socket:type1", "5"}, + {"socket:type2", "2;3;5"}, + {"socket:type2:output", "50;43;7.4"}}; + kvs_new = {{"socket:type2_combo", "10;2"}, + {"socket:type2_combo:output", "250;100"}, + {"socket:chademo", "2"}, + {"socket:type2", "2;3"}, + {"socket:type2:output", "50;43"}}; + diff = {{"socket:type1", "5", ""}, + {"socket:type2", "2;3;5", "2;3"}, + {"socket:type2:output", "50;43;7.4", "50;43"}, + {"socket:chademo", "", "2"}}; + TEST_EQUAL(FromKVs(kvs_new).Diff(FromKVs(kvs_old).GetSockets()), diff, ()); } } // namespace feature_charge_sockets_test