forked from organicmaps/organicmaps
[new downloader] Quick access to country tree items.
This commit is contained in:
parent
a23f0c9fa7
commit
927a12dfc2
7 changed files with 164 additions and 89 deletions
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
135
storage/country_tree_facade.hpp
Normal file
135
storage/country_tree_facade.hpp
Normal 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); }
|
||||
};
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
Loading…
Add table
Reference in a new issue