From 0056e6b11af4785e27bc3f5be18c51b050c7e77b Mon Sep 17 00:00:00 2001 From: Maxim Pimenov Date: Wed, 23 Dec 2020 14:54:04 +0300 Subject: [PATCH] [search] Search in downloader by country names. When a request to search in downloader arrives, we used to only find features on the world map that match the request and return the mwms that contain these features. This commit mixes in the results of search directly in the country tree (countries.txt), or, to be more precise, by the translations of the names of the countries there (countries_names.txt). This is not the most efficient implementation but hopefully it isolated enough to make improvements easy and it was also useful as an exploration where our current search APIs are lacking, for example * The unnecessary std::string<->UniString conversions. * Indexes such as MemSearchIndex pretending to be generic while in fact being tailored to a particular use-case. * The difficulty of mixing search results from different sources. --- android/assets/countries_names.txt | 1 + android/script/replace_links.bat | 1 + defines.hpp | 1 + iphone/Maps/Maps.xcodeproj/project.pbxproj | 4 + map/framework.cpp | 4 + map/search_api.cpp | 8 +- search/CMakeLists.txt | 2 + search/countries_names_index.cpp | 89 +++++++++++++++++++ search/countries_names_index.hpp | 65 ++++++++++++++ search/downloader_search_callback.cpp | 73 ++++++++++----- search/processor.cpp | 26 ++++++ search/processor.hpp | 7 ++ search/result.cpp | 6 ++ search/result.hpp | 13 ++- search/search_tests/CMakeLists.txt | 1 + .../countries_names_index_tests.cpp | 47 ++++++++++ storage/country_tree.hpp | 2 +- xcode/search/search.xcodeproj/project.pbxproj | 16 +++- 18 files changed, 334 insertions(+), 32 deletions(-) create mode 120000 android/assets/countries_names.txt create mode 100644 search/countries_names_index.cpp create mode 100644 search/countries_names_index.hpp create mode 100644 search/search_tests/countries_names_index_tests.cpp diff --git a/android/assets/countries_names.txt b/android/assets/countries_names.txt new file mode 120000 index 00000000000..327b6d60a7e --- /dev/null +++ b/android/assets/countries_names.txt @@ -0,0 +1 @@ +../../data/countries_names.txt \ No newline at end of file diff --git a/android/script/replace_links.bat b/android/script/replace_links.bat index 476a0bac0b4..4d55c99fd50 100644 --- a/android/script/replace_links.bat +++ b/android/script/replace_links.bat @@ -8,6 +8,7 @@ cp ../data/classificator.txt assets/ cp ../data/colors.txt assets/ cp ../data/copyright.html assets/ cp ../data/countries.txt assets/ +cp ../data/countries_names.txt assets/ cp ../data/drules_proto_dark.bin assets/ cp ../data/drules_proto_clear.bin assets/ cp ../data/drules_proto_vehicle_dark.bin assets/ diff --git a/defines.hpp b/defines.hpp index 11e890dde3a..b308a9f6a61 100644 --- a/defines.hpp +++ b/defines.hpp @@ -80,6 +80,7 @@ #define COUNTRIES_FILE "countries.txt" #define COUNTRIES_META_FILE "countries_meta.txt" +#define COUNTRIES_NAMES_FILE "countries_names.txt" #define LEAP_SPEEDS_FILE "leap_speeds.json" #define WORLD_FILE_NAME "World" diff --git a/iphone/Maps/Maps.xcodeproj/project.pbxproj b/iphone/Maps/Maps.xcodeproj/project.pbxproj index fa88d52927d..54c0161b46c 100644 --- a/iphone/Maps/Maps.xcodeproj/project.pbxproj +++ b/iphone/Maps/Maps.xcodeproj/project.pbxproj @@ -278,6 +278,7 @@ 34F73FA31E08300E00AC1FD6 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 34F73FA11E08300E00AC1FD6 /* Images.xcassets */; }; 34F742321E0834F400AC1FD6 /* UIViewController+Navigation.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F742301E0834F400AC1FD6 /* UIViewController+Navigation.m */; }; 34FE5A6F1F18F30F00BCA729 /* TrafficButtonArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FE5A6D1F18F30F00BCA729 /* TrafficButtonArea.swift */; }; + 3970A6A825B64EE400CF5828 /* countries_names.txt in Resources */ = {isa = PBXBuildFile; fileRef = 3970A6A725B64EE300CF5828 /* countries_names.txt */; }; 39CDE69123E1B6C8007CDA58 /* libge0.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 39CDE69023E1B6C8007CDA58 /* libge0.a */; }; 3D0D2F7623D858BF00945C8D /* IsolinesTutorialBlur.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3D0D2F7523D858BF00945C8D /* IsolinesTutorialBlur.xib */; }; 3D15ACEE2155117000F725D5 /* MWMObjectsCategorySelectorDataSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D15ACED2155117000F725D5 /* MWMObjectsCategorySelectorDataSource.mm */; }; @@ -1416,6 +1417,7 @@ 34FE4C431BCC013500066718 /* MWMMapWidgets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapWidgets.h; sourceTree = ""; }; 34FE4C441BCC013500066718 /* MWMMapWidgets.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapWidgets.mm; sourceTree = ""; }; 34FE5A6D1F18F30F00BCA729 /* TrafficButtonArea.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrafficButtonArea.swift; sourceTree = ""; }; + 3970A6A725B64EE300CF5828 /* countries_names.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = countries_names.txt; path = ../../data/countries_names.txt; sourceTree = ""; }; 39CDE69023E1B6C8007CDA58 /* libge0.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libge0.a; sourceTree = BUILT_PRODUCTS_DIR; }; 3D0D2F7523D858BF00945C8D /* IsolinesTutorialBlur.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IsolinesTutorialBlur.xib; sourceTree = ""; }; 3D15ACED2155117000F725D5 /* MWMObjectsCategorySelectorDataSource.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMObjectsCategorySelectorDataSource.mm; sourceTree = ""; }; @@ -2360,6 +2362,7 @@ 29B97314FDCFA39411CA2CEA /* Maps */ = { isa = PBXGroup; children = ( + 3970A6A725B64EE300CF5828 /* countries_names.txt */, 47AEF83F2231249E00D20538 /* categories_brands.txt */, 471BBD92213038E000EB17C9 /* TipsAndTricks */, FA36B8011540388B004560CC /* Bookmarks */, @@ -5187,6 +5190,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3970A6A825B64EE400CF5828 /* countries_names.txt in Resources */, 47AEF8402231249E00D20538 /* categories_brands.txt in Resources */, F6C3A1B221AC22810060EEC8 /* Alert 5.m4a in Resources */, 4560F585213D53C100CC736C /* shaders_metal.metallib in Resources */, diff --git a/map/framework.cpp b/map/framework.cpp index 9b2773ea821..b805e9263f5 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -1707,6 +1707,10 @@ void Framework::SelectSearchResult(search::Result const & result, bool animation m_currentPlacePageInfo = {}; ASSERT(false, ("Suggests should not be here.")); return; + case Result::Type::DownloaderEntry: + m_currentPlacePageInfo = {}; + ASSERT(false, ("Downloader entries should not be here.")); + return; } m_currentPlacePageInfo = BuildPlacePageInfo(info); diff --git a/map/search_api.cpp b/map/search_api.cpp index bab15eff9fa..0901e3508bf 100644 --- a/map/search_api.cpp +++ b/map/search_api.cpp @@ -4,24 +4,28 @@ #include "map/discovery/discovery_search_params.hpp" #include "map/everywhere_search_params.hpp" -#include "partners_api/booking_api.hpp" - #include "search/bookmarks/processor.hpp" #include "search/geometry_utils.hpp" #include "search/hotels_filter.hpp" #include "search/tracer.hpp" #include "search/utils.hpp" +#include "partners_api/booking_api.hpp" + #include "storage/downloader_search_params.hpp" +#include "platform/platform.hpp" #include "platform/preferred_languages.hpp" #include "platform/safe_callback.hpp" #include "geometry/mercator.hpp" #include "base/checked_cast.hpp" +#include "base/file_name_utils.hpp" #include "base/string_utils.hpp" +#include "defines.hpp" + #include #include #include diff --git a/search/CMakeLists.txt b/search/CMakeLists.txt index 079d1943e4d..a7a7cc25e9f 100644 --- a/search/CMakeLists.txt +++ b/search/CMakeLists.txt @@ -37,6 +37,8 @@ set( city_finder.cpp city_finder.hpp common.hpp + countries_names_index.cpp + countries_names_index.hpp cuisine_filter.cpp cuisine_filter.hpp displayed_categories.cpp diff --git a/search/countries_names_index.cpp b/search/countries_names_index.cpp new file mode 100644 index 00000000000..3bb48123f37 --- /dev/null +++ b/search/countries_names_index.cpp @@ -0,0 +1,89 @@ +#include "search/countries_names_index.hpp" + +#include "platform/platform.hpp" + +#include "coding/file_reader.hpp" + +#include "base/assert.hpp" + +#include +#include +#include + +using namespace std; + +namespace search +{ +CountriesNamesIndex::CountriesNamesIndex() +{ + ReadCountryNamesFromFile(m_countries); + BuildIndexFromTranslations(); +} + +void CountriesNamesIndex::CollectMatchingCountries(string const & query, + vector & results) +{ + set ids; + auto insertId = [&ids](size_t id, bool /* exactMatch */) { ids.insert(id); }; + + vector tokens; + search::NormalizeAndTokenizeString(query, tokens); + search::Delimiters delims; + bool const lastTokenIsPrefix = !query.empty() && !delims(strings::LastUniChar(query)); + for (size_t i = 0; i < tokens.size(); ++i) + { + auto const & token = tokens[i]; + if (i + 1 == tokens.size() && lastTokenIsPrefix) + Retrieve>(token, insertId); + else + Retrieve(token, insertId); + } + + // todo(@m) Do not bother with tf/idf for now. + results.clear(); + for (auto id : ids) + { + CHECK_LESS(id, m_countries.size(), ()); + results.emplace_back(m_countries[id].m_countryId); + } +} + +void CountriesNamesIndex::ReadCountryNamesFromFile(vector & countries) +{ + string contents; + + GetPlatform().GetReader(COUNTRIES_NAMES_FILE)->ReadAsString(contents); + istringstream ifs(contents); + + string line; + countries.clear(); + while (getline(ifs, line)) + { + if (line.empty()) + continue; + strings::Trim(line); + if (line[0] == '[') + { + CHECK_EQUAL(line[line.size() - 1], ']', ()); + countries.push_back({}); + countries.back().m_countryId = line.substr(1, line.size() - 2); + continue; + } + auto pos = line.find('='); + if (pos == string::npos) + continue; + // Ignore the language code: the language sets differ for StringUtf8Multilang + // and for the translations used by this class. + auto t = line.substr(pos + 1); + strings::Trim(t); + if (!countries.empty()) + countries.back().m_doc.m_translations.push_back(t); + } +} + +void CountriesNamesIndex::BuildIndexFromTranslations() +{ + for (size_t i = 0; i < m_countries.size(); ++i) + m_index.Add(i, m_countries[i].m_doc); +} +} // namespace search diff --git a/search/countries_names_index.hpp b/search/countries_names_index.hpp new file mode 100644 index 00000000000..e4da35303e7 --- /dev/null +++ b/search/countries_names_index.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "search/base/mem_search_index.hpp" +#include "search/feature_offset_match.hpp" + +#include "storage/storage_defines.hpp" + +#include "indexer/search_string_utils.hpp" + +#include "base/string_utils.hpp" + +#include +#include +#include +#include + +namespace search +{ +class CountriesNamesIndex +{ +public: + struct Doc + { + template + void ForEachToken(Fn && fn) const + { + for (auto const & s : m_translations) + fn(StringUtf8Multilang::kDefaultCode, NormalizeAndSimplifyString(s)); + } + + std::vector m_translations; + }; + + CountriesNamesIndex(); + + void CollectMatchingCountries(std::string const & query, + std::vector & results); + +private: + struct Country + { + storage::CountryId m_countryId; + Doc m_doc; + }; + + // todo(@m) Almost the same as in bookmarks/processor.hpp. + template + void Retrieve(strings::UniString const & s, Fn && fn) const + { + SearchTrieRequest request; + request.m_names.emplace_back(BuildLevenshteinDFA(s)); + request.m_langs.insert(StringUtf8Multilang::kDefaultCode); + + MatchFeaturesInTrie( + request, m_index.GetRootIterator(), [](size_t id) { return true; } /* filter */, + std::forward(fn)); + } + + void ReadCountryNamesFromFile(std::vector & countries); + void BuildIndexFromTranslations(); + + std::vector m_countries; + search_base::MemSearchIndex m_index; +}; +} // namespace search diff --git a/search/downloader_search_callback.cpp b/search/downloader_search_callback.cpp index 201466655cd..5b7cf8fd73e 100644 --- a/search/downloader_search_callback.cpp +++ b/search/downloader_search_callback.cpp @@ -2,26 +2,40 @@ #include "search/result.hpp" +#include "storage/country_info_getter.hpp" +#include "storage/storage.hpp" + #include "editor/editable_data_source.hpp" #include "indexer/data_source.hpp" -#include "storage/country_info_getter.hpp" -#include "storage/storage.hpp" - +#include "base/assert.hpp" #include "base/logging.hpp" #include "base/string_utils.hpp" -#include #include #include namespace { +bool GetGroupCountryId(storage::Storage const & storage, std::string & name) +{ + auto const & synonyms = storage.GetCountryNameSynonyms(); + + if (storage.IsInnerNode(name)) + return true; + auto const it = synonyms.find(name); + if (it == synonyms.end()) + return false; + if (!storage.IsInnerNode(it->second)) + return false; + name = it->second; + return true; +} + bool GetGroupCountryIdFromFeature(storage::Storage const & storage, FeatureType & ft, std::string & name) { - auto const & synonyms = storage.GetCountryNameSynonyms(); int8_t const langIndices[] = {StringUtf8Multilang::kEnglishCode, StringUtf8Multilang::kDefaultCode, StringUtf8Multilang::kInternationalCode}; @@ -30,15 +44,8 @@ bool GetGroupCountryIdFromFeature(storage::Storage const & storage, FeatureType { if (!ft.GetName(langIndex, name)) continue; - if (storage.IsInnerNode(name)) + if (GetGroupCountryId(storage, name)) return true; - auto const it = synonyms.find(name); - if (it == synonyms.end()) - continue; - if (!storage.IsInnerNode(it->second)) - continue; - name = it->second; - return true; } return false; } @@ -66,6 +73,22 @@ void DownloaderSearchCallback::operator()(search::Results const & results) for (auto const & result : results) { + if (result.GetResultType() == search::Result::Type::DownloaderEntry) + { + std::string groupFeatureName = result.GetCountryId(); + if (!GetGroupCountryId(m_storage, groupFeatureName)) + continue; + + storage::DownloaderSearchResult downloaderResult(groupFeatureName, + result.GetString() /* m_matchedName */); + if (uniqueResults.find(downloaderResult) == uniqueResults.end()) + { + uniqueResults.insert(downloaderResult); + downloaderSearchResults.m_results.push_back(downloaderResult); + } + continue; + } + if (!result.HasPoint()) continue; @@ -98,21 +121,25 @@ void DownloaderSearchCallback::operator()(search::Results const & results) } } } - auto const & mercator = result.GetFeatureCenter(); - storage::CountryId const & countryId = m_infoGetter.GetRegionCountryId(mercator); - if (countryId == storage::kInvalidCountryId) - continue; - storage::DownloaderSearchResult downloaderResult(countryId, - result.GetString() /* m_matchedName */); - if (uniqueResults.find(downloaderResult) == uniqueResults.end()) + if (result.GetResultType() == search::Result::Type::LatLon) { - uniqueResults.insert(downloaderResult); - downloaderSearchResults.m_results.push_back(downloaderResult); + auto const & mercator = result.GetFeatureCenter(); + storage::CountryId const & countryId = m_infoGetter.GetRegionCountryId(mercator); + if (countryId == storage::kInvalidCountryId) + continue; + + storage::DownloaderSearchResult downloaderResult(countryId, + result.GetString() /* m_matchedName */); + if (uniqueResults.find(downloaderResult) == uniqueResults.end()) + { + uniqueResults.insert(downloaderResult); + downloaderSearchResults.m_results.push_back(downloaderResult); + } + continue; } } - downloaderSearchResults.m_query = m_params.m_query; downloaderSearchResults.m_endMarker = results.IsEndMarker(); if (m_params.m_onResults) diff --git a/search/processor.cpp b/search/processor.cpp index 00f767eabda..3450a4deb57 100644 --- a/search/processor.cpp +++ b/search/processor.cpp @@ -647,6 +647,9 @@ void Processor::Search(SearchParams const & params) SetQuery(params.m_query); SetViewport(viewport); + if (params.m_mode == Mode::Downloader) + SearchInDownloaderByCountryName(params); + // Used to store the earliest available cancellation status: // if the search has been cancelled, we need to pinpoint the reason // for cancellation and a further call to CancellationStatus() may @@ -835,6 +838,29 @@ void Processor::SearchBookmarks(bookmarks::GroupId const & groupId) m_bookmarksProcessor.Finish(IsCancelled()); } +void Processor::SearchInDownloaderByCountryName(SearchParams const & params) +{ + // This index is heavy (several megabytes) but we expect that a small number of + // user sessions involves a search in downloader. + // Therefore, it is initialized lazily upon first request. + if (m_countriesNamesIndex == nullptr) + m_countriesNamesIndex = make_unique(); + + vector countries; + auto trimmedQuery = params.m_query; + strings::Trim(trimmedQuery); + m_countriesNamesIndex->CollectMatchingCountries(trimmedQuery, countries); + size_t const kMaxResultsFromCountriesTree = 5; + if (countries.size() > kMaxResultsFromCountriesTree) + countries.resize(kMaxResultsFromCountriesTree); + + for (auto const & country : countries) + { + m_emitter.AddResultNoChecks(Result(country, trimmedQuery /* matchedName */, false)); + m_emitter.Emit(); + } +} + void Processor::InitParams(QueryParams & params) const { params.SetQuery(m_query); diff --git a/search/processor.hpp b/search/processor.hpp index f15e4982ce9..a1bde74e118 100644 --- a/search/processor.hpp +++ b/search/processor.hpp @@ -6,6 +6,7 @@ #include "search/categories_set.hpp" #include "search/cities_boundaries_table.hpp" #include "search/common.hpp" +#include "search/countries_names_index.hpp" #include "search/emitter.hpp" #include "search/geocoder.hpp" #include "search/pre_ranker.hpp" @@ -87,6 +88,10 @@ class Processor : public base::Cancellable void SearchBookmarks(bookmarks::GroupId const & groupId); + // Searches by the names of countries in countries.txt and their translations. + // Does not involve the *.mwm data at all. + void SearchInDownloaderByCountryName(SearchParams const & params); + void InitParams(QueryParams & params) const; void InitGeocoder(Geocoder::Params & geocoderParams, SearchParams const & searchParams); @@ -153,6 +158,8 @@ class Processor : public base::Cancellable using CountriesTrie = base::MemTrie>; CountriesTrie m_countriesTrie; + std::unique_ptr m_countriesNamesIndex; + std::string m_region; std::string m_query; QueryTokens m_tokens; diff --git a/search/result.cpp b/search/result.cpp index 64afa3cea9d..73114d95db3 100644 --- a/search/result.cpp +++ b/search/result.cpp @@ -53,6 +53,11 @@ Result::Result(Result const & res, string const & suggest) m_resultType = m_id.IsValid() ? Type::SuggestFromFeature : Type::PureSuggest; } +Result::Result(storage::CountryId const & countryId, std::string const & matchedName, bool) + : m_resultType(Type::DownloaderEntry), m_str(matchedName), m_countryId(countryId) +{ +} + bool Result::IsSuggest() const { return m_resultType == Type::SuggestFromFeature || m_resultType == Type::PureSuggest; @@ -161,6 +166,7 @@ string DebugPrint(Result::Type type) case Result::Type::PureSuggest: return "PureSuggest"; case Result::Type::SuggestFromFeature: return "SuggestFromFeature"; case Result::Type::Postcode: return "Postcode"; + case Result::Type::DownloaderEntry: return "DownloaderEntry"; } return "Unknown"; diff --git a/search/result.hpp b/search/result.hpp index ffaec56aef2..9741f04e858 100644 --- a/search/result.hpp +++ b/search/result.hpp @@ -5,10 +5,12 @@ #include "search/ranking_info.hpp" #include "search/tracer.hpp" -#include "indexer/feature_decl.hpp" +#include "storage/storage_defines.hpp" #include "editor/yes_no_unknown.hpp" +#include "indexer/feature_decl.hpp" + #include "geometry/point2d.hpp" #include "base/assert.hpp" @@ -38,7 +40,8 @@ class Result LatLon, PureSuggest, SuggestFromFeature, - Postcode + Postcode, + DownloaderEntry }; // Search results details. Considered valid if GetResultType() == Type::Feature. @@ -89,6 +92,10 @@ class Result // For Type::SuggestFromFeature. Result(Result const & res, std::string const & suggest); + // For Type::DownloaderEntry. + Result(storage::CountryId const & countryId, std::string const & matchedName, + bool /* to distinguish from Type::PureSuggest */); + Type GetResultType() const { return m_resultType; } std::string const & GetString() const { return m_str; } @@ -97,6 +104,7 @@ class Result std::string const & GetAirportIata() const { return m_details.m_airportIata; } std::string const & GetBrand() const { return m_details.m_brand; } std::string const & GetRoadShields() const { return m_details.m_roadShields; } + storage::CountryId const & GetCountryId() const { return m_countryId; } float GetHotelRating() const { return m_details.m_hotelRating; } std::string const & GetHotelApproximatePricing() const { @@ -169,6 +177,7 @@ class Result uint32_t m_featureType = 0; std::string m_suggestionStr; buffer_vector, 4> m_hightlightRanges; + storage::CountryId m_countryId; RankingInfo m_info = {}; diff --git a/search/search_tests/CMakeLists.txt b/search/search_tests/CMakeLists.txt index 1ecd6f644ed..5b3097a9dd1 100644 --- a/search/search_tests/CMakeLists.txt +++ b/search/search_tests/CMakeLists.txt @@ -6,6 +6,7 @@ set( SRC algos_tests.cpp bookmarks_processor_tests.cpp + countries_names_index_tests.cpp feature_offset_match_tests.cpp highlighting_tests.cpp house_detector_tests.cpp diff --git a/search/search_tests/countries_names_index_tests.cpp b/search/search_tests/countries_names_index_tests.cpp new file mode 100644 index 00000000000..e63b092e5d3 --- /dev/null +++ b/search/search_tests/countries_names_index_tests.cpp @@ -0,0 +1,47 @@ +#include "testing/testing.hpp" + +#include "search/countries_names_index.hpp" + +#include +#include +#include + +using namespace search; +using namespace storage; +using namespace std; + +namespace +{ +UNIT_TEST(CountriesNamesIndex_Smoke) +{ + search::CountriesNamesIndex index; + + { + string const query = ""; + vector results; + index.CollectMatchingCountries(query, results); + TEST(results.empty(), ()); + } + + { + string const query = "Чехия "; + vector results; + index.CollectMatchingCountries(query, results); + TEST_EQUAL(results.size(), 2, (results)); + TEST_EQUAL(results[0], "Czech Republic", ()); + TEST_EQUAL(results[1], "Czech Republic Short", ()); + } + + { + string const query = "Slovenia"; + vector results; + index.CollectMatchingCountries(query, results); + TEST_EQUAL(results.size(), 4, ()); + sort(results.begin(), results.end()); + TEST_EQUAL(results[0], "Slovakia", ()); + TEST_EQUAL(results[1], "Slovenia", ()); + TEST_EQUAL(results[2], "Slovenia_East", ()); + TEST_EQUAL(results[3], "Slovenia_West", ()); + } +} +} // namespace diff --git a/storage/country_tree.hpp b/storage/country_tree.hpp index 5ac61de842d..aa052217cd9 100644 --- a/storage/country_tree.hpp +++ b/storage/country_tree.hpp @@ -104,7 +104,7 @@ class CountryTree Node const * const FindFirst(CountryId const & key) const; /// \brief Find only leaves. - /// \note It's a termprary fucntion for compatablity with old countries.txt. + /// \note It's a temporary 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. diff --git a/xcode/search/search.xcodeproj/project.pbxproj b/xcode/search/search.xcodeproj/project.pbxproj index 64827aa7d7f..8391c0c4c47 100644 --- a/xcode/search/search.xcodeproj/project.pbxproj +++ b/xcode/search/search.xcodeproj/project.pbxproj @@ -88,6 +88,9 @@ 392688CD20B2D1D600721762 /* interval_set_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34586B841DCB1E8300CF7FC9 /* interval_set_test.cpp */; }; 392688CE20B2D1D600721762 /* locality_scorer_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34586B851DCB1E8300CF7FC9 /* locality_scorer_test.cpp */; }; 392688CF20B2D1D600721762 /* locality_selector_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34586B861DCB1E8300CF7FC9 /* locality_selector_test.cpp */; }; + 393472BB25BD8D7400E87F8E /* countries_names_index.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 393472B925BD8D7400E87F8E /* countries_names_index.hpp */; }; + 393472BC25BD8D7400E87F8E /* countries_names_index.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 393472BA25BD8D7400E87F8E /* countries_names_index.cpp */; }; + 393472BE25BD8D8900E87F8E /* countries_names_index_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 393472BD25BD8D8900E87F8E /* countries_names_index_tests.cpp */; }; 3936A60D20EA2F5F00A68C09 /* header.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3936A60520EA2F5E00A68C09 /* header.cpp */; }; 3936A60E20EA2F5F00A68C09 /* header.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3936A60620EA2F5E00A68C09 /* header.hpp */; }; 3936A60F20EA2F5F00A68C09 /* text_index.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3936A60720EA2F5E00A68C09 /* text_index.hpp */; }; @@ -161,8 +164,6 @@ 39BBC1401F9FD683009D1687 /* point_rect_matcher_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39BBC13F1F9FD683009D1687 /* point_rect_matcher_tests.cpp */; }; 39BBC1421F9FD68C009D1687 /* highlighting_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39BBC1411F9FD68C009D1687 /* highlighting_tests.cpp */; }; 3D0AEB021FBB102C00AD042B /* libgenerator_tests_support.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D0AEB041FBB102C00AD042B /* libgenerator_tests_support.a */; }; - 3D0BBB9F23F3FDE100A50354 /* helpers.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D0BBB9D23F3FDE100A50354 /* helpers.hpp */; }; - 3D0BBBA023F3FDE100A50354 /* helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D0BBB9E23F3FDE100A50354 /* helpers.cpp */; }; 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 */; }; @@ -402,6 +403,9 @@ 392688B620B2D1BF00721762 /* results_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = results_tests.cpp; sourceTree = ""; }; 392688B720B2D1BF00721762 /* region_info_getter_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = region_info_getter_tests.cpp; sourceTree = ""; }; 392688B820B2D1BF00721762 /* text_index_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = text_index_tests.cpp; sourceTree = ""; }; + 393472B925BD8D7400E87F8E /* countries_names_index.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = countries_names_index.hpp; sourceTree = ""; }; + 393472BA25BD8D7400E87F8E /* countries_names_index.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = countries_names_index.cpp; sourceTree = ""; }; + 393472BD25BD8D8900E87F8E /* countries_names_index_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = countries_names_index_tests.cpp; sourceTree = ""; }; 3936A60520EA2F5E00A68C09 /* header.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = header.cpp; path = ../text_index/header.cpp; sourceTree = ""; }; 3936A60620EA2F5E00A68C09 /* header.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = header.hpp; path = ../text_index/header.hpp; sourceTree = ""; }; 3936A60720EA2F5E00A68C09 /* text_index.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = text_index.hpp; path = ../text_index/text_index.hpp; sourceTree = ""; }; @@ -449,8 +453,6 @@ 39BBC1411F9FD68C009D1687 /* highlighting_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = highlighting_tests.cpp; sourceTree = ""; }; 3D0AEB041FBB102C00AD042B /* libgenerator_tests_support.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libgenerator_tests_support.a; sourceTree = BUILT_PRODUCTS_DIR; }; 3D0AEB051FBB102C00AD042B /* libindexer_tests_support.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libindexer_tests_support.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 3D0BBB9D23F3FDE100A50354 /* helpers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = helpers.hpp; sourceTree = ""; }; - 3D0BBB9E23F3FDE100A50354 /* helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = helpers.cpp; sourceTree = ""; }; 3DA5722820C1956D007BDE27 /* integration_tests_helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = integration_tests_helpers.cpp; sourceTree = ""; }; 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 = ""; }; @@ -783,6 +785,7 @@ 671C620D1AE9225100076BD0 /* search_tests */ = { isa = PBXGroup; children = ( + 393472BD25BD8D8900E87F8E /* countries_names_index_tests.cpp */, 406B98D9229C3ED90062EBEC /* feature_offset_match_tests.cpp */, 40DF58292170F63E00E4E0FC /* localities_source_tests.cpp */, 392688B420B2D1BF00721762 /* bookmarks_processor_tests.cpp */, @@ -842,6 +845,8 @@ 675346B21A4055CF00A0A8C3 /* search */ = { isa = PBXGroup; children = ( + 393472BA25BD8D7400E87F8E /* countries_names_index.cpp */, + 393472B925BD8D7400E87F8E /* countries_names_index.hpp */, 40DB153023F2B56A00E49602 /* search_index_header.hpp */, 0831F24A200E56100034C365 /* base */, 0831F24D200E56100034C365 /* bookmarks */, @@ -1063,6 +1068,7 @@ 0831F256200E56110034C365 /* results.hpp in Headers */, 56D5456F1C74A48C00E3719C /* mode.hpp in Headers */, 0810EC371D6D9D2E00ABFEE7 /* displayed_categories.hpp in Headers */, + 393472BB25BD8D7400E87F8E /* countries_names_index.hpp in Headers */, 347F332A1C4540A8009758CC /* search_index_values.hpp in Headers */, 39BBC13C1F9FD65C009D1687 /* highlighting.hpp in Headers */, 347F33161C4540A8009758CC /* cancel_exception.hpp in Headers */, @@ -1271,6 +1277,7 @@ 671C621F1AE9227C00076BD0 /* keyword_matcher_test.cpp in Sources */, 392688C720B2D1D600721762 /* text_index_tests.cpp in Sources */, 392688C620B2D1D600721762 /* results_tests.cpp in Sources */, + 393472BE25BD8D8900E87F8E /* countries_names_index_tests.cpp in Sources */, 3974BB901FB471AB00F265E5 /* ranking_tests.cpp in Sources */, 671C62251AE9229A00076BD0 /* testingmain.cpp in Sources */, 671C621D1AE9227C00076BD0 /* house_detector_tests.cpp in Sources */, @@ -1341,6 +1348,7 @@ F652D9061CFDE21900FC29A0 /* ranking_info.cpp in Sources */, 39B2B94B1FB4620200AB85A1 /* ranker_test.cpp in Sources */, 40DF582A2170F63E00E4E0FC /* localities_source_tests.cpp in Sources */, + 393472BC25BD8D7400E87F8E /* countries_names_index.cpp in Sources */, F652D9001CFDE21900FC29A0 /* nested_rects_cache.cpp in Sources */, 3936A61320EA2F5F00A68C09 /* text_index.cpp in Sources */, 3936A61020EA2F5F00A68C09 /* mem.cpp in Sources */,