From 289c4d10d83bafe3a0ac0a7c1a3af4ff80d85728 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Fri, 29 Sep 2017 11:50:49 +0300 Subject: [PATCH] Using visitors for serialization, deserialization, deserialization from json and debug print. And some review fixes. --- generator/generator_tests/CMakeLists.txt | 1 + generator/generator_tests/generator_tests.pro | 3 + generator/generator_tests/transit_test.cpp | 69 ++++++ generator/transit_generator.cpp | 208 +++++++----------- generator/transit_generator.hpp | 64 ++++++ routing_common/CMakeLists.txt | 7 +- routing_common/routing_common.pro | 5 +- .../routing_common_tests/transit_test.cpp | 16 +- routing_common/transit_header.hpp | 64 ------ routing_common/transit_serdes.cpp | 13 ++ routing_common/transit_serdes.hpp | 136 ++++++++++++ routing_common/transit_stop.cpp | 33 --- routing_common/transit_stop.hpp | 74 ------- .../{transit_header.cpp => transit_types.cpp} | 33 ++- routing_common/transit_types.hpp | 64 +++++- .../generator_tool.xcodeproj/project.pbxproj | 4 + .../routing_common.xcodeproj/project.pbxproj | 29 ++- 17 files changed, 475 insertions(+), 348 deletions(-) create mode 100644 generator/generator_tests/transit_test.cpp delete mode 100644 routing_common/transit_header.hpp create mode 100644 routing_common/transit_serdes.cpp create mode 100644 routing_common/transit_serdes.hpp delete mode 100644 routing_common/transit_stop.cpp delete mode 100644 routing_common/transit_stop.hpp rename routing_common/{transit_header.cpp => transit_types.cpp} (60%) diff --git a/generator/generator_tests/CMakeLists.txt b/generator/generator_tests/CMakeLists.txt index ca06c008e6..332be172fa 100644 --- a/generator/generator_tests/CMakeLists.txt +++ b/generator/generator_tests/CMakeLists.txt @@ -21,6 +21,7 @@ set( srtm_parser_test.cpp tag_admixer_test.cpp tesselator_test.cpp + transit_test.cpp triangles_tree_coding_test.cpp types_helper.hpp ugc_test.cpp diff --git a/generator/generator_tests/generator_tests.pro b/generator/generator_tests/generator_tests.pro index 2384daa0ba..6b917cd00c 100644 --- a/generator/generator_tests/generator_tests.pro +++ b/generator/generator_tests/generator_tests.pro @@ -23,6 +23,8 @@ win32*|linux* { QT *= network } +INCLUDEPATH += $$ROOT_DIR/3party/jansson/src + HEADERS += \ source_data.hpp \ types_helper.hpp \ @@ -47,5 +49,6 @@ SOURCES += \ srtm_parser_test.cpp \ tag_admixer_test.cpp \ tesselator_test.cpp \ + transit_test.cpp \ triangles_tree_coding_test.cpp \ ugc_test.cpp \ diff --git a/generator/generator_tests/transit_test.cpp b/generator/generator_tests/transit_test.cpp new file mode 100644 index 0000000000..05968af0c6 --- /dev/null +++ b/generator/generator_tests/transit_test.cpp @@ -0,0 +1,69 @@ +#include "testing/testing.hpp" + +#include "generator/transit_generator.hpp" + +#include "routing_common/transit_types.hpp" + +#include "base/assert.hpp" + +#include +#include + +using namespace routing; +using namespace routing::transit; +using namespace std; + +namespace +{ +UNIT_TEST(DeserializerFromJson_Stops) +{ + string const jsonBuffer = R"( + { + "stops": [{ + "id": 343259523, + "line_ids": [ + 19207936, + 19207937 + ], + "osm_id": 1234, + "point": { + "x": 27.4970954, + "y": 64.20146835878187 + }, + "title_anchors": [] + }, + { + "id": 266680843, + "transfer_id" : 5, + "line_ids": [ + 19213568, + 19213569 + ], + "osm_id": 2345, + "point": { + "x": 27.5227942, + "y": 64.25206634443111 + }, + "title_anchors": [] + } + ]})"; + + my::Json root(jsonBuffer.c_str()); + CHECK(root.get() != nullptr, ("Cannot parse the json.")); + + DeserializerFromJson deserializer(root.get()); + + vector stops; + deserializer(stops, "stops"); + + vector const expected = { + Stop(343259523 /* id */, 1234 /* featureId */, kTransferIdInvalid /* transfer id */, + {19207936, 19207937} /* lineIds */, {27.4970954, 64.20146835878187} /* point */), + Stop(266680843 /* id */, 2345 /* featureId */, 5 /* transfer id */, + {19213568, 19213569} /* lineIds */, {27.5227942, 64.25206634443111} /* point */)}; + + TEST_EQUAL(stops.size(), expected.size(), ()); + for (size_t i = 0; i < stops.size(); ++i) + TEST(stops[i].IsEqualForTesting(expected[i]), (stops[i], "is not equal to", expected[i])); +} +} // namespace diff --git a/generator/transit_generator.cpp b/generator/transit_generator.cpp index 66777aa967..d4934441db 100644 --- a/generator/transit_generator.cpp +++ b/generator/transit_generator.cpp @@ -2,8 +2,8 @@ #include "generator/osm_id.hpp" -#include "routing_common/transit_header.hpp" -#include "routing_common/transit_stop.hpp" +#include "routing_common/transit_serdes.hpp" +#include "routing_common/transit_types.hpp" #include "coding/file_container.hpp" #include "coding/file_name_utils.hpp" @@ -11,6 +11,7 @@ #include "platform/platform.hpp" +#include "base/checked_cast.hpp" #include "base/logging.hpp" #include "base/macros.hpp" @@ -24,52 +25,6 @@ namespace using namespace routing; using namespace routing::transit; -/// \brief Fills Stop instance based on a json field. |node| should point at jansson item at -/// array: -/// "stops": [ -/// { -/// "id": 343259523, -/// "line_ids": [ -/// 19207936, -/// 19207937 -/// ], -/// "osm_id": 4611686018770647427, -/// "point": { -/// "x": 27.4970954, -/// "y": 64.20146835878187 -/// }, -/// "title_anchors": [] -/// }, -/// ... -/// ] -void ReadJsonArrayItem(json_struct_t * node, Stop & stop) -{ - json_t * idItem = my::GetJSONObligatoryField(node, "id"); - StopId id; - FromJSON(idItem, id); - - json_t * osmIdItem = my::GetJSONObligatoryField(node, "osm_id"); - json_int_t osmId; - FromJSON(osmIdItem, osmId); - // @TODO(bykoianko) |osmId| should be converted to feature id here. - FeatureId const featureId = 0; - - vector lineIds; - FromJSONObject(node, "line_ids", lineIds); - - json_t * pointItem = my::GetJSONObligatoryField(node, "point"); - CHECK(json_is_object(pointItem), ()); - json_t * xItem = my::GetJSONObligatoryField(pointItem, "x"); - m2::PointD point; - FromJSON(xItem, point.x); - json_t * yItem = my::GetJSONObligatoryField(pointItem, "y"); - FromJSON(yItem, point.y); - - stop = Stop(id, featureId, lineIds, point); -} - -// @TODO(bykoianko) ReadJsonArrayItem(...) methods for the other transit graph structures should be added here. - /// \returns file name without extension by a file path if a file name which have zero, one of several extensions. /// For example, /// GetFileName("Russia_Nizhny Novgorod Oblast.transit.json") returns "Russia_Nizhny Novgorod Oblast" @@ -90,18 +45,17 @@ string GetFileName(string const & filePath) return name; } -template -void SerializeObject(my::Json const & root, string const & key, Sink & sink) +/// \brief Reads from |root| (json) and serialize an array to |serializer|. +template +void SerializeObject(my::Json const & root, string const & key, Serializer & serializer) { - json_t const * const stops = json_object_get(root.get(), key.c_str()); - CHECK(stops, ()); - size_t const sz = json_array_size(stops); - for (size_t i = 0; i < sz; ++i) - { - Item item; - ReadJsonArrayItem(json_array_get(stops, i), item); - item.Serialize(sink); - } + vector items; + + DeserializerFromJson deserializer(root.get()); + deserializer(items, key.c_str()); + + for (auto const & s : items) + s.Visit(serializer); } } // namespace @@ -109,84 +63,84 @@ namespace routing { namespace transit { -string GetCountryId(string & graphCountryId); +// DeserializerFromJson --------------------------------------------------------------------------- +void DeserializerFromJson::operator()(m2::PointD & p, char const * name) +{ + json_t * pointItem = my::GetJSONOptionalField(m_node, name); + if (pointItem == nullptr) + return; + CHECK(json_is_object(pointItem), ()); + FromJSONObject(pointItem, "x", p.x); + FromJSONObject(pointItem, "y", p.y); +} + void BuildTransit(string const & mwmPath, string const & transitDir) { - // This method is under construction and should not be used for building production mwm sections. + LOG(LERROR, ("This method is under construction and should not be used for building production mwm " + "sections.")); NOTIMPLEMENTED(); string const countryId = GetFileName(mwmPath); LOG(LINFO, ("countryId:", countryId)); - Platform::FilesList filesList; - Platform::GetFilesByExt(transitDir, ".json", filesList); + string const graphFullPath = my::JoinFoldersToPath(transitDir, countryId + ".transit.json"); - LOG(LINFO, - ("mwm path:", mwmPath, ", directory with transit:", transitDir, "filesList:", filesList)); - - for (string const & graphFileName : filesList) + Platform::EFileType fileType; + Platform::EError const errCode = Platform::GetFileType(graphFullPath, fileType); + if (errCode != Platform::EError::ERR_OK || fileType != Platform::EFileType::FILE_TYPE_REGULAR) { - string const graphFullPath = my::JoinFoldersToPath(transitDir, graphFileName); - - Platform::EFileType fileType; - Platform::EError errCode = Platform::GetFileType(graphFullPath, fileType); - CHECK_EQUAL(errCode, Platform::EError::ERR_OK, - ("File is not found:", graphFullPath, ", errCode:", errCode)); - CHECK_EQUAL(fileType, Platform::EFileType::FILE_TYPE_REGULAR, - ("File is not found:", graphFullPath, ", fileType:", fileType)); - - // @TODO(bykoianko) In the future transit edges which cross mwm border will be split in the generator. Then - // routing will support cross mwm transit routing. In current version every json with transit graph - // should have a special name: .transit.json. - string const graphCountryId = GetFileName(graphFileName); - LOG(LINFO, ("graphCountryId:", graphCountryId)); - - if (graphCountryId != countryId) - continue; - - LOG(LINFO, ("Creating", TRANSIT_FILE_TAG, "section for:", countryId, "based on", graphFullPath)); - - string jsonBuffer; - try - { - GetPlatform().GetReader(graphFullPath)->ReadAsString(jsonBuffer); - } - catch (RootException const & ex) - { - LOG(LCRITICAL, ("Can't open", graphFullPath, ex.what())); - } - - // @TODO(bykoianko) If it's necessary to parse an integer jansson parser keeps it to time long long value. - // It's not good because osm id and stop id are uint64_t. This should be solve before continue writing - // transit jansson parsing. According to C++ signed long long is not smaller than long and at least 64 bits. - // So as a variant before saving to json osm id and stop id should be converted to signed long long and - // then after reading at generator they should be converted back. - my::Json root(jsonBuffer.c_str()); - CHECK(root.get() != nullptr, ("Cannot parse the json file:", graphFullPath)); - - FilesContainerW cont(mwmPath, FileWriter::OP_WRITE_EXISTING); - FileWriter w = cont.GetWriter(TRANSIT_FILE_TAG); - - TransitHeader header; - - auto const startOffset = w.Pos(); - header.Serialize(w); - - SerializeObject(root, "stops", w); - header.m_gatesOffset = base::checked_cast(w.Pos() - startOffset); - - // @TODO(bykoianko) It's necessary to serialize other transit graph data here. - - w.WritePaddingByEnd(8); - header.m_endOffset = base::checked_cast(w.Pos() - startOffset); - - // Rewriting header info. - auto const endOffset = w.Pos(); - w.Seek(startOffset); - header.Serialize(w); - w.Seek(endOffset); - LOG(LINFO, (TRANSIT_FILE_TAG, "section is ready. The size is", header.m_endOffset)); + LOG(LINFO, ("For mwm:", mwmPath, ".transit.json file not found")); + return; } + + // @TODO(bykoianko) In the future transit edges which cross mwm border will be split in the generator. Then + // routing will support cross mwm transit routing. In current version every json with transit graph + // should have a special name: .transit.json. + + LOG(LINFO, ("Creating", TRANSIT_FILE_TAG, "section for:", countryId, "based on", graphFullPath)); + + string jsonBuffer; + try + { + GetPlatform().GetReader(graphFullPath)->ReadAsString(jsonBuffer); + } + catch (RootException const & ex) + { + LOG(LCRITICAL, ("Can't open", graphFullPath, ex.what())); + } + + // @TODO(bykoianko) If it's necessary to parse an integer jansson parser keeps it to time long long value. + // It's not good because osm id and stop id are uint64_t. This should be solve before continue writing + // transit jansson parsing. According to C++ signed long long is not smaller than long and at least 64 bits. + // So as a variant before saving to json osm id and stop id should be converted to signed long long and + // then after reading at generator they should be converted back. + // @TODO(bykoianko) |osmId| should be converted to feature id while deserialing from json. + my::Json root(jsonBuffer.c_str()); + CHECK(root.get() != nullptr, ("Cannot parse the json file:", graphFullPath)); + + FilesContainerW cont(mwmPath, FileWriter::OP_WRITE_EXISTING); + FileWriter w = cont.GetWriter(TRANSIT_FILE_TAG); + + TransitHeader header; + + auto const startOffset = w.Pos(); + Serializer serializer(w); + header.Visit(serializer); + + SerializeObject(root, "stops", serializer); + header.m_gatesOffset = base::checked_cast(w.Pos() - startOffset); + + // @TODO(bykoianko) It's necessary to serialize other transit graph data here. + + w.WritePaddingByEnd(8); + header.m_endOffset = base::checked_cast(w.Pos() - startOffset); + + // Rewriting header info. + auto const endOffset = w.Pos(); + w.Seek(startOffset); + header.Visit(serializer); + w.Seek(endOffset); + LOG(LINFO, (TRANSIT_FILE_TAG, "section is ready. The size is", header.m_endOffset)); } } // namespace transit } // namespace routing diff --git a/generator/transit_generator.hpp b/generator/transit_generator.hpp index a3526f6629..e14672fd40 100644 --- a/generator/transit_generator.hpp +++ b/generator/transit_generator.hpp @@ -1,11 +1,75 @@ #pragma once +#include "geometry/point2d.hpp" + +#include "3party/jansson/myjansson.hpp" + +#include #include +#include namespace routing { namespace transit { +class DeserializerFromJson +{ +public: + DeserializerFromJson(json_struct_t * node) : m_node(node) {} + + void operator()(uint8_t & d, char const * name = nullptr) { GetField(d, name); } + void operator()(uint16_t & d, char const * name = nullptr) { GetField(d, name); } + void operator()(uint32_t & d, char const * name = nullptr) { GetField(d, name); } + void operator()(uint64_t & d, char const * name = nullptr) { GetField(d, name); } + void operator()(double & d, char const * name = nullptr) { GetField(d, name); } + void operator()(std::string & s, char const * name = nullptr) { GetField(s, name); } + void operator()(m2::PointD & p, char const * name = nullptr); + + template + void operator()(R & r, char const * name = nullptr) + { + r.Visit(*this); + } + + template + void operator()(std::vector & vs, char const * name = nullptr) + { + auto * arr = my::GetJSONOptionalField(m_node, name); + if (arr == nullptr) + return; + + if (!json_is_array(arr)) + MYTHROW(my::Json::Exception, ("The field", name, "must contain a json array.")); + size_t const sz = json_array_size(arr); + vs.resize(sz); + for (size_t i = 0; i < sz; ++i) + { + DeserializerFromJson arrayItem(json_array_get(arr, i)); + arrayItem(vs[i]); + } + } + +private: + template + void GetField(T & t, char const * name = nullptr) + { + if (name == nullptr) + { + // |name| is not set in case of array items + FromJSON(m_node, t); + } + else + { + json_struct_t * field = my::GetJSONOptionalField(m_node, name); + if (field == nullptr) + return; // No field |name| at |m_node|. + FromJSON(field, t); + } + } + + json_struct_t * m_node; +}; + /// \brief Builds transit section at mwm. /// \param mwmPath relative or full path to built mwm. The name of mwm without extension is considered /// as country id. diff --git a/routing_common/CMakeLists.txt b/routing_common/CMakeLists.txt index d130e3307f..9304a8c668 100644 --- a/routing_common/CMakeLists.txt +++ b/routing_common/CMakeLists.txt @@ -8,11 +8,10 @@ set( car_model.hpp pedestrian_model.cpp pedestrian_model.hpp - transit_header.cpp - transit_header.hpp transit_max_speed.hpp - transit_stop.cpp - transit_stop.hpp + transit_serdes.cpp + transit_serdes.hpp + transit_types.cpp transit_types.hpp vehicle_model.cpp vehicle_model.hpp diff --git a/routing_common/routing_common.pro b/routing_common/routing_common.pro index fa218bea0d..56fd7525ce 100644 --- a/routing_common/routing_common.pro +++ b/routing_common/routing_common.pro @@ -16,8 +16,7 @@ SOURCES += \ bicycle_model.cpp \ car_model.cpp \ pedestrian_model.cpp \ - transit_header.cpp \ - transit_stop.cpp \ + transit_types.cpp \ vehicle_model.cpp \ @@ -25,8 +24,6 @@ HEADERS += \ bicycle_model.hpp \ car_model.hpp \ pedestrian_model.hpp \ - transit_header.hpp \ transit_max_speed.hpp \ - transit_stop.hpp \ transit_types.hpp \ vehicle_model.hpp \ diff --git a/routing_common/routing_common_tests/transit_test.cpp b/routing_common/routing_common_tests/transit_test.cpp index 29ee62a346..de0996d73f 100644 --- a/routing_common/routing_common_tests/transit_test.cpp +++ b/routing_common/routing_common_tests/transit_test.cpp @@ -3,8 +3,7 @@ #include "coding/reader.hpp" #include "coding/writer.hpp" -#include "routing_common/transit_header.hpp" -#include "routing_common/transit_stop.hpp" +#include "routing_common/transit_serdes.hpp" #include "routing_common/transit_types.hpp" #include @@ -21,14 +20,17 @@ void TestSerialization(Obj const & obj) { vector buffer; MemWriter> writer(buffer); - obj.Serialize(writer); + + Serializer>> serializer(writer); + obj.Visit(serializer); MemReader reader(buffer.data(), buffer.size()); ReaderSource src(reader); - Obj deserializedHeader; - deserializedHeader.Deserialize(src); + Obj deserializedObj; + Deserializer> deserializer(src); + deserializedObj.Visit(deserializer); - TEST(obj.IsEqualForTesting(deserializedHeader), (obj, "is not equal to", deserializedHeader)); + TEST(obj.IsEqualForTesting(deserializedObj), ()); } UNIT_TEST(ZeroTransitHeaderSerialization) @@ -53,7 +55,7 @@ UNIT_TEST(ZeroTransitStopSerialization) UNIT_TEST(TransitStopSerialization) { - Stop stop(1234 /* id */, 5678 /* feature id */, {7, 8, 9, 10} /* line id */, {55.0, 37.0}); + Stop stop(1234 /* id */, 5678 /* feature id */, 7 /* transfer id */, {7, 8, 9, 10} /* line id */, {55.0, 37.0}); TestSerialization(stop); } } // namespace diff --git a/routing_common/transit_header.hpp b/routing_common/transit_header.hpp deleted file mode 100644 index 046dc08a9a..0000000000 --- a/routing_common/transit_header.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include "coding/reader.hpp" -#include "coding/write_to_sink.hpp" - -#include - -namespace routing -{ -namespace transit -{ -struct TransitHeader final -{ - TransitHeader() { Reset(); } - TransitHeader(uint16_t version, uint32_t gatesOffset, uint32_t edgesOffset, - uint32_t transfersOffset, uint32_t linesOffset, uint32_t shapesOffset, - uint32_t networksOffset, uint32_t endOffset); - void Reset(); - bool IsEqualForTesting(TransitHeader const & header) const; - - template - void Serialize(TSink & sink) const - { - WriteToSink(sink, m_version); - WriteToSink(sink, m_reserve); - WriteToSink(sink, m_gatesOffset); - WriteToSink(sink, m_edgesOffset); - WriteToSink(sink, m_transfersOffset); - WriteToSink(sink, m_linesOffset); - WriteToSink(sink, m_shapesOffset); - WriteToSink(sink, m_networksOffset); - WriteToSink(sink, m_endOffset); - } - - template - void Deserialize(TSource & src) - { - m_version = ReadPrimitiveFromSource(src); - m_reserve = ReadPrimitiveFromSource(src); - m_gatesOffset = ReadPrimitiveFromSource(src); - m_edgesOffset = ReadPrimitiveFromSource(src); - m_transfersOffset = ReadPrimitiveFromSource(src); - m_linesOffset = ReadPrimitiveFromSource(src); - m_shapesOffset = ReadPrimitiveFromSource(src); - m_networksOffset = ReadPrimitiveFromSource(src); - m_endOffset = ReadPrimitiveFromSource(src); - } - - uint16_t m_version; - uint16_t m_reserve; - uint32_t m_gatesOffset; - uint32_t m_edgesOffset; - uint32_t m_transfersOffset; - uint32_t m_linesOffset; - uint32_t m_shapesOffset; - uint32_t m_networksOffset; - uint32_t m_endOffset; -}; - -static_assert(sizeof(TransitHeader) == 32, "Wrong header size of transit section."); - -string DebugPrint(TransitHeader const & turnItem); -} // namespace transit -} // namespace routing diff --git a/routing_common/transit_serdes.cpp b/routing_common/transit_serdes.cpp new file mode 100644 index 0000000000..631305e87c --- /dev/null +++ b/routing_common/transit_serdes.cpp @@ -0,0 +1,13 @@ +#include "routing_common/transit_serdes.hpp" + +#include "coding/point_to_integer.hpp" + +namespace routing +{ +namespace transit +{ +// DeserializerToString --------------------------------------------------------------------------- + + +} // namespace transit +} // namespace routing diff --git a/routing_common/transit_serdes.hpp b/routing_common/transit_serdes.hpp new file mode 100644 index 0000000000..0fc2ef650d --- /dev/null +++ b/routing_common/transit_serdes.hpp @@ -0,0 +1,136 @@ +#pragma once + +#include "geometry/point2d.hpp" + +#include "coding/point_to_integer.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 +#include +#include +#include +#include +#include + +namespace routing +{ +namespace transit +{ +template +class Serializer +{ +public: + Serializer(Sink & sink) : m_sink(sink) {} + + void operator()(uint8_t const d, char const * /* name */ = nullptr) { WriteToSink(m_sink, d); } + void operator()(uint16_t const d, char const * /* name */ = nullptr) { WriteToSink(m_sink, d); } + void operator()(uint32_t const d, char const * /* name */ = nullptr) { WriteToSink(m_sink, d); } + void operator()(uint64_t const d, char const * /* name */ = nullptr) { WriteToSink(m_sink, d); } + void operator()(double const d, char const * /* name */ = nullptr) + { + NOTIMPLEMENTED(); + } + + 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) + { + m2::PointU const pointU = PointD2PointU(p, POINT_COORD_BITS); + (*this)(pointU.x); + (*this)(pointU.y); + } + + template + void operator()(R const & r, char const * /* name */ = nullptr) + { + r.Visit(*this); + } + + template + void operator()(std::vector const & vs, char const * /* name */ = nullptr) + { + CHECK_LESS(vs.size(), std::numeric_limits::max(), ()); + WriteVarUint(m_sink, static_cast(vs.size())); + for (auto const & v : vs) + (*this)(v); + } + +private: + Sink & m_sink; +}; + +template +class Deserializer +{ +public: + Deserializer(Source & source) : m_source(source) {} + + void operator()(uint8_t & d, char const * /* name */ = nullptr) + { + ReadPrimitiveFromSource(m_source, d); + } + + void operator()(uint16_t & d, char const * /* name */ = nullptr) + { + ReadPrimitiveFromSource(m_source, d); + } + + void operator()(uint32_t & d, char const * /* name */ = nullptr) + { + ReadPrimitiveFromSource(m_source, d); + } + + void operator()(uint64_t & d, char const * /* name */ = nullptr) + { + ReadPrimitiveFromSource(m_source, d); + } + + void operator()(double & d, char const * /* name */ = nullptr) + { + NOTIMPLEMENTED(); + } + + void operator()(std::string & s, char const * /* name */ = nullptr) + { + rw::Read(m_source, s); + } + + void operator()(m2::PointD & p, char const * /* name */ = nullptr) + { + m2::PointU pointU; + (*this)(pointU.x); + (*this)(pointU.y); + p = PointU2PointD(pointU, POINT_COORD_BITS); + } + + + template + void operator()(R & r, char const * /* name */ = nullptr) + { + r.Visit(*this); + } + + template + void operator()(vector & vs, char const * /* name */ = nullptr) + { + auto const size = ReadVarUint(m_source); + vs.resize(size); + for (auto & v : vs) + (*this)(v); + } + +private: + Source & m_source; +}; +} // namespace transit +} // namespace routing diff --git a/routing_common/transit_stop.cpp b/routing_common/transit_stop.cpp deleted file mode 100644 index 23f87c81b0..0000000000 --- a/routing_common/transit_stop.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "routing_common/transit_stop.hpp" - -#include - -namespace routing -{ -namespace transit -{ -Stop::Stop(StopId id, FeatureId featureId, std::vector const & lineIds, - m2::PointD const & point) - : m_id(id), m_featureId(featureId), m_lineIds(lineIds), m_point(point) -{ -} - -bool Stop::IsEqualForTesting(Stop const & stop) const -{ - double constexpr kPointsEqualEpsilon = 1e-6; - return m_id == stop.m_id && m_featureId == stop.m_featureId && m_lineIds == stop.m_lineIds && - my::AlmostEqualAbs(m_point, stop.m_point, kPointsEqualEpsilon); -} - -std::string DebugPrint(Stop const & stop) -{ - std::stringstream out; - out << "Stop [ m_id = " << stop.m_id - << ", m_featureId = " << stop.m_featureId - << ", m_lineIds = " << ::DebugPrint(stop.m_lineIds) - << ", m_point = " << DebugPrint(stop.m_point) - << " ]" << endl; - return out.str(); -} -} // namespace transit -} // namespace routing diff --git a/routing_common/transit_stop.hpp b/routing_common/transit_stop.hpp deleted file mode 100644 index b09f198db9..0000000000 --- a/routing_common/transit_stop.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include "routing_common/transit_types.hpp" - -#include "coding/point_to_integer.hpp" -#include "coding/reader.hpp" -#include "coding/write_to_sink.hpp" - -#include "geometry/point2d.hpp" - -#include -#include -#include - -namespace routing -{ -namespace transit -{ -class Stop final -{ - friend std::string DebugPrint(Stop const & stop); - -public: - Stop() = default; - Stop(StopId id, FeatureId featureId, std::vector const & lineIds, m2::PointD const & point); - bool IsEqualForTesting(Stop const & stop) const; - - template - void Serialize(TSink & sink) const - { - WriteToSink(sink, m_id); - WriteToSink(sink, m_featureId); - WriteToSink(sink, static_cast(m_lineIds.size())); - for (LineId lineId : m_lineIds) - WriteToSink(sink, lineId); - - m2::PointU const pointU = PointD2PointU(m_point, POINT_COORD_BITS); - WriteToSink(sink, pointU.x); - WriteToSink(sink, pointU.y); - } - - template - void Deserialize(TSource & src) - { - m_id = ReadPrimitiveFromSource(src); - m_featureId = ReadPrimitiveFromSource(src); - uint32_t const lineIdsSize = ReadPrimitiveFromSource(src); - m_lineIds.resize(lineIdsSize); - for (uint32_t i = 0; i < lineIdsSize; ++i) - m_lineIds[i] = ReadPrimitiveFromSource(src); - m2::PointU pointU; - pointU.x = ReadPrimitiveFromSource(src); - pointU.y = ReadPrimitiveFromSource(src); - m_point = PointU2PointD(pointU, POINT_COORD_BITS); - } - -private: - StopId m_id = kStopIdInvalid; - FeatureId m_featureId = kFeatureIdInvalid; - std::vector m_lineIds; - m2::PointD m_point; - // @TODO(bykoianko) It's necessary to add field m_titleAnchors here and implement serialization - // and deserialization. -}; - -std::string DebugPrint(Stop const & stop); - -// @TODO(bykoianko) Method bool DeserializeStops(Stops const & stops) should be implemented here. -// This method will parse table "stops" at TRANSIT_FILE_TAG mwm section and fills its parameter. - -// @TODO(bykoianko) Data structures and methods for other transit data should be implemented in -// separate units. -} // namespace transit -} // namespace routing diff --git a/routing_common/transit_header.cpp b/routing_common/transit_types.cpp similarity index 60% rename from routing_common/transit_header.cpp rename to routing_common/transit_types.cpp index 9ffc8f3734..894e704952 100644 --- a/routing_common/transit_header.cpp +++ b/routing_common/transit_types.cpp @@ -1,13 +1,12 @@ -#include "routing_common/transit_header.hpp" +#include "routing_common/transit_types.hpp" -#include +#include "routing_common/transit_serdes.hpp" namespace routing { namespace transit { -using namespace std; - +// TransitHeader ---------------------------------------------------------------------------------- TransitHeader::TransitHeader(uint16_t version, uint32_t gatesOffset, uint32_t edgesOffset, uint32_t transfersOffset, uint32_t linesOffset, uint32_t shapesOffset, uint32_t networksOffset, uint32_t endOffset) @@ -45,20 +44,18 @@ bool TransitHeader::IsEqualForTesting(TransitHeader const & header) const m_endOffset == header.m_endOffset; } -string DebugPrint(TransitHeader const & header) +// Stop ------------------------------------------------------------------------------------------- +Stop::Stop(StopId id, FeatureId featureId, TransferId transferId, std::vector const & lineIds, + m2::PointD const & point) + : m_id(id), m_featureId(featureId), m_transferId(transferId), m_lineIds(lineIds), m_point(point) { - stringstream out; - out << "TransitHeader [ m_version = " << header.m_version - << ", m_reserve = " << header.m_reserve - << ", m_gatesOffset = " << header.m_gatesOffset - << ", m_edgesOffset = " << header.m_edgesOffset - << ", m_transfersOffset = " << header.m_transfersOffset - << ", m_linesOffset = " << header.m_linesOffset - << ", m_shapesOffset = " << header.m_shapesOffset - << ", m_networksOffset = " << header.m_networksOffset - << ", m_endOffset = " << header.m_endOffset - << " ]" << endl; - return out.str(); +} + +bool Stop::IsEqualForTesting(Stop const & stop) const +{ + double constexpr kPointsEqualEpsilon = 1e-6; + return m_id == stop.m_id && m_featureId == stop.m_featureId && m_transferId == stop.m_transferId && + m_lineIds == stop.m_lineIds && my::AlmostEqualAbs(m_point, stop.m_point, kPointsEqualEpsilon); } } // namespace transit -} // namespace routing +} // namespace routing \ No newline at end of file diff --git a/routing_common/transit_types.hpp b/routing_common/transit_types.hpp index df5876c301..b820f086e7 100644 --- a/routing_common/transit_types.hpp +++ b/routing_common/transit_types.hpp @@ -1,7 +1,12 @@ #pragma once +#include "geometry/point2d.hpp" + +#include "base/visitor.hpp" + #include #include +#include namespace routing { @@ -9,15 +14,70 @@ namespace transit { using LineId = uint32_t; using StopId = uint64_t; -using TransfersId = uint64_t; +using TransferId = uint64_t; using NetworkId = uint32_t; using FeatureId = uint32_t; LineId constexpr kLineIdInvalid = std::numeric_limits::max(); StopId constexpr kStopIdInvalid = std::numeric_limits::max(); -TransfersId constexpr kTransferIdInvalid = std::numeric_limits::max(); +TransferId constexpr kTransferIdInvalid = std::numeric_limits::max(); NetworkId constexpr kNetworkIdInvalid = std::numeric_limits::max(); FeatureId constexpr kFeatureIdInvalid = std::numeric_limits::max(); +struct TransitHeader +{ + TransitHeader() { Reset(); } + TransitHeader(uint16_t version, uint32_t gatesOffset, uint32_t edgesOffset, + uint32_t transfersOffset, uint32_t linesOffset, uint32_t shapesOffset, + uint32_t networksOffset, uint32_t endOffset); + void Reset(); + bool IsEqualForTesting(TransitHeader const & header) const; + + DECLARE_VISITOR(visitor(m_version, "m_version"), visitor(m_reserve, "m_reserve"), + visitor(m_gatesOffset, "m_gatesOffset"), visitor(m_edgesOffset, "m_edgesOffset"), + visitor(m_transfersOffset, "m_transfersOffset"), + visitor(m_linesOffset, "m_linesOffset"), + visitor(m_shapesOffset, "m_shapesOffset"), + visitor(m_networksOffset, "m_networksOffset"), + visitor(m_endOffset, "m_endOffset")) + DECLARE_DEBUG_PRINT(TransitHeader) + + uint16_t m_version; + uint16_t m_reserve; + uint32_t m_gatesOffset; + uint32_t m_edgesOffset; + uint32_t m_transfersOffset; + uint32_t m_linesOffset; + uint32_t m_shapesOffset; + uint32_t m_networksOffset; + uint32_t m_endOffset; +}; + +static_assert(sizeof(TransitHeader) == 32, "Wrong header size of transit section."); + +class Stop +{ +public: + Stop() = default; + Stop(StopId id, FeatureId featureId, TransferId m_transferId, std::vector const & lineIds, + m2::PointD const & point); + bool IsEqualForTesting(Stop const & stop) const; + + DECLARE_VISITOR(visitor(m_id, "id"), visitor(m_featureId, "osm_id"), + visitor(m_transferId, "transfer_id"), visitor(m_lineIds, "line_ids"), + visitor(m_point, "point")) + DECLARE_DEBUG_PRINT(Stop) + +private: + StopId m_id = kStopIdInvalid; + FeatureId m_featureId = kFeatureIdInvalid; + TransferId m_transferId = kTransferIdInvalid; + std::vector m_lineIds; + m2::PointD m_point; + // @TODO(bykoianko) It's necessary to add field m_titleAnchors here and implement serialization + // and deserialization. +}; + +// @TODO(bykoianko) Data structures and methods for other transit data should be implemented in here. } // namespace transit } // namespace routing diff --git a/xcode/generator_tool/generator_tool.xcodeproj/project.pbxproj b/xcode/generator_tool/generator_tool.xcodeproj/project.pbxproj index 5c3e52751d..53de3a5d6e 100644 --- a/xcode/generator_tool/generator_tool.xcodeproj/project.pbxproj +++ b/xcode/generator_tool/generator_tool.xcodeproj/project.pbxproj @@ -29,6 +29,7 @@ 34F558571DBF3CD800A4FC11 /* libstdc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F558561DBF3CD800A4FC11 /* libstdc++.tbd */; }; 562147271F6AA36A002D2214 /* libbsdiff.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 562147261F6AA36A002D2214 /* libbsdiff.a */; }; 562147291F6AA37E002D2214 /* libmwm_diff.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 562147281F6AA37E002D2214 /* libmwm_diff.a */; }; + 56E2EDAA1F7E3FBB0092E9C2 /* transit_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56E2EDA91F7E3FBB0092E9C2 /* transit_test.cpp */; }; 670E7BBC1EF9832200A8E9ED /* libicu.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 670E7BBB1EF9832200A8E9ED /* libicu.a */; }; 670E7BBE1EF9839C00A8E9ED /* librouting_common.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 670E7BBD1EF9839C00A8E9ED /* librouting_common.a */; }; 670E7BC01EF983A400A8E9ED /* libtraffic.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 670E7BBF1EF983A400A8E9ED /* libtraffic.a */; }; @@ -203,6 +204,7 @@ 34F558561DBF3CD800A4FC11 /* libstdc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.tbd"; path = "usr/lib/libstdc++.tbd"; sourceTree = SDKROOT; }; 562147261F6AA36A002D2214 /* libbsdiff.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbsdiff.a; path = ../bsdiff/build/Debug/libbsdiff.a; sourceTree = ""; }; 562147281F6AA37E002D2214 /* libmwm_diff.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmwm_diff.a; path = "../../../../Library/Developer/Xcode/DerivedData/omim-gsfdicnjgjjbizhdmwedavcucpok/Build/Products/Debug/libmwm_diff.a"; sourceTree = ""; }; + 56E2EDA91F7E3FBB0092E9C2 /* transit_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = transit_test.cpp; sourceTree = ""; }; 670E7BBB1EF9832200A8E9ED /* libicu.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libicu.a; path = "../../../../Library/Developer/Xcode/DerivedData/omim-gzleizqujktwggdwiejzkgjrsgvp/Build/Products/Debug/libicu.a"; sourceTree = ""; }; 670E7BBD1EF9839C00A8E9ED /* librouting_common.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = librouting_common.a; path = "../../../../Library/Developer/Xcode/DerivedData/omim-gzleizqujktwggdwiejzkgjrsgvp/Build/Products/Debug/librouting_common.a"; sourceTree = ""; }; 670E7BBF1EF983A400A8E9ED /* libtraffic.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtraffic.a; path = "../../../../Library/Developer/Xcode/DerivedData/omim-gzleizqujktwggdwiejzkgjrsgvp/Build/Products/Debug/libtraffic.a"; sourceTree = ""; }; @@ -451,6 +453,7 @@ 6726C1D71A4C27A5005EEA39 /* generator_tests */ = { isa = PBXGroup; children = ( + 56E2EDA91F7E3FBB0092E9C2 /* transit_test.cpp */, 677E2A0B1CAAC7CB001DC42A /* osm2meta_test.cpp */, 677E2A0C1CAAC7CB001DC42A /* tag_admixer_test.cpp */, 677792501C1B2E9300EC9499 /* metadata_parser_test.cpp */, @@ -711,6 +714,7 @@ buildActionMask = 2147483647; files = ( 675341631A3F54F600A0A8C3 /* generator_tool.cpp in Sources */, + 56E2EDAA1F7E3FBB0092E9C2 /* transit_test.cpp in Sources */, 677E2A0D1CAAC7CB001DC42A /* osm2meta_test.cpp in Sources */, 677E2A0E1CAAC7CB001DC42A /* tag_admixer_test.cpp in Sources */, ); diff --git a/xcode/routing_common/routing_common.xcodeproj/project.pbxproj b/xcode/routing_common/routing_common.xcodeproj/project.pbxproj index 589145e9eb..7502158a12 100644 --- a/xcode/routing_common/routing_common.xcodeproj/project.pbxproj +++ b/xcode/routing_common/routing_common.xcodeproj/project.pbxproj @@ -11,10 +11,9 @@ 40FF45D01F388EF80046BD40 /* vehicle_model_for_country_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 40FF45CF1F388EF80046BD40 /* vehicle_model_for_country_test.cpp */; }; 5647A4511F72BEB600DE1125 /* libicu.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5647A4521F72BEB600DE1125 /* libicu.a */; }; 5667C1DD1F751F2700C6B31B /* transit_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5647A4531F72BF2B00DE1125 /* transit_test.cpp */; }; - 5667C1E11F751F4200C6B31B /* transit_header.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5667C1DF1F751F4200C6B31B /* transit_header.cpp */; }; - 5667C1E21F751F4200C6B31B /* transit_stop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5667C1E01F751F4200C6B31B /* transit_stop.cpp */; }; - 56E41D841F72A64B00E28E2D /* transit_stop.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56E41D831F72A64B00E28E2D /* transit_stop.hpp */; }; - 56E41D871F72B42F00E28E2D /* transit_header.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56E41D851F72B42F00E28E2D /* transit_header.hpp */; }; + 56E2EDA61F7E3F8A0092E9C2 /* transit_serdes.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56E2EDA31F7E3F890092E9C2 /* transit_serdes.hpp */; }; + 56E2EDA71F7E3F8A0092E9C2 /* transit_serdes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56E2EDA41F7E3F890092E9C2 /* transit_serdes.cpp */; }; + 56E2EDA81F7E3F8A0092E9C2 /* transit_types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56E2EDA51F7E3F8A0092E9C2 /* transit_types.cpp */; }; 56E41D881F72B42F00E28E2D /* transit_types.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56E41D861F72B42F00E28E2D /* transit_types.hpp */; }; 671E78881E6A3C5D00B2859B /* bicycle_model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 671E78801E6A3C5D00B2859B /* bicycle_model.cpp */; }; 671E78891E6A3C5D00B2859B /* bicycle_model.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 671E78811E6A3C5D00B2859B /* bicycle_model.hpp */; }; @@ -48,10 +47,9 @@ 5647A4521F72BEB600DE1125 /* libicu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libicu.a; sourceTree = BUILT_PRODUCTS_DIR; }; 5647A4531F72BF2B00DE1125 /* transit_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = transit_test.cpp; sourceTree = ""; }; 5667C1DE1F751F4200C6B31B /* routing_common.pro */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = routing_common.pro; sourceTree = ""; }; - 5667C1DF1F751F4200C6B31B /* transit_header.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = transit_header.cpp; sourceTree = ""; }; - 5667C1E01F751F4200C6B31B /* transit_stop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = transit_stop.cpp; sourceTree = ""; }; - 56E41D831F72A64B00E28E2D /* transit_stop.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = transit_stop.hpp; sourceTree = ""; }; - 56E41D851F72B42F00E28E2D /* transit_header.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = transit_header.hpp; sourceTree = ""; }; + 56E2EDA31F7E3F890092E9C2 /* transit_serdes.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = transit_serdes.hpp; sourceTree = ""; }; + 56E2EDA41F7E3F890092E9C2 /* transit_serdes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = transit_serdes.cpp; sourceTree = ""; }; + 56E2EDA51F7E3F8A0092E9C2 /* transit_types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = transit_types.cpp; sourceTree = ""; }; 56E41D861F72B42F00E28E2D /* transit_types.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = transit_types.hpp; sourceTree = ""; }; 671E78721E6A3BE200B2859B /* librouting_common.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = librouting_common.a; sourceTree = BUILT_PRODUCTS_DIR; }; 671E78801E6A3C5D00B2859B /* bicycle_model.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bicycle_model.cpp; sourceTree = ""; }; @@ -140,12 +138,11 @@ 671E78741E6A3BE200B2859B /* routing_common */ = { isa = PBXGroup; children = ( + 56E2EDA41F7E3F890092E9C2 /* transit_serdes.cpp */, + 56E2EDA31F7E3F890092E9C2 /* transit_serdes.hpp */, + 56E2EDA51F7E3F8A0092E9C2 /* transit_types.cpp */, 5667C1DE1F751F4200C6B31B /* routing_common.pro */, - 5667C1DF1F751F4200C6B31B /* transit_header.cpp */, - 5667C1E01F751F4200C6B31B /* transit_stop.cpp */, - 56E41D851F72B42F00E28E2D /* transit_header.hpp */, 56E41D861F72B42F00E28E2D /* transit_types.hpp */, - 56E41D831F72A64B00E28E2D /* transit_stop.hpp */, 671E78801E6A3C5D00B2859B /* bicycle_model.cpp */, 671E78811E6A3C5D00B2859B /* bicycle_model.hpp */, 671E78821E6A3C5D00B2859B /* car_model.cpp */, @@ -202,8 +199,8 @@ buildActionMask = 2147483647; files = ( 671E788D1E6A3C5D00B2859B /* pedestrian_model.hpp in Headers */, - 56E41D871F72B42F00E28E2D /* transit_header.hpp in Headers */, 56E41D881F72B42F00E28E2D /* transit_types.hpp in Headers */, + 56E2EDA61F7E3F8A0092E9C2 /* transit_serdes.hpp in Headers */, 671E78891E6A3C5D00B2859B /* bicycle_model.hpp in Headers */, 40576F7A1F7AA1B4000B593B /* transit_max_speed.hpp in Headers */, 56E41D841F72A64B00E28E2D /* transit_stop.hpp in Headers */, @@ -302,12 +299,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 5667C1E11F751F4200C6B31B /* transit_header.cpp in Sources */, + 56E2EDA81F7E3F8A0092E9C2 /* transit_types.cpp in Sources */, 671E788A1E6A3C5D00B2859B /* car_model.cpp in Sources */, + 56E2EDA71F7E3F8A0092E9C2 /* transit_serdes.cpp in Sources */, 671E78881E6A3C5D00B2859B /* bicycle_model.cpp in Sources */, 671E788E1E6A3C5D00B2859B /* vehicle_model.cpp in Sources */, 40FF45D01F388EF80046BD40 /* vehicle_model_for_country_test.cpp in Sources */, - 5667C1E21F751F4200C6B31B /* transit_stop.cpp in Sources */, 671E788C1E6A3C5D00B2859B /* pedestrian_model.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -392,6 +389,7 @@ 671E787F1E6A3BE200B2859B /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 671E78AA1E6A3DA800B2859B /* Build configuration list for PBXNativeTarget "routing_common_tests" */ = { isa = XCConfigurationList; @@ -400,6 +398,7 @@ 671E78AC1E6A3DA800B2859B /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ };