[new downloader] Quick access to country tree items.

This commit is contained in:
Vladimir Byko-Ianko 2016-03-01 18:25:53 +03:00 committed by Sergey Yershov
parent a23f0c9fa7
commit 927a12dfc2
7 changed files with 164 additions and 89 deletions

View file

@ -144,11 +144,11 @@ namespace
{
class DoStoreCountriesSingleMwms
{
TCountriesContainer & m_cont;
TCountriesFacade & m_cont;
TMapping m_idsMapping;
public:
DoStoreCountriesSingleMwms(TCountriesContainer & cont) : m_cont(cont) {}
DoStoreCountriesSingleMwms(TCountriesFacade & cont) : m_cont(cont) {}
Country * operator()(TCountryId const & id, uint32_t mapSize, int depth, TCountryId const & parent)
{
@ -177,10 +177,10 @@ public:
class DoStoreCountriesTwoComponentMwms
{
TCountriesContainer & m_cont;
TCountriesFacade & m_cont;
public:
DoStoreCountriesTwoComponentMwms(TCountriesContainer & cont) : m_cont(cont) {}
DoStoreCountriesTwoComponentMwms(TCountriesFacade & cont) : m_cont(cont) {}
void operator()(string const & file, uint32_t mapSize,
uint32_t routingSize, int depth, TCountryId const & parent)
@ -243,7 +243,7 @@ public:
};
} // namespace
int64_t LoadCountries(string const & jsonBuffer, TCountriesContainer & countries, TMapping * mapping /* = nullptr */)
int64_t LoadCountries(string const & jsonBuffer, TCountriesFacade & countries, TMapping * mapping /* = nullptr */)
{
countries.Clear();

View file

@ -2,7 +2,7 @@
#include "storage/country_decl.hpp"
#include "storage/index.hpp"
#include "storage/country_tree.hpp"
#include "storage/country_tree_facade.hpp"
#include "storage/storage_defines.hpp"
#include "platform/local_country_file.hpp"
@ -25,7 +25,7 @@ namespace storage
{
using TMapping = map<TCountryId, TCountriesSet>;
/// This class keeps all the information about a country in countre tree (TCountriesContainer).
/// This class keeps all the information about a country in countre tree (TCountriesFacade).
/// It is guaranteed that every node represent a unique region has a unique |m_name| in country tree.
/// If several nodes have the same |m_name| they represent the same region.
/// It happends in case of disputed territories.
@ -58,6 +58,7 @@ public:
: m_name(name), m_parent(parent) {}
bool operator<(Country const & other) const { return Name() < other.Name(); }
bool operator==(Country const & other) const { return Name() == other.Name(); }
void SetFile(platform::CountryFile const & file) { m_file = file; }
void SetSubtreeAttrs(uint32_t subtreeMwmNumber, size_t subtreeMwmSizeBytes)
{
@ -75,9 +76,10 @@ public:
};
typedef CountryTree<Country> TCountriesContainer;
typedef CountryTreeFacade<Country> TCountriesFacade;
/// @return version of country file or -1 if error was encountered
int64_t LoadCountries(string const & jsonBuffer, TCountriesContainer & countries, TMapping * mapping = nullptr);
int64_t LoadCountries(string const & jsonBuffer, TCountriesFacade & countries, TMapping * mapping = nullptr);
void LoadCountryFile2CountryInfo(string const & jsonBuffer, map<string, CountryInfo> & id2info,
bool & isSingleMwm);

View file

@ -3,9 +3,12 @@
#include "base/assert.hpp"
#include "std/algorithm.hpp"
#include "std/unique_ptr.hpp"
#include "std/shared_ptr.hpp"
#include "std/vector.hpp"
template <class T>
bool IsEqual(T const & v1, T const & v2) { return !(v1 < v2) && !(v2 < v1); }
/// This class is developed for using in Storage. It's a implementation of a tree.
/// It should be filled with AddAtDepth method.
/// This class is used in Storage and filled based on countries.txt (countries_migrate.txt).
@ -18,12 +21,14 @@ class CountryTree
/// \brief m_children contains all first generation descendants of the node.
/// Note. Once created the order of elements of |m_children| should not be changed.
/// See implementation of AddAtDepth and Add methods for details.
vector<unique_ptr<CountryTree<T>>> m_children;
vector<shared_ptr<CountryTree<T>>> m_children;
CountryTree<T> * m_parent;
static bool IsEqual(T const & v1, T const & v2)
/// @return reference is valid only up to the next tree structure modification
shared_ptr<CountryTree<T>> Add(T const & value)
{
return !(v1 < v2) && !(v2 < v1);
m_children.emplace_back(make_shared<CountryTree<T>>(value, this));
return m_children.back();
}
public:
@ -33,19 +38,13 @@ public:
}
/// @return reference is valid only up to the next tree structure modification
T const & Value() const
{
return m_value;
}
T const & Value() const { return m_value; }
/// @return reference is valid only up to the next tree structure modification
T & Value()
{
return m_value;
}
T & Value() { return m_value; }
/// @return reference is valid only up to the next tree structure modification
T & AddAtDepth(int level, T const & value)
shared_ptr<CountryTree<T>> AddAtDepth(int level, T const & value)
{
CountryTree<T> * node = this;
while (level-- > 0 && !node->m_children.empty())
@ -54,70 +53,10 @@ public:
return node->Add(value);
}
/// @return reference is valid only up to the next tree structure modification
T & Add(T const & value)
{
m_children.emplace_back(make_unique<CountryTree<T>>(value, this));
return m_children.back()->Value();
}
/// Deletes all children and makes tree empty
void Clear()
{
m_children.clear();
}
void Clear() { m_children.clear(); }
bool operator<(CountryTree<T> const & other) const
{
return Value() < other.Value();
}
/// \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.
/// @TODO(bykoianko) The complexity of the method is O(n). But the structure (tree) is built on the start of the program
/// and then actively used on run time. This method (and class) should be redesigned to make the function work faster.
/// A hash table is being planned to use.
void Find(T const & value, vector<CountryTree<T> const *> & found) const
{
if (IsEqual(m_value, value))
found.push_back(this);
for (auto const & child : m_children)
child->Find(value, found);
}
CountryTree<T> const * const FindFirst(T const & value) const
{
if (IsEqual(m_value, value))
return this;
for (auto const & child : m_children)
{
CountryTree<T> const * const found = child->FindFirst(value);
if (found != nullptr)
return found;
}
return nullptr;
}
/// \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.
CountryTree<T> const * const FindFirstLeaf(T const & value) const
{
if (IsEqual(m_value, value) && m_children.empty())
return this; // It's a leaf.
for (auto const & child : m_children)
{
CountryTree<T> const * const found = child->FindFirstLeaf(value);
if (found != nullptr)
return found;
}
return nullptr;
}
bool operator<(CountryTree<T> const & other) const { return Value() < other.Value(); }
bool HasParent() const { return m_parent != nullptr; }
@ -133,10 +72,7 @@ public:
return *m_children[index];
}
size_t ChildrenCount() const
{
return m_children.size();
}
size_t ChildrenCount() const { return m_children.size(); }
/// \brief Calls functor f for each first generation descendant of the node.
template <class TFunctor>

View file

@ -0,0 +1,135 @@
#pragma once
#include "storage/country_tree.hpp"
#include "std/algorithm.hpp"
#include "std/unordered_map.hpp"
template <class K>
struct CountryTreeKeyHasher
{
size_t operator()(K const & k) const { return hash<string>()(k.Name()); }
};
template<>
struct CountryTreeKeyHasher<int>
{
size_t operator()(int k) const { return hash<int>()(k); }
};
/// This class is developed for using in Storage. It's a implementation of a tree.
/// It should be filled with AddAtDepth method.
/// This class is used in Storage and filled based on countries.txt (countries_migrate.txt).
/// While filling CountryTree nodes in countries.txt should be visited in DFS order.
template <class T>
class CountryTreeFacade
{
using TCountryTreeHashTable = unordered_multimap<T, shared_ptr<CountryTree<T>>, CountryTreeKeyHasher<T>>;
CountryTree<T> m_countryTree;
TCountryTreeHashTable m_countryTreeHashTable;
public:
CountryTreeFacade(T const & value = T(), CountryTree<T> * parent = nullptr)
: m_countryTree(value, parent) {}
/// @return reference is valid only up to the next tree structure modification
T const & Value() const { return m_countryTree.Value(); }
/// @return reference is valid only up to the next tree structure modification
T & Value() { return m_countryTree.Value(); }
/// @return reference is valid only up to the next tree structure modification
T & AddAtDepth(int level, T const & value)
{
shared_ptr<CountryTree<T>> const added = m_countryTree.AddAtDepth(level, value);
m_countryTreeHashTable.insert(make_pair(value, added));
return added->Value();
}
/// Deletes all children and makes tree empty
void Clear() { m_countryTree.Clear(); }
bool operator<(CountryTree<T> const & other) const { return m_countryTree < other; }
/// \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.
/// @TODO(bykoianko) The complexity of the method is O(n). But the structure (tree) is built on the start of the program
/// and then actively used on run time. This method (and class) should be redesigned to make the function work faster.
/// A hash table is being planned to use.
void Find(T const & value, vector<CountryTree<T> const *> & found) const
{
found.clear();
if (IsEqual(value, m_countryTree.Value()))
found.push_back(&m_countryTree);
auto const range = m_countryTreeHashTable.equal_range(value);
auto const end = m_countryTreeHashTable.end();
if (range.first == end && range.second == end)
return;
for_each(range.first, range.second,
[&found](typename TCountryTreeHashTable::value_type const & node) { found.push_back(&*node.second); });
}
CountryTree<T> const * const FindFirst(T const & value) const
{
vector<CountryTree<T> const *> found;
Find(value, found);
if (found.empty())
return nullptr;
return found[0];
}
/// \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.
CountryTree<T> const * const FindFirstLeaf(T const & value) const
{
vector<CountryTree<T> const *> found;
Find(value, found);
for (auto node : found)
if (node->ChildrenCount() == 0)
return node;
return nullptr;
}
bool HasParent() const { m_countryTree.HasParent(); }
CountryTree<T> const & Parent() const { return m_countryTree.Parent(); }
CountryTree<T> const & Child(size_t index) const { return m_countryTree.Child(index); }
size_t ChildrenCount() const { return m_countryTree.ChildrenCount(); }
/// \brief Calls functor f for each first generation descendant of the node.
template <class TFunctor>
void ForEachChild(TFunctor && f) { return m_countryTree.ForEachChild(f); }
template <class TFunctor>
void ForEachChild(TFunctor && f) const { return m_countryTree.ForEachChild(f); }
/// \brief Calls functor f for all nodes (add descendant) in the tree.
template <class TFunctor>
void ForEachDescendant(TFunctor && f) { return m_countryTree.ForEachDescendant(f); }
template <class TFunctor>
void ForEachDescendant(TFunctor && f) const { return m_countryTree.ForEachDescendant(f); }
template <class TFunctor>
void ForEachInSubtree(TFunctor && f) { return m_countryTree.ForEachInSubtree(f); }
template <class TFunctor>
void ForEachInSubtree(TFunctor && f) const { return m_countryTree.ForEachInSubtree(f); }
template <class TFunctor>
void ForEachAncestorExceptForTheRoot(TFunctor && f) { return m_countryTree.ForEachAncestorExceptForTheRoot(f); }
template <class TFunctor>
void ForEachAncestorExceptForTheRoot(TFunctor && f) const { return m_countryTree.ForEachAncestorExceptForTheRoot(f); }
};

View file

@ -76,7 +76,7 @@ void DeleteFromDiskWithIndexes(LocalCountryFile const & localFile, MapOptions op
localFile.DeleteFromDisk(options);
}
TCountriesContainer const & LeafNodeFromCountryId(TCountriesContainer const & root,
TCountriesContainer const & LeafNodeFromCountryId(TCountriesFacade const & root,
TCountryId const & countryId)
{
CountryTree<Country> const * node = root.FindFirstLeaf(Country(countryId));

View file

@ -2,6 +2,7 @@
#include "storage/country.hpp"
#include "storage/country_name_getter.hpp"
#include "storage/country_tree_facade.hpp"
#include "storage/index.hpp"
#include "storage/map_files_downloader.hpp"
#include "storage/queued_country.hpp"
@ -97,7 +98,7 @@ private:
/// stores timestamp for update checks
int64_t m_currentVersion;
TCountriesContainer m_countries;
CountryTreeFacade<Country> m_countries;
/// @todo. It appeared that our application uses m_queue from
/// different threads without any synchronization. To reproduce it

View file

@ -17,6 +17,7 @@ HEADERS += \
country_name_getter.hpp \
country_polygon.hpp \
country_tree.hpp \
country_tree_facade.hpp \
http_map_files_downloader.hpp \
index.hpp \
map_files_downloader.hpp \