diff --git a/generator/search_index_builder.cpp b/generator/search_index_builder.cpp index bf15531086..7c78dd7d2c 100644 --- a/generator/search_index_builder.cpp +++ b/generator/search_index_builder.cpp @@ -1,6 +1,7 @@ #include "generator/search_index_builder.hpp" #include "search/common.hpp" +#include "search/house_to_street_table.hpp" #include "search/mwm_context.hpp" #include "search/reverse_geocoder.hpp" #include "search/search_index_values.hpp" @@ -491,7 +492,7 @@ void BuildAddressTable(FilesContainerR & container, string const & addressDataFi // Flush results to disk. { // Code corresponds to the HouseToStreetTable decoding. - MapUint32ToValueBuilder builder; + search::HouseToStreetTableBuilder builder; uint32_t houseToStreetCount = 0; for (size_t i = 0; i < results.size(); ++i) { @@ -502,22 +503,7 @@ void BuildAddressTable(FilesContainerR & container, string const & addressDataFi } } - // Each street id is encoded as delta from some prediction. - // First street id in the block encoded as VarUint, all other street ids in the block - // encoded as VarInt delta from previous id. - auto const writeBlockCallback = [&](Writer & w, vector::const_iterator begin, - vector::const_iterator end) { - CHECK(begin != end, ("MapUint32ToValueBuilder should guarantee begin != end.")); - WriteVarUint(w, *begin); - auto prevIt = begin; - for (auto it = begin + 1; it != end; ++it) - { - int32_t const delta = base::asserted_cast(*it) - *prevIt; - WriteVarInt(w, delta); - prevIt = it; - } - }; - builder.Freeze(writer, writeBlockCallback); + builder.Freeze(writer); LOG(LINFO, ("Address: BuildingToStreet entries count:", houseToStreetCount)); } diff --git a/platform/mwm_traits.cpp b/platform/mwm_traits.cpp index 6ad953a2e4..935d529f56 100644 --- a/platform/mwm_traits.cpp +++ b/platform/mwm_traits.cpp @@ -16,6 +16,9 @@ MwmTraits::SearchIndexFormat MwmTraits::GetSearchIndexFormat() const MwmTraits::HouseToStreetTableFormat MwmTraits::GetHouseToStreetTableFormat() const { + if (GetFormat() >= version::Format::v10) + return HouseToStreetTableFormat::EliasFanoMapWithHeader; + if (GetFormat() < version::Format::v7) return HouseToStreetTableFormat::Unknown; @@ -80,6 +83,8 @@ std::string DebugPrint(MwmTraits::HouseToStreetTableFormat format) return "Fixed3BitsDDVector"; case MwmTraits::HouseToStreetTableFormat::EliasFanoMap: return "EliasFanoMap"; + case MwmTraits::HouseToStreetTableFormat::EliasFanoMapWithHeader: + return "EliasFanoMapWithHeader"; case MwmTraits::HouseToStreetTableFormat::Unknown: return "Unknown"; } diff --git a/platform/mwm_traits.hpp b/platform/mwm_traits.hpp index 405b0ef889..54c85b5702 100644 --- a/platform/mwm_traits.hpp +++ b/platform/mwm_traits.hpp @@ -37,6 +37,10 @@ public: // Elias-Fano based map from feature id to corresponding street feature id. EliasFanoMap, + // Elias-Fano based map from feature id to corresponding street feature id + // with srction header and version. + EliasFanoMapWithHeader, + // The format of relation is unknown. Most likely, an error has occured. Unknown }; diff --git a/search/house_to_street_table.cpp b/search/house_to_street_table.cpp index 2f02484758..91211fc216 100644 --- a/search/house_to_street_table.cpp +++ b/search/house_to_street_table.cpp @@ -4,17 +4,22 @@ #include "platform/mwm_traits.hpp" +#include "coding/files_container.hpp" #include "coding/fixed_bits_ddvector.hpp" #include "coding/map_uint32_to_val.hpp" #include "coding/reader.hpp" +#include "coding/varint.hpp" +#include "coding/write_to_sink.hpp" +#include "coding/writer.hpp" #include "base/assert.hpp" #include "base/checked_cast.hpp" - -#include +#include "base/logging.hpp" #include "defines.hpp" +#include + using namespace std; namespace search @@ -49,10 +54,10 @@ class EliasFanoMap : public HouseToStreetTable public: using Map = MapUint32ToValue; - explicit EliasFanoMap(MwmValue const & value) : m_reader(unique_ptr()) + explicit EliasFanoMap(unique_ptr reader) : m_reader(move(reader)) { - auto const readBlockCallback = [&](NonOwningReaderSource & source, uint32_t blockSize, - vector & values) { + ASSERT(m_reader, ()); + auto readBlockCallback = [](auto & source, uint32_t blockSize, vector & values) { CHECK_GREATER(blockSize, 0, ()); values.resize(blockSize); values[0] = ReadVarUint(source); @@ -66,10 +71,7 @@ public: } }; - m_reader = value.m_cont.GetReader(SEARCH_ADDRESS_FILE_TAG); - ASSERT(m_reader.GetPtr(), ("Can't get", SEARCH_ADDRESS_FILE_TAG, "section reader.")); - - m_map = Map::Load(*m_reader.GetPtr(), readBlockCallback); + m_map = Map::Load(*m_reader, readBlockCallback); ASSERT(m_map.get(), ("Can't instantiate MapUint32ToValue.")); } @@ -82,7 +84,7 @@ public: StreetIdType GetStreetIdType() const override { return StreetIdType::FeatureId; } private: - FilesContainerR::TReader m_reader; + unique_ptr m_reader; unique_ptr m_map; }; @@ -95,6 +97,18 @@ public: }; } // namespace +// HouseToStreetTable::Header --------------------------------------------------------------------- +void HouseToStreetTable::Header::Read(Reader & reader) +{ + NonOwningReaderSource source(reader); + m_version = static_cast(ReadPrimitiveFromSource(source)); + CHECK_EQUAL(static_cast(m_version), static_cast(Version::V2), ()); + m_tableOffset = ReadPrimitiveFromSource(source); + m_tableSize = ReadPrimitiveFromSource(source); +} + +// HouseToStreetTable ------------------------------------------------------------------------------ +// static unique_ptr HouseToStreetTable::Load(MwmValue const & value) { version::MwmTraits traits(value.GetMwmVersion()); @@ -105,9 +119,28 @@ unique_ptr HouseToStreetTable::Load(MwmValue const & value) try { if (format == version::MwmTraits::HouseToStreetTableFormat::Fixed3BitsDDVector) + { result = make_unique(value); + } if (format == version::MwmTraits::HouseToStreetTableFormat::EliasFanoMap) - result = make_unique(value); + { + FilesContainerR::TReader reader = value.m_cont.GetReader(SEARCH_ADDRESS_FILE_TAG); + ASSERT(reader.GetPtr(), ("Can't get", SEARCH_ADDRESS_FILE_TAG, "section reader.")); + result = make_unique(unique_ptr(reader.GetPtr())); + } + if (format == version::MwmTraits::HouseToStreetTableFormat::EliasFanoMapWithHeader) + { + FilesContainerR::TReader reader = value.m_cont.GetReader(SEARCH_ADDRESS_FILE_TAG); + ASSERT(reader.GetPtr(), ("Can't get", SEARCH_ADDRESS_FILE_TAG, "section reader.")); + + Header header; + header.Read(*reader.GetPtr()); + CHECK(header.m_version == Version::V2, (base::Underlying(header.m_version))); + + auto subreader = (*reader.GetPtr()).CreateSubReader(header.m_tableOffset, header.m_tableSize); + CHECK(subreader, ()); + result = make_unique(move(subreader)); + } } catch (Reader::OpenException const & ex) { @@ -119,4 +152,46 @@ unique_ptr HouseToStreetTable::Load(MwmValue const & value) return result; } +// HouseToStreetTableBuilder ----------------------------------------------------------------------- +void HouseToStreetTableBuilder::Put(uint32_t houseId, uint32_t streetId) +{ + m_builder.Put(houseId, streetId); +} + +void HouseToStreetTableBuilder::Freeze(Writer & writer) const +{ + size_t startOffset = writer.Pos(); + CHECK(coding::IsAlign8(startOffset), ()); + + HouseToStreetTable::Header header; + header.Serialize(writer); + + uint64_t bytesWritten = writer.Pos(); + coding::WritePadding(writer, bytesWritten); + + // Each street id is encoded as delta from some prediction. + // First street id in the block encoded as VarUint, all other street ids in the block + // encoded as VarInt delta from previous id + auto const writeBlockCallback = [](auto & w, auto begin, auto end) { + CHECK(begin != end, ("MapUint32ToValueBuilder should guarantee begin != end.")); + WriteVarUint(w, *begin); + auto prevIt = begin; + for (auto it = begin + 1; it != end; ++it) + { + int32_t const delta = base::asserted_cast(*it) - *prevIt; + WriteVarInt(w, delta); + prevIt = it; + } + }; + + header.m_tableOffset = base::asserted_cast(writer.Pos() - startOffset); + m_builder.Freeze(writer, writeBlockCallback); + header.m_tableSize = + base::asserted_cast(writer.Pos() - header.m_tableOffset - startOffset); + + auto const endOffset = writer.Pos(); + writer.Seek(startOffset); + header.Serialize(writer); + writer.Seek(endOffset); +} } // namespace search diff --git a/search/house_to_street_table.hpp b/search/house_to_street_table.hpp index 049776b7d5..85a5f10d9b 100644 --- a/search/house_to_street_table.hpp +++ b/search/house_to_street_table.hpp @@ -1,15 +1,28 @@ #pragma once +#include "coding/map_uint32_to_val.hpp" + #include #include +#include class MwmValue; +class Reader; +class Writer; namespace search { class HouseToStreetTable { public: + enum class Version : uint8_t + { + V0 = 0, + V1 = 1, + V2 = 2, + Latest = V2 + }; + enum class StreetIdType { // Table stores the index number of the correct street corresponding @@ -21,6 +34,25 @@ public: None }; + struct Header + { + template + void Serialize(Sink & sink) const + { + CHECK_EQUAL(static_cast(m_version), static_cast(Version::V2), ()); + WriteToSink(sink, static_cast(m_version)); + WriteToSink(sink, m_tableOffset); + WriteToSink(sink, m_tableSize); + } + + void Read(Reader & reader); + + Version m_version = Version::Latest; + // All offsets are relative to the start of the section (offset of header is zero). + uint32_t m_tableOffset = 0; + uint32_t m_tableSize = 0; + }; + virtual ~HouseToStreetTable() = default; /// @todo Actually, value may be nullptr in the very common case. @@ -34,4 +66,14 @@ public: virtual StreetIdType GetStreetIdType() const = 0; }; + +class HouseToStreetTableBuilder +{ +public: + void Put(uint32_t featureId, uint32_t offset); + void Freeze(Writer & writer) const; + +private: + MapUint32ToValueBuilder m_builder; +}; } // namespace search