diff --git a/storage/country_tree.cpp b/storage/country_tree.cpp index bf6b47a207..512e7370ec 100644 --- a/storage/country_tree.cpp +++ b/storage/country_tree.cpp @@ -5,13 +5,15 @@ #include "coding/reader.hpp" +#include "base/assert.hpp" #include "base/logging.hpp" #include "base/stl_helpers.hpp" -#include "3party/jansson/myjansson.hpp" - +#include #include +#include "3party/jansson/myjansson.hpp" + using namespace std; using platform::CountryFile; @@ -20,7 +22,7 @@ namespace storage // Mwm subtree attributes. They can be calculated based on information contained in countries.txt. // The first in the pair is number of mwms in a subtree. The second is sum of sizes of // all mwms in a subtree. -using TMwmSubtreeAttrs = pair; +using MwmSubtreeAttrs = pair; namespace { @@ -139,8 +141,179 @@ public: }; } // namespace -TMwmSubtreeAttrs LoadGroupSingleMwmsImpl(size_t depth, json_t * node, CountryId const & parent, - StoreSingleMwmInterface & store) +// CountryTree::Node ------------------------------------------------------------------------------- + +CountryTree::Node * CountryTree::Node::AddAtDepth(size_t level, Country const & value) +{ + Node * node = this; + while (--level > 0 && !node->m_children.empty()) + node = node->m_children.back().get(); + ASSERT_EQUAL(level, 0, ()); + return node->Add(value); +} + +CountryTree::Node const & CountryTree::Node::Parent() const +{ + CHECK(HasParent(), ()); + return *m_parent; +} + +CountryTree::Node const & CountryTree::Node::Child(size_t index) const +{ + ASSERT_LESS(index, m_children.size(), ()); + return *m_children[index]; +} + +void CountryTree::Node::ForEachChild(CountryTree::Node::NodeCallback const & f) +{ + for (auto & child : m_children) + f(*child); +} + +void CountryTree::Node::ForEachChild(CountryTree::Node::NodeCallback const & f) const +{ + for (auto const & child : m_children) + f(*child); +} + +void CountryTree::Node::ForEachDescendant(CountryTree::Node::NodeCallback const & f) +{ + for (auto & child : m_children) + { + f(*child); + child->ForEachDescendant(f); + } +} + +void CountryTree::Node::ForEachDescendant(CountryTree::Node::NodeCallback const & f) const +{ + for (auto const & child : m_children) + { + f(*child); + child->ForEachDescendant(f); + } +} + +void CountryTree::Node::ForEachInSubtree(CountryTree::Node::NodeCallback const & f) +{ + f(*this); + for (auto & child : m_children) + child->ForEachInSubtree(f); +} + +void CountryTree::Node::ForEachInSubtree(CountryTree::Node::NodeCallback const & f) const +{ + f(*this); + for (auto const & child : m_children) + child->ForEachInSubtree(f); +} + +void CountryTree::Node::ForEachAncestorExceptForTheRoot(CountryTree::Node::NodeCallback const & f) +{ + if (m_parent == nullptr || m_parent->m_parent == nullptr) + return; + f(*m_parent); + m_parent->ForEachAncestorExceptForTheRoot(f); +} + +void CountryTree::Node::ForEachAncestorExceptForTheRoot( + CountryTree::Node::NodeCallback const & f) const +{ + if (m_parent == nullptr || m_parent->m_parent == nullptr) + return; + f(*m_parent); + m_parent->ForEachAncestorExceptForTheRoot(f); +} + +CountryTree::Node * CountryTree::Node::Add(Country const & value) +{ + m_children.emplace_back(std::make_unique(value, this)); + return m_children.back().get(); +} + +// CountryTree ------------------------------------------------------------------------------------- + +CountryTree::Node const & CountryTree::GetRoot() const +{ + CHECK(m_countryTree, ()); + return *m_countryTree; +} + +CountryTree::Node & CountryTree::GetRoot() +{ + CHECK(m_countryTree, ()); + return *m_countryTree; +} + +Country & CountryTree::AddAtDepth(size_t level, Country const & value) +{ + Node * added = nullptr; + if (level == 0) + { + ASSERT(IsEmpty(), ()); + m_countryTree = std::make_unique(value, nullptr); // Creating the root node. + added = m_countryTree.get(); + } + else + { + added = m_countryTree->AddAtDepth(level, value); + } + + ASSERT(added, ()); + m_countryTreeMap.insert(make_pair(value.Name(), added)); + return added->Value(); +} + +void CountryTree::Clear() +{ + m_countryTree.reset(); + m_countryTreeMap.clear(); +} + +void CountryTree::Find(CountryId const & key, vector & found) const +{ + found.clear(); + if (IsEmpty()) + return; + + if (key == m_countryTree->Value().Name()) + found.push_back(m_countryTree.get()); + + auto const range = m_countryTreeMap.equal_range(key); + for (auto it = range.first; it != range.second; ++it) + found.push_back(it->second); +} + +CountryTree::Node const * const CountryTree::FindFirst(CountryId const & key) const +{ + if (IsEmpty()) + return nullptr; + + vector found; + Find(key, found); + if (found.empty()) + return nullptr; + return found[0]; +} + +CountryTree::Node const * const CountryTree::FindFirstLeaf(CountryId const & key) const +{ + if (IsEmpty()) + return nullptr; + + vector found; + Find(key, found); + + for (auto node : found) + { + if (node->ChildrenCount() == 0) + return node; + } + return nullptr; +} + +MwmSubtreeAttrs LoadGroupSingleMwmsImpl(size_t depth, json_t * node, CountryId const & parent, + StoreSingleMwmInterface & store) { CountryId id; FromJSONObject(node, "id", id); @@ -185,7 +358,7 @@ TMwmSubtreeAttrs LoadGroupSingleMwmsImpl(size_t depth, json_t * node, CountryId { for (json_t * child : children) { - TMwmSubtreeAttrs const childAttr = LoadGroupSingleMwmsImpl(depth + 1, child, id, store); + MwmSubtreeAttrs const childAttr = LoadGroupSingleMwmsImpl(depth + 1, child, id, store); mwmCounter += childAttr.first; mwmSize += childAttr.second; } @@ -272,9 +445,8 @@ public: }; } // namespace -TMwmSubtreeAttrs LoadGroupTwoComponentMwmsImpl(size_t depth, json_t * node, - CountryId const & parent, - StoreTwoComponentMwmInterface & store) +MwmSubtreeAttrs LoadGroupTwoComponentMwmsImpl(size_t depth, json_t * node, CountryId const & parent, + StoreTwoComponentMwmInterface & store) { // @TODO(bykoianko) After we stop supporting two component mwms (with routing files) // remove code below. @@ -306,7 +478,7 @@ TMwmSubtreeAttrs LoadGroupTwoComponentMwmsImpl(size_t depth, json_t * node, { for (json_t * child : children) { - TMwmSubtreeAttrs const childAttr = + MwmSubtreeAttrs const childAttr = LoadGroupTwoComponentMwmsImpl(depth + 1, child, file, store); countryCounter += childAttr.first; countrySize += childAttr.second; diff --git a/storage/country_tree.hpp b/storage/country_tree.hpp index 18c2ac1554..c4cd916a78 100644 --- a/storage/country_tree.hpp +++ b/storage/country_tree.hpp @@ -3,12 +3,10 @@ #include "storage/country.hpp" #include "storage/storage_defines.hpp" -#include "base/assert.hpp" - -#include #include #include #include +#include #include namespace storage @@ -45,101 +43,38 @@ public: /// \param value is a value of node which will be added. /// \note This method does not let to add a node to an arbitrary place in the tree. /// It's posible to add children only from "right side". - Node * AddAtDepth(size_t level, Country const & value) - { - Node * node = this; - while (--level > 0 && !node->m_children.empty()) - node = node->m_children.back().get(); - ASSERT_EQUAL(level, 0, ()); - return node->Add(value); - } + Node * AddAtDepth(size_t level, Country const & value); bool HasParent() const { return m_parent != nullptr; } bool IsRoot() const { return !HasParent(); } - Node const & Parent() const - { - CHECK(HasParent(), ()); - return *m_parent; - } + Node const & Parent() const; - Node const & Child(size_t index) const - { - ASSERT_LESS(index, m_children.size(), ()); - return *m_children[index]; - } + Node const & Child(size_t index) const; size_t ChildrenCount() const { return m_children.size(); } /// \brief Calls |f| for each first generation descendant of the node. - void ForEachChild(NodeCallback const & f) - { - for (auto & child : m_children) - f(*child); - } + void ForEachChild(NodeCallback const & f); - void ForEachChild(NodeCallback const & f) const - { - for (auto const & child : m_children) - f(*child); - } + void ForEachChild(NodeCallback const & f) const; /// \brief Calls |f| for all nodes (add descendant) in the tree. - void ForEachDescendant(NodeCallback const & f) - { - for (auto & child : m_children) - { - f(*child); - child->ForEachDescendant(f); - } - } + void ForEachDescendant(NodeCallback const & f); - void ForEachDescendant(NodeCallback const & f) const - { - for (auto const & child : m_children) - { - f(*child); - child->ForEachDescendant(f); - } - } + void ForEachDescendant(NodeCallback const & f) const; - void ForEachInSubtree(NodeCallback const & f) - { - f(*this); - for (auto & child : m_children) - child->ForEachInSubtree(f); - } + void ForEachInSubtree(NodeCallback const & f); - void ForEachInSubtree(NodeCallback const & f) const - { - f(*this); - for (auto const & child : m_children) - child->ForEachInSubtree(f); - } + void ForEachInSubtree(NodeCallback const & f) const; - void ForEachAncestorExceptForTheRoot(NodeCallback const & f) - { - if (m_parent == nullptr || m_parent->m_parent == nullptr) - return; - f(*m_parent); - m_parent->ForEachAncestorExceptForTheRoot(f); - } + void ForEachAncestorExceptForTheRoot(NodeCallback const & f); - void ForEachAncestorExceptForTheRoot(NodeCallback const & f) const - { - if (m_parent == nullptr || m_parent->m_parent == nullptr) - return; - f(*m_parent); - m_parent->ForEachAncestorExceptForTheRoot(f); - } + void ForEachAncestorExceptForTheRoot(NodeCallback const & f) const; private: - Node * Add(Country const & value) - { - m_children.emplace_back(std::make_unique(value, this)); - return m_children.back().get(); - } + Node * Add(Country const & value); Country m_value; @@ -152,104 +87,32 @@ public: bool IsEmpty() const { return m_countryTree == nullptr; } - Node const & GetRoot() const - { - CHECK(m_countryTree, ()); - return *m_countryTree; - } + Node const & GetRoot() const; - Node & GetRoot() - { - CHECK(m_countryTree, ()); - return *m_countryTree; - } + Node & GetRoot(); - Country & AddAtDepth(size_t level, Country const & value) - { - Node * added = nullptr; - if (level == 0) - { - ASSERT(IsEmpty(), ()); - m_countryTree = std::make_unique(value, nullptr); // Creating the root node. - added = m_countryTree.get(); - } - else - { - added = m_countryTree->AddAtDepth(level, value); - } - - ASSERT(added, ()); - m_countryTreeHashTable.insert(make_pair(value.Name(), added)); - return added->Value(); - } + Country & AddAtDepth(size_t level, Country const & value); /// Deletes all children and makes tree empty - void Clear() - { - m_countryTree.reset(); - m_countryTreeHashTable.clear(); - } + void Clear(); /// \brief Checks all nodes in tree to find an equal one. If there're several equal nodes /// returns the first found. /// \returns a poiter item in the tree if found and nullptr otherwise. - void Find(CountryId const & key, std::vector & found) const - { - found.clear(); - if (IsEmpty()) - return; + void Find(CountryId const & key, std::vector & found) const; - if (key == m_countryTree->Value().Name()) - found.push_back(m_countryTree.get()); - - auto const range = m_countryTreeHashTable.equal_range(key); - if (range.first == range.second) - return; - - std::for_each(range.first, range.second, - [&found](typename CountryTreeHashTable::value_type const & node) { - found.push_back(node.second); - }); - } - - Node const * const FindFirst(CountryId const & key) const - { - if (IsEmpty()) - return nullptr; - - std::vector found; - Find(key, found); - if (found.empty()) - return nullptr; - return found[0]; - } + Node const * const FindFirst(CountryId const & key) const; /// \brief Find only leaves. /// \note It's a termprary fucntion for compatablity with old countries.txt. /// When new countries.txt with unique ids will be added FindLeaf will be removed /// and Find will be used intead. /// @TODO(bykoianko) Remove this method on countries.txt update. - Node const * const FindFirstLeaf(CountryId const & key) const - { - if (IsEmpty()) - return nullptr; - - std::vector found; - Find(key, found); - - for (auto node : found) - { - if (node->ChildrenCount() == 0) - return node; - } - return nullptr; - } + Node const * const FindFirstLeaf(CountryId const & key) const; private: - using CountryTreeHashTable = std::multimap; - std::unique_ptr m_countryTree; - CountryTreeHashTable m_countryTreeHashTable; + std::multimap m_countryTreeMap; }; /// @return version of country file or -1 if error was encountered