#pragma once #include "kml/types_v3.hpp" #include "kml/types_v6.hpp" #include "kml/types_v7.hpp" #include "kml/types_v8.hpp" #include "kml/types.hpp" #include "coding/geometry_coding.hpp" #include "coding/point_coding.hpp" #include "coding/text_storage.hpp" #include "coding/varint.hpp" #include "geometry/mercator.hpp" #include "geometry/point_with_altitude.hpp" #include "base/bits.hpp" #include #include #include namespace kml { template class CollectorVisitor { // The class checks for the existence of collection methods. template class HasCollectionMethods { template static char Test(decltype(&C::ClearCollectionIndex)); template static int Test(...); public: enum {value = sizeof(Test(0)) == sizeof(char)}; }; // All types which will be visited to collect. template class VisitedTypes { public: enum {value = std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value}; }; public: explicit CollectorVisitor(Collector & collector, bool clearIndex = false) : m_collector(collector) , m_clearIndex(clearIndex) {} template std::enable_if_t::value> PerformActionIfPossible(T & t) { if (m_clearIndex) t.ClearCollectionIndex(); else t.Collect(m_collector); } template std::enable_if_t::value> PerformActionIfPossible(T & t) {} template std::enable_if_t::value> VisitIfPossible(T & t) { t.Visit(*this); } template std::enable_if_t::value> VisitIfPossible(T & t) {} template void operator()(T & t, char const * /* name */ = nullptr) { PerformActionIfPossible(t); VisitIfPossible(t); } template void operator()(std::vector & vs, char const * /* name */ = nullptr) { for (auto & v : vs) (*this)(v); } private: Collector & m_collector; bool const m_clearIndex; }; class LocalizableStringCollector { public: explicit LocalizableStringCollector(size_t reservedCollectionSize) { m_collection.reserve(reservedCollectionSize + 1); m_collection.emplace_back(std::string()); } template void Collect(LocalizableStringIndex & index, LocalizableString const & str, OtherStrings const & ... args) { index.emplace_back(LocalizableStringSubIndex()); for (auto const & p : str) CollectString(index.back(), p.first, p.second); Collect(index, args...); } template void Collect(LocalizableStringIndex & index, std::string const & str, OtherStrings const & ... args) { int8_t constexpr kFakeIndex = 0; index.emplace_back(LocalizableStringSubIndex()); CollectString(index.back(), kFakeIndex, str); Collect(index, args...); } template void Collect(LocalizableStringIndex & index, std::vector const & stringsArray, OtherStrings const & ... args) { index.emplace_back(LocalizableStringSubIndex()); auto constexpr kMaxSize = static_cast(std::numeric_limits::max()); auto const sz = std::min(stringsArray.size(), kMaxSize); for (size_t i = 0; i < sz; ++i) CollectString(index.back(), static_cast(i), stringsArray[i]); Collect(index, args...); } template void Collect(LocalizableStringIndex & index, Properties const & properties, OtherStrings const & ... args) { index.emplace_back(LocalizableStringSubIndex()); auto constexpr kMaxSize = std::numeric_limits::max() - 1; int8_t counter = 0; for (auto const & p : properties) { if (counter >= kMaxSize) break; CollectString(index.back(), counter++, p.first); CollectString(index.back(), counter++, p.second); } Collect(index, args...); } template void Collect(LocalizableStringIndex & index) {} std::vector && StealCollection() { return std::move(m_collection); } private: void CollectString(LocalizableStringSubIndex & subIndex, int8_t code, std::string const & str) { if (str.empty()) { subIndex.insert(std::make_pair(code, kEmptyStringId)); } else { subIndex.insert(std::make_pair(code, m_counter)); m_counter++; m_collection.push_back(str); } } uint32_t m_counter = kEmptyStringId + 1; std::vector m_collection; }; namespace binary { template void WriteLocalizableStringIndex(Sink & sink, LocalizableStringIndex const & index) { WriteVarUint(sink, static_cast(index.size())); for (auto const & subIndex : index) { WriteVarUint(sink, static_cast(subIndex.size())); for (auto const & p : subIndex) { WriteToSink(sink, p.first); WriteVarUint(sink, p.second); } } } template void ReadLocalizableStringIndex(Source & source, LocalizableStringIndex & index) { auto const indexSize = ReadVarUint(source); index.reserve(indexSize); for (uint32_t i = 0; i < indexSize; ++i) { index.emplace_back(LocalizableStringSubIndex()); auto & subIndex = index.back(); auto const subIndexSize = ReadVarUint(source); for (uint32_t j = 0; j < subIndexSize; ++j) { auto const lang = ReadPrimitiveFromSource(source); auto const strIndex = ReadVarUint(source); subIndex[lang] = strIndex; } } } template inline void WritePointU(Sink & sink, m2::PointU const & pt) { WriteVarUint(sink, pt.x); WriteVarUint(sink, pt.y); } template inline void WritePointD(Sink & sink, m2::PointD const & pt, uint8_t doubleBits) { WritePointU(sink, PointDToPointU(pt, doubleBits)); } template inline m2::PointU ReadPointU(Source & source) { auto x = ReadVarUint(source); auto y = ReadVarUint(source); return {x, y}; } template inline m2::PointD ReadPointD(Source & source, uint8_t doubleBits) { return PointUToPointD(ReadPointU(source), doubleBits); } template class CategorySerializerVisitor { public: explicit CategorySerializerVisitor(Sink & sink, uint8_t doubleBits) : m_sink(sink) , m_doubleBits(doubleBits) {} void operator()(LocalizableStringIndex const & index, char const * /* name */ = nullptr) { WriteLocalizableStringIndex(m_sink, index); } void operator()(bool b, char const * /* name */ = nullptr) { (*this)(static_cast(b)); } void operator()(AccessRules rules, char const * /* name */ = nullptr) { (*this)(static_cast(rules)); } void operator()(CompilationType type, char const * /* name */ = nullptr) { (*this)(static_cast(type)); } void operator()(Timestamp const & t, char const * /* name */ = nullptr) { WriteVarUint(m_sink, ToSecondsSinceEpoch(t)); } void operator()(double d, char const * /* name */ = nullptr) { auto const encoded = DoubleToUint32(d, kMinRating, kMaxRating, m_doubleBits); WriteVarUint(m_sink, encoded); } void operator()(m2::PointD const & pt, char const * /* name */ = nullptr) { WritePointD(m_sink, pt, m_doubleBits); } void operator()(CategoryData const & compilationData, char const * /* name */ = nullptr) { compilationData.Visit(*this); } template void operator()(std::vector const & vs, char const * /* name */ = nullptr) { WriteVarUint(m_sink, static_cast(vs.size())); for (auto const & v : vs) (*this)(v); } template std::enable_if_t::value> operator()(D d, char const * /* name */ = nullptr) { WriteToSink(m_sink, d); } template std::enable_if_t::value> operator()(R const & r, char const * /* name */ = nullptr) { r.Visit(*this); } // Skip visiting. It is stored in the separate sections. SKIP_VISITING(LocalizableString const &) SKIP_VISITING(std::string const &) SKIP_VISITING(std::vector const &) SKIP_VISITING(Properties const &) SKIP_VISITING(std::vector const &) SKIP_VISITING(std::vector const &) private: Sink & m_sink; uint8_t const m_doubleBits; }; template class BookmarkSerializerVisitor { public: explicit BookmarkSerializerVisitor(Sink & sink, uint8_t doubleBits) : m_sink(sink) , m_doubleBits(doubleBits) {} void operator()(LocalizableStringIndex const & index, char const * /* name */ = nullptr) { WriteLocalizableStringIndex(m_sink, index); } void operator()(bool b, char const * /* name */ = nullptr) { (*this)(static_cast(b)); } void operator()(m2::PointD const & pt, char const * /* name */ = nullptr) { WritePointD(m_sink, pt, m_doubleBits); } void operator()(geometry::PointWithAltitude const & pt, char const * /* name */ = nullptr) { WritePointD(m_sink, pt.GetPoint(), m_doubleBits); WriteVarInt(m_sink, pt.GetAltitude()); } void operator()(double d, char const * /* name */ = nullptr) { auto const encoded = DoubleToUint32(d, kMinLineWidth, kMaxLineWidth, m_doubleBits); WriteVarUint(m_sink, encoded); } void operator()(Timestamp const & t, char const * name = nullptr) { WriteVarUint(m_sink, ToSecondsSinceEpoch(t)); } void operator()(PredefinedColor color, char const * /* name */ = nullptr) { (*this)(static_cast(color)); } void operator()(BookmarkIcon icon, char const * /* name */ = nullptr) { (*this)(static_cast(icon)); } template void operator()(std::vector const & vs, char const * /* name */ = nullptr) { WriteVarUint(m_sink, static_cast(vs.size())); for (auto const & v : vs) (*this)(v); } void operator()(std::vector const & points, char const * /* name */ = nullptr) { WriteVarUint(m_sink, static_cast(points.size())); m2::PointU lastUpt = m2::PointU::Zero(); for (uint32_t i = 0; i < static_cast(points.size()); ++i) { auto const upt = PointDToPointU(points[i], m_doubleBits); coding::EncodePointDelta(m_sink, lastUpt, upt); lastUpt = upt; } } void operator()(std::vector const & points, char const * /* name */ = nullptr) { WriteVarUint(m_sink, static_cast(points.size())); m2::PointU lastUpt = m2::PointU::Zero(); for (auto const & point : points) { auto const upt = PointDToPointU(point.GetPoint(), m_doubleBits); coding::EncodePointDelta(m_sink, lastUpt, upt); lastUpt = upt; } geometry::Altitude lastAltitude = geometry::kDefaultAltitudeMeters; for (auto const & point : points) { WriteVarInt(m_sink, point.GetAltitude() - lastAltitude); lastAltitude = point.GetAltitude(); } } template std::enable_if_t::value> operator()(D d, char const * /* name */ = nullptr) { WriteToSink(m_sink, d); } template std::enable_if_t::value> operator()(R const & r, char const * /* name */ = nullptr) { r.Visit(*this); } // Skip visiting. It is stored in the separate sections. SKIP_VISITING(LocalizableString const &) SKIP_VISITING(std::string const &) SKIP_VISITING(std::vector const &) SKIP_VISITING(Properties const &) private: Sink & m_sink; uint8_t const m_doubleBits; }; template class CategoryDeserializerVisitor { public: explicit CategoryDeserializerVisitor(Source & source, uint8_t doubleBits) : m_source(source) , m_doubleBits(doubleBits) {} void operator()(LocalizableStringIndex & index, char const * /* name */ = nullptr) { ReadLocalizableStringIndex(m_source, index); } void operator()(bool & b, char const * /* name */ = nullptr) { b = static_cast(ReadPrimitiveFromSource(m_source)); } void operator()(AccessRules & rules, char const * /* name */ = nullptr) { rules = static_cast(ReadPrimitiveFromSource(m_source)); } void operator()(CompilationType & type, char const * /* name */ = nullptr) { type = static_cast(ReadPrimitiveFromSource(m_source)); } void operator()(Timestamp & t, char const * /* name */ = nullptr) { auto const v = ReadVarUint(m_source); t = FromSecondsSinceEpoch(v); } void operator()(double & d, char const * /* name */ = nullptr) { auto const v = ReadVarUint(m_source); d = Uint32ToDouble(v, kMinRating, kMaxRating, m_doubleBits); } void operator()(m2::PointD & pt, char const * /* name */ = nullptr) { pt = ReadPointD(m_source, m_doubleBits); } void operator()(CategoryData & compilationData, char const * /* name */ = nullptr) { compilationData.Visit(*this); } template void operator()(std::vector & vs, char const * /* name */ = nullptr) { auto const sz = ReadVarUint(m_source); vs.reserve(sz); for (uint32_t i = 0; i < sz; ++i) { vs.emplace_back(T()); (*this)(vs.back()); } } template std::enable_if_t::value> operator()(D & d, char const * /* name */ = nullptr) { d = ReadPrimitiveFromSource(m_source); } template std::enable_if_t::value> operator()(R & r, char const * /* name */ = nullptr) { r.Visit(*this); } // Skip visiting. It is stored in the separate sections. SKIP_VISITING(LocalizableString &) SKIP_VISITING(std::string &) SKIP_VISITING(std::vector &) SKIP_VISITING(Properties &) SKIP_VISITING(std::vector &) SKIP_VISITING(std::vector &) private: Source & m_source; uint8_t const m_doubleBits; }; template class BookmarkDeserializerVisitor { public: explicit BookmarkDeserializerVisitor(Source & source, uint8_t doubleBits) : m_source(source) , m_doubleBits(doubleBits) {} void operator()(LocalizableStringIndex & index, char const * /* name */ = nullptr) { ReadLocalizableStringIndex(m_source, index); } void operator()(bool & b, char const * /* name */ = nullptr) { b = static_cast(ReadPrimitiveFromSource(m_source)); } void operator()(m2::PointD & pt, char const * /* name */ = nullptr) { pt = ReadPointD(m_source, m_doubleBits); } void operator()(geometry::PointWithAltitude & pt, char const * /* name */ = nullptr) { pt.SetPoint(ReadPointD(m_source, m_doubleBits)); pt.SetAltitude(ReadVarInt(m_source)); } void operator()(double & d, char const * /* name */ = nullptr) { auto const v = ReadVarUint(m_source); d = Uint32ToDouble(v, kMinLineWidth, kMaxLineWidth, m_doubleBits); } void operator()(Timestamp & t, char const * /* name */ = nullptr) { auto const v = ReadVarUint(m_source); t = FromSecondsSinceEpoch(v); } void operator()(PredefinedColor & color, char const * /* name */ = nullptr) { color = static_cast(ReadPrimitiveFromSource(m_source)); } void operator()(AccessRules & rules, char const * /* name */ = nullptr) { rules = static_cast(ReadPrimitiveFromSource(m_source)); } void operator()(BookmarkIcon & icon, char const * /* name */ = nullptr) { icon = static_cast(ReadPrimitiveFromSource(m_source)); } template void operator()(std::vector & vs, char const * /* name */ = nullptr) { auto const sz = ReadVarUint(m_source); vs.reserve(sz); for (uint32_t i = 0; i < sz; ++i) { vs.emplace_back(T()); (*this)(vs.back()); } } void operator()(std::vector & points, char const * /* name */ = nullptr) { auto const sz = ReadVarUint(m_source); points.reserve(sz); m2::PointU lastUpt = m2::PointU::Zero(); for (uint32_t i = 0; i < sz; ++i) { lastUpt = coding::DecodePointDelta(m_source, lastUpt); points.emplace_back(PointUToPointD(lastUpt, m_doubleBits)); } } void operator()(std::vector & points, char const * /* name */ = nullptr) { auto const sz = ReadVarUint(m_source); points.reserve(sz); m2::PointU lastUpt = m2::PointU::Zero(); for (uint32_t i = 0; i < sz; ++i) { lastUpt = coding::DecodePointDelta(m_source, lastUpt); points.emplace_back(PointUToPointD(lastUpt, m_doubleBits), geometry::kDefaultAltitudeMeters); } geometry::Altitude lastAltitude = geometry::kDefaultAltitudeMeters; for (auto & point : points) { point.SetAltitude(lastAltitude + ReadVarInt(m_source)); lastAltitude = point.GetAltitude(); } } template std::enable_if_t::value> operator()(D & d, char const * /* name */ = nullptr) { d = ReadPrimitiveFromSource(m_source); } template std::enable_if_t::value> operator()(R & r, char const * /* name */ = nullptr) { r.Visit(*this); } // Skip visiting. It is stored in the separate sections. SKIP_VISITING(LocalizableString &) SKIP_VISITING(std::string &) SKIP_VISITING(std::vector &) SKIP_VISITING(Properties &) private: Source & m_source; uint8_t const m_doubleBits; }; template class DeserializedStringCollector { public: explicit DeserializedStringCollector(coding::BlockedTextStorage & textStorage) : m_textStorage(textStorage) {} template void Collect(LocalizableStringIndex & index, LocalizableString & str, OtherStrings & ... args) { if (!SwitchSubIndexIfNeeded(index)) return; auto subIndex = index[m_counter]; for (auto const & p : subIndex) str[p.first] = ExtractString(p.second); m_counter++; Collect(index, args...); } template void Collect(LocalizableStringIndex & index, std::string & str, OtherStrings & ... args) { if (!SwitchSubIndexIfNeeded(index)) return; auto subIndex = index[m_counter]; if (!subIndex.empty()) str = ExtractString(subIndex.begin()->second); else str = {}; m_counter++; Collect(index, args...); } template void Collect(LocalizableStringIndex & index, std::vector & stringsArray, OtherStrings & ... args) { if (!SwitchSubIndexIfNeeded(index)) return; auto subIndex = index[m_counter]; stringsArray.reserve(subIndex.size()); for (auto const & p : subIndex) stringsArray.emplace_back(ExtractString(p.second)); m_counter++; Collect(index, args...); } template void Collect(LocalizableStringIndex & index, Properties & properties, OtherStrings & ... args) { if (!SwitchSubIndexIfNeeded(index)) return; auto subIndex = index[m_counter]; auto const sz = static_cast(subIndex.size() / 2); for (int8_t i = 0; i < sz; i++) { properties.insert(std::make_pair(ExtractString(subIndex[2 * i]), ExtractString(subIndex[2 * i + 1]))); } m_counter++; Collect(index, args...); } template void Collect(LocalizableStringIndex & index) {} private: bool SwitchSubIndexIfNeeded(LocalizableStringIndex & index) { if (m_lastIndex != &index) { m_counter = 0; m_lastIndex = &index; } return m_counter < index.size(); } std::string ExtractString(uint32_t stringIndex) const { auto const stringsCount = m_textStorage.GetNumStrings(); if (stringIndex >= stringsCount) return {}; return m_textStorage.ExtractString(stringIndex); } coding::BlockedTextStorage & m_textStorage; LocalizableStringIndex * m_lastIndex = nullptr; size_t m_counter = 0; }; } // namespace binary } // namespace kml