#pragma once #include "transit/transit_types.hpp" #include "geometry/point2d.hpp" #include "coding/geometry_coding.hpp" #include "coding/point_to_integer.hpp" #include "coding/pointd_to_pointu.hpp" #include "coding/read_write_utils.hpp" #include "coding/reader.hpp" #include "coding/varint.hpp" #include "coding/write_to_sink.hpp" #include "base/assert.hpp" #include "base/exception.hpp" #include "base/macros.hpp" #include "base/newtype.hpp" #include #include #include #include #include #include #include namespace routing { namespace transit { // Note. For the time being double in transit section is used only for saving weight of edges (in seconds). // Let us assume that it takes less than 10^7 seconds (115 days) to get from one station to a neighboring one. double constexpr kMinDoubleAtTransitSection = kInvalidWeight; double constexpr kMaxDoubleAtTransitSection = 10000000.0; uint32_t constexpr kDoubleBits = 32; template class Serializer { public: explicit Serializer(Sink & sink) : m_sink(sink) {} template std::enable_if_t<(std::is_integral::value || std::is_enum::value) && !std::is_same::value && !std::is_same::value && !std::is_same::value && !std::is_same::value> operator()(T const & t, char const * /* name */ = nullptr) { WriteToSink(m_sink, t); } template std::enable_if_t::value || std::is_same::value> operator()( T t, char const * /* name */ = nullptr) const { WriteVarUint(m_sink, t); } template std::enable_if_t::value || std::is_same::value> operator()( T t, char const * name = nullptr) const { WriteVarInt(m_sink, t); } template std::enable_if_t::value || std::is_same::value> operator()( T d, char const * name = nullptr) { CHECK_GREATER_OR_EQUAL(d, kMinDoubleAtTransitSection, ()); CHECK_LESS_OR_EQUAL(d, kMaxDoubleAtTransitSection, ()); (*this)(DoubleToUint32(d, kMinDoubleAtTransitSection, kMaxDoubleAtTransitSection, kDoubleBits), name); } void operator()(std::string const & s, char const * /* name */ = nullptr) { rw::Write(m_sink, s); } void operator()(m2::PointD const & p, char const * /* name */ = nullptr) { WriteVarInt(m_sink, PointToInt64Obsolete(p, POINT_COORD_BITS)); } void operator()(std::vector const & vs, char const * /* name */ = nullptr) { CHECK_LESS_OR_EQUAL(vs.size(), std::numeric_limits::max(), ()); WriteVarUint(m_sink, static_cast(vs.size())); m2::PointU lastEncodedPoint; for (auto const & p : vs) { m2::PointU const pointU = PointDToPointU(p, POINT_COORD_BITS); WriteVarUint(m_sink, coding::EncodePointDeltaAsUint(pointU, lastEncodedPoint)); lastEncodedPoint = pointU; } } void operator()(Edge::WrappedEdgeId const & id, char const * /* name */ = nullptr) { CHECK_GREATER_OR_EQUAL(id.Get(), m_lastWrappedEdgeId.Get(), ()); WriteVarUint(m_sink, static_cast(id.Get() - m_lastWrappedEdgeId.Get())); m_lastWrappedEdgeId = id; } void operator()(Stop::WrappedStopId const & id, char const * /* name */ = nullptr) { CHECK_GREATER_OR_EQUAL(id.Get(), m_lastWrappedStopId.Get(), ()); WriteVarUint(m_sink, static_cast(id.Get() - m_lastWrappedStopId.Get())); m_lastWrappedStopId = id; } void operator()(FeatureIdentifiers const & id, char const * name = nullptr) { if (id.IsSerializeFeatureIdOnly()) (*this)(id.GetFeatureId(), name); else id.Visit(*this); } void operator()(Edge const & e, char const * /* name */ = nullptr) { (*this)(e.m_stop1Id); (*this)(e.m_stop2Id); (*this)(e.m_weight); (*this)(e.m_lineId); // Note. |Edge::m_flags| is not filled fully after deserialization from json. // So it's necessary to fill it here. EdgeFlags const flags = GetEdgeFlags(e.GetTransfer(), e.GetStop1Id(), e.GetStop2Id(), e.GetShapeIds()); (*this)(flags); if (flags.m_isShapeIdsEmpty || flags.m_isShapeIdsSame || flags.m_isShapeIdsReversed) return; if (flags.m_isShapeIdsSingle) { CHECK_EQUAL(e.GetShapeIds().size(), 1, ()); (*this)(e.GetShapeIds()[0]); return; } (*this)(e.GetShapeIds()); } void operator()(EdgeFlags const & f, char const * /* name */ = nullptr) { (*this)(f.GetFlags()); } template void operator()(std::vector const & vs, char const * /* name */ = nullptr) { CHECK_LESS_OR_EQUAL(vs.size(), std::numeric_limits::max(), ()); WriteVarUint(m_sink, static_cast(vs.size())); for (auto const & v : vs) (*this)(v); } template std::enable_if_t::value> operator()(T const & t, char const * /* name */ = nullptr) { t.Visit(*this); } private: Sink & m_sink; Edge::WrappedEdgeId m_lastWrappedEdgeId = {}; Stop::WrappedStopId m_lastWrappedStopId = {}; }; template class Deserializer { public: explicit Deserializer(Source & source) : m_source(source) {} template std::enable_if_t<(std::is_integral::value || std::is_enum::value) && !std::is_same::value && !std::is_same::value && !std::is_same::value && !std::is_same::value> operator()(T & t, char const * name = nullptr) { ReadPrimitiveFromSource(m_source, t); } template std::enable_if_t::value || std::is_same::value> operator()( T & t, char const * name = nullptr) { t = ReadVarUint(m_source); } template std::enable_if_t::value || std::is_same::value> operator()( T & t, char const * name = nullptr) { t = ReadVarInt(m_source); } template std::enable_if_t::value || std::is_same::value> operator()( T & d, char const * name = nullptr) { uint32_t ui; (*this)(ui, name); d = Uint32ToDouble(ui, kMinDoubleAtTransitSection, kMaxDoubleAtTransitSection, kDoubleBits); } void operator()(std::string & s, char const * /* name */ = nullptr) { rw::Read(m_source, s); } void operator()(m2::PointD & p, char const * /* name */ = nullptr) { p = Int64ToPointObsolete(ReadVarInt(m_source), POINT_COORD_BITS); } void operator()(Edge::WrappedEdgeId & id, char const * /* name */ = nullptr) { id = m_lastWrappedEdgeId + Edge::WrappedEdgeId(ReadVarUint(m_source)); m_lastWrappedEdgeId = id; } void operator()(Stop::WrappedStopId & id, char const * /* name */ = nullptr) { id = m_lastWrappedStopId + Stop::WrappedStopId(ReadVarUint(m_source)); m_lastWrappedStopId = id; } void operator()(FeatureIdentifiers & id, char const * name = nullptr) { if (id.IsSerializeFeatureIdOnly()) { FeatureId featureId; operator()(featureId, name); id.SetOsmId(kInvalidOsmId); id.SetFeatureId(featureId); return; } id.Visit(*this); } void operator()(Edge & e, char const * name = nullptr) { (*this)(e.m_stop1Id); (*this)(e.m_stop2Id); (*this)(e.m_weight); (*this)(e.m_lineId); (*this)(e.m_flags); e.m_shapeIds.clear(); if (e.m_flags.m_isShapeIdsEmpty) return; if (e.m_flags.m_isShapeIdsSame) { e.m_shapeIds.emplace_back(e.GetStop1Id(), e.GetStop2Id()); return; } if (e.m_flags.m_isShapeIdsReversed) { e.m_shapeIds.emplace_back(e.GetStop2Id(), e.GetStop1Id()); return; } if (e.m_flags.m_isShapeIdsSingle) { e.m_shapeIds.resize(1 /* single shape id */); (*this)(e.m_shapeIds.back()); return; } (*this)(e.m_shapeIds); } void operator()(EdgeFlags & f, char const * /* name */ = nullptr) { uint8_t flags = 0; (*this)(flags); f.SetFlags(flags); } void operator()(vector & vs, char const * /* name */ = nullptr) { auto const size = ReadVarUint(m_source); m2::PointU lastDecodedPoint; vs.resize(size); for (auto & p : vs) { m2::PointU const pointU = coding::DecodePointDeltaFromUint( ReadVarUint(m_source), lastDecodedPoint); p = PointUToPointD(pointU, POINT_COORD_BITS); lastDecodedPoint = pointU; } } template void operator()(vector & vs, char const * /* name */ = nullptr) { auto const size = ReadVarUint(m_source); vs.resize(size); for (auto & v : vs) (*this)(v); } template std::enable_if_t::value> operator()(T & t, char const * /* name */ = nullptr) { t.Visit(*this); } private: Source & m_source; Edge::WrappedEdgeId m_lastWrappedEdgeId = {}; Stop::WrappedStopId m_lastWrappedStopId = {}; }; template class FixedSizeSerializer { public: explicit FixedSizeSerializer(Sink & sink) : m_sink(sink) {} template std::enable_if_t::value || std::is_enum::value, void> operator()( T const & t, char const * /* name */ = nullptr) { WriteToSink(m_sink, t); } void operator()(TransitHeader const & header) { header.Visit(*this); } private: Sink & m_sink; }; template class FixedSizeDeserializer { public: explicit FixedSizeDeserializer(Source & source) : m_source(source) {} template std::enable_if_t::value || std::is_enum::value, void> operator()( T & t, char const * name = nullptr) { ReadPrimitiveFromSource(m_source, t); } void operator()(TransitHeader & header) { header.Visit(*this); } private: Source & m_source; }; } // namespace transit } // namespace routing