diff --git a/base/base_tests/clustering_map_tests.cpp b/base/base_tests/clustering_map_tests.cpp index f1d670b0d2..7203a4fcc4 100644 --- a/base/base_tests/clustering_map_tests.cpp +++ b/base/base_tests/clustering_map_tests.cpp @@ -19,19 +19,19 @@ vector Sort(vector vs) return vs; } -template > +template > class ClusteringMapAdapter { public: template void Append(Key const & key, V && value) { - m_m.Append(key, std::forward(value)); + m_m.Append(key, forward(value)); } void Union(Key const & u, Key const & v) { m_m.Union(u, v); } - std::vector Get(Key const & key) { return Sort(m_m.Get(key)); } + vector Get(Key const & key) { return Sort(m_m.Get(key)); } private: ClusteringMap m_m; diff --git a/base/clustering_map.hpp b/base/clustering_map.hpp index 6eeed876f8..5df48da0dc 100644 --- a/base/clustering_map.hpp +++ b/base/clustering_map.hpp @@ -4,24 +4,31 @@ #include #include +#include +#include #include #include namespace base { -// Maps keys to lists of values, but allows to clusterize keys -// together, and to get all values from a cluster. +// Maps keys to lists of values, but allows to combine keys into +// clusters and to get all values from a cluster. // -// NOTE: the map is NOT thread-safe. +// NOTE: this class is NOT thread-safe. template > class ClusteringMap { public: + // In complexity specifications below: + // * n is the total number of keys in the map + // * m is the total number of values in the map + // * α() is the inverse Ackermann function + // * F is the complexity of find() in unordered_map + // Appends |value| to the list of values in the cluster // corresponding to |key|. // - // Amortized complexity: O(log*(n) * F), where n is the total number - // of keys in the map, F is the complexity of find in unordered_map. + // Amortized complexity: O(α(n) * F). template void Append(Key const & key, V && value) { @@ -31,9 +38,7 @@ public: // Unions clusters corresponding to |u| and |v|. // - // Amortized complexity: O(log*(n) * F + log(m)), where n is the - // total number of keys and m is the total number of values in the - // map, F is the complexity of find in unordered_map. + // Amortized complexity: O(α(n) * F + log(m)). void Union(Key const & u, Key const & v) { auto & ru = GetRoot(u); @@ -49,8 +54,7 @@ public: // Returns all values from the cluster corresponding to |key|. // - // Amortized complexity: O(log*(n) * F), where n is the total number - // of keys in the map, F is the complexity of find in unordered map. + // Amortized complexity: O(α(n) * F). std::vector const & Get(Key const & key) { auto const & entry = GetRoot(key); @@ -76,6 +80,17 @@ private: return root; } + Entry & GetEntry(Key const & key) + { + auto it = m_table.find(key); + if (it != m_table.end()) + return it->second; + + auto & entry = m_table[key]; + entry.m_root = key; + return entry; + } + void Attach(Entry & parent, Entry & child) { ASSERT_LESS_OR_EQUAL(child.m_rank, parent.m_rank, ()); @@ -88,18 +103,9 @@ private: auto & cv = child.m_values; if (pv.size() < cv.size()) pv.swap(cv); - pv.insert(pv.end(), cv.begin(), cv.end()); - } - - Entry & GetEntry(Key const & key) - { - auto it = m_table.find(key); - if (it != m_table.end()) - return it->second; - - auto & entry = m_table[key]; - entry.m_root = key; - return entry; + std::move(cv.begin(), cv.end(), std::back_inserter(pv)); + cv.clear(); + cv.shrink_to_fit(); } std::unordered_map m_table;