diff --git a/indexer/ftypes_matcher.cpp b/indexer/ftypes_matcher.cpp index 253bf11ae2..aa7c19e15b 100644 --- a/indexer/ftypes_matcher.cpp +++ b/indexer/ftypes_matcher.cpp @@ -393,6 +393,12 @@ IsFoodChecker:: IsFoodChecker() m_types.push_back(c.GetTypeByPath({path[0], path[1]})); } +IsCuisineChecker::IsCuisineChecker() : BaseChecker(1 /* level */) +{ + Classificator const & c = classif(); + m_types.push_back(c.GetTypeByPath({"cuisine"})); +} + IsCityChecker::IsCityChecker() { m_types.push_back(classif().GetTypeByPath({"place", "city"})); diff --git a/indexer/ftypes_matcher.hpp b/indexer/ftypes_matcher.hpp index c90952784c..f615e0bedd 100644 --- a/indexer/ftypes_matcher.hpp +++ b/indexer/ftypes_matcher.hpp @@ -221,6 +221,14 @@ public: DECLARE_CHECKER_INSTANCE(IsFoodChecker); }; +class IsCuisineChecker : public BaseChecker +{ + IsCuisineChecker(); + +public: + DECLARE_CHECKER_INSTANCE(IsCuisineChecker); +}; + class IsCityChecker : public BaseChecker { IsCityChecker(); diff --git a/search/CMakeLists.txt b/search/CMakeLists.txt index 640173cdbb..d0706d8eb9 100644 --- a/search/CMakeLists.txt +++ b/search/CMakeLists.txt @@ -36,6 +36,8 @@ set( city_finder.cpp city_finder.hpp common.hpp + cuisine_filter.cpp + cuisine_filter.hpp displayed_categories.cpp displayed_categories.hpp doc_vec.cpp diff --git a/search/categories_cache.cpp b/search/categories_cache.cpp index 00b75f978c..df090e1d68 100644 --- a/search/categories_cache.cpp +++ b/search/categories_cache.cpp @@ -67,4 +67,10 @@ HotelsCache::HotelsCache(base::Cancellable const & cancellable) : CategoriesCache(ftypes::IsHotelChecker::Instance(), cancellable) { } + +// FoodCache --------------------------------------------------------------------------------------- +FoodCache::FoodCache(base::Cancellable const & cancellable) + : CategoriesCache(ftypes::IsFoodChecker::Instance(), cancellable) +{ +} } // namespace search diff --git a/search/categories_cache.hpp b/search/categories_cache.hpp index f3ee90a308..2c442a5a98 100644 --- a/search/categories_cache.hpp +++ b/search/categories_cache.hpp @@ -63,4 +63,10 @@ class HotelsCache : public CategoriesCache public: HotelsCache(base::Cancellable const & cancellable); }; + +class FoodCache : public CategoriesCache +{ +public: + FoodCache(base::Cancellable const & cancellable); +}; } // namespace search diff --git a/search/cuisine_filter.cpp b/search/cuisine_filter.cpp new file mode 100644 index 0000000000..e252439375 --- /dev/null +++ b/search/cuisine_filter.cpp @@ -0,0 +1,91 @@ +#include "search/cuisine_filter.hpp" + +#include "indexer/feature.hpp" +#include "indexer/feature_meta.hpp" +#include "indexer/ftypes_matcher.hpp" + +#include "base/assert.hpp" +#include "base/checked_cast.hpp" + +#include + +using namespace std; + +namespace search +{ +namespace cuisine_filter +{ +// Description ------------------------------------------------------------------------------------- +void Description::FromFeature(FeatureType & ft) +{ + m_types.clear(); + ft.ForEachType([this](uint32_t t) { + if (ftypes::IsCuisineChecker::Instance().IsMatched(t)) + m_types.push_back(t); + }); +} + +CuisineFilter::ScopedFilter::ScopedFilter(MwmSet::MwmId const & mwmId, + Descriptions const & descriptions, + vector const & types) + : m_mwmId(mwmId), m_descriptions(descriptions), m_types(types) +{ + sort(m_types.begin(), m_types.end()); +} + +bool CuisineFilter::ScopedFilter::Matches(FeatureID const & fid) const +{ + if (fid.m_mwmId != m_mwmId) + return false; + + auto it = lower_bound( + m_descriptions.begin(), m_descriptions.end(), make_pair(fid.m_index, Description{}), + [](pair const & lhs, pair const & rhs) { + return lhs.first < rhs.first; + }); + if (it == m_descriptions.end() || it->first != fid.m_index) + return false; + + for (auto const t : it->second.m_types) + { + if (binary_search(m_types.begin(), m_types.end(), t)) + return true; + } + return false; +} + +// CuisineFilter ------------------------------------------------------------------------------------ +CuisineFilter::CuisineFilter(FoodCache & food) : m_food(food) {} + +unique_ptr CuisineFilter::MakeScopedFilter( + MwmContext const & context, vector const & types) +{ + if (types.empty()) + return {}; + return make_unique(context.GetId(), GetDescriptions(context), types); +} + +void CuisineFilter::ClearCaches() { m_descriptions.clear(); } + +CuisineFilter::Descriptions const & CuisineFilter::GetDescriptions(MwmContext const & context) +{ + auto const & mwmId = context.GetId(); + auto const it = m_descriptions.find(mwmId); + if (it != m_descriptions.end()) + return it->second; + + auto const food = m_food.Get(context); + auto & descriptions = m_descriptions[mwmId]; + food.ForEach([&descriptions, &context](uint64_t bit) { + auto const id = base::asserted_cast(bit); + FeatureType ft; + + Description description; + if (context.GetFeature(id, ft)) + description.FromFeature(ft); + descriptions.emplace_back(id, description); + }); + return descriptions; +} +} // namespace cuisine_filter +} // namespace search diff --git a/search/cuisine_filter.hpp b/search/cuisine_filter.hpp new file mode 100644 index 0000000000..faca17c9b1 --- /dev/null +++ b/search/cuisine_filter.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include "search/categories_cache.hpp" +#include "search/mwm_context.hpp" + +#include "indexer/mwm_set.hpp" + +#include +#include +#include +#include + +class FeatureType; + +namespace search +{ +namespace cuisine_filter +{ +struct Description +{ + void FromFeature(FeatureType & ft); + + std::vector m_types; +}; + +class CuisineFilter +{ +public: + using Descriptions = std::vector>; + + class ScopedFilter + { + public: + ScopedFilter(MwmSet::MwmId const & mwmId, Descriptions const & descriptions, + std::vector const & types); + + bool Matches(FeatureID const & fid) const; + + private: + MwmSet::MwmId const m_mwmId; + Descriptions const & m_descriptions; + std::vector m_types; + }; + + CuisineFilter(FoodCache & food); + + std::unique_ptr MakeScopedFilter(MwmContext const & context, + std::vector const & types); + + void ClearCaches(); + +private: + Descriptions const & GetDescriptions(MwmContext const & context); + + FoodCache & m_food; + std::map m_descriptions; +}; +} // namespace cuisine_filter +} // namespace search diff --git a/xcode/search/search.xcodeproj/project.pbxproj b/xcode/search/search.xcodeproj/project.pbxproj index cd1038d785..baab79f117 100644 --- a/xcode/search/search.xcodeproj/project.pbxproj +++ b/xcode/search/search.xcodeproj/project.pbxproj @@ -164,6 +164,8 @@ 3DA5722B20C1956D007BDE27 /* integration_tests_helpers.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DA5722920C1956D007BDE27 /* integration_tests_helpers.hpp */; }; 3DFEBF761EF2D55800317D5C /* city_finder.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DFEBF751EF2D55800317D5C /* city_finder.hpp */; }; 405DB10720FF472300EE3824 /* utils_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 405DB10620FF472300EE3824 /* utils_test.cpp */; }; + 40AC86EA214A96EC003A96D1 /* cuisine_filter.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 40AC86E8214A96EB003A96D1 /* cuisine_filter.hpp */; }; + 40AC86EB214A96EC003A96D1 /* cuisine_filter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 40AC86E9214A96EB003A96D1 /* cuisine_filter.cpp */; }; 453C623B2004BABE00467120 /* region_info_getter.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 453C62392004BABE00467120 /* region_info_getter.hpp */; }; 453C623C2004BABE00467120 /* region_info_getter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 453C623A2004BABE00467120 /* region_info_getter.cpp */; }; 456E1B3E1F9A3C8E009C32E1 /* cities_boundaries_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 456E1B3C1F9A3C8D009C32E1 /* cities_boundaries_table.cpp */; }; @@ -426,6 +428,8 @@ 3DA5722920C1956D007BDE27 /* integration_tests_helpers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = integration_tests_helpers.hpp; sourceTree = ""; }; 3DFEBF751EF2D55800317D5C /* city_finder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = city_finder.hpp; sourceTree = ""; }; 405DB10620FF472300EE3824 /* utils_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utils_test.cpp; sourceTree = ""; }; + 40AC86E8214A96EB003A96D1 /* cuisine_filter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = cuisine_filter.hpp; sourceTree = ""; }; + 40AC86E9214A96EB003A96D1 /* cuisine_filter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cuisine_filter.cpp; sourceTree = ""; }; 453C62392004BABE00467120 /* region_info_getter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = region_info_getter.hpp; sourceTree = ""; }; 453C623A2004BABE00467120 /* region_info_getter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = region_info_getter.cpp; sourceTree = ""; }; 456E1B3C1F9A3C8D009C32E1 /* cities_boundaries_table.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cities_boundaries_table.cpp; sourceTree = ""; }; @@ -808,6 +812,8 @@ F63CE2BA1FBB206800716AD3 /* city_finder.cpp */, 3DFEBF751EF2D55800317D5C /* city_finder.hpp */, F652D8BA1CFDE1E800FC29A0 /* common.hpp */, + 40AC86E9214A96EB003A96D1 /* cuisine_filter.cpp */, + 40AC86E8214A96EB003A96D1 /* cuisine_filter.hpp */, 0810EC341D6D9D2E00ABFEE7 /* displayed_categories.cpp */, 0810EC351D6D9D2E00ABFEE7 /* displayed_categories.hpp */, 45A0084E1FE9088300D77690 /* doc_vec.cpp */, @@ -982,6 +988,7 @@ 3453BD5B1DAF91C100380ECB /* hotels_filter.hpp in Headers */, F652D90A1CFDE21900FC29A0 /* stats_cache.hpp in Headers */, 39AEF83A1FB4598900943FC9 /* tracer.hpp in Headers */, + 40AC86EA214A96EC003A96D1 /* cuisine_filter.hpp in Headers */, 675346E11A40560D00A0A8C3 /* geometry_utils.hpp in Headers */, 675346E31A40560D00A0A8C3 /* house_detector.hpp in Headers */, F652D9071CFDE21900FC29A0 /* ranking_info.hpp in Headers */, @@ -1304,6 +1311,7 @@ 39B2B9501FB4620800AB85A1 /* smoke_test.cpp in Sources */, F652D8EC1CFDE21900FC29A0 /* features_layer_path_finder.cpp in Sources */, 39B2B9421FB461F800AB85A1 /* downloader_search_test.cpp in Sources */, + 40AC86EB214A96EC003A96D1 /* cuisine_filter.cpp in Sources */, 39AEF8361FB4597300943FC9 /* tracer.cpp in Sources */, F6E2AFFF1D9E794800793C36 /* categories_cache.cpp in Sources */, 39AEF84C1FB45D7800943FC9 /* feature_loader.cpp in Sources */,