diff --git a/defines.hpp b/defines.hpp index e061d7db4c..6ee4147f35 100644 --- a/defines.hpp +++ b/defines.hpp @@ -29,6 +29,7 @@ #define INDEX_FILE_TAG "idx" #define SEARCH_INDEX_FILE_TAG "sdx" #define SEARCH_ADDRESS_FILE_TAG "addr" +#define POSTCODE_POINTS_FILE_TAG "postcodes" #define CITIES_BOUNDARIES_FILE_TAG "cities_boundaries" #define FEATURE_TO_OSM_FILE_TAG "feature_to_osm" #define HEADER_FILE_TAG "header" diff --git a/generator/generator_tests_support/test_mwm_builder.cpp b/generator/generator_tests_support/test_mwm_builder.cpp index 2784b83200..53068a69f7 100644 --- a/generator/generator_tests_support/test_mwm_builder.cpp +++ b/generator/generator_tests_support/test_mwm_builder.cpp @@ -17,6 +17,8 @@ #include "indexer/index_builder.hpp" #include "indexer/rank_table.hpp" +#include "storage/country_info_getter.hpp" + #include "platform/local_country_file.hpp" #include "coding/internal/file_data.hpp" @@ -110,6 +112,13 @@ bool TestMwmBuilder::Add(FeatureBuilder & fb) return true; } +void TestMwmBuilder::SetPostcodesData(string const & datasetPath, + shared_ptr countryInfoGetter) +{ + m_postcodesDataset = datasetPath; + m_postcodesCountryInfoGetter = countryInfoGetter; +} + void TestMwmBuilder::SetMwmLanguages(vector const & languages) { m_languages = languages; @@ -141,6 +150,14 @@ void TestMwmBuilder::Finish() CHECK(indexer::BuildSearchIndexFromDataFile(path, true /* forceRebuild */, 1 /* threadsCount */), ("Can't build search index.")); + if (!m_postcodesDataset.empty() && m_postcodesCountryInfoGetter) + { + CHECK(indexer::BuildPostcodesWithInfoGetter(m_file.GetDirectory(), m_file.GetCountryName(), + m_postcodesDataset, true /* forceRebuild */, + *m_postcodesCountryInfoGetter), + ("Can't build postcodes section.")); + } + if (m_type == DataHeader::MapType::World) { CHECK(generator::BuildCitiesBoundariesForTesting(path, m_boundariesTable), ()); diff --git a/generator/generator_tests_support/test_mwm_builder.hpp b/generator/generator_tests_support/test_mwm_builder.hpp index d43b8fc223..8ba54e7722 100644 --- a/generator/generator_tests_support/test_mwm_builder.hpp +++ b/generator/generator_tests_support/test_mwm_builder.hpp @@ -19,6 +19,10 @@ namespace platform { class LocalCountryFile; } +namespace storage +{ +class CountryInfoGetter; +} namespace generator { namespace tests_support @@ -35,6 +39,8 @@ public: void Add(TestFeature const & feature); bool Add(feature::FeatureBuilder & fb); + void SetPostcodesData(std::string const & datasetPath, + std::shared_ptr countryInfoGetter); void SetMwmLanguages(std::vector const & languages); void Finish(); @@ -45,6 +51,8 @@ private: std::vector m_languages; std::unique_ptr m_collector; TestIdToBoundariesTable m_boundariesTable; + std::shared_ptr m_postcodesCountryInfoGetter; + std::string m_postcodesDataset; uint32_t m_version = 0; }; } // namespace tests_support diff --git a/generator/generator_tool/generator_tool.cpp b/generator/generator_tool/generator_tool.cpp index 8a0da57462..02cda90232 100644 --- a/generator/generator_tool/generator_tool.cpp +++ b/generator/generator_tool/generator_tool.cpp @@ -166,6 +166,8 @@ DEFINE_string(popular_places_data, "", DEFINE_string(brands_data, "", "Path to json with OSM objects to brand ID map."); DEFINE_string(brands_translations_data, "", "Path to json with brands translations and synonyms."); +DEFINE_string(postcodes_dataset, "", "Path to dataset with postcodes data"); + // Printing stuff. DEFINE_bool(calc_statistics, false, "Calculate feature statistics for specified mwm bucket files."); DEFINE_bool(type_statistics, false, "Calculate statistics by type for specified mwm bucket files."); @@ -380,7 +382,15 @@ int GeneratorToolMain(int argc, char ** argv) /// @todo Make threads count according to environment (single mwm build or planet build). if (!indexer::BuildSearchIndexFromDataFile(datFile, true /* forceRebuild */, 1 /* threadsCount */)) + { LOG(LCRITICAL, ("Error generating search index.")); + } + + if (!FLAGS_postcodes_dataset.empty()) + { + if (!indexer::BuildPostcodes(path, country, FLAGS_postcodes_dataset, true /*forceRebuild*/)) + LOG(LCRITICAL, ("Error generating postcodes section.")); + } LOG(LINFO, ("Generating rank table for", datFile)); if (!search::SearchRankTableBuilder::CreateIfNotExists(datFile)) diff --git a/generator/search_index_builder.cpp b/generator/search_index_builder.cpp index 36d42ff271..63e1e349e9 100644 --- a/generator/search_index_builder.cpp +++ b/generator/search_index_builder.cpp @@ -2,6 +2,7 @@ #include "search/common.hpp" #include "search/mwm_context.hpp" +#include "search/postcode_points.hpp" #include "search/reverse_geocoder.hpp" #include "search/search_index_values.hpp" #include "search/search_trie.hpp" @@ -21,7 +22,8 @@ #include "indexer/search_string_utils.hpp" #include "indexer/trie_builder.hpp" -#include "defines.hpp" +#include "storage/country_info_getter.hpp" +#include "storage/storage_defines.hpp" #include "platform/platform.hpp" @@ -29,6 +31,8 @@ #include "coding/reader_writer_ops.hpp" #include "coding/writer.hpp" +#include "geometry/mercator.hpp" + #include "base/assert.hpp" #include "base/checked_cast.hpp" #include "base/file_name_utils.hpp" @@ -46,6 +50,8 @@ #include #include +#include "defines.hpp" + using namespace std; #define SYNONYMS_FILE "synonyms.txt" @@ -235,6 +241,63 @@ struct FeatureNameInserter bool m_hasStreetType = false; }; +template +void GetUKPostcodes(string const & filename, storage::CountryId const & countryId, + storage::CountryInfoGetter & infoGetter, vector & valueMapping, + vector> & keyValuePairs) +{ + if (filename.empty()) + return; + + // ,,,,,,<2+6 NGR>,, + size_t constexpr kOutwardIndex = 0; + size_t constexpr kInwardIndex = 1; + size_t constexpr kLatIndex = 4; + size_t constexpr kLonIndex = 5; + size_t constexpr kDatasetCount = 9; + + ifstream data(filename); + string line; + size_t index = 0; + while (getline(data, line)) + { + // Skip comments. + if (line[0] == '#') + continue; + + vector fields; + strings::ParseCSVRow(line, ',', fields); + // Some lines have comma in "source". It leads to fields number greater than kDatasetCount. + CHECK_GREATER_OR_EQUAL(fields.size(), kDatasetCount, (line)); + + // Skip outward-only postcodes, build outward from inwards. + if (fields[kInwardIndex].empty()) + continue; + + double lon; + CHECK(strings::to_double(fields[kLonIndex], lon), ()); + auto const x = MercatorBounds::LonToX(lon); + + double lat; + CHECK(strings::to_double(fields[kLatIndex], lat), ()); + auto const y = MercatorBounds::LatToY(lat); + + vector countries; + infoGetter.GetRegionsCountryId(m2::PointD(x, y), countries); + if (find(countries.begin(), countries.end(), countryId) == countries.end()) + continue; + + CHECK_EQUAL(valueMapping.size(), index, ()); + valueMapping.push_back(m2::PointD(x, y)); + keyValuePairs.emplace_back( + search::NormalizeAndSimplifyString(fields[kOutwardIndex] + " " + fields[kInwardIndex]), + Value(index)); + keyValuePairs.emplace_back(search::NormalizeAndSimplifyString(fields[kOutwardIndex]), + Value(index)); + ++index; + } +} + template class FeatureInserter { @@ -487,6 +550,11 @@ void BuildAddressTable(FilesContainerR & container, Writer & writer, uint32_t th namespace indexer { +void BuildSearchIndex(FilesContainerR & container, Writer & indexWriter); +bool BuildPostcodesImpl(FilesContainerR & container, storage::CountryId const & country, + string const & dataset, std::string const & tmpFileName, + storage::CountryInfoGetter & infoGetter, Writer & indexWriter); + bool BuildSearchIndexFromDataFile(string const & filename, bool forceRebuild, uint32_t threadsCount) { Platform & platform = GetPlatform(); @@ -555,6 +623,125 @@ bool BuildSearchIndexFromDataFile(string const & filename, bool forceRebuild, ui return true; } +bool BuildPostcodesWithInfoGetter(string const & path, string const & country, + string const & datasetPath, bool forceRebuild, + storage::CountryInfoGetter & infoGetter) +{ + auto const filename = base::JoinPath(path, country + DATA_FILE_EXTENSION); + Platform & platform = GetPlatform(); + + FilesContainerR readContainer(platform.GetReader(filename, "f")); + if (readContainer.IsExist(POSTCODE_POINTS_FILE_TAG) && !forceRebuild) + return true; + + string const postcodesFilePath = filename + "." + POSTCODE_POINTS_FILE_TAG EXTENSION_TMP; + // Temporary file used to reverse trie part of postcodes section. + string const trieTmpFilePath = + filename + "." + POSTCODE_POINTS_FILE_TAG + "_trie" + EXTENSION_TMP; + SCOPE_GUARD(postcodesFileGuard, bind(&FileWriter::DeleteFileX, postcodesFilePath)); + SCOPE_GUARD(trieTmpFileGuard, bind(&FileWriter::DeleteFileX, trieTmpFilePath)); + + if (filename == WORLD_FILE_NAME || filename == WORLD_COASTS_FILE_NAME) + return true; + + try + { + FileWriter writer(postcodesFilePath); + if (!BuildPostcodesImpl(readContainer, storage::CountryId(country), datasetPath, + trieTmpFilePath, infoGetter, writer)) + { + // No postcodes for country. + return true; + } + + LOG(LINFO, ("Postcodes section size =", writer.Size())); + FilesContainerW writeContainer(readContainer.GetFileName(), FileWriter::OP_WRITE_EXISTING); + writeContainer.Write(postcodesFilePath, POSTCODE_POINTS_FILE_TAG); + } + catch (Reader::Exception const & e) + { + LOG(LERROR, ("Error while reading file:", e.Msg())); + return false; + } + catch (Writer::Exception const & e) + { + LOG(LERROR, ("Error writing file:", e.Msg())); + return false; + } + + return true; +} + +bool BuildPostcodes(string const & path, string const & country, string const & datasetPath, + bool forceRebuild) +{ + auto const & platform = GetPlatform(); + auto infoGetter = storage::CountryInfoReader::CreateCountryInfoReader(platform); + CHECK(infoGetter, ()); + return BuildPostcodesWithInfoGetter(path, country, datasetPath, forceRebuild, *infoGetter); +} + +bool BuildPostcodesImpl(FilesContainerR & container, storage::CountryId const & country, + string const & dataset, string const & tmpName, + storage::CountryInfoGetter & infoGetter, Writer & writer) +{ + using Key = strings::UniString; + using Value = FeatureIndexValue; + + search::PostcodePoints::Header header; + + auto const startOffset = writer.Pos(); + header.Serialize(writer); + + auto alighmentSize = (8 - (writer.Pos() % 8) % 8); + WriteZeroesToSink(writer, alighmentSize); + + header.m_trieOffset = base::asserted_cast(writer.Pos() - startOffset); + + vector> ukPostcodesKeyValuePairs; + vector valueMapping; + GetUKPostcodes(dataset, country, infoGetter, valueMapping, ukPostcodesKeyValuePairs); + + if (ukPostcodesKeyValuePairs.empty()) + return false; + + sort(ukPostcodesKeyValuePairs.begin(), ukPostcodesKeyValuePairs.end()); + + { + FileWriter tmpWriter(tmpName); + SingleValueSerializer serializer; + trie::Build, SingleValueSerializer>( + tmpWriter, serializer, ukPostcodesKeyValuePairs); + } + + rw_ops::Reverse(FileReader(tmpName), writer); + + header.m_trieSize = + base::asserted_cast(writer.Pos() - header.m_trieOffset - startOffset); + + alighmentSize = (8 - (writer.Pos() % 8) % 8); + WriteZeroesToSink(writer, alighmentSize); + + header.m_pointsOffset = base::asserted_cast(writer.Pos() - startOffset); + + { + search::CentersTableBuilder builder; + builder.SetGeometryCodingParams(feature::DataHeader(container).GetDefGeometryCodingParams()); + for (size_t i = 0; i < valueMapping.size(); ++i) + builder.Put(base::asserted_cast(i), valueMapping[i]); + + builder.Freeze(writer); + } + + header.m_pointsSize = + base::asserted_cast(writer.Pos() - header.m_pointsOffset - startOffset); + auto const endOffset = writer.Pos(); + writer.Seek(startOffset); + header.Serialize(writer); + writer.Seek(endOffset); + return true; +} + void BuildSearchIndex(FilesContainerR & container, Writer & indexWriter) { using Key = strings::UniString; diff --git a/generator/search_index_builder.hpp b/generator/search_index_builder.hpp index 7ea1f6ff9d..54ef7f9822 100644 --- a/generator/search_index_builder.hpp +++ b/generator/search_index_builder.hpp @@ -2,8 +2,10 @@ #include -class FilesContainerR; -class Writer; +namespace storage +{ +class CountryInfoGetter; +} namespace indexer { @@ -14,5 +16,11 @@ namespace indexer bool BuildSearchIndexFromDataFile(std::string const & filename, bool forceRebuild, uint32_t threadsCount); -void BuildSearchIndex(FilesContainerR & container, Writer & indexWriter); +// Builds postcodes section with external postcodes data and writes it to the mwm file. +bool BuildPostcodes(std::string const & path, std::string const & country, + std::string const & datasetPath, bool forceRebuild); +// Exposed for testing. +bool BuildPostcodesWithInfoGetter(std::string const & path, std::string const & country, + std::string const & datasetPath, bool forceRebuild, + storage::CountryInfoGetter & infoGetter); } // namespace indexer diff --git a/search/CMakeLists.txt b/search/CMakeLists.txt index 3b74bca969..079d1943e4 100644 --- a/search/CMakeLists.txt +++ b/search/CMakeLists.txt @@ -115,6 +115,8 @@ set( nested_rects_cache.cpp nested_rects_cache.hpp point_rect_matcher.hpp + postcode_points.cpp + postcode_points.hpp pre_ranker.cpp pre_ranker.hpp pre_ranking_info.cpp diff --git a/search/postcode_points.cpp b/search/postcode_points.cpp new file mode 100644 index 0000000000..03f1082f58 --- /dev/null +++ b/search/postcode_points.cpp @@ -0,0 +1,87 @@ +#include "search/postcode_points.hpp" + +#include "indexer/trie_reader.hpp" + +#include "coding/reader_wrapper.hpp" + +#include "geometry/mercator.hpp" + +#include "base/checked_cast.hpp" +#include "base/string_utils.hpp" + +#include +#include + +#include "defines.hpp" + +using namespace std; + +namespace search +{ +void PostcodePoints::Header::Read(Reader & reader) +{ + NonOwningReaderSource source(reader); + CHECK_EQUAL(static_cast(m_version), static_cast(Version::V0), ()); + m_version = static_cast(ReadPrimitiveFromSource(source)); + CHECK_EQUAL(static_cast(m_version), static_cast(Version::V0), ()); + m_trieOffset = ReadPrimitiveFromSource(source); + m_trieSize = ReadPrimitiveFromSource(source); + m_pointsOffset = ReadPrimitiveFromSource(source); + m_pointsSize = ReadPrimitiveFromSource(source); +} + +PostcodePoints::PostcodePoints(MwmValue const & value) +{ + auto reader = value.m_cont.GetReader(POSTCODE_POINTS_FILE_TAG); + m_header.Read(*reader.GetPtr()); + + m_trieSubReader = reader.GetPtr()->CreateSubReader(m_header.m_trieOffset, m_header.m_trieSize); + m_root = trie::ReadTrie, ValueList>( + SubReaderWrapper(m_trieSubReader.get()), SingleValueSerializer()); + CHECK(m_root, ()); + + m_pointsSubReader = + reader.GetPtr()->CreateSubReader(m_header.m_pointsOffset, m_header.m_pointsSize); + auto const codingParams = value.GetHeader().GetDefGeometryCodingParams(); + m_points = CentersTable::Load(*m_pointsSubReader, codingParams); + CHECK(m_points, ()); +} + +void PostcodePoints::Get(TokenSlice const & tokens, vector & points) const +{ + if (!m_root || !m_points || !m_trieSubReader || !m_pointsSubReader || tokens.Size() == 0) + return; + + strings::UniString postcode = tokens.Get(0).GetOriginal(); + auto const space = strings::MakeUniString(" "); + for (size_t i = 1; i < tokens.Size(); ++i) + postcode += space + tokens.Get(i).GetOriginal(); + + auto postcodeIt = postcode.begin(); + auto trieIt = m_root->Clone(); + + while (postcodeIt != postcode.end()) + { + auto it = find_if(trieIt->m_edges.begin(), trieIt->m_edges.end(), [&](auto const & edge) { + return strings::StartsWith(postcodeIt, postcode.end(), edge.m_label.begin(), + edge.m_label.end()); + }); + if (it == trieIt->m_edges.end()) + return; + trieIt = trieIt->GoToEdge(distance(trieIt->m_edges.begin(), it)); + postcodeIt += it->m_label.size(); + } + + if (postcodeIt != postcode.end()) + return; + + vector indexes; + trieIt->m_values.ForEach([&indexes](auto const & v) { + indexes.push_back(base::asserted_cast(v.m_featureId)); + }); + + points.resize(indexes.size()); + for (size_t i = 0; i < indexes.size(); ++i) + CHECK(m_points->Get(indexes[i], points[i]), ()); +} +} // namespace search diff --git a/search/postcode_points.hpp b/search/postcode_points.hpp new file mode 100644 index 0000000000..8f289f92fc --- /dev/null +++ b/search/postcode_points.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include "search/mwm_context.hpp" +#include "search/search_index_values.hpp" +#include "search/token_slice.hpp" + +#include "indexer/centers_table.hpp" +#include "indexer/mwm_set.hpp" +#include "indexer/trie.hpp" + +#include "coding/reader.hpp" +#include "coding/write_to_sink.hpp" + +#include "geometry/point2d.hpp" + +#include +#include +#include + +namespace search +{ +class PostcodePoints +{ +public: + enum class Version : uint8_t + { + V0 = 0, + Latest = V0 + }; + + struct Header + { + template + void Serialize(Sink & sink) const + { + CHECK_EQUAL(static_cast(m_version), static_cast(Version::V0), ()); + WriteToSink(sink, static_cast(m_version)); + WriteToSink(sink, m_trieOffset); + WriteToSink(sink, m_trieSize); + WriteToSink(sink, m_pointsOffset); + WriteToSink(sink, m_pointsSize); + } + + void Read(Reader & reader); + + Version m_version = Version::V0; + uint32_t m_trieOffset; + uint32_t m_trieSize; + uint32_t m_pointsOffset; + uint32_t m_pointsSize; + }; + + PostcodePoints(MwmValue const & value); + + void Get(TokenSlice const & tokens, std::vector & points) const; + +private: + Header m_header; + std::unique_ptr m_points; + std::unique_ptr>> m_root; + std::unique_ptr m_trieSubReader; + std::unique_ptr m_pointsSubReader; +}; +} // namespace search diff --git a/search/search_integration_tests/CMakeLists.txt b/search/search_integration_tests/CMakeLists.txt index 652d155ac6..71d4e0fed6 100644 --- a/search/search_integration_tests/CMakeLists.txt +++ b/search/search_integration_tests/CMakeLists.txt @@ -4,6 +4,7 @@ set( SRC downloader_search_test.cpp generate_tests.cpp + postcode_points_tests.cpp pre_ranker_test.cpp processor_test.cpp ranker_test.cpp @@ -20,6 +21,7 @@ omim_link_libraries( search_tests_support editor_tests_support generator_tests_support + platform_tests_support generator routing routing_common diff --git a/search/search_integration_tests/postcode_points_tests.cpp b/search/search_integration_tests/postcode_points_tests.cpp new file mode 100644 index 0000000000..f19b172f5a --- /dev/null +++ b/search/search_integration_tests/postcode_points_tests.cpp @@ -0,0 +1,114 @@ +#include "testing/testing.hpp" + +#include "search/postcode_points.hpp" +#include "search/query_params.hpp" +#include "search/search_tests_support/helpers.hpp" +#include "search/utils.hpp" + +#include "generator/generator_tests_support/test_mwm_builder.hpp" + +#include "storage/country_info_getter.hpp" + +#include "indexer/search_string_utils.hpp" + +#include "platform/platform.hpp" +#include "platform/platform_tests_support/scoped_file.hpp" + +#include "coding/point_coding.hpp" + +#include "base/file_name_utils.hpp" +#include "base/math.hpp" +#include "base/stl_helpers.hpp" +#include "base/string_utils.hpp" + +#include +#include +#include +#include + +using namespace generator::tests_support; +using namespace platform::tests_support; +using namespace search::tests_support; +using namespace search; +using namespace std; + +namespace +{ +class PostcodePointsTest : public SearchTest +{ +}; + +TokenSlice GetSlice(string const & query, QueryParams & params) +{ + search::Delimiters delims; + + vector tokens; + SplitUniString(NormalizeAndSimplifyString(query), base::MakeBackInsertFunctor(tokens), delims); + params.InitNoPrefix(tokens.begin(), tokens.end()); + + TokenRange tokenRange(0, tokens.size()); + return TokenSlice(params, tokenRange); +} + +UNIT_CLASS_TEST(PostcodePointsTest, Smoke) +{ + string const countryName = "Wonderland"; + + Platform & platform = GetPlatform(); + auto const & writableDir = platform.WritableDir(); + string const testFile = "postcodes.csv"; + auto const postcodesRelativePath = base::JoinPath(writableDir, testFile); + + // ,,,,,,<2+6 NGR>,, + ScopedFile const osmScopedFile(testFile, + "aa11, 0, dummy, dummy, 0.0, 0.0, dummy, dummy, dummy\n" + "aa11, 1, dummy, dummy, 0.1, 0.1, dummy, dummy, dummy\n" + "aa11, 2, dummy, dummy, 0.2, 0.2, dummy, dummy, dummy\n"); + + auto infoGetter = std::make_shared(); + infoGetter->AddCountry( + storage::CountryDef(countryName, m2::RectD(m2::PointD(-1.0, -1.0), m2::PointD(1.0, 1.0)))); + + auto const id = BuildCountry(countryName, [&](TestMwmBuilder & builder) { + builder.SetPostcodesData(postcodesRelativePath, infoGetter); + }); + + auto handle = m_dataSource.GetMwmHandleById(id); + auto value = handle.GetValue(); + CHECK(value, ()); + TEST(value->m_cont.IsExist(POSTCODE_POINTS_FILE_TAG), ()); + + PostcodePoints p(*value); + { + vector points; + QueryParams params; + p.Get(GetSlice("aa11 0", params), points); + TEST_EQUAL(points.size(), 1, ()); + TEST(base::AlmostEqualAbs(points[0], m2::PointD(0.0, 0.0), kMwmPointAccuracy), ()); + } + { + vector points; + QueryParams params; + p.Get(GetSlice("aa11 1", params), points); + TEST_EQUAL(points.size(), 1, ()); + TEST(base::AlmostEqualAbs(points[0], m2::PointD(0.1, 0.1), kMwmPointAccuracy), ()); + } + { + vector points; + QueryParams params; + p.Get(GetSlice("aa11 2", params), points); + TEST_EQUAL(points.size(), 1, ()); + TEST(base::AlmostEqualAbs(points[0], m2::PointD(0.2, 0.2), kMwmPointAccuracy), ()); + } + { + vector points; + QueryParams params; + p.Get(GetSlice("aa11", params), points); + TEST_EQUAL(points.size(), 3, ()); + sort(points.begin(), points.end()); + TEST(base::AlmostEqualAbs(points[0], m2::PointD(0.0, 0.0), kMwmPointAccuracy), ()); + TEST(base::AlmostEqualAbs(points[1], m2::PointD(0.1, 0.1), kMwmPointAccuracy), ()); + TEST(base::AlmostEqualAbs(points[2], m2::PointD(0.2, 0.2), kMwmPointAccuracy), ()); + } +} +} // namespace diff --git a/xcode/search/search.xcodeproj/project.pbxproj b/xcode/search/search.xcodeproj/project.pbxproj index 0afacd6627..372dbd02e7 100644 --- a/xcode/search/search.xcodeproj/project.pbxproj +++ b/xcode/search/search.xcodeproj/project.pbxproj @@ -169,6 +169,9 @@ 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 */; }; 40DF582A2170F63E00E4E0FC /* localities_source_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 40DF58292170F63E00E4E0FC /* localities_source_tests.cpp */; }; + 40EAD7DF2329310B0025013B /* postcode_points.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 40EAD7DD2329310A0025013B /* postcode_points.hpp */; }; + 40EAD7E02329310B0025013B /* postcode_points.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 40EAD7DE2329310B0025013B /* postcode_points.cpp */; }; + 40EAD7E2232931420025013B /* postcode_points_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 40EAD7E1232931410025013B /* postcode_points_tests.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 */; }; @@ -436,6 +439,9 @@ 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 = ""; }; 40DF58292170F63E00E4E0FC /* localities_source_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = localities_source_tests.cpp; sourceTree = ""; }; + 40EAD7DD2329310A0025013B /* postcode_points.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = postcode_points.hpp; sourceTree = ""; }; + 40EAD7DE2329310B0025013B /* postcode_points.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = postcode_points.cpp; sourceTree = ""; }; + 40EAD7E1232931410025013B /* postcode_points_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = postcode_points_tests.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 = ""; }; @@ -713,6 +719,7 @@ 39B387691FB4609700964D61 /* search_integration_tests */ = { isa = PBXGroup; children = ( + 40EAD7E1232931410025013B /* postcode_points_tests.cpp */, 405DB10620FF472300EE3824 /* utils_test.cpp */, 39B2B94E1FB4620800AB85A1 /* smoke_test.cpp */, 39B2B94D1FB4620800AB85A1 /* tracer_tests.cpp */, @@ -899,6 +906,8 @@ F652D8D91CFDE21900FC29A0 /* nested_rects_cache.cpp */, F652D8DA1CFDE21900FC29A0 /* nested_rects_cache.hpp */, 39AEF8371FB4597E00943FC9 /* point_rect_matcher.hpp */, + 40EAD7DE2329310B0025013B /* postcode_points.cpp */, + 40EAD7DD2329310A0025013B /* postcode_points.hpp */, F659FC6B1CF4A30B000A06B1 /* pre_ranker.cpp */, F659FC6C1CF4A30B000A06B1 /* pre_ranker.hpp */, F652D8DB1CFDE21900FC29A0 /* pre_ranking_info.cpp */, @@ -984,6 +993,7 @@ 3461C9A51D79949600E6E6F5 /* utils.hpp in Headers */, 345C8DB01D2D15A50037E3A6 /* cbv.hpp in Headers */, F652D90C1CFDE21900FC29A0 /* street_vicinity_loader.hpp in Headers */, + 40EAD7DF2329310B0025013B /* postcode_points.hpp in Headers */, F652D9011CFDE21900FC29A0 /* nested_rects_cache.hpp in Headers */, 670F88751CE4C032003F68BA /* types_skipper.hpp in Headers */, 0831F254200E56110034C365 /* inverted_list.hpp in Headers */, @@ -1256,6 +1266,7 @@ 34586B8C1DCB1E8300CF7FC9 /* locality_scorer_test.cpp in Sources */, 34EEAD721E55AE5C00E95575 /* utils.cpp in Sources */, 345C8DB11D2D15A50037E3A6 /* geocoder_context.cpp in Sources */, + 40EAD7E2232931420025013B /* postcode_points_tests.cpp in Sources */, 39B2B9491FB4620200AB85A1 /* pre_ranker_test.cpp in Sources */, 3461C9A31D79949600E6E6F5 /* editor_delegate.cpp in Sources */, 39BBC13B1F9FD65C009D1687 /* highlighting.cpp in Sources */, @@ -1285,6 +1296,7 @@ 675346F11A40560D00A0A8C3 /* result.cpp in Sources */, F652D8C11CFDE1E800FC29A0 /* features_filter.cpp in Sources */, 39B2B94A1FB4620200AB85A1 /* processor_test.cpp in Sources */, + 40EAD7E02329310B0025013B /* postcode_points.cpp in Sources */, F652D8F81CFDE21900FC29A0 /* intersection_result.cpp in Sources */, 34586B891DCB1E8300CF7FC9 /* hotels_filter_test.cpp in Sources */, 453C623C2004BABE00467120 /* region_info_getter.cpp in Sources */,