diff options
Diffstat (limited to 'indexer/data_source.cpp')
-rw-r--r-- | indexer/data_source.cpp | 244 |
1 files changed, 235 insertions, 9 deletions
diff --git a/indexer/data_source.cpp b/indexer/data_source.cpp index bb6b7ea3ed..fffe4650d7 100644 --- a/indexer/data_source.cpp +++ b/indexer/data_source.cpp @@ -2,15 +2,172 @@ #include "base/logging.hpp" +#include <limits> +#include <type_traits> + using platform::CountryFile; using platform::LocalCountryFile; using namespace std; -////////////////////////////////////////////////////////////////////////////////// -// DataSourceBase implementation -////////////////////////////////////////////////////////////////////////////////// +namespace +{ +template <typename Element> +class ReadMWMFunctor +{ +public: + using Fn = function<void(Element &)>; + + ReadMWMFunctor(Fn const & fn, FeatureSourceFactory const & factory) : m_fn(fn), m_factory(factory) + { + } + + template <typename T> + enable_if_t<is_same<T, FeatureID const>::value> ProcessElement(FeatureSource & src, + uint32_t index) const + { + if (FeatureStatus::Deleted == src.GetFeatureStatus(index)) + return; + + m_fn(src.GetFeatureId(index)); + } + + template <typename T> + enable_if_t<is_same<T, FeatureType>::value> ProcessElement(FeatureSource & src, + uint32_t index) const + { + FeatureType feature; + switch (src.GetFeatureStatus(index)) + { + case FeatureStatus::Created: CHECK(false, ("Created features index should be generated.")); + case FeatureStatus::Deleted: + case FeatureStatus::Obsolete: return; + case FeatureStatus::Modified: + { + VERIFY(src.GetModifiedFeature(index, feature), ()); + break; + } + case FeatureStatus::Untouched: + { + src.GetOriginalFeature(index, feature); + break; + } + } + m_fn(feature); + } + + // Reads features visible at |scale| covered by |cov| from mwm and applies |m_fn| to it. + // Feature reading process consists of two steps: untouched (original) features reading and + // touched (created, edited etc.) features reading. + void operator()(MwmSet::MwmHandle const & handle, covering::CoveringGetter & cov, int scale) const + { + auto src = m_factory(handle); + + MwmValue const * pValue = handle.GetValue<MwmValue>(); + if (pValue) + { + // Untouched (original) features reading. Applies covering |cov| to geometry index, gets + // feature ids from it, gets untouched features by ids from |src| and applies |m_fn| by + // ProcessElement. + feature::DataHeader const & header = pValue->GetHeader(); + CheckUniqueIndexes checkUnique(header.GetFormat() >= version::Format::v5); + + // In case of WorldCoasts we should pass correct scale in ForEachInIntervalAndScale. + auto const lastScale = header.GetLastScale(); + if (scale > lastScale) + scale = lastScale; + + // Use last coding scale for covering (see index_builder.cpp). + covering::Intervals const & intervals = cov.Get<RectId::DEPTH_LEVELS>(lastScale); + ScaleIndex<ModelReaderPtr> index(pValue->m_cont.GetReader(INDEX_FILE_TAG), pValue->m_factory); + + // iterate through intervals + for (auto const & i : intervals) + { + index.ForEachInIntervalAndScale(i.first, i.second, scale, [&](uint32_t index) { + if (!checkUnique(index)) + return; + ProcessElement<Element>(*src, index); + }); + } + } + // Check created features container. + // Need to do it on a per-mwm basis, because Drape relies on features in a sorted order. + // Touched (created, edited) features reading. + src->ForEachInRectAndScale(cov.GetRect(), scale, m_fn); + } + +private: + Fn m_fn; + FeatureSourceFactory const & m_factory; +}; +} // namespace + +//------------------------- DataSource::FeaturesLoaderGuard ---------------------- + +string DataSource::FeaturesLoaderGuard::GetCountryFileName() const +{ + if (!m_handle.IsAlive()) + return string(); + + return m_handle.GetValue<MwmValue>()->GetCountryFileName(); +} + +bool DataSource::FeaturesLoaderGuard::IsWorld() const +{ + if (!m_handle.IsAlive()) + return false; + + return m_handle.GetValue<MwmValue>()->GetHeader().GetType() == feature::DataHeader::world; +} + +unique_ptr<FeatureType> DataSource::FeaturesLoaderGuard::GetOriginalFeatureByIndex( + uint32_t index) const +{ + auto feature = make_unique<FeatureType>(); + if (GetOriginalFeatureByIndex(index, *feature)) + return feature; + + return {}; +} -unique_ptr<MwmInfo> DataSourceBase::CreateInfo(platform::LocalCountryFile const & localFile) const +unique_ptr<FeatureType> DataSource::FeaturesLoaderGuard::GetOriginalOrEditedFeatureByIndex( + uint32_t index) const +{ + auto feature = make_unique<FeatureType>(); + if (!m_handle.IsAlive()) + return {}; + + ASSERT_NOT_EQUAL(m_source->GetFeatureStatus(index), FeatureStatus::Created, ()); + if (GetFeatureByIndex(index, *feature)) + return feature; + + return {}; +} + +/// Everyone, except Editor core, should use this method. +WARN_UNUSED_RESULT bool DataSource::FeaturesLoaderGuard::GetFeatureByIndex(uint32_t index, + FeatureType & ft) const +{ + if (!m_handle.IsAlive()) + return false; + + ASSERT_NOT_EQUAL(FeatureStatus::Deleted, m_source->GetFeatureStatus(index), + ("Deleted feature was cached. It should not be here. Please review your code.")); + if (m_source->GetModifiedFeature(index, ft)) + return true; + return GetOriginalFeatureByIndex(index, ft); +} + +/// Editor core only method, to get 'untouched', original version of feature. +WARN_UNUSED_RESULT bool DataSource::FeaturesLoaderGuard::GetOriginalFeatureByIndex( + uint32_t index, FeatureType & ft) const +{ + return m_handle.IsAlive() ? m_source->GetOriginalFeature(index, ft) : false; +} + +//---------------- DataSource ----------------------------------------------- + +unique_ptr<MwmInfo> DataSource::CreateInfo(platform::LocalCountryFile const & localFile) const { MwmValue value(localFile); @@ -32,7 +189,7 @@ unique_ptr<MwmInfo> DataSourceBase::CreateInfo(platform::LocalCountryFile const return unique_ptr<MwmInfo>(move(info)); } -unique_ptr<MwmSet::MwmValueBase> DataSourceBase::CreateValue(MwmInfo & info) const +unique_ptr<MwmSet::MwmValueBase> DataSource::CreateValue(MwmInfo & info) const { // Create a section with rank table if it does not exist. platform::LocalCountryFile const & localFile = info.GetLocalFile(); @@ -42,15 +199,15 @@ unique_ptr<MwmSet::MwmValueBase> DataSourceBase::CreateValue(MwmInfo & info) con return unique_ptr<MwmSet::MwmValueBase>(move(p)); } -pair<MwmSet::MwmId, MwmSet::RegResult> DataSourceBase::RegisterMap(LocalCountryFile const & localFile) +pair<MwmSet::MwmId, MwmSet::RegResult> DataSource::RegisterMap(LocalCountryFile const & localFile) { return Register(localFile); } -bool DataSourceBase::DeregisterMap(CountryFile const & countryFile) { return Deregister(countryFile); } +bool DataSource::DeregisterMap(CountryFile const & countryFile) { return Deregister(countryFile); } -void DataSourceBase::ForEachInIntervals(ReaderCallback const & fn, covering::CoveringMode mode, - m2::RectD const & rect, int scale) const +void DataSource::ForEachInIntervals(ReaderCallback const & fn, covering::CoveringMode mode, + m2::RectD const & rect, int scale) const { vector<shared_ptr<MwmInfo>> mwms; GetMwmsInfo(mwms); @@ -80,3 +237,72 @@ void DataSourceBase::ForEachInIntervals(ReaderCallback const & fn, covering::Cov if (worldID[1].IsAlive()) fn(GetMwmHandleById(worldID[1]), cov, scale); } + +void DataSource::ForEachFeatureIDInRect(FeatureIdCallback const & f, m2::RectD const & rect, + int scale) const +{ + ReadMWMFunctor<FeatureID const> readFunctor(f, *m_factory); + ForEachInIntervals(readFunctor, covering::LowLevelsOnly, rect, scale); +} + +void DataSource::ForEachInRect(FeatureCallback const & f, m2::RectD const & rect, int scale) const +{ + ReadMWMFunctor<FeatureType> readFunctor(f, *m_factory); + ForEachInIntervals(readFunctor, covering::ViewportWithLowLevels, rect, scale); +} + +void DataSource::ForEachInScale(FeatureCallback const & f, int scale) const +{ + ReadMWMFunctor<FeatureType> readFunctor(f, *m_factory); + ForEachInIntervals(readFunctor, covering::FullCover, m2::RectD::GetInfiniteRect(), scale); +} + +void DataSource::ForEachInRectForMWM(FeatureCallback const & f, m2::RectD const & rect, int scale, + MwmId const & id) const +{ + MwmHandle const handle = GetMwmHandleById(id); + if (handle.IsAlive()) + { + covering::CoveringGetter cov(rect, covering::ViewportWithLowLevels); + ReadMWMFunctor<FeatureType> readFunctor(f, *m_factory); + readFunctor(handle, cov, scale); + } +} + +void DataSource::ReadFeatures(FeatureConstCallback const & fn, + vector<FeatureID> const & features) const +{ + ASSERT(is_sorted(features.begin(), features.end()), ()); + + auto fidIter = features.begin(); + auto const endIter = features.end(); + while (fidIter != endIter) + { + MwmId const & id = fidIter->m_mwmId; + MwmHandle const handle = GetMwmHandleById(id); + if (handle.IsAlive()) + { + // Prepare features reading. + auto src = (*m_factory)(handle); + do + { + auto const fts = src->GetFeatureStatus(fidIter->m_index); + ASSERT_NOT_EQUAL( + FeatureStatus::Deleted, fts, + ("Deleted feature was cached. It should not be here. Please review your code.")); + FeatureType featureType; + if (fts == FeatureStatus::Modified || fts == FeatureStatus::Created) + VERIFY(src->GetModifiedFeature(fidIter->m_index, featureType), ()); + else + src->GetOriginalFeature(fidIter->m_index, featureType); + fn(featureType); + } while (++fidIter != endIter && id == fidIter->m_mwmId); + } + else + { + // Skip unregistered mwm files. + while (++fidIter != endIter && id == fidIter->m_mwmId) + ; + } + } +} |