diff --git a/base/base.pro b/base/base.pro index 934e3298ac..49052f5b1a 100644 --- a/base/base.pro +++ b/base/base.pro @@ -57,6 +57,7 @@ HEADERS += \ object_tracker.hpp \ observer_list.hpp \ range_iterator.hpp \ + ref_counted.hpp \ regexp.hpp \ rolling_hash.hpp \ scope_guard.hpp \ diff --git a/base/base_tests/base_tests.pro b/base/base_tests/base_tests.pro index c447870577..7624cc052f 100644 --- a/base/base_tests/base_tests.pro +++ b/base/base_tests/base_tests.pro @@ -28,6 +28,7 @@ SOURCES += \ mem_trie_test.cpp \ observer_list_test.cpp \ range_iterator_test.cpp \ + ref_counted_tests.cpp \ regexp_test.cpp \ rolling_hash_test.cpp \ scope_guard_test.cpp \ diff --git a/base/base_tests/ref_counted_tests.cpp b/base/base_tests/ref_counted_tests.cpp new file mode 100644 index 0000000000..de27a7c01f --- /dev/null +++ b/base/base_tests/ref_counted_tests.cpp @@ -0,0 +1,78 @@ +#include "testing/testing.hpp" + +#include "base/ref_counted.hpp" + +using namespace my; + +namespace +{ +struct Resource : public RefCounted +{ + Resource(bool & destroyed) : m_destroyed(destroyed) {} + ~Resource() override { m_destroyed = true; } + + bool & m_destroyed; +}; + +UNIT_TEST(RefCounted_Smoke) +{ + { + RefCountPtr p; + } + + { + bool destroyed = false; + { + RefCountPtr p(new Resource(destroyed)); + TEST_EQUAL(1, p->NumRefs(), ()); + TEST(!destroyed, ()); + } + TEST(destroyed, ()); + } + + { + bool destroyed = false; + { + RefCountPtr a(new Resource(destroyed)); + TEST_EQUAL(1, a->NumRefs(), ()); + TEST(!destroyed, ()); + + RefCountPtr b(a); + TEST(a.Get() == b.Get(), ()); + TEST_EQUAL(2, a->NumRefs(), ()); + TEST(!destroyed, ()); + + { + RefCountPtr c; + TEST(c.Get() == nullptr, ()); + + c = b; + TEST(a.Get() == b.Get(), ()); + TEST(b.Get() == c.Get(), ()); + TEST_EQUAL(3, a->NumRefs(), ()); + TEST(!destroyed, ()); + } + + TEST(a.Get() == b.Get(), ()); + TEST_EQUAL(2, a->NumRefs(), ()); + TEST(!destroyed, ()); + + RefCountPtr d(move(b)); + TEST(b.Get() == nullptr, ()); + TEST(a.Get() == d.Get(), ()); + TEST_EQUAL(2, a->NumRefs(), ()); + TEST(!destroyed, ()); + + a = a; + TEST_EQUAL(a.Get(), d.Get(), ()); + TEST_EQUAL(2, a->NumRefs(), ()); + TEST(!destroyed, ()); + + TEST_EQUAL(a.Get(), d.Get(), ()); + TEST_EQUAL(2, a->NumRefs(), ()); + TEST(!destroyed, ()); + } + TEST(destroyed, ()); + } +} +} // namespace diff --git a/base/ref_counted.hpp b/base/ref_counted.hpp new file mode 100644 index 0000000000..54feffc08b --- /dev/null +++ b/base/ref_counted.hpp @@ -0,0 +1,107 @@ +#pragma once + +#include "base/macros.hpp" + +#include "std/cstdint.hpp" +#include "std/unique_ptr.hpp" + +namespace my +{ +class RefCounted +{ +public: + virtual ~RefCounted() = default; + + inline void IncRef() noexcept { ++m_refs; } + inline uint64_t DecRef() noexcept { return --m_refs; } + inline uint64_t NumRefs() const noexcept { return m_refs; } + +protected: + RefCounted() noexcept = default; + + uint64_t m_refs = 0; + + DISALLOW_COPY_AND_MOVE(RefCounted); +}; + +template +class RefCountPtr +{ +public: + RefCountPtr() noexcept = default; + + explicit RefCountPtr(T * p) noexcept : m_p(p) + { + if (m_p) + m_p->IncRef(); + } + + explicit RefCountPtr(unique_ptr p) noexcept : RefCountPtr(p.release()) {} + + RefCountPtr(RefCountPtr const & rhs) { *this = rhs; } + + RefCountPtr(RefCountPtr && rhs) { *this = move(rhs); } + + ~RefCountPtr() { Reset(); } + + RefCountPtr & operator=(unique_ptr p) + { + Reset(); + + m_p = p.release(); + if (m_p) + m_p->IncRef(); + + return *this; + } + + RefCountPtr & operator=(RefCountPtr const & rhs) + { + if (this == &rhs) + return *this; + + Reset(); + m_p = rhs.m_p; + if (m_p) + m_p->IncRef(); + + return *this; + } + + RefCountPtr & operator=(RefCountPtr && rhs) + { + if (this == &rhs) + return *this; + + Reset(); + m_p = rhs.m_p; + rhs.m_p = nullptr; + + return *this; + } + + void Reset() + { + if (!m_p) + return; + + if (m_p->DecRef() == 0) + delete m_p; + m_p = nullptr; + } + + T * Get() noexcept { return m_p; } + T const * Get() const noexcept { return m_p; } + + T & operator*() { return *m_p; } + T const & operator*() const { return *m_p; } + + T * operator->() noexcept { return m_p; } + T const * operator->() const noexcept { return m_p; } + + inline operator bool() const noexcept { return m_p != nullptr; } + +private: + T * m_p = nullptr; +}; +} // namespace my diff --git a/coding/compressed_bit_vector.hpp b/coding/compressed_bit_vector.hpp index 5fcf630919..925759d83d 100644 --- a/coding/compressed_bit_vector.hpp +++ b/coding/compressed_bit_vector.hpp @@ -5,6 +5,7 @@ #include "coding/writer.hpp" #include "base/assert.hpp" +#include "base/ref_counted.hpp" #include "std/algorithm.hpp" #include "std/unique_ptr.hpp" @@ -13,7 +14,7 @@ namespace coding { -class CompressedBitVector +class CompressedBitVector : public my::RefCounted { public: enum class StorageStrategy @@ -250,10 +251,10 @@ public: { uint64_t const kBase = 127; uint64_t hash = 0; - CompressedBitVectorEnumerator::ForEach(cbv, [&](uint64_t i) + CompressedBitVectorEnumerator::ForEach(cbv, [&hash](uint64_t i) { - hash = hash * kBase + i; - }); + hash = hash * kBase + i + 1; + }); return hash; } }; diff --git a/search/cbv.cpp b/search/cbv.cpp new file mode 100644 index 0000000000..437abe7c36 --- /dev/null +++ b/search/cbv.cpp @@ -0,0 +1,114 @@ +#include "search/cbv.hpp" + +#include "std/limits.hpp" +#include "std/vector.hpp" + +using namespace my; + +namespace search +{ +namespace +{ +uint64_t const kModulo = 18446744073709551557LLU; +} // namespace + +CBV::CBV(unique_ptr p) : m_p(move(p)) {} + +CBV::CBV(CBV && cbv) : m_p(move(cbv.m_p)), m_isFull(cbv.m_isFull) { cbv.m_isFull = false; } + +CBV & CBV::operator=(unique_ptr p) +{ + m_p = move(p); + m_isFull = false; + + return *this; +} + +CBV & CBV::operator=(CBV && rhs) +{ + if (this == &rhs) + return *this; + + m_p = move(rhs.m_p); + m_isFull = rhs.m_isFull; + + rhs.m_isFull = false; + + return *this; +} + +void CBV::SetFull() +{ + m_p.Reset(); + m_isFull = true; +} + +void CBV::Reset() +{ + m_p.Reset(); + m_isFull = false; +} + +bool CBV::HasBit(uint64_t id) const +{ + if (IsFull()) + return true; + if (IsEmpty()) + return false; + return m_p->GetBit(id); +} + +uint64_t CBV::PopCount() const +{ + ASSERT(!IsFull(), ()); + if (IsEmpty()) + return 0; + return m_p->PopCount(); +} + +CBV CBV::Union(CBV const & rhs) const +{ + if (IsFull() || rhs.IsEmpty()) + return *this; + if (IsEmpty() || rhs.IsFull()) + return rhs; + return CBV(coding::CompressedBitVector::Union(*m_p, *rhs.m_p)); +} + +CBV CBV::Intersect(CBV const & rhs) const +{ + if (IsFull() || rhs.IsEmpty()) + return rhs; + if (IsEmpty() || rhs.IsFull()) + return *this; + return CBV(coding::CompressedBitVector::Intersect(*m_p, *rhs.m_p)); +} + +CBV CBV::Take(uint64_t n) const +{ + if (IsEmpty()) + return *this; + if (IsFull()) + { + vector groups((n + 63) / 64, numeric_limits::max()); + uint64_t const r = n % 64; + if (r != 0) + { + ASSERT(!groups.empty(), ()); + groups.back() = (static_cast(1) << r) - 1; + } + return CBV(coding::DenseCBV::BuildFromBitGroups(move(groups))); + } + + return CBV(m_p->LeaveFirstSetNBits(n)); +} + +uint64_t CBV::Hash() const +{ + if (IsEmpty()) + return 0; + if (IsFull()) + return kModulo; + return coding::CompressedBitVectorHasher::Hash(*m_p) % kModulo; +} +} // namespace search diff --git a/search/cbv.hpp b/search/cbv.hpp new file mode 100644 index 0000000000..b52ff839f6 --- /dev/null +++ b/search/cbv.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include "coding/compressed_bit_vector.hpp" + +#include "base/ref_counted.hpp" + +#include "std/function.hpp" +#include "std/utility.hpp" + +namespace search +{ +// A wrapper around coding::CompressedBitVector that augments the +// latter with the "full" state and uses reference counting for +// ownership sharing. +class CBV +{ +public: + CBV() = default; + explicit CBV(unique_ptr p); + CBV(CBV const & cbv) = default; + CBV(CBV && cbv); + + inline operator bool() const { return !IsEmpty(); } + CBV & operator=(unique_ptr p); + CBV & operator=(CBV const & rhs) = default; + CBV & operator=(CBV && rhs); + + void SetFull(); + void Reset(); + + inline bool IsEmpty() const { return !m_isFull && coding::CompressedBitVector::IsEmpty(m_p.Get()); } + inline bool IsFull() const { return m_isFull; } + + bool HasBit(uint64_t id) const; + uint64_t PopCount() const; + + template + void ForEach(TFn && fn) const + { + ASSERT(!m_isFull, ()); + if (!IsEmpty()) + coding::CompressedBitVectorEnumerator::ForEach(*m_p, forward(fn)); + } + + CBV Union(CBV const & rhs) const; + CBV Intersect(CBV const & rhs) const; + + // Takes first set |n| bits. + CBV Take(uint64_t n) const; + + uint64_t Hash() const; + +private: + my::RefCountPtr m_p; + + // True iff all bits are set to one. + bool m_isFull = false; +}; +} // namespace search diff --git a/search/cbv_ptr.cpp b/search/cbv_ptr.cpp deleted file mode 100644 index 65eef82fd7..0000000000 --- a/search/cbv_ptr.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "search/cbv_ptr.hpp" - -namespace search -{ -CBVPtr::CBVPtr(coding::CompressedBitVector const * p, bool isOwner) { Set(p, isOwner); } - -CBVPtr::CBVPtr(CBVPtr && rhs) { *this = move(rhs); } - -CBVPtr::~CBVPtr() { Release(); } - -void CBVPtr::Release() -{ - if (m_isOwner) - delete m_ptr; - - m_ptr = nullptr; - m_isOwner = false; - m_isFull = false; -} - -void CBVPtr::SetFull() -{ - Release(); - m_isFull = true; -} - -void CBVPtr::Set(coding::CompressedBitVector const * p, bool isOwner /* = false*/) -{ - Release(); - - m_ptr = p; - m_isOwner = p && isOwner; -} - -void CBVPtr::Set(unique_ptr p) -{ - Set(p.release(), true /* isOwner */); -} - -CBVPtr & CBVPtr::operator=(CBVPtr && rhs) noexcept -{ - if (this == &rhs) - return *this; - - m_ptr = rhs.m_ptr; - m_isOwner = rhs.m_isOwner; - m_isFull = rhs.m_isFull; - - rhs.m_ptr = nullptr; - rhs.m_isOwner = false; - rhs.m_isFull = false; - - return *this; -} - -void CBVPtr::Union(coding::CompressedBitVector const * p) -{ - if (!p || m_isFull) - return; - - if (!m_ptr) - { - m_ptr = p; - m_isFull = false; - m_isOwner = false; - } - else - { - Set(coding::CompressedBitVector::Union(*m_ptr, *p).release(), true /* isOwner */); - } -} - -void CBVPtr::Intersect(coding::CompressedBitVector const * p) -{ - if (!p) - { - Release(); - return; - } - - if (m_ptr) - { - Set(coding::CompressedBitVector::Intersect(*m_ptr, *p).release(), true /* isOwner */); - } - else if (m_isFull) - { - m_ptr = p; - m_isFull = false; - m_isOwner = false; - } -} - -void CBVPtr::CopyTo(CBVPtr & rhs) -{ - rhs.Release(); - - if (m_isFull) - { - rhs.SetFull(); - return; - } - - if (m_ptr) - rhs.Set(m_ptr->Clone()); -} -} // namespace search diff --git a/search/cbv_ptr.hpp b/search/cbv_ptr.hpp deleted file mode 100644 index a769ac6886..0000000000 --- a/search/cbv_ptr.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "coding/compressed_bit_vector.hpp" - -#include "base/assert.hpp" -#include "base/macros.hpp" - -#include "std/function.hpp" -#include "std/utility.hpp" - -namespace search -{ -/// CompressedBitVector pointer class that incapsulates -/// binary operators logic and takes ownership if needed. -class CBVPtr -{ - DISALLOW_COPY(CBVPtr); - - coding::CompressedBitVector const * m_ptr = nullptr; - bool m_isOwner = false; - bool m_isFull = false; ///< True iff all bits are set to one. - - void Release(); - -public: - CBVPtr() = default; - CBVPtr(coding::CompressedBitVector const * p, bool isOwner); - CBVPtr(CBVPtr && rhs); - ~CBVPtr(); - - void SetFull(); - void Set(coding::CompressedBitVector const * p, bool isOwner = false); - void Set(unique_ptr p); - - inline coding::CompressedBitVector const * Get() const { return m_ptr; } - - inline coding::CompressedBitVector const & operator*() const { return *m_ptr; } - inline coding::CompressedBitVector const * operator->() const { return m_ptr; } - CBVPtr & operator=(CBVPtr && rhs) noexcept; - - inline bool IsEmpty() const { return !m_isFull && coding::CompressedBitVector::IsEmpty(m_ptr); } - inline bool IsFull() const { return m_isFull; } - inline bool IsOwner() const noexcept { return m_isOwner; } - - void Union(coding::CompressedBitVector const * p); - void Intersect(coding::CompressedBitVector const * p); - - void CopyTo(CBVPtr & rhs); - - template - void ForEach(TFn && fn) const - { - ASSERT(!m_isFull, ()); - if (!IsEmpty()) - coding::CompressedBitVectorEnumerator::ForEach(*m_ptr, forward(fn)); - } -}; -} // namespace search diff --git a/search/features_filter.cpp b/search/features_filter.cpp index 0f9912ad07..5f04345b6c 100644 --- a/search/features_filter.cpp +++ b/search/features_filter.cpp @@ -1,47 +1,48 @@ #include "search/features_filter.hpp" -#include "coding/compressed_bit_vector.hpp" +#include "search/cbv.hpp" #include "std/algorithm.hpp" +#include "std/vector.hpp" namespace search { // FeaturesFilter ---------------------------------------------------------------------------------- -FeaturesFilter::FeaturesFilter(coding::CompressedBitVector const & filter, uint32_t threshold) +FeaturesFilter::FeaturesFilter(CBV const & filter, uint32_t threshold) : m_filter(filter), m_threshold(threshold) { } -bool FeaturesFilter::NeedToFilter(coding::CompressedBitVector const & cbv) const +bool FeaturesFilter::NeedToFilter(CBV const & cbv) const { + if (cbv.IsFull()) + return true; return cbv.PopCount() > m_threshold; } // LocalityFilter ---------------------------------------------------------------------------------- -LocalityFilter::LocalityFilter(coding::CompressedBitVector const & filter) +LocalityFilter::LocalityFilter(CBV const & filter) : FeaturesFilter(filter, 0 /* threshold */) { } -unique_ptr LocalityFilter::Filter( - coding::CompressedBitVector const & cbv) const +CBV LocalityFilter::Filter(CBV const & cbv) const { - return coding::CompressedBitVector::Intersect(m_filter, cbv); + return m_filter.Intersect(cbv); } // ViewportFilter ---------------------------------------------------------------------------------- -ViewportFilter::ViewportFilter(coding::CompressedBitVector const & filter, uint32_t threshold) +ViewportFilter::ViewportFilter(CBV const & filter, uint32_t threshold) : FeaturesFilter(filter, threshold) { } -unique_ptr ViewportFilter::Filter( - coding::CompressedBitVector const & cbv) const +CBV ViewportFilter::Filter(CBV const & cbv) const { - auto result = coding::CompressedBitVector::Intersect(m_filter, cbv); - if (!coding::CompressedBitVector::IsEmpty(result)) + auto result = m_filter.Intersect(cbv); + if (!result.IsEmpty()) return result; - return cbv.LeaveFirstSetNBits(m_threshold); -} + return cbv.Take(m_threshold); +} } // namespace search diff --git a/search/features_filter.hpp b/search/features_filter.hpp index fb5f425c3c..8aaf27d782 100644 --- a/search/features_filter.hpp +++ b/search/features_filter.hpp @@ -2,30 +2,26 @@ #include "std/unique_ptr.hpp" -namespace coding -{ -class CompressedBitVector; -} - namespace search { +class CBV; + // A lightweight filter of features. // // NOTE: this class and its subclasses *ARE* thread-safe. class FeaturesFilter { public: - FeaturesFilter(coding::CompressedBitVector const & filter, uint32_t threshold); + FeaturesFilter(CBV const & filter, uint32_t threshold); virtual ~FeaturesFilter() = default; - bool NeedToFilter(coding::CompressedBitVector const & features) const; + bool NeedToFilter(CBV const & features) const; - virtual unique_ptr Filter( - coding::CompressedBitVector const & cbv) const = 0; + virtual CBV Filter(CBV const & cbv) const = 0; protected: - coding::CompressedBitVector const & m_filter; + CBV const & m_filter; uint32_t const m_threshold; }; @@ -34,11 +30,10 @@ protected: class LocalityFilter : public FeaturesFilter { public: - LocalityFilter(coding::CompressedBitVector const & filter); + LocalityFilter(CBV const & filter); // FeaturesFilter overrides: - unique_ptr Filter( - coding::CompressedBitVector const & cbv) const override; + CBV Filter(CBV const & cbv) const override; }; // Fuzzy filter - tries to leave only features belonging to the set it @@ -49,11 +44,10 @@ public: class ViewportFilter : public FeaturesFilter { public: - ViewportFilter(coding::CompressedBitVector const & filter, uint32_t threshold); + ViewportFilter(CBV const & filter, uint32_t threshold); // FeaturesFilter overrides: - unique_ptr Filter( - coding::CompressedBitVector const & cbv) const override; + CBV Filter(CBV const & cbv) const override; }; } // namespace search diff --git a/search/features_layer_matcher.cpp b/search/features_layer_matcher.cpp index 1f98b22ffb..9dae2741fd 100644 --- a/search/features_layer_matcher.cpp +++ b/search/features_layer_matcher.cpp @@ -34,7 +34,7 @@ void FeaturesLayerMatcher::SetContext(MwmContext * context) m_loader.SetContext(context); } -void FeaturesLayerMatcher::SetPostcodes(coding::CompressedBitVector const * postcodes) +void FeaturesLayerMatcher::SetPostcodes(CBV const * postcodes) { m_postcodes = postcodes; } diff --git a/search/features_layer_matcher.hpp b/search/features_layer_matcher.hpp index f9ae2df657..387b98feb6 100644 --- a/search/features_layer_matcher.hpp +++ b/search/features_layer_matcher.hpp @@ -1,6 +1,7 @@ #pragma once #include "search/cancel_exception.hpp" +#include "search/cbv.hpp" #include "search/features_layer.hpp" #include "search/house_numbers_matcher.hpp" #include "search/model.hpp" @@ -19,8 +20,6 @@ #include "geometry/point2d.hpp" #include "geometry/rect2d.hpp" -#include "coding/compressed_bit_vector.hpp" - #include "base/cancellable.hpp" #include "base/logging.hpp" #include "base/macros.hpp" @@ -61,7 +60,7 @@ public: FeaturesLayerMatcher(Index & index, my::Cancellable const & cancellable); void SetContext(MwmContext * context); - void SetPostcodes(coding::CompressedBitVector const * postcodes); + void SetPostcodes(CBV const * postcodes); template void Match(FeaturesLayer const & child, FeaturesLayer const & parent, TFn && fn) @@ -165,7 +164,7 @@ private: MercatorBounds::RectByCenterXYAndSizeInMeters(poiCenters[i], kBuildingRadiusMeters), [&](FeatureType & ft) { - if (m_postcodes && !m_postcodes->GetBit(ft.GetID().m_index)) + if (m_postcodes && !m_postcodes->HasBit(ft.GetID().m_index)) return; if (house_numbers::HouseNumbersMatch(strings::MakeUniString(ft.GetHouseNumber()), queryParse)) @@ -252,7 +251,7 @@ private: if (binary_search(buildings.begin(), buildings.end(), id)) return true; - if (m_postcodes && !m_postcodes->GetBit(id)) + if (m_postcodes && !m_postcodes->HasBit(id)) return false; if (!loaded) @@ -344,7 +343,7 @@ private: MwmContext * m_context; - coding::CompressedBitVector const * m_postcodes; + CBV const * m_postcodes; ReverseGeocoder m_reverseGeocoder; diff --git a/search/geocoder.cpp b/search/geocoder.cpp index 0c5079f6fb..de8a7a5b00 100644 --- a/search/geocoder.cpp +++ b/search/geocoder.cpp @@ -1,6 +1,6 @@ #include "search/geocoder.hpp" -#include "search/cbv_ptr.hpp" +#include "search/cbv.hpp" #include "search/dummy_rank_table.hpp" #include "search/features_filter.hpp" #include "search/features_layer_matcher.hpp" @@ -387,14 +387,14 @@ size_t OrderCountries(m2::RectD const & pivot, vector> & inf // Performs pairwise union of adjacent bit vectors // until at most one bit vector is left. -void UniteCBVs(vector> & cbvs) +void UniteCBVs(vector & cbvs) { while (cbvs.size() > 1) { size_t i = 0; size_t j = 0; for (; j + 1 < cbvs.size(); j += 2) - cbvs[i++] = coding::CompressedBitVector::Union(*cbvs[j], *cbvs[j + 1]); + cbvs[i++] = cbvs[j].Union(cbvs[j + 1]); for (; j < cbvs.size(); ++j) cbvs[i++] = move(cbvs[j]); cbvs.resize(i); @@ -580,14 +580,12 @@ void Geocoder::GoImpl(PreRanker & preRanker, vector> & infos BaseContext ctx; InitBaseContext(ctx); - coding::CompressedBitVector const * viewportCBV = nullptr; if (inViewport) - viewportCBV = RetrieveGeometryFeatures(*m_context, m_params.m_pivot, RECT_ID_PIVOT); - - if (viewportCBV) { + auto const viewportCBV = + RetrieveGeometryFeatures(*m_context, m_params.m_pivot, RECT_ID_PIVOT); for (auto & features : ctx.m_features) - features = coding::CompressedBitVector::Intersect(*features, *viewportCBV); + features = features.Intersect(viewportCBV); } ctx.m_villages = LoadVillages(*m_context); @@ -659,7 +657,6 @@ void Geocoder::InitBaseContext(BaseContext & ctx) PrepareRetrievalParams(i, i + 1); ctx.m_features[i] = RetrieveAddressFeatures(m_context->GetId(), m_context->m_value, m_cancellable, m_retrievalParams); - ASSERT(ctx.m_features[i], ()); } } @@ -676,8 +673,7 @@ void Geocoder::InitLayer(SearchModel::SearchType type, size_t startToken, size_t layer.m_lastTokenIsPrefix = (layer.m_endToken > m_params.m_tokens.size()); } -void Geocoder::FillLocalityCandidates(BaseContext const & ctx, - coding::CompressedBitVector const * filter, +void Geocoder::FillLocalityCandidates(BaseContext const & ctx, CBV const & filter, size_t const maxNumLocalities, vector & preLocalities) { @@ -685,19 +681,12 @@ void Geocoder::FillLocalityCandidates(BaseContext const & ctx, for (size_t startToken = 0; startToken < ctx.m_numTokens; ++startToken) { - CBVPtr intersection; - CBVPtr unfilteredIntersection; - intersection.SetFull(); - unfilteredIntersection.SetFull(); - if (filter) - { - intersection.Intersect(filter); - unfilteredIntersection.Intersect(ctx.m_features[startToken].get()); - } - intersection.Intersect(ctx.m_features[startToken].get()); + CBV intersection = filter.Intersect(ctx.m_features[startToken]); if (intersection.IsEmpty()) continue; + CBV unfilteredIntersection = ctx.m_features[startToken]; + for (size_t endToken = startToken + 1; endToken <= ctx.m_numTokens; ++endToken) { // Skip locality candidates that match only numbers. @@ -710,22 +699,19 @@ void Geocoder::FillLocalityCandidates(BaseContext const & ctx, l.m_featureId = featureId; l.m_startToken = startToken; l.m_endToken = endToken; - if (filter) - { - l.m_prob = static_cast(intersection->PopCount()) / - static_cast(unfilteredIntersection->PopCount()); - } + l.m_prob = static_cast(intersection.PopCount()) / + static_cast(unfilteredIntersection.PopCount()); preLocalities.push_back(l); }); } if (endToken < ctx.m_numTokens) { - intersection.Intersect(ctx.m_features[endToken].get()); - if (filter) - unfilteredIntersection.Intersect(ctx.m_features[endToken].get()); + intersection = intersection.Intersect(ctx.m_features[endToken]); if (intersection.IsEmpty()) break; + + unfilteredIntersection = unfilteredIntersection.Intersect(ctx.m_features[endToken]); } } } @@ -738,7 +724,10 @@ void Geocoder::FillLocalityCandidates(BaseContext const & ctx, void Geocoder::FillLocalitiesTable(BaseContext const & ctx) { vector preLocalities; - FillLocalityCandidates(ctx, nullptr /* filter */, kMaxNumLocalities, preLocalities); + + CBV filter; + filter.SetFull(); + FillLocalityCandidates(ctx, filter, kMaxNumLocalities, preLocalities); size_t numCities = 0; size_t numStates = 0; @@ -810,7 +799,7 @@ void Geocoder::FillLocalitiesTable(BaseContext const & ctx) void Geocoder::FillVillageLocalities(BaseContext const & ctx) { vector preLocalities; - FillLocalityCandidates(ctx, ctx.m_villages.get() /* filter */, kMaxNumVillages, preLocalities); + FillLocalityCandidates(ctx, ctx.m_villages /* filter */, kMaxNumVillages, preLocalities); size_t numVillages = 0; @@ -971,13 +960,12 @@ void Geocoder::MatchCities(BaseContext & ctx) if (m_context->GetInfo()->GetType() == MwmInfo::WORLD) continue; - auto const * cityFeatures = - RetrieveGeometryFeatures(*m_context, city.m_rect, RECT_ID_LOCALITY); + auto cityFeatures = RetrieveGeometryFeatures(*m_context, city.m_rect, RECT_ID_LOCALITY); - if (coding::CompressedBitVector::IsEmpty(cityFeatures)) + if (cityFeatures.IsEmpty()) continue; - LocalityFilter filter(*cityFeatures); + LocalityFilter filter(cityFeatures); LimitedSearch(ctx, filter); } } @@ -985,12 +973,8 @@ void Geocoder::MatchCities(BaseContext & ctx) void Geocoder::MatchAroundPivot(BaseContext & ctx) { - auto const * features = RetrieveGeometryFeatures(*m_context, m_params.m_pivot, RECT_ID_PIVOT); - - if (!features) - return; - - ViewportFilter filter(*features, m_preRanker->Limit() /* threshold */); + auto const features = RetrieveGeometryFeatures(*m_context, m_params.m_pivot, RECT_ID_PIVOT); + ViewportFilter filter(features, m_preRanker->Limit() /* threshold */); LimitedSearch(ctx, filter); } @@ -1007,7 +991,7 @@ void Geocoder::LimitedSearch(BaseContext & ctx, FeaturesFilter const & filter) MatchUnclassified(ctx, 0 /* curToken */); - auto search = [this, &ctx]() + auto const search = [this, &ctx]() { GreedilyMatchStreets(ctx); MatchPOIsAndBuildings(ctx, 0 /* curToken */); @@ -1045,7 +1029,7 @@ void Geocoder::WithPostcodes(BaseContext & ctx, TFn && fn) m_postcodes.Clear(); }); - if (!coding::CompressedBitVector::IsEmpty(postcodes)) + if (!postcodes.IsEmpty()) { ScopedMarkTokens mark(ctx.m_usedTokens, startToken, endToken); @@ -1080,7 +1064,7 @@ void Geocoder::CreateStreetsLayerAndMatchLowerLayers(BaseContext & ctx, InitLayer(SearchModel::SEARCH_TYPE_STREET, prediction.m_startToken, prediction.m_endToken, layer); vector sortedFeatures; - sortedFeatures.reserve(prediction.m_features->PopCount()); + sortedFeatures.reserve(prediction.m_features.PopCount()); prediction.m_features.ForEach(MakeBackInsertFunctor(sortedFeatures)); layer.m_sortedFeatures = &sortedFeatures; @@ -1097,18 +1081,16 @@ void Geocoder::MatchPOIsAndBuildings(BaseContext & ctx, size_t curToken) { // All tokens were consumed, find paths through layers, emit // features. - if (m_postcodes.IsEmpty()) + if (m_postcodes.m_features.IsEmpty()) return FindPaths(); // When there are no layers but user entered a postcode, we have // to emit all features matching to the postcode. if (m_layers.size() == 0) { - CBVPtr filtered; - if (m_filter->NeedToFilter(*m_postcodes.m_features)) - filtered.Set(m_filter->Filter(*m_postcodes.m_features)); - else - filtered.Set(m_postcodes.m_features.get(), false /* isOwner */); + CBV filtered = m_postcodes.m_features; + if (m_filter->NeedToFilter(m_postcodes.m_features)) + filtered = m_filter->Filter(m_postcodes.m_features); filtered.ForEach([&](uint32_t id) { EmitResult(m_context->GetId(), id, GetSearchTypeInGeocoding(ctx, id), @@ -1130,7 +1112,7 @@ void Geocoder::MatchPOIsAndBuildings(BaseContext & ctx, size_t curToken) { for (auto const & id : *m_layers.back().m_sortedFeatures) { - if (!m_postcodes.Has(id)) + if (!m_postcodes.m_features.HasBit(id)) continue; EmitResult(m_context->GetId(), id, SearchModel::SEARCH_TYPE_STREET, m_layers.back().m_startToken, m_layers.back().m_endToken); @@ -1147,8 +1129,7 @@ void Geocoder::MatchPOIsAndBuildings(BaseContext & ctx, size_t curToken) layer); vector features; - coding::CompressedBitVectorEnumerator::ForEach(*m_postcodes.m_features, - MakeBackInsertFunctor(features)); + m_postcodes.m_features.ForEach(MakeBackInsertFunctor(features)); layer.m_sortedFeatures = &features; return FindPaths(); } @@ -1172,12 +1153,12 @@ void Geocoder::MatchPOIsAndBuildings(BaseContext & ctx, size_t curToken) // filtered in GreedilyMatchStreets(). if (searchType < kNumClusters) { - if (m_postcodes.IsEmpty() || m_postcodes.m_features->GetBit(featureId)) + if (m_postcodes.m_features.IsEmpty() || m_postcodes.m_features.HasBit(featureId)) clusters[searchType].push_back(featureId); } }; - CBVPtr features; + CBV features; features.SetFull(); // Try to consume [curToken, m_numTokens) tokens range. @@ -1194,15 +1175,11 @@ void Geocoder::MatchPOIsAndBuildings(BaseContext & ctx, size_t curToken) InitLayer(layer.m_type, curToken, curToken + n, layer); } - features.Intersect(ctx.m_features[curToken + n - 1].get()); - ASSERT(features.Get(), ()); + features = features.Intersect(ctx.m_features[curToken + n - 1]); - CBVPtr filtered; - if (m_filter->NeedToFilter(*features)) - filtered.Set(m_filter->Filter(*features)); - else - filtered.Set(features.Get(), false /* isOwner */); - ASSERT(filtered.Get(), ()); + CBV filtered = features; + if (m_filter->NeedToFilter(features)) + filtered = m_filter->Filter(features); bool const looksLikeHouseNumber = house_numbers::LooksLikeHouseNumber( m_layers.back().m_subQuery, m_layers.back().m_lastTokenIsPrefix); @@ -1218,7 +1195,7 @@ void Geocoder::MatchPOIsAndBuildings(BaseContext & ctx, size_t curToken) { auto noFeature = [&filtered](uint32_t featureId) -> bool { - return !filtered->GetBit(featureId); + return !filtered.HasBit(featureId); }; for (auto & cluster : clusters) my::EraseIf(cluster, noFeature); @@ -1330,7 +1307,10 @@ void Geocoder::FindPaths() auto const & innermostLayer = *sortedLayers.front(); - m_matcher->SetPostcodes(m_postcodes.m_features.get()); + if (!m_postcodes.m_features.IsEmpty()) + m_matcher->SetPostcodes(&m_postcodes.m_features); + else + m_matcher->SetPostcodes(nullptr); m_finder.ForEachReachableVertex( *m_matcher, sortedLayers, [this, &innermostLayer](IntersectionResult const & result) { @@ -1427,21 +1407,18 @@ void Geocoder::MatchUnclassified(BaseContext & ctx, size_t curToken) if (ctx.NumUnusedTokenGroups() != 1) return; - CBVPtr allFeatures; + CBV allFeatures; allFeatures.SetFull(); auto startToken = curToken; for (curToken = ctx.SkipUsedTokens(curToken); curToken < ctx.m_numTokens && !ctx.m_usedTokens[curToken]; ++curToken) { - allFeatures.Intersect(ctx.m_features[curToken].get()); + allFeatures = allFeatures.Intersect(ctx.m_features[curToken]); } - if (m_filter->NeedToFilter(*allFeatures)) - allFeatures.Set(m_filter->Filter(*allFeatures)); - - if (allFeatures.IsEmpty()) - return; + if (m_filter->NeedToFilter(allFeatures)) + allFeatures = m_filter->Filter(allFeatures); auto emitUnclassified = [&](uint32_t featureId) { @@ -1452,8 +1429,7 @@ void Geocoder::MatchUnclassified(BaseContext & ctx, size_t curToken) allFeatures.ForEach(emitUnclassified); } -unique_ptr Geocoder::LoadCategories( - MwmContext & context, vector const & categories) +CBV Geocoder::LoadCategories(MwmContext & context, vector const & categories) { ASSERT(context.m_handle.IsAlive(), ()); ASSERT(HasSearchIndex(context.m_value), ()); @@ -1462,75 +1438,69 @@ unique_ptr Geocoder::LoadCategories( m_retrievalParams.m_tokens[0].resize(1); m_retrievalParams.m_prefixTokens.clear(); - vector> cbvs; + vector cbvs; for_each(categories.begin(), categories.end(), [&](strings::UniString const & category) { m_retrievalParams.m_tokens[0][0] = category; - auto cbv = RetrieveAddressFeatures(context.GetId(), context.m_value, m_cancellable, - m_retrievalParams); - if (!coding::CompressedBitVector::IsEmpty(cbv)) + CBV cbv(RetrieveAddressFeatures(context.GetId(), context.m_value, m_cancellable, + m_retrievalParams)); + if (!cbv.IsEmpty()) cbvs.push_back(move(cbv)); }); UniteCBVs(cbvs); if (cbvs.empty()) - cbvs.push_back(make_unique()); + cbvs.emplace_back(); return move(cbvs[0]); } -coding::CompressedBitVector const * Geocoder::LoadStreets(MwmContext & context) +CBV Geocoder::LoadStreets(MwmContext & context) { if (!context.m_handle.IsAlive() || !HasSearchIndex(context.m_value)) - return nullptr; + return CBV(); auto mwmId = context.m_handle.GetId(); auto const it = m_streetsCache.find(mwmId); if (it != m_streetsCache.cend()) - return it->second.get(); + return it->second; auto streets = LoadCategories(context, StreetCategories::Instance().GetCategories()); - - auto const * result = streets.get(); - m_streetsCache[mwmId] = move(streets); - return result; + m_streetsCache[mwmId] = streets; + return streets; } -unique_ptr Geocoder::LoadVillages(MwmContext & context) +CBV Geocoder::LoadVillages(MwmContext & context) { if (!context.m_handle.IsAlive() || !HasSearchIndex(context.m_value)) - return make_unique(); + return CBV(); return LoadCategories(context, GetVillageCategories()); } -unique_ptr Geocoder::RetrievePostcodeFeatures( - MwmContext const & context, TokenSlice const & slice) +CBV Geocoder::RetrievePostcodeFeatures(MwmContext const & context, TokenSlice const & slice) { - return ::search::RetrievePostcodeFeatures(context.GetId(), context.m_value, m_cancellable, slice); + return CBV( + ::search::RetrievePostcodeFeatures(context.GetId(), context.m_value, m_cancellable, slice)); } -coding::CompressedBitVector const * Geocoder::RetrieveGeometryFeatures(MwmContext const & context, - m2::RectD const & rect, - RectId id) +CBV Geocoder::RetrieveGeometryFeatures(MwmContext const & context, m2::RectD const & rect, + RectId id) { switch (id) { case RECT_ID_PIVOT: return m_pivotRectsCache.Get(context, rect, m_params.m_scale); case RECT_ID_LOCALITY: return m_localityRectsCache.Get(context, rect, m_params.m_scale); - case RECT_ID_COUNT: ASSERT(false, ("Invalid RectId.")); return nullptr; + case RECT_ID_COUNT: ASSERT(false, ("Invalid RectId.")); return CBV(); } } SearchModel::SearchType Geocoder::GetSearchTypeInGeocoding(BaseContext const & ctx, uint32_t featureId) { - ASSERT(ctx.m_streets, ()); - ASSERT(ctx.m_villages, ()); - - if (ctx.m_streets->GetBit(featureId)) + if (ctx.m_streets.HasBit(featureId)) return SearchModel::SEARCH_TYPE_STREET; - if (ctx.m_villages->GetBit(featureId)) + if (ctx.m_villages.HasBit(featureId)) return SearchModel::SEARCH_TYPE_VILLAGE; FeatureType feature; @@ -1545,5 +1515,4 @@ string DebugPrint(Geocoder::Locality const & locality) << ", startToken=" << locality.m_startToken << ", endToken=" << locality.m_endToken << "]"; return os.str(); } - } // namespace search diff --git a/search/geocoder.hpp b/search/geocoder.hpp index 876f5b762b..1afd6798e7 100644 --- a/search/geocoder.hpp +++ b/search/geocoder.hpp @@ -172,16 +172,12 @@ private: { m_startToken = 0; m_endToken = 0; - m_features.reset(); + m_features.Reset(); } - inline bool Has(uint64_t id) const { return m_features->GetBit(id); } - - inline bool IsEmpty() const { return coding::CompressedBitVector::IsEmpty(m_features); } - size_t m_startToken = 0; size_t m_endToken = 0; - unique_ptr m_features; + CBV m_features; }; void GoImpl(PreRanker & preRanker, vector> & infos, bool inViewport); @@ -202,7 +198,7 @@ private: void InitLayer(SearchModel::SearchType type, size_t startToken, size_t endToken, FeaturesLayer & layer); - void FillLocalityCandidates(BaseContext const & ctx, coding::CompressedBitVector const * filter, + void FillLocalityCandidates(BaseContext const & ctx, CBV const & filter, size_t const maxNumLocalities, vector & preLocalities); void FillLocalitiesTable(BaseContext const & ctx); @@ -272,20 +268,17 @@ private: // UNCLASSIFIED objects that match to all currently unused tokens. void MatchUnclassified(BaseContext & ctx, size_t curToken); - unique_ptr LoadCategories( - MwmContext & context, vector const & categories); + CBV LoadCategories(MwmContext & context, vector const & categories); - coding::CompressedBitVector const * LoadStreets(MwmContext & context); + CBV LoadStreets(MwmContext & context); - unique_ptr LoadVillages(MwmContext & context); + CBV LoadVillages(MwmContext & context); // A wrapper around RetrievePostcodeFeatures. - unique_ptr RetrievePostcodeFeatures(MwmContext const & context, - TokenSlice const & slice); + CBV RetrievePostcodeFeatures(MwmContext const & context, TokenSlice const & slice); // A caching wrapper around Retrieval::RetrieveGeometryFeatures. - coding::CompressedBitVector const * RetrieveGeometryFeatures(MwmContext const & context, - m2::RectD const & rect, RectId id); + CBV RetrieveGeometryFeatures(MwmContext const & context, m2::RectD const & rect, RectId id); // This is a faster wrapper around SearchModel::GetSearchType(), as // it uses pre-loaded lists of streets and villages. @@ -327,7 +320,7 @@ private: NestedRectsCache m_pivotFeatures; // Cache of street ids in mwms. - map> m_streetsCache; + map m_streetsCache; // Postcodes features in the mwm that is currently being processed. Postcodes m_postcodes; diff --git a/search/geocoder_context.hpp b/search/geocoder_context.hpp index ab43007047..3954416af6 100644 --- a/search/geocoder_context.hpp +++ b/search/geocoder_context.hpp @@ -1,6 +1,6 @@ #pragma once -#include "coding/compressed_bit_vector.hpp" +#include "search/cbv.hpp" #include "std/unique_ptr.hpp" #include "std/vector.hpp" @@ -25,14 +25,15 @@ struct BaseContext // Counts number of groups of consecutive unused tokens. size_t NumUnusedTokenGroups() const; - vector> m_features; - unique_ptr m_villages; - coding::CompressedBitVector const * m_streets = nullptr; + vector m_features; + CBV m_villages; + CBV m_streets; - // This vector is used to indicate what tokens were matched by - // locality and can't be re-used during the geocoding process. + // This vector is used to indicate what tokens were already matched + // and can't be re-used during the geocoding process. vector m_usedTokens; + // Number of tokens in the query. size_t m_numTokens = 0; }; } // namespace search diff --git a/search/geometry_cache.cpp b/search/geometry_cache.cpp index 275c2ff875..990cae77cd 100644 --- a/search/geometry_cache.cpp +++ b/search/geometry_cache.cpp @@ -35,8 +35,7 @@ PivotRectsCache::PivotRectsCache(size_t maxNumEntries, my::Cancellable const & c { } -coding::CompressedBitVector const * PivotRectsCache::Get(MwmContext const & context, - m2::RectD const & rect, int scale) +CBV PivotRectsCache::Get(MwmContext const & context, m2::RectD const & rect, int scale) { auto p = FindOrCreateEntry( context.GetId(), [&rect, &scale](Entry const & entry) @@ -53,7 +52,7 @@ coding::CompressedBitVector const * PivotRectsCache::Get(MwmContext const & cont normRect = rect; InitEntry(context, normRect, scale, entry); } - return entry.m_cbv.get(); + return entry.m_cbv; } // LocalityRectsCache ------------------------------------------------------------------------------ @@ -62,8 +61,7 @@ LocalityRectsCache::LocalityRectsCache(size_t maxNumEntries, my::Cancellable con { } -coding::CompressedBitVector const * LocalityRectsCache::Get(MwmContext const & context, - m2::RectD const & rect, int scale) +CBV LocalityRectsCache::Get(MwmContext const & context, m2::RectD const & rect, int scale) { auto p = FindOrCreateEntry(context.GetId(), [&rect, &scale](Entry const & entry) { @@ -73,7 +71,7 @@ coding::CompressedBitVector const * LocalityRectsCache::Get(MwmContext const & c auto & entry = p.first; if (p.second) InitEntry(context, rect, scale, entry); - return entry.m_cbv.get(); + return entry.m_cbv; } } // namespace search diff --git a/search/geometry_cache.hpp b/search/geometry_cache.hpp index d5d305301b..2b36707cc2 100644 --- a/search/geometry_cache.hpp +++ b/search/geometry_cache.hpp @@ -1,8 +1,8 @@ #pragma once -#include "indexer/mwm_set.hpp" +#include "search/cbv.hpp" -#include "coding/compressed_bit_vector.hpp" +#include "indexer/mwm_set.hpp" #include "geometry/rect2d.hpp" @@ -35,8 +35,7 @@ public: // Returns (hopefully, cached) list of features in a given // rect. Note that return value may be invalidated on next calls to // this method. - virtual coding::CompressedBitVector const * Get(MwmContext const & context, - m2::RectD const & rect, int scale) = 0; + virtual CBV Get(MwmContext const & context, m2::RectD const & rect, int scale) = 0; inline void Clear() { m_entries.clear(); } @@ -44,7 +43,7 @@ protected: struct Entry { m2::RectD m_rect; - unique_ptr m_cbv; + CBV m_cbv; int m_scale = 0; }; @@ -87,8 +86,7 @@ public: double maxRadiusMeters); // GeometryCache overrides: - coding::CompressedBitVector const * Get(MwmContext const & context, m2::RectD const & rect, - int scale) override; + CBV Get(MwmContext const & context, m2::RectD const & rect, int scale) override; private: double const m_maxRadiusMeters; @@ -100,8 +98,7 @@ public: LocalityRectsCache(size_t maxNumEntries, my::Cancellable const & cancellable); // GeometryCache overrides: - coding::CompressedBitVector const * Get(MwmContext const & context, m2::RectD const & rect, - int scale) override; + CBV Get(MwmContext const & context, m2::RectD const & rect, int scale) override; }; } // namespace search diff --git a/search/search.pro b/search/search.pro index 5ddaf35a28..2f5b17318c 100644 --- a/search/search.pro +++ b/search/search.pro @@ -12,7 +12,7 @@ HEADERS += \ algos.hpp \ approximate_string_match.hpp \ cancel_exception.hpp \ - cbv_ptr.hpp \ + cbv.hpp \ common.hpp \ dummy_rank_table.hpp \ engine.hpp \ @@ -69,7 +69,7 @@ HEADERS += \ SOURCES += \ approximate_string_match.cpp \ - cbv_ptr.cpp \ + cbv.cpp \ dummy_rank_table.cpp \ engine.cpp \ features_filter.cpp \ diff --git a/search/streets_matcher.cpp b/search/streets_matcher.cpp index 7d8125437c..dfd524f327 100644 --- a/search/streets_matcher.cpp +++ b/search/streets_matcher.cpp @@ -31,7 +31,7 @@ bool LessByHash(StreetsMatcher::Prediction const & lhs, StreetsMatcher::Predicti void StreetsMatcher::Go(BaseContext const & ctx, FeaturesFilter const & filter, QueryParams const & params, vector & predictions) { - size_t const kMaxNumPredictions = 3; + size_t const kMaxNumOfImprobablePredictions = 3; double const kTailProbability = 0.05; predictions.clear(); @@ -46,8 +46,11 @@ void StreetsMatcher::Go(BaseContext const & ctx, FeaturesFilter const & filter, predictions.end()); sort(predictions.rbegin(), predictions.rend(), my::LessBy(&Prediction::m_prob)); - while (predictions.size() > kMaxNumPredictions && predictions.back().m_prob < kTailProbability) + while (predictions.size() > kMaxNumOfImprobablePredictions && + predictions.back().m_prob < kTailProbability) + { predictions.pop_back(); + } } // static @@ -65,9 +68,9 @@ void StreetsMatcher::FindStreets(BaseContext const & ctx, FeaturesFilter const & // each time a token that looks like a beginning of a house number // is met, we try to use current intersection of tokens as a // street layer and try to match BUILDINGs or POIs. - CBVPtr streets(ctx.m_streets, false /* isOwner */); + CBV streets(ctx.m_streets); - CBVPtr all; + CBV all; all.SetFull(); size_t curToken = startToken; @@ -88,23 +91,20 @@ void StreetsMatcher::FindStreets(BaseContext const & ctx, FeaturesFilter const & { if (!streets.IsEmpty() && !emptyIntersection && !incomplete && lastToken != curToken) { - CBVPtr fs(streets.Get(), false /* isOwner */); - CBVPtr fa(all.Get(), false /* isOwner */); + CBV fs(streets); + CBV fa(all); ASSERT(!fs.IsFull(), ()); ASSERT(!fa.IsFull(), ()); - if (filter.NeedToFilter(*fs)) - fs.Set(filter.Filter(*fs)); + if (filter.NeedToFilter(fs)) + fs = filter.Filter(fs); if (fs.IsEmpty()) return; - if (filter.NeedToFilter(*fa)) - { - fa.Set(filter.Filter(*fa)); - fa.Union(fs.Get()); - } + if (filter.NeedToFilter(fa)) + fa = filter.Filter(fa).Union(fs); predictions.emplace_back(); auto & prediction = predictions.back(); @@ -112,31 +112,26 @@ void StreetsMatcher::FindStreets(BaseContext const & ctx, FeaturesFilter const & prediction.m_startToken = startToken; prediction.m_endToken = curToken; - ASSERT_LESS_OR_EQUAL(fs->PopCount(), fa->PopCount(), ()); - prediction.m_prob = - static_cast(fs->PopCount()) / static_cast(fa->PopCount()); + ASSERT_NOT_EQUAL(fs.PopCount(), 0, ()); + ASSERT_LESS_OR_EQUAL(fs.PopCount(), fa.PopCount(), ()); + prediction.m_prob = static_cast(fs.PopCount()) / static_cast(fa.PopCount()); - if (fs.IsOwner()) - prediction.m_features = move(fs); - else - fs.CopyTo(prediction.m_features); - - prediction.m_hash = coding::CompressedBitVectorHasher::Hash(*prediction.m_features); + prediction.m_features = move(fs); + prediction.m_hash = prediction.m_features.Hash(); } }; StreetTokensFilter filter([&](strings::UniString const & /* token */, size_t tag) { - auto buffer = coding::CompressedBitVector::Intersect( - *streets, *ctx.m_features[tag]); + auto buffer = streets.Intersect(ctx.m_features[tag]); if (tag < curToken) { // This is the case for delayed // street synonym. Therefore, // |streets| is temporarily in the // incomplete state. - streets.Set(move(buffer)); - all.Intersect(ctx.m_features[tag].get()); + streets = buffer; + all = all.Intersect(ctx.m_features[tag]); emptyIntersection = false; incomplete = true; @@ -147,11 +142,11 @@ void StreetsMatcher::FindStreets(BaseContext const & ctx, FeaturesFilter const & // |streets| will become empty after // the intersection. Therefore we need // to create streets layer right now. - if (coding::CompressedBitVector::IsEmpty(buffer)) + if (buffer.IsEmpty()) emit(); - streets.Set(move(buffer)); - all.Intersect(ctx.m_features[tag].get()); + streets = buffer; + all = all.Intersect(ctx.m_features[tag]); emptyIntersection = false; incomplete = false; }); diff --git a/search/streets_matcher.hpp b/search/streets_matcher.hpp index 43062db676..7918380774 100644 --- a/search/streets_matcher.hpp +++ b/search/streets_matcher.hpp @@ -1,6 +1,6 @@ #pragma once -#include "search/cbv_ptr.hpp" +#include "search/cbv.hpp" #include "search/geocoder_context.hpp" #include "std/vector.hpp" @@ -17,7 +17,7 @@ public: { inline size_t GetNumTokens() const { return m_endToken - m_startToken; } - CBVPtr m_features; + CBV m_features; size_t m_startToken = 0; size_t m_endToken = 0;