#pragma once #include "routing/coding.hpp" #include "routing/road_access.hpp" #include "routing/road_point.hpp" #include "routing/segment.hpp" #include "routing/vehicle_mask.hpp" #include "routing_common/num_mwm_id.hpp" #include "coding/bit_streams.hpp" #include "coding/reader.hpp" #include "coding/varint.hpp" #include "coding/write_to_sink.hpp" #include "base/assert.hpp" #include "base/checked_cast.hpp" #include #include #include #include #include #include namespace routing { class RoadAccessSerializer final { public: using RoadAccessTypesFeatureMap = std::unordered_map; using RoadAccessTypesPointMap = std::unordered_map; using RoadAccessByVehicleType = std::array(VehicleType::Count)>; RoadAccessSerializer() = delete; template static void Serialize(Sink & sink, RoadAccessByVehicleType const & roadAccessByType) { uint32_t const header = kLatestVersion; WriteToSink(sink, header); auto const sectionSizesPos = sink.Pos(); std::array(VehicleType::Count)> sectionSizes; for (size_t i = 0; i < sectionSizes.size(); ++i) { sectionSizes[i] = 0; WriteToSink(sink, sectionSizes[i]); } for (size_t i = 0; i < static_cast(VehicleType::Count); ++i) { auto const pos = sink.Pos(); SerializeOneVehicleType(sink, roadAccessByType[i].GetFeatureTypes(), roadAccessByType[i].GetPointTypes()); sectionSizes[i] = base::checked_cast(sink.Pos() - pos); } auto const endPos = sink.Pos(); sink.Seek(sectionSizesPos); for (size_t i = 0; i < sectionSizes.size(); ++i) WriteToSink(sink, sectionSizes[i]); sink.Seek(endPos); } template static void Deserialize(Source & src, VehicleType vehicleType, RoadAccess & roadAccess) { auto const subsectionNumberToVehicleType = [](uint32_t version, size_t subsection) { if (version == 0) { switch (subsection) { case 0: return VehicleType::Pedestrian; case 1: return VehicleType::Bicycle; case 2: return VehicleType::Car; default: return VehicleType::Count; } } return static_cast(subsection); }; uint32_t const header = ReadPrimitiveFromSource(src); std::vector sectionSizes; for (size_t i = 0; subsectionNumberToVehicleType(header, i) < VehicleType::Count; ++i) sectionSizes.push_back(ReadPrimitiveFromSource(src)); for (size_t i = 0; subsectionNumberToVehicleType(header, i) < VehicleType::Count; ++i) { if (vehicleType != subsectionNumberToVehicleType(header, i)) { src.Skip(sectionSizes[i]); continue; } RoadAccessTypesFeatureMap mf; RoadAccessTypesPointMap mp; DeserializeOneVehicleType(src, mf, mp); roadAccess.SetAccessTypes(std::move(mf), std::move(mp)); } } private: template static void SerializeOneVehicleType(Sink & sink, RoadAccessTypesFeatureMap const & mf, RoadAccessTypesPointMap const & mp) { std::array, static_cast(RoadAccess::Type::Count)> segmentsByRoadAccessType; for (auto const & kv : mf) { segmentsByRoadAccessType[static_cast(kv.second)].push_back( Segment(kFakeNumMwmId, kv.first, 0 /* wildcard segmentIdx */, true /* widcard forward */)); } // For nodes we store |pointId + 1| because 0 is reserved for wildcard segmentIdx. for (auto const & kv : mp) { segmentsByRoadAccessType[static_cast(kv.second)].push_back( Segment(kFakeNumMwmId, kv.first.GetFeatureId(), kv.first.GetPointId() + 1, true)); } for (auto & segs : segmentsByRoadAccessType) { std::sort(segs.begin(), segs.end()); SerializeSegments(sink, segs); } } template static void DeserializeOneVehicleType(Source & src, RoadAccessTypesFeatureMap & mf, RoadAccessTypesPointMap & mp) { mf.clear(); mp.clear(); for (size_t i = 0; i < static_cast(RoadAccess::Type::Count); ++i) { // An earlier version allowed blocking any segment of a feature (or the entire feature // by providing a wildcard segment index). // At present, we either block the feature entirely or block any of its road points. The // the serialization code remains the same, although its semantics changes as we now // work with point indices instead of segment indices. std::vector segs; DeserializeSegments(src, segs); for (auto const & seg : segs) { if (seg.GetSegmentIdx() == 0) { // Wildcard segmentIdx. mf[seg.GetFeatureId()] = static_cast(i); } else { // For nodes we store |pointId + 1| because 0 is reserved for wildcard segmentIdx. mp[RoadPoint(seg.GetFeatureId(), seg.GetSegmentIdx() - 1)] = static_cast(i); } } } } // todo(@m) This code borrows heavily from traffic/traffic_info.hpp:SerializeTrafficKeys. template static void SerializeSegments(Sink & sink, std::vector const & segments) { std::vector featureIds(segments.size()); std::vector segmentIndices(segments.size()); std::vector isForward(segments.size()); for (size_t i = 0; i < segments.size(); ++i) { auto const & seg = segments[i]; CHECK_EQUAL(seg.GetMwmId(), kFakeNumMwmId, ("Numeric mwm ids are temporary and must not be serialized.")); featureIds[i] = seg.GetFeatureId(); segmentIndices[i] = seg.GetSegmentIdx(); isForward[i] = seg.IsForward(); } WriteVarUint(sink, segments.size()); { BitWriter bitWriter(sink); uint32_t prevFid = 0; for (auto const fid : featureIds) { CHECK_GREATER_OR_EQUAL(fid, prevFid, ()); uint64_t const fidDiff = static_cast(fid - prevFid); WriteGamma(bitWriter, fidDiff + 1); prevFid = fid; } for (auto const idx : segmentIndices) WriteGamma(bitWriter, idx + 1); for (auto const val : isForward) bitWriter.Write(val ? 1 : 0, 1 /* numBits */); } } template static void DeserializeSegments(Source & src, std::vector & segments) { auto const n = static_cast(ReadVarUint(src)); std::vector featureIds(n); std::vector segmentIndices(n); std::vector isForward(n); BitReader bitReader(src); uint32_t prevFid = 0; for (size_t i = 0; i < n; ++i) { prevFid += ReadGamma(bitReader) - 1; featureIds[i] = prevFid; } for (size_t i = 0; i < n; ++i) segmentIndices[i] = ReadGamma(bitReader) - 1; for (size_t i = 0; i < n; ++i) isForward[i] = bitReader.Read(1) > 0; // Read the padding bits. auto bitsRead = bitReader.BitsRead(); while (bitsRead % CHAR_BIT != 0) { bitReader.Read(1); ++bitsRead; } segments.clear(); segments.reserve(n); for (size_t i = 0; i < n; ++i) segments.emplace_back(kFakeNumMwmId, featureIds[i], segmentIndices[i], isForward[i]); } uint32_t static const kLatestVersion; }; } // namespace routing