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..3c739b8b48a 100644 --- a/search/downloader_search_callback.cpp +++ b/search/downloader_search_callback.cpp @@ -2,17 +2,17 @@ #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 @@ -66,6 +66,18 @@ void DownloaderSearchCallback::operator()(search::Results const & results) for (auto const & result : results) { + if (result.GetResultType() == search::Result::Type::DownloaderEntry) + { + storage::DownloaderSearchResult downloaderResult(result.GetCountryId(), + 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 +110,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..00c58388292 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, "" /* 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 */,