From d3ab6f1fcadbabe0a90a59c19aa561b836cf5e4a Mon Sep 17 00:00:00 2001 From: Michael Bell Date: Tue, 22 Sep 2020 21:32:35 +0100 Subject: [PATCH 01/17] Remove unused future The serialization of the compressed node based graph was changed in c410c2 to no longer be asynchronous. This removes the unused future object. --- src/extractor/extractor.cpp | 42 ++++++------------------------------- 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index 6892232d3..3fb5ff1f0 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -1,5 +1,6 @@ #include "extractor/extractor.hpp" +#include "extractor/compressed_edge_container.hpp" #include "extractor/compressed_node_based_graph_edge.hpp" #include "extractor/edge_based_edge.hpp" #include "extractor/extraction_containers.hpp" @@ -11,47 +12,34 @@ #include "extractor/maneuver_override_relation_parser.hpp" #include "extractor/name_table.hpp" #include "extractor/node_based_graph_factory.hpp" -#include "extractor/raster_source.hpp" #include "extractor/restriction_filter.hpp" +#include "extractor/restriction_index.hpp" #include "extractor/restriction_parser.hpp" #include "extractor/scripting_environment.hpp" +#include "extractor/tarjan_scc.hpp" +#include "extractor/way_restriction_map.hpp" #include "guidance/files.hpp" #include "guidance/guidance_processing.hpp" #include "guidance/segregated_intersection_classification.hpp" #include "guidance/turn_data_container.hpp" -#include "storage/io.hpp" - #include "util/exception.hpp" #include "util/exception_utils.hpp" #include "util/integer_range.hpp" #include "util/log.hpp" -#include "util/range_table.hpp" -#include "util/timing_util.hpp" - -#include "extractor/compressed_edge_container.hpp" -#include "extractor/restriction_index.hpp" -#include "extractor/way_restriction_map.hpp" #include "util/static_graph.hpp" #include "util/static_rtree.hpp" +#include "util/timing_util.hpp" // Keep debug include to make sure the debug header is in sync with types. #include "util/debug.hpp" -#include "extractor/tarjan_scc.hpp" - #include -#include -#include -#include -#include -#include #include #include #include -#include #include #include @@ -62,15 +50,11 @@ #endif #include -#include - #include #include #include #include -#include #include -#include #include #include #include @@ -193,7 +177,7 @@ std::vector toEdgeList(const util::NodeBasedDynami return edges; } -} +} // namespace /** * TODO: Refactor this function into smaller functions for better readability. @@ -288,16 +272,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) // // Luckily node based node ids still coincide with the coordinate array. // That's the reason we can only here write out the final compressed node based graph. - - // Dumps to file asynchronously and makes sure we wait for its completion. - std::future compressed_node_based_graph_writing; - - BOOST_SCOPE_EXIT_ALL(&) - { - if (compressed_node_based_graph_writing.valid()) - compressed_node_based_graph_writing.wait(); - }; - files::writeCompressedNodeBasedGraph(config.GetPath(".osrm.cnbg").string(), toEdgeList(node_based_graph)); @@ -519,7 +493,6 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment, // OSM elements Lua parser tbb::filter_t buffer_transformer( tbb::filter::parallel, [&](const SharedBuffer buffer) { - ParsedBuffer parsed_buffer; parsed_buffer.buffer = buffer; scripting_environment.ProcessElements(*buffer, @@ -540,7 +513,6 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment, unsigned number_of_maneuver_overrides = 0; tbb::filter_t buffer_storage( tbb::filter::serial_in_order, [&](const ParsedBuffer &parsed_buffer) { - number_of_nodes += parsed_buffer.resulting_nodes.size(); // put parsed objects thru extractor callbacks for (const auto &result : parsed_buffer.resulting_nodes) @@ -564,7 +536,6 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment, { extractor_callbacks->ProcessManeuverOverride(result); } - }); tbb::filter_t> buffer_relation_cache( @@ -606,7 +577,6 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment, tbb::filter_t, void> buffer_storage_relation( tbb::filter::serial_in_order, [&](const std::shared_ptr parsed_relations) { - number_of_relations += parsed_relations->GetRelationsNum(); relations.Merge(std::move(*parsed_relations)); }); From 4799b46eeb934278d9d101f682a95da2b66af621 Mon Sep 17 00:00:00 2001 From: Michael Bell Date: Thu, 1 Oct 2020 02:44:22 +0100 Subject: [PATCH 02/17] Incorrect error message when unable to snap all input coordinates (#5846) In cases where we are unable to find a phantom node for an input coordinate, we return an error indicating which coordinate failed. This would always refer to the coordinate with index equal to the number of valid phantom nodes found. We fix this by instead returning the first index for which a phantom node could not be found. --- CHANGELOG.md | 1 + include/engine/plugins/plugin_base.hpp | 16 ++++++++++++++++ src/engine/plugins/table.cpp | 6 ++---- src/engine/plugins/trip.cpp | 3 +-- src/engine/plugins/viaroute.cpp | 3 +-- unit_tests/library/table.cpp | 2 ++ 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c44f9ab8e..c2f756194 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - CHANGED: Reduce memory usage for raster source handling. [#5572](https://github.com/Project-OSRM/osrm-backend/pull/5572) - CHANGED: Add cmake option `ENABLE_DEBUG_LOGGING` to control whether output debug logging. [#3427](https://github.com/Project-OSRM/osrm-backend/issues/3427) - CHANGED: updated extent of Hong Kong as left hand drive country. [#5535](https://github.com/Project-OSRM/osrm-backend/issues/5535) + - FIXED: corrected error message when failing to snap input coordinates [#5846](https://github.com/Project-OSRM/osrm-backend/pull/5846) - Infrastructure - REMOVED: STXXL support removed as STXXL became abandonware. [#5760](https://github.com/Project-OSRM/osrm-backend/pull/5760) # 5.21.0 diff --git a/include/engine/plugins/plugin_base.hpp b/include/engine/plugins/plugin_base.hpp index 28e3db72f..6fc23adcd 100644 --- a/include/engine/plugins/plugin_base.hpp +++ b/include/engine/plugins/plugin_base.hpp @@ -371,6 +371,22 @@ class BasePlugin } return phantom_node_pairs; } + + std::string MissingPhantomErrorMessage(const std::vector &phantom_nodes, + const std::vector &coordinates) const + { + BOOST_ASSERT(phantom_nodes.size() < coordinates.size()); + auto mismatch = std::mismatch(phantom_nodes.begin(), + phantom_nodes.end(), + coordinates.begin(), + coordinates.end(), + [](const auto &phantom_node, const auto &coordinate) { + return phantom_node.first.input_location == coordinate; + }); + std::size_t missing_index = std::distance(phantom_nodes.begin(), mismatch.first); + return std::string("Could not find a matching segment for coordinate ") + + std::to_string(missing_index); + } }; } } diff --git a/src/engine/plugins/table.cpp b/src/engine/plugins/table.cpp index 190a0138c..5b517ac17 100644 --- a/src/engine/plugins/table.cpp +++ b/src/engine/plugins/table.cpp @@ -75,10 +75,8 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms, if (phantom_nodes.size() != params.coordinates.size()) { - return Error("NoSegment", - std::string("Could not find a matching segment for coordinate ") + - std::to_string(phantom_nodes.size()), - result); + return Error( + "NoSegment", MissingPhantomErrorMessage(phantom_nodes, params.coordinates), result); } auto snapped_phantoms = SnapPhantomNodes(phantom_nodes); diff --git a/src/engine/plugins/trip.cpp b/src/engine/plugins/trip.cpp index 75a38d50a..74a4452aa 100644 --- a/src/engine/plugins/trip.cpp +++ b/src/engine/plugins/trip.cpp @@ -199,8 +199,7 @@ Status TripPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms, if (phantom_node_pairs.size() != number_of_locations) { return Error("NoSegment", - std::string("Could not find a matching segment for coordinate ") + - std::to_string(phantom_node_pairs.size()), + MissingPhantomErrorMessage(phantom_node_pairs, parameters.coordinates), result); } BOOST_ASSERT(phantom_node_pairs.size() == number_of_locations); diff --git a/src/engine/plugins/viaroute.cpp b/src/engine/plugins/viaroute.cpp index 8c4e3e891..9b0f3ebfc 100644 --- a/src/engine/plugins/viaroute.cpp +++ b/src/engine/plugins/viaroute.cpp @@ -90,8 +90,7 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm if (phantom_node_pairs.size() != route_parameters.coordinates.size()) { return Error("NoSegment", - std::string("Could not find a matching segment for coordinate ") + - std::to_string(phantom_node_pairs.size()), + MissingPhantomErrorMessage(phantom_node_pairs, route_parameters.coordinates), result); } BOOST_ASSERT(phantom_node_pairs.size() == route_parameters.coordinates.size()); diff --git a/unit_tests/library/table.cpp b/unit_tests/library/table.cpp index 139830856..26fbdec78 100644 --- a/unit_tests/library/table.cpp +++ b/unit_tests/library/table.cpp @@ -242,6 +242,8 @@ BOOST_AUTO_TEST_CASE(test_table_no_segment_for_some_coordinates) BOOST_CHECK(rc == Status::Error); const auto code = json_result.values.at("code").get().value; BOOST_CHECK_EQUAL(code, "NoSegment"); + const auto message = json_result.values.at("message").get().value; + BOOST_CHECK_EQUAL(message, "Could not find a matching segment for coordinate 0"); } BOOST_AUTO_TEST_CASE(test_table_serialiaze_fb) From 3451d1ec8237914b4a598e6f5f82147d5a45bf77 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Wed, 30 Sep 2020 18:45:44 -0700 Subject: [PATCH 03/17] Lock access to facade_factory in data_watchdog to avoid accessing destructed object (#5844) * Wrap access to facade_factory in a shared lock so it doesn't get changed partway through access which leads to a crash. --- CHANGELOG.md | 1 + include/engine/data_watchdog.hpp | 31 +++++++++++++++++++++---------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2f756194..a7eab1b7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - CHANGED: default car weight was reduced to 2000 kg. [#5371](https://github.com/Project-OSRM/osrm-backend/pull/5371) - CHANGED: default car height was reduced to 2 meters. [#5389](https://github.com/Project-OSRM/osrm-backend/pull/5389) - FIXED: treat `bicycle=use_sidepath` as no access on the tagged way. [#5622](https://github.com/Project-OSRM/osrm-backend/pull/5622) + - FIXED: fix occasional segfault when swapping data with osrm-datastore and using `exclude=` [#5844](https://github.com/Project-OSRM/osrm-backend/pull/5844) - Misc: - CHANGED: Reduce memory usage for raster source handling. [#5572](https://github.com/Project-OSRM/osrm-backend/pull/5572) - CHANGED: Add cmake option `ENABLE_DEBUG_LOGGING` to control whether output debug logging. [#3427](https://github.com/Project-OSRM/osrm-backend/issues/3427) diff --git a/include/engine/data_watchdog.hpp b/include/engine/data_watchdog.hpp index b44274545..416f1df76 100644 --- a/include/engine/data_watchdog.hpp +++ b/include/engine/data_watchdog.hpp @@ -56,11 +56,14 @@ class DataWatchdogImpl( - std::make_shared( - std::vector{ - static_region.shm_key, updatable_region.shm_key})); + { + boost::unique_lock swap_lock(factory_mutex); + facade_factory = + DataFacadeFactory( + std::make_shared( + std::vector{ + static_region.shm_key, updatable_region.shm_key})); + } } watcher = std::thread(&DataWatchdogImpl::Run, this); @@ -75,10 +78,14 @@ class DataWatchdogImpl Get(const api::BaseParameters ¶ms) const { + // make sure facade_factory stays stable while we call Get() + boost::shared_lock swap_lock(factory_mutex); return facade_factory.Get(params); } std::shared_ptr Get(const api::TileParameters ¶ms) const { + // make sure facade_factory stays stable while we call Get() + boost::shared_lock swap_lock(factory_mutex); return facade_factory.Get(params); } @@ -111,16 +118,20 @@ class DataWatchdogImpl( - std::make_shared( - std::vector{ - static_region.shm_key, updatable_region.shm_key})); + { + boost::unique_lock swap_lock(factory_mutex); + facade_factory = + DataFacadeFactory( + std::make_shared( + std::vector{ + static_region.shm_key, updatable_region.shm_key})); + } } util::Log() << "DataWatchdog thread stopped"; } + mutable boost::shared_mutex factory_mutex; const std::string dataset_name; storage::SharedMonitor barrier; std::thread watcher; From 55b3260cc3119576665981867dd534ddfdedc964 Mon Sep 17 00:00:00 2001 From: Denis Chaplygin Date: Tue, 6 Oct 2020 09:01:22 +0300 Subject: [PATCH 04/17] Driving side property added to driving_side.geojson --- data/driving_side.geojson | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/data/driving_side.geojson b/data/driving_side.geojson index 88a26f1d7..9dc8e7652 100644 --- a/data/driving_side.geojson +++ b/data/driving_side.geojson @@ -4,7 +4,7 @@ { "type": "Feature", "properties": { - + "driving_side": "left" }, "geometry": { "type": "Polygon", @@ -301,7 +301,7 @@ { "type": "Feature", "properties": { - + "driving_side": "left" }, "geometry": { "type": "Polygon", @@ -334,7 +334,7 @@ { "type": "Feature", "properties": { - + "driving_side": "left" }, "geometry": { "type": "Polygon", @@ -783,7 +783,7 @@ { "type": "Feature", "properties": { - + "driving_side": "left" }, "geometry": { "type": "Polygon", @@ -1528,7 +1528,7 @@ { "type": "Feature", "properties": { - + "driving_side": "left" }, "geometry": { "type": "Polygon", @@ -1557,7 +1557,7 @@ { "type": "Feature", "properties": { - + "driving_side": "left" }, "geometry": { "type": "Polygon", @@ -1586,7 +1586,7 @@ { "type": "Feature", "properties": { - + "driving_side": "left" }, "geometry": { "type": "Polygon", @@ -1623,7 +1623,7 @@ { "type": "Feature", "properties": { - + "driving_side": "left" }, "geometry": { "type": "Polygon", @@ -3040,7 +3040,7 @@ { "type": "Feature", "properties": { - + "driving_side": "left" }, "geometry": { "type": "Polygon", @@ -3081,7 +3081,7 @@ { "type": "Feature", "properties": { - + "driving_side": "left" }, "geometry": { "type": "Polygon", @@ -3126,7 +3126,7 @@ { "type": "Feature", "properties": { - + "driving_side": "left" }, "geometry": { "type": "Polygon", From c24f917dcfc4c87d8c104dafb5d592e207155e52 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Wed, 7 Oct 2020 14:58:38 -0600 Subject: [PATCH 05/17] Cleanup changelog in master to match current release state. --- CHANGELOG.md | 14 ++++++++++---- package.json | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7eab1b7a..9a370ff25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,8 @@ # Unreleased - - Changes from 5.21.0 + - Changes from 5.22.0 - Build: - - ADDED: optionally build Node `lts` and `latest` bindings [#5347](https://github.com/Project-OSRM/osrm-backend/pull/5347) - FIXED: pessimistic calls to std::move [#5560](https://github.com/Project-OSRM/osrm-backend/pull/5561) - Features: - - ADDED: new waypoints parameter to the `route` plugin, enabling silent waypoints [#5345](https://github.com/Project-OSRM/osrm-backend/pull/5345) - - ADDED: data timestamp information in the response (saved in new file `.osrm.timestamp`). [#5115](https://github.com/Project-OSRM/osrm-backend/issues/5115) - ADDED: new API parameter - `snapping=any|default` to allow snapping to previously unsnappable edges [#5361](https://github.com/Project-OSRM/osrm-backend/pull/5361) - ADDED: keepalive support to the osrm-routed HTTP server [#5518](https://github.com/Project-OSRM/osrm-backend/pull/5518) - ADDED: flatbuffers output format support [#5513](https://github.com/Project-OSRM/osrm-backend/pull/5513) @@ -25,6 +22,15 @@ - FIXED: corrected error message when failing to snap input coordinates [#5846](https://github.com/Project-OSRM/osrm-backend/pull/5846) - Infrastructure - REMOVED: STXXL support removed as STXXL became abandonware. [#5760](https://github.com/Project-OSRM/osrm-backend/pull/5760) + +# 5.22.0 + - Changes from 5.21.0 + - Build: + - ADDED: optionally build Node `lts` and `latest` bindings [#5347](https://github.com/Project-OSRM/osrm-backend/pull/5347) + - Features: + - ADDED: new waypoints parameter to the `route` plugin, enabling silent waypoints [#5345](https://github.com/Project-OSRM/osrm-backend/pull/5345) + - ADDED: data timestamp information in the response (saved in new file `.osrm.timestamp`). [#5115](https://github.com/Project-OSRM/osrm-backend/issues/5115) + # 5.21.0 - Changes from 5.20.0 - Features: diff --git a/package.json b/package.json index 7aa41401a..5e884d51d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "osrm", - "version": "5.22.0-customsnapping.2", + "version": "5.23.0-unreleased", "private": false, "description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.", "dependencies": { From e033e0b5538e0a07abdcd71acbc329afeea1062b Mon Sep 17 00:00:00 2001 From: Michael Bell Date: Wed, 7 Oct 2020 22:58:13 +0100 Subject: [PATCH 06/17] Fix table result when source and destination on same one-way segment (#5828) Fixes #5788 Table queries where source and destination are phantom nodes on the same one-way segment can fail to find valid routes. This is due to a bug in the MLD table generation for the special case where the query can be simplified to a one-to-many search. If the destination is before the source on the one-way segment, it will fail to find a route. We fix this case by not marking the node as visited at the start, so that valid paths to this node can be found later in the search. We also remove redundant initialization for the source node as the same actions are performed by a search step. --- CHANGELOG.md | 1 + features/testbot/oneway_phantom.feature | 85 +++++++++++ .../routing_algorithms/many_to_many_mld.cpp | 138 +++++++++--------- 3 files changed, 152 insertions(+), 72 deletions(-) create mode 100644 features/testbot/oneway_phantom.feature diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a370ff25..40cc724b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - CHANGED: default car weight was reduced to 2000 kg. [#5371](https://github.com/Project-OSRM/osrm-backend/pull/5371) - CHANGED: default car height was reduced to 2 meters. [#5389](https://github.com/Project-OSRM/osrm-backend/pull/5389) - FIXED: treat `bicycle=use_sidepath` as no access on the tagged way. [#5622](https://github.com/Project-OSRM/osrm-backend/pull/5622) + - FIXED: fix table result when source and destination on same one-way segment. [#5828](https://github.com/Project-OSRM/osrm-backend/pull/5828) - FIXED: fix occasional segfault when swapping data with osrm-datastore and using `exclude=` [#5844](https://github.com/Project-OSRM/osrm-backend/pull/5844) - Misc: - CHANGED: Reduce memory usage for raster source handling. [#5572](https://github.com/Project-OSRM/osrm-backend/pull/5572) diff --git a/features/testbot/oneway_phantom.feature b/features/testbot/oneway_phantom.feature new file mode 100644 index 000000000..9d728a507 --- /dev/null +++ b/features/testbot/oneway_phantom.feature @@ -0,0 +1,85 @@ +@routing @testbot @oneway +Feature: Handle multiple phantom nodes in one-way segment + +# Check we handle routes where source and destination are +# phantom nodes on the same one-way segment. +# See: https://github.com/Project-OSRM/osrm-backend/issues/5788 + + Background: + Given the profile "testbot" + + Scenario: One-way segment with adjacent phantom nodes + Given the node map + """ + d c + + a12b + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | no | + | cd | no | + | da | no | + + When I route I should get + | from | to | route | time | distance | + | 1 | 2 | ab,ab | 5s +-0.1 | 50m ~1% | + | 1 | c | ab,bc,bc | 30s +-0.1 | 300m ~1% | + | 2 | 1 | ab,bc,cd,da,ab | 65s +-0.1 | 650m ~1% | + | 2 | c | ab,bc,bc | 25s +-0.1 | 250m ~1% | + | c | 1 | cd,da,ab | 40s +-0.1 | 400m ~1% | + | c | 2 | cd,da,ab | 45s +-0.1 | 450m ~1% | + + When I request a travel time matrix I should get + | | 1 | 2 | c | + | 1 | 0 | 5 +-0.1 | 30 +-0.1 | + | 2 | 65 +-0.1 | 0 | 25 +-0.1 | + | c | 40 +-0.1 | 45 +-0.1 | 0 | + + When I request a travel time matrix I should get + | | 1 | 2 | c | + | 1 | 0 | 5 +-0.1 | 30 +-0.1 | + + When I request a travel time matrix I should get + | | 1 | 2 | c | + | 2 | 65 +-0.1 | 0 | 25 +-0.1 | + + When I request a travel time matrix I should get + | | 1 | + | 1 | 0 | + | 2 | 65 +-0.1 | + | c | 40 +-0.1 | + + When I request a travel time matrix I should get + | | 2 | + | 1 | 5 +-0.1 | + | 2 | 0 | + | c | 45 +-0.1 | + + When I request a travel distance matrix I should get + | | 1 | 2 | c | + | 1 | 0 | 50 ~1% | 300 ~1% | + | 2 | 650 ~1% | 0 | 250 ~1% | + | c | 400 ~1% | 450 ~1% | 0 | + + When I request a travel distance matrix I should get + | | 1 | 2 | c | + | 1 | 0 | 50 ~1% | 300 ~1% | + + When I request a travel distance matrix I should get + | | 1 | 2 | c | + | 2 | 650 ~1% | 0 | 250 ~1% | + + When I request a travel distance matrix I should get + | | 1 | + | 1 | 0 | + | 2 | 650 ~1% | + | c | 400 ~1% | + + When I request a travel distance matrix I should get + | | 2 | + | 1 | 50 ~1% | + | 2 | 0 | + | c | 450 ~1% | diff --git a/src/engine/routing_algorithms/many_to_many_mld.cpp b/src/engine/routing_algorithms/many_to_many_mld.cpp index 55544c4bb..bd41f7aba 100644 --- a/src/engine/routing_algorithms/many_to_many_mld.cpp +++ b/src/engine/routing_algorithms/many_to_many_mld.cpp @@ -36,6 +36,59 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition, return node_level; } +template +void relaxBorderEdges(const DataFacade &facade, + const NodeID node, + const EdgeWeight weight, + const EdgeDuration duration, + const EdgeDistance distance, + typename SearchEngineData::ManyToManyQueryHeap &query_heap, + LevelID level) +{ + for (const auto edge : facade.GetBorderEdgeRange(level, node)) + { + const auto &data = facade.GetEdgeData(edge); + if ((DIRECTION == FORWARD_DIRECTION) ? facade.IsForwardEdge(edge) + : facade.IsBackwardEdge(edge)) + { + const NodeID to = facade.GetTarget(edge); + if (facade.ExcludeNode(to)) + { + continue; + } + + const auto turn_id = data.turn_id; + const auto node_id = DIRECTION == FORWARD_DIRECTION ? node : facade.GetTarget(edge); + const auto node_weight = facade.GetNodeWeight(node_id); + const auto node_duration = facade.GetNodeDuration(node_id); + const auto node_distance = facade.GetNodeDistance(node_id); + const auto turn_weight = node_weight + facade.GetWeightPenaltyForEdgeID(turn_id); + const auto turn_duration = node_duration + facade.GetDurationPenaltyForEdgeID(turn_id); + + BOOST_ASSERT_MSG(node_weight + turn_weight > 0, "edge weight is invalid"); + const auto to_weight = weight + turn_weight; + const auto to_duration = duration + turn_duration; + const auto to_distance = distance + node_distance; + + // New Node discovered -> Add to Heap + Node Info Storage + if (!query_heap.WasInserted(to)) + { + query_heap.Insert(to, to_weight, {node, false, to_duration, to_distance}); + } + // Found a shorter Path -> Update weight and set new parent + else if (std::tie(to_weight, to_duration, to_distance, node) < + std::tie(query_heap.GetKey(to), + query_heap.GetData(to).duration, + query_heap.GetData(to).distance, + query_heap.GetData(to).parent)) + { + query_heap.GetData(to) = {node, false, to_duration, to_distance}; + query_heap.DecreaseKey(to, to_weight); + } + } + } +} + template void relaxOutgoingEdges(const DataFacade &facade, const NodeID node, @@ -140,48 +193,7 @@ void relaxOutgoingEdges(const DataFacade &facade, } } - for (const auto edge : facade.GetBorderEdgeRange(level, node)) - { - const auto &data = facade.GetEdgeData(edge); - if ((DIRECTION == FORWARD_DIRECTION) ? facade.IsForwardEdge(edge) - : facade.IsBackwardEdge(edge)) - { - const NodeID to = facade.GetTarget(edge); - if (facade.ExcludeNode(to)) - { - continue; - } - - const auto turn_id = data.turn_id; - const auto node_id = DIRECTION == FORWARD_DIRECTION ? node : facade.GetTarget(edge); - const auto node_weight = facade.GetNodeWeight(node_id); - const auto node_duration = facade.GetNodeDuration(node_id); - const auto node_distance = facade.GetNodeDistance(node_id); - const auto turn_weight = node_weight + facade.GetWeightPenaltyForEdgeID(turn_id); - const auto turn_duration = node_duration + facade.GetDurationPenaltyForEdgeID(turn_id); - - BOOST_ASSERT_MSG(node_weight + turn_weight > 0, "edge weight is invalid"); - const auto to_weight = weight + turn_weight; - const auto to_duration = duration + turn_duration; - const auto to_distance = distance + node_distance; - - // New Node discovered -> Add to Heap + Node Info Storage - if (!query_heap.WasInserted(to)) - { - query_heap.Insert(to, to_weight, {node, false, to_duration, to_distance}); - } - // Found a shorter Path -> Update weight and set new parent - else if (std::tie(to_weight, to_duration, to_distance, node) < - std::tie(query_heap.GetKey(to), - query_heap.GetData(to).duration, - query_heap.GetData(to).distance, - query_heap.GetData(to).parent)) - { - query_heap.GetData(to) = {node, false, to_duration, to_distance}; - query_heap.DecreaseKey(to, to_weight); - } - } - } + relaxBorderEdges(facade, node, weight, duration, distance, query_heap, level); } // @@ -297,37 +309,19 @@ oneToManySearch(SearchEngineData &engine_working_data, EdgeWeight initial_weight, EdgeDuration initial_duration, EdgeDistance initial_distance) { - - // Update single node paths - update_values(node, initial_weight, initial_duration, initial_distance); - - query_heap.Insert(node, initial_weight, {node, initial_duration, initial_distance}); - - // Place adjacent nodes into heap - for (auto edge : facade.GetAdjacentEdgeRange(node)) + if (target_nodes_index.count(node)) { - const auto &data = facade.GetEdgeData(edge); - const auto to = facade.GetTarget(edge); - - if (facade.ExcludeNode(to)) - { - continue; - } - - if ((DIRECTION == FORWARD_DIRECTION ? facade.IsForwardEdge(edge) - : facade.IsBackwardEdge(edge)) && - !query_heap.WasInserted(to)) - { - const auto turn_id = data.turn_id; - const auto node_id = DIRECTION == FORWARD_DIRECTION ? node : to; - const auto edge_weight = initial_weight + facade.GetNodeWeight(node_id) + - facade.GetWeightPenaltyForEdgeID(turn_id); - const auto edge_duration = initial_duration + facade.GetNodeDuration(node_id) + - facade.GetDurationPenaltyForEdgeID(turn_id); - const auto edge_distance = initial_distance + facade.GetNodeDistance(node_id); - - query_heap.Insert(to, edge_weight, {node, edge_duration, edge_distance}); - } + // Source and target on the same edge node. If target is not reachable directly via + // the node (e.g destination is before source on oneway segment) we want to allow + // node to be visited later in the search along a reachable path. + // Therefore, we manually run first step of search without marking node as visited. + update_values(node, initial_weight, initial_duration, initial_distance); + relaxBorderEdges( + facade, node, initial_weight, initial_duration, initial_distance, query_heap, 0); + } + else + { + query_heap.Insert(node, initial_weight, {node, initial_duration, initial_distance}); } }; From 2222ee6a67d46426fb6f2ae99459c48ad04f6fa2 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Wed, 7 Oct 2020 16:21:00 -0600 Subject: [PATCH 07/17] Prepare 5.23.0-rc.1 --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40cc724b7..f21edea0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# Unreleased +# 5.23.0-rc.1 - Changes from 5.22.0 - Build: - FIXED: pessimistic calls to std::move [#5560](https://github.com/Project-OSRM/osrm-backend/pull/5561) diff --git a/package.json b/package.json index 5e884d51d..eb87dc7ff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "osrm", - "version": "5.23.0-unreleased", + "version": "5.23.0-rc.1", "private": false, "description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.", "dependencies": { From f87a324633c2a1ebe5de4602a612c85aad34c101 Mon Sep 17 00:00:00 2001 From: Michael Bell Date: Thu, 8 Oct 2020 23:27:02 +0100 Subject: [PATCH 08/17] Fix crash in MLD alternative search if source or target are invalid (#5851) In situations where there is not a valid source or target phantom node (e.g. when snapping to an edge with a zero weight), a heap assertion will fail in the MLD alternative search code. We fix this by checking for empty heaps before proceeding with the search. --- CHANGELOG.md | 1 + features/testbot/zero-speed-updates.feature | 25 +++++++++++++++++++ .../alternative_path_mld.cpp | 4 +++ 3 files changed, 30 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40cc724b7..40fa33b2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - FIXED: treat `bicycle=use_sidepath` as no access on the tagged way. [#5622](https://github.com/Project-OSRM/osrm-backend/pull/5622) - FIXED: fix table result when source and destination on same one-way segment. [#5828](https://github.com/Project-OSRM/osrm-backend/pull/5828) - FIXED: fix occasional segfault when swapping data with osrm-datastore and using `exclude=` [#5844](https://github.com/Project-OSRM/osrm-backend/pull/5844) + - FIXED: fix crash in MLD alternative search if source or target are invalid [#5851](https://github.com/Project-OSRM/osrm-backend/pull/5851) - Misc: - CHANGED: Reduce memory usage for raster source handling. [#5572](https://github.com/Project-OSRM/osrm-backend/pull/5572) - CHANGED: Add cmake option `ENABLE_DEBUG_LOGGING` to control whether output debug logging. [#3427](https://github.com/Project-OSRM/osrm-backend/issues/3427) diff --git a/features/testbot/zero-speed-updates.feature b/features/testbot/zero-speed-updates.feature index 6acb2b0c8..c2bc82c94 100644 --- a/features/testbot/zero-speed-updates.feature +++ b/features/testbot/zero-speed-updates.feature @@ -93,6 +93,31 @@ Feature: Check zero speed updates | 1 | 2 | NoRoute | + Scenario: Routing with alternatives on restricted way + Given the node map + """ + a-1-b-2-c + """ + + And the ways + | nodes | oneway | + | abc | no | + And the contract extra arguments "--segment-speed-file {speeds_file}" + And the customize extra arguments "--segment-speed-file {speeds_file}" + And the speed file + """ + 1,2,0 + 2,1,0 + """ + And the query options + | alternatives | true | + + + When I route I should get + | from | to | code | alternative | + | 1 | 2 | NoRoute | | + + Scenario: Routing on restricted oneway Given the node map """ diff --git a/src/engine/routing_algorithms/alternative_path_mld.cpp b/src/engine/routing_algorithms/alternative_path_mld.cpp index 7bc14e566..51688c825 100644 --- a/src/engine/routing_algorithms/alternative_path_mld.cpp +++ b/src/engine/routing_algorithms/alternative_path_mld.cpp @@ -663,6 +663,10 @@ makeCandidateVias(SearchEngineData &search_engine_data, Heap &reverse_heap = *search_engine_data.reverse_heap_1; insertNodesInHeaps(forward_heap, reverse_heap, phantom_node_pair); + if (forward_heap.Empty() || reverse_heap.Empty()) + { + return {}; + } // The single via node in the shortest paths s,via and via,t sub-paths and // the weight for the shortest path s,t we return and compare alternatives to. From 628784eb7d2eb0387d91e7629ff8caec84187357 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Thu, 8 Oct 2020 20:14:10 -0600 Subject: [PATCH 09/17] Prepare 5.23.0-rc.2 --- CHANGELOG.md | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dbfa3984..206341394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# 5.23.0-rc.1 +# 5.23.0-rc.2 - Changes from 5.22.0 - Build: - FIXED: pessimistic calls to std::move [#5560](https://github.com/Project-OSRM/osrm-backend/pull/5561) diff --git a/package-lock.json b/package-lock.json index d69596244..e6abe33c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "osrm", - "version": "5.22.0-customsnapping.2", + "version": "5.23.0-rc.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index eb87dc7ff..e8584c428 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "osrm", - "version": "5.23.0-rc.1", + "version": "5.23.0-rc.2", "private": false, "description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.", "dependencies": { From c021cea7708fb98254d5a50f9a585df16c8ab429 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Wed, 14 Oct 2020 14:08:23 -0700 Subject: [PATCH 10/17] Prepare 5.23.0 release --- CHANGELOG.md | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 206341394..91fca9f51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# 5.23.0-rc.2 +# 5.23.0 - Changes from 5.22.0 - Build: - FIXED: pessimistic calls to std::move [#5560](https://github.com/Project-OSRM/osrm-backend/pull/5561) diff --git a/package-lock.json b/package-lock.json index e6abe33c4..cb61b4c3f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "osrm", - "version": "5.23.0-rc.2", + "version": "5.23.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e8584c428..b21a30918 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "osrm", - "version": "5.23.0-rc.2", + "version": "5.23.0", "private": false, "description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.", "dependencies": { From df3ed43d7026f7bfa01fff2861189dcc02c3a974 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Wed, 14 Oct 2020 14:10:33 -0700 Subject: [PATCH 11/17] Reset master for next version. --- CHANGELOG.md | 2 ++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91fca9f51..17e53921e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +# Unreleased + # 5.23.0 - Changes from 5.22.0 - Build: diff --git a/package-lock.json b/package-lock.json index cb61b4c3f..461bc1231 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "osrm", - "version": "5.23.0", + "version": "5.24.0-unreleased", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b21a30918..43634204a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "osrm", - "version": "5.23.0", + "version": "5.24.0-unreleased", "private": false, "description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.", "dependencies": { From a8362d75b5bf31fb282aa3593318964d64a37475 Mon Sep 17 00:00:00 2001 From: Denis Chaplygin Date: Fri, 16 Oct 2020 10:25:52 +0300 Subject: [PATCH 12/17] Updated bundled protozero to v1.7.0 --- CHANGELOG.md | 3 + third_party/protozero/.clang-tidy | 27 +- third_party/protozero/.travis.yml | 252 +- third_party/protozero/CHANGELOG.md | 91 +- third_party/protozero/CMakeLists.txt | 11 +- third_party/protozero/README.md | 6 +- third_party/protozero/UPGRADING.md | 5 + third_party/protozero/appveyor.yml | 35 +- third_party/protozero/build-appveyor.bat | 65 - third_party/protozero/build-local.bat | 29 - third_party/protozero/build-msys2.bat | 18 - third_party/protozero/doc/Doxyfile.in | 4 +- third_party/protozero/doc/advanced.md | 55 + .../include/protozero/basic_pbf_builder.hpp | 266 + .../include/protozero/basic_pbf_writer.hpp | 1054 + .../include/protozero/buffer_fixed.hpp | 222 + .../include/protozero/buffer_string.hpp | 76 + .../include/protozero/buffer_tmpl.hpp | 113 + .../include/protozero/buffer_vector.hpp | 76 + .../protozero/include/protozero/byteswap.hpp | 62 +- .../protozero/include/protozero/data_view.hpp | 18 +- .../protozero/include/protozero/iterators.hpp | 74 +- .../include/protozero/pbf_builder.hpp | 243 +- .../include/protozero/pbf_message.hpp | 6 +- .../include/protozero/pbf_reader.hpp | 52 +- .../include/protozero/pbf_writer.hpp | 1009 +- .../protozero/include/protozero/types.hpp | 4 +- .../protozero/include/protozero/varint.hpp | 111 +- .../protozero/include/protozero/version.hpp | 6 +- third_party/protozero/test/catch/catch.hpp | 24446 ++++++++++------ .../protozero/test/create_pbf_test_data.sh | 7 + third_party/protozero/test/include/buffer.hpp | 162 + .../protozero/test/include/packed_access.hpp | 27 +- .../protozero/test/include/scalar_access.hpp | 2 +- third_party/protozero/test/include/test.hpp | 3 + third_party/protozero/test/reader_tests.cpp | 2 + .../test/t/alignment/reader_test_cases.cpp | 8 +- .../protozero/test/t/bool/bool_testcase.proto | 1 + .../test/t/bool/reader_test_cases.cpp | 2 +- .../protozero/test/t/bool/testcase.cpp | 3 +- .../test/t/bool/writer_test_cases.cpp | 13 +- .../test/t/bytes/bytes_testcase.proto | 1 + .../test/t/bytes/reader_test_cases.cpp | 2 +- .../protozero/test/t/bytes/testcase.cpp | 3 +- .../test/t/bytes/writer_test_cases.cpp | 17 +- .../test/t/complex/reader_test_cases.cpp | 116 +- .../protozero/test/t/complex/testcase.cpp | 3 +- .../protozero/test/t/complex/testcase.proto | 1 + .../test/t/double/double_testcase.proto | 1 + .../test/t/double/reader_test_cases.cpp | 2 +- .../protozero/test/t/double/testcase.cpp | 3 +- .../test/t/double/writer_test_cases.cpp | 15 +- .../protozero/test/t/enum/enum_testcase.proto | 1 + .../protozero/test/t/enum/testcase.cpp | 3 +- .../test/t/enum/writer_test_cases.cpp | 19 +- .../test/t/fixed32/fixed32_testcase.proto | 1 + .../protozero/test/t/fixed32/testcase.cpp | 3 +- .../test/t/fixed32/writer_test_cases.cpp | 15 +- .../protozero/test/t/fixed64/testcase.cpp | 3 +- .../protozero/test/t/fixed64/testcase.proto | 1 + .../test/t/float/reader_test_cases.cpp | 8 +- .../protozero/test/t/float/testcase.cpp | 3 +- .../protozero/test/t/float/testcase.proto | 1 + .../test/t/int32/int32_testcase.proto | 1 + .../protozero/test/t/int32/testcase.cpp | 3 +- .../test/t/int32/writer_test_cases.cpp | 19 +- .../protozero/test/t/int64/testcase.cpp | 3 +- .../protozero/test/t/int64/testcase.proto | 1 + .../test/t/message/message_testcase.proto | 1 + .../test/t/message/reader_test_cases.cpp | 8 +- .../protozero/test/t/message/testcase.cpp | 3 +- .../test/t/message/writer_test_cases.cpp | 15 +- .../test/t/nested/nested_testcase.proto | 1 + .../protozero/test/t/nested/testcase.cpp | 3 +- .../test/t/nested/writer_test_cases.cpp | 19 +- .../test/t/repeated/reader_test_cases.cpp | 2 +- .../test/t/repeated/repeated_testcase.proto | 1 + .../protozero/test/t/repeated/testcase.cpp | 3 +- .../test/t/repeated/writer_test_cases.cpp | 13 +- .../reader_test_cases.cpp | 10 +- .../test/t/repeated_packed_bool/testcase.cpp | 3 +- .../reader_test_cases.cpp | 12 +- .../t/repeated_packed_double/testcase.cpp | 3 +- .../reader_test_cases.cpp | 10 +- .../test/t/repeated_packed_enum/testcase.cpp | 3 +- .../repeated_packed_fixed32_testcase.proto | 1 + .../t/repeated_packed_fixed32/testcase.cpp | 3 +- .../writer_test_cases.cpp | 37 +- .../t/repeated_packed_fixed64/testcase.cpp | 3 +- .../reader_test_cases.cpp | 18 +- .../test/t/repeated_packed_float/testcase.cpp | 3 +- .../test/t/repeated_packed_int32/testcase.cpp | 3 +- .../test/t/repeated_packed_int64/testcase.cpp | 3 +- .../reader_test_cases.cpp | 2 +- .../t/repeated_packed_sfixed32/testcase.cpp | 3 +- .../t/repeated_packed_sfixed64/testcase.cpp | 3 +- .../t/repeated_packed_sint32/testcase.cpp | 3 +- .../t/repeated_packed_sint64/testcase.cpp | 3 +- .../t/repeated_packed_uint32/testcase.cpp | 3 +- .../t/repeated_packed_uint64/testcase.cpp | 3 +- .../test/t/rollback/reader_test_cases.cpp | 8 +- .../protozero/test/t/sfixed32/testcase.cpp | 3 +- .../protozero/test/t/sfixed64/testcase.cpp | 3 +- .../protozero/test/t/sint32/testcase.cpp | 3 +- .../protozero/test/t/sint64/testcase.cpp | 3 +- .../test/t/skip/reader_test_cases.cpp | 4 +- .../test/t/string/reader_test_cases.cpp | 4 +- .../test/t/string/string_testcase.proto | 1 + .../protozero/test/t/string/testcase.cpp | 3 +- .../test/t/string/writer_test_cases.cpp | 15 +- .../test/t/tag_and_type/reader_test_cases.cpp | 12 +- .../test/t/tag_and_type/testcase.cpp | 3 +- .../test/t/tags/reader_test_cases.cpp | 10 +- .../protozero/test/t/tags/testcase.cpp | 3 +- .../protozero/test/t/uint32/testcase.cpp | 3 +- .../protozero/test/t/uint64/testcase.cpp | 3 +- .../test/t/vector_tile/reader_test_cases.cpp | 2 + .../t/wrong_type_access/reader_test_cases.cpp | 24 +- .../protozero/test/unit/CMakeLists.txt | 2 + .../protozero/test/unit/test_basic.cpp | 128 +- .../protozero/test/unit/test_buffer.cpp | 50 + .../protozero/test/unit/test_data_view.cpp | 2 +- .../protozero/test/unit/test_endian.cpp | 36 +- .../protozero/test/unit/test_iterators.cpp | 18 + .../protozero/test/unit/test_varint.cpp | 94 +- .../protozero/test/unit/test_zigzag.cpp | 12 +- 126 files changed, 18489 insertions(+), 11079 deletions(-) delete mode 100644 third_party/protozero/build-appveyor.bat delete mode 100644 third_party/protozero/build-local.bat delete mode 100644 third_party/protozero/build-msys2.bat create mode 100644 third_party/protozero/include/protozero/basic_pbf_builder.hpp create mode 100644 third_party/protozero/include/protozero/basic_pbf_writer.hpp create mode 100644 third_party/protozero/include/protozero/buffer_fixed.hpp create mode 100644 third_party/protozero/include/protozero/buffer_string.hpp create mode 100644 third_party/protozero/include/protozero/buffer_tmpl.hpp create mode 100644 third_party/protozero/include/protozero/buffer_vector.hpp create mode 100644 third_party/protozero/test/include/buffer.hpp create mode 100644 third_party/protozero/test/unit/test_buffer.cpp create mode 100644 third_party/protozero/test/unit/test_iterators.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 17e53921e..2179a18c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ # Unreleased + - Changes from 5.23.0 + - Infrastructure + - CHANGED: Bundled protozero updated to v1.7.0. [#5858](https://github.com/Project-OSRM/osrm-backend/pull/5858) # 5.23.0 - Changes from 5.22.0 diff --git a/third_party/protozero/.clang-tidy b/third_party/protozero/.clang-tidy index 1ba914c7c..2bf058632 100644 --- a/third_party/protozero/.clang-tidy +++ b/third_party/protozero/.clang-tidy @@ -1,14 +1,33 @@ --- -Checks: '*,-cert-dcl21-cpp,-cert-err60-cpp,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-type-reinterpret-cast,-fuchsia-*,-google-runtime-references,-hicpp-no-array-decay' +Checks: '*,-bugprone-signed-char-misuse,-cert-dcl21-cpp,-cert-err58-cpp,-cert-err60-cpp,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-macro-usage,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-type-reinterpret-cast,-fuchsia-*,-google-runtime-references,-hicpp-avoid-c-arrays,-hicpp-no-array-decay,-hicpp-vararg,-modernize-avoid-c-arrays,-modernize-use-trailing-return-type,-readability-implicit-bool-conversion,-readability-magic-numbers' # # Disabled checks: # +# bugprone-signed-char-misuse +# Lots of warnings in varint.hpp otherwise. +# # cert-dcl21-cpp # It is unclear whether this is still a good recommendation in modern C++. # +# cert-err58-cpp +# Due to the Catch2 test framework. +# # cert-err60-cpp # Reports std::runtime_error as broken which we can't do anything about. # +# cppcoreguidelines-avoid-c-arrays +# hicpp-avoid-c-arrays +# modernize-avoid-c-arrays +# Makes sense for some array, but especially for char arrays using +# std::array isn't a good solution. +# +# cppcoreguidelines-avoid-magic-numbers +# readability-magic-numbers +# Good idea, but it goes too far to force this everywhere. +# +# cppcoreguidelines-macro-usage +# There are cases where macros are simply needed. +# # cppcoreguidelines-pro-bounds-array-to-pointer-decay # Limited use and many false positives including for all asserts. # @@ -28,6 +47,12 @@ Checks: '*,-cert-dcl21-cpp,-cert-err60-cpp,-cppcoreguidelines-pro-bounds-pointer # hicpp-no-array-decay # Limited use and many false positives including for all asserts. # +# modernize-use-trailing-return-type +# We are not quite that modern. +# +# readability-implicit-bool-conversion +# Not necessarily more readable. +# WarningsAsErrors: '*' HeaderFilterRegex: '\/include\/' AnalyzeTemporaryDtors: false diff --git a/third_party/protozero/.travis.yml b/third_party/protozero/.travis.yml index 891e59bba..e0e94d8e7 100644 --- a/third_party/protozero/.travis.yml +++ b/third_party/protozero/.travis.yml @@ -6,10 +6,6 @@ language: generic -sudo: false - -dist: trusty - #----------------------------------------------------------------------------- # Save common build configurations as shortcuts, so we can reference them later. @@ -17,147 +13,265 @@ addons_shortcuts: addons_clang35: &clang35 apt: sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.5' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-3.5' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-3.5' ] addons_clang38: &clang38 apt: - sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.8' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-3.8' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-3.8' ] addons_clang39: &clang39 apt: - sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.9' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-3.9' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-3.9' ] addons_clang40: &clang40 apt: - sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-4.0' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-4.0' ] + sources: [ 'ubuntu-toolchain-r-test' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-4.0' ] addons_clang50: &clang50 apt: - sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-5.0', 'clang-tidy-5.0' ] - addons_gcc47: &gcc47 + sources: [ 'ubuntu-toolchain-r-test' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-5.0' ] + addons_clang60: &clang60 apt: sources: [ 'ubuntu-toolchain-r-test' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-4.7', 'gcc-4.7' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-6.0' ] + addons_clang7: &clang7 + apt: + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-7' ] + addons_clang8: &clang8 + apt: + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-8' ] + addons_clang9: &clang9 + apt: + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-9', 'clang-tidy-9' ] addons_gcc48: &gcc48 apt: sources: [ 'ubuntu-toolchain-r-test' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-4.8', 'gcc-4.8' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'g++-4.8', 'gcc-4.8' ] addons_gcc49: &gcc49 apt: sources: [ 'ubuntu-toolchain-r-test' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-4.9', 'gcc-4.9' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'g++-4.9', 'gcc-4.9' ] addons_gcc5: &gcc5 apt: sources: [ 'ubuntu-toolchain-r-test' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-5', 'gcc-5' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'g++-5', 'gcc-5' ] addons_gcc6: &gcc6 apt: sources: [ 'ubuntu-toolchain-r-test' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-6', 'gcc-6' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'g++-6', 'gcc-6' ] + addons_gcc7: &gcc7 + apt: + packages: [ 'libprotobuf-dev', 'protobuf-compiler' ] + addons_gcc8: &gcc8 + apt: + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'g++-8', 'gcc-8' ] #----------------------------------------------------------------------------- -matrix: +jobs: include: - os: linux + dist: trusty compiler: "clang-3.5" - env: BUILD='Debug' CC=clang-3.5 CXX=clang++-3.5 + env: BUILD=Debug CC=clang-3.5 CXX=clang++-3.5 addons: *clang35 + - os: linux + dist: xenial compiler: "clang-3.8" - env: BUILD='Debug' CC=clang-3.8 CXX=clang++-3.8 + env: BUILD=Debug CC=clang-3.8 CXX=clang++-3.8 addons: *clang38 + - os: linux + dist: xenial compiler: "clang-3.9" - env: BUILD='Debug' CC=clang-3.9 CXX=clang++-3.9 + env: BUILD=Debug CC=clang-3.9 CXX=clang++-3.9 addons: *clang39 + - os: linux + dist: xenial compiler: "clang-4.0" - env: BUILD='Debug' CC=clang-4.0 CXX=clang++-4.0 + env: BUILD=Debug CC=clang-4.0 CXX=clang++-4.0 addons: *clang40 + - os: linux + dist: xenial compiler: "clang-5.0" - env: BUILD='Debug' CC=clang-5.0 CXX=clang++-5.0 - CLANG_TIDY=clang-tidy-5.0 + env: BUILD=Debug CC=clang-5.0 CXX=clang++-5.0 addons: *clang50 + - os: linux - compiler: "clang-5.0" - env: BUILD='Release' CC=clang-5.0 CXX=clang++-5.0 - addons: *clang50 + dist: xenial + compiler: "clang-6.0" + env: BUILD=Debug CC=clang-6.0 CXX=clang++-6.0 + addons: *clang60 + - os: linux - compiler: "clang-5.0" - env: BUILD='Debug' CC=clang-5.0 CXX=clang++-5.0 + dist: bionic + compiler: "clang-7" + env: BUILD=Debug CC=clang-7 CXX=clang++-7 + addons: *clang7 + + - os: linux + dist: bionic + compiler: "clang-8" + env: BUILD=Debug CC=clang-8 CXX=clang++-8 + addons: *clang8 + + - os: linux + dist: bionic + compiler: "clang-9" + env: BUILD=Debug CC=clang-9 CXX=clang++-9 + CLANG_TIDY=clang-tidy-9 + addons: *clang9 + + - os: linux + dist: bionic + compiler: "clang-9" + env: BUILD=Debug CC=clang-9 CXX=clang++-9 CXXFLAGS="-fsanitize=address,undefined,integer -fno-sanitize-recover=all -fno-omit-frame-pointer" LDFLAGS="-fsanitize=address,undefined,integer" - # LSAN doesn't work on container-based system - sudo: required - addons: *clang50 + addons: *clang9 + - os: linux - compiler: "gcc-4.7" - env: BUILD='Debug' CC=gcc-4.7 CXX=g++-4.7 - addons: *gcc47 + dist: bionic + compiler: "clang-9" + env: BUILD=Release CC=clang-9 CXX=clang++-9 + addons: *clang9 + - os: linux + arch: arm64 + dist: bionic + compiler: "clang-9" + env: BUILD=Debug CC=clang-9 CXX=clang++-9 + CXXFLAGS="-fsanitize=address,undefined,integer -fno-sanitize-recover=all -fno-omit-frame-pointer" + LDFLAGS="-fsanitize=address,undefined,integer" + addons: *clang9 + + - os: linux + arch: ppc64le + dist: bionic + compiler: "clang-9" + env: BUILD=Debug CC=clang-9 CXX=clang++-9 + CXXFLAGS="-fsanitize=address,undefined,integer -fno-sanitize-recover=all -fno-omit-frame-pointer" + LDFLAGS="-fsanitize=address,undefined,integer" + addons: *clang9 + + - os: linux + arch: s390x + dist: bionic + compiler: "clang-9" + env: BUILD=Debug CC=clang-9 CXX=clang++-9 + CXXFLAGS="-fsanitize=address,undefined,integer -fno-sanitize-recover=all -fno-omit-frame-pointer" + LDFLAGS="-fsanitize=address,undefined,integer" + addons: *clang9 + + - os: linux + dist: trusty compiler: "gcc-4.8" - env: BUILD='Debug' CC=gcc-4.8 CXX=g++-4.8 + env: BUILD=Debug CC=gcc-4.8 CXX=g++-4.8 addons: *gcc48 + - os: linux + dist: trusty compiler: "gcc-4.9" - env: BUILD='Debug' CC=gcc-4.9 CXX=g++-4.9 - COVERAGE=gcov-4.9 - CXXFLAGS="--coverage" LDFLAGS="--coverage" + env: BUILD=Debug CC=gcc-4.9 CXX=g++-4.9 addons: *gcc49 + - os: linux + dist: trusty compiler: "gcc-5" - env: BUILD='Debug' CC=gcc-5 CXX=g++-5 + env: BUILD=Debug CC=gcc-5 CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0" addons: *gcc5 + - os: linux + dist: xenial compiler: "gcc-5" - env: BUILD='Debug' CC=gcc-5 CXX=g++-5 + env: BUILD=Debug CC=gcc-5 CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=1" addons: *gcc5 + - os: linux + dist: xenial compiler: "gcc-6" - env: BUILD='Debug' CC=gcc-6 CXX=g++-6 + env: BUILD=Debug CC=gcc-6 CXX=g++-6 addons: *gcc6 + - os: linux - compiler: "gcc-6" - env: BUILD='Debug' CC=gcc-6 CXX=g++-6 - PROTOZERO_DATA_VIEW=std::experimental::string_view - addons: *gcc6 + dist: bionic + compiler: "gcc-7" + env: BUILD=Debug CC=gcc-7 CXX=g++-7 + addons: *gcc7 + - os: linux - compiler: "gcc-6" - env: BUILD='Release' CC=gcc-6 CXX=g++-6 - addons: *gcc6 + dist: bionic + compiler: "gcc-8" + env: BUILD=Debug CC=gcc-8 CXX=g++-8 + addons: *gcc8 + + - os: linux + dist: bionic + compiler: "gcc-8" + env: BUILD=Debug CC=gcc-8 CXX=g++-8 + COVERAGE=gcov-8 + CXXFLAGS="--coverage" LDFLAGS="--coverage" + addons: *gcc8 + + - os: linux + dist: bionic + compiler: "gcc-8" + env: BUILD=Debug CC=gcc-8 CXX=g++-8 + PROTOZERO_DATA_VIEW=std::string_view + addons: *gcc8 + + - os: linux + dist: bionic + compiler: "gcc-8" + env: BUILD=Release CC=gcc-8 CXX=g++-8 + addons: *gcc8 + + - os: linux + arch: arm64 + dist: bionic + compiler: "gcc-8" + env: BUILD=Debug CC=gcc-8 CXX=g++-8 + addons: *gcc8 + + - os: linux + arch: ppc64le + dist: bionic + compiler: "gcc-8" + env: BUILD=Debug CC=gcc-8 CXX=g++-8 + addons: *gcc8 + + - os: linux + arch: s390x + dist: bionic + compiler: "gcc-8" + env: BUILD=Debug CC=gcc-8 CXX=g++-8 + addons: *gcc8 + - os: osx - osx_image: xcode6.4 + osx_image: xcode9.4 compiler: clang - env: BUILD='Debug' + env: BUILD=Debug + - os: osx - osx_image: xcode7.3 + osx_image: xcode10.3 compiler: clang - env: BUILD='Debug' + env: BUILD=Debug + - os: osx - osx_image: xcode8.3 + osx_image: xcode11.4 compiler: clang - env: BUILD='Debug' + env: BUILD=Debug + - os: osx - osx_image: xcode9.1 + osx_image: xcode11.4 compiler: clang - env: BUILD='Debug' - - os: osx - osx_image: xcode9.1 - compiler: clang - env: BUILD='Release' + env: BUILD=Release #----------------------------------------------------------------------------- -install: - - if [[ $(uname -s) == 'Darwin' ]]; then - brew update; - brew install protobuf; - fi - script: - mkdir build - cd build diff --git a/third_party/protozero/CHANGELOG.md b/third_party/protozero/CHANGELOG.md index d43f422b6..cfdb6a647 100644 --- a/third_party/protozero/CHANGELOG.md +++ b/third_party/protozero/CHANGELOG.md @@ -5,7 +5,6 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) This project adheres to [Semantic Versioning](http://semver.org/). - ## [unreleased] - ### Added @@ -15,6 +14,87 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed +## [1.7.0] - 2020-06-08 + +### Added + +- Support for buffer types other that `std::string`. `pbf_writer` is now + just a typedef for `basic_pbf_writer`. Other buffer types + can be used with `basic_pbf_writer`. See `doc/advanced.md` for details. + +### Changed + +- Switched to *catch2* for testing. +- Some minor tweaks. + +### Fixed + +- Removed some undefined behaviour. + + +## [1.6.8] - 2019-08-15 + +### Changed + +- Various code cleanups due to clang-tidy warnings. + +### Fixed + +- Made `data_view::compare` noexcept. + + +## [1.6.7] - 2018-02-21 + +### Fixed + +- Signed-unsigned comparison on 32 bit systems. + + +## [1.6.6] - 2018-02-20 + +### Fixed + +- Fixed several place with possible undefined behaviour. + + +## [1.6.5] - 2018-02-05 + +### Fixed + +- Avoid UB: Do not calculate pointer outside array bounds. +- Specify proto2 syntax in .proto files to appease protoc. + + +## [1.6.4] - 2018-11-08 + +### Added + +- Add function `data()` to get the not yet read data from a `pbf_reader`. +- New `add_packed_fixed()` template function for `pbf_writer`. +- New `length_of_varint()` helper function calculates how long a varint + would be for a specified value. + +### Changed + +- More consistent implementation of operators as free friend functions. + +### Fixed + +- Fixed some zigzag encoding tests on MSVC. +- Add extra cast so we do an xor with unsigned ints. +- No more bitwise operations on signed integers in varint decoder. +- No more bitwise operations on signed integers in zigzag encoder/decoder. + + +## [1.6.3] - 2018-07-17 + +### Changed + +- Moved `byteswap_inplace` functions from detail into protozero namespace. + They can be useful outsize protozero. +- More asserts and unit tests and small cleanups. + + ## [1.6.2] - 2018-03-09 ### Changed @@ -301,7 +381,14 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Make pbf reader and writer code endianess-aware. -[unreleased]: https://github.com/osmcode/libosmium/compare/v1.6.2...HEAD +[unreleased]: https://github.com/osmcode/libosmium/compare/v1.7.0...HEAD +[1.7.0]: https://github.com/osmcode/libosmium/compare/v1.6.8...v1.7.0 +[1.6.8]: https://github.com/osmcode/libosmium/compare/v1.6.7...v1.6.8 +[1.6.7]: https://github.com/osmcode/libosmium/compare/v1.6.6...v1.6.7 +[1.6.6]: https://github.com/osmcode/libosmium/compare/v1.6.5...v1.6.6 +[1.6.5]: https://github.com/osmcode/libosmium/compare/v1.6.4...v1.6.5 +[1.6.4]: https://github.com/osmcode/libosmium/compare/v1.6.3...v1.6.4 +[1.6.3]: https://github.com/osmcode/libosmium/compare/v1.6.2...v1.6.3 [1.6.2]: https://github.com/osmcode/libosmium/compare/v1.6.1...v1.6.2 [1.6.1]: https://github.com/osmcode/libosmium/compare/v1.6.0...v1.6.1 [1.6.0]: https://github.com/osmcode/libosmium/compare/v1.5.3...v1.6.0 diff --git a/third_party/protozero/CMakeLists.txt b/third_party/protozero/CMakeLists.txt index 24e293d73..f9702d603 100644 --- a/third_party/protozero/CMakeLists.txt +++ b/third_party/protozero/CMakeLists.txt @@ -13,8 +13,8 @@ cmake_minimum_required(VERSION 2.8 FATAL_ERROR) project(protozero) set(PROTOZERO_VERSION_MAJOR 1) -set(PROTOZERO_VERSION_MINOR 6) -set(PROTOZERO_VERSION_PATCH 2) +set(PROTOZERO_VERSION_MINOR 7) +set(PROTOZERO_VERSION_PATCH 0) set(PROTOZERO_VERSION "${PROTOZERO_VERSION_MAJOR}.${PROTOZERO_VERSION_MINOR}.${PROTOZERO_VERSION_PATCH}") @@ -26,7 +26,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) option(WERROR "Add -Werror flag to build (turns warnings into errors)" ON) if(MSVC) - add_definitions(-std=c++11 /W3) + add_definitions(/W3) add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) else() add_definitions(-std=c++11 -Wall -Wextra -pedantic -Wsign-compare -Wunused-parameter -Wno-float-equal -Wno-covered-switch-default) @@ -58,7 +58,7 @@ find_package(Protobuf) # #----------------------------------------------------------------------------- message(STATUS "Looking for clang-tidy") -find_program(CLANG_TIDY NAMES clang-tidy clang-tidy-6.0 clang-tidy-5.0) +find_program(CLANG_TIDY NAMES clang-tidy clang-tidy-10 clang-tidy-9 clang-tidy-8 clang-tidy-7 clang-tidy-6.0 clang-tidy-5.0) if(CLANG_TIDY) message(STATUS "Looking for clang-tidy - found ${CLANG_TIDY}") @@ -66,7 +66,8 @@ if(CLANG_TIDY) ${CLANG_TIDY} -p ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/test/*.cpp - ${CMAKE_SOURCE_DIR}/test/t/*/*.cpp + ${CMAKE_SOURCE_DIR}/test/t/*/reader_test_cases.cpp + ${CMAKE_SOURCE_DIR}/test/t/*/writer_test_cases.cpp ${CMAKE_SOURCE_DIR}/test/unit/*.cpp ${CMAKE_SOURCE_DIR}/tools/*.cpp ) diff --git a/third_party/protozero/README.md b/third_party/protozero/README.md index 63972e0a6..d6e982751 100644 --- a/third_party/protozero/README.md +++ b/third_party/protozero/README.md @@ -56,9 +56,9 @@ You have to have a working knowledge of how * Read the [upgrading instructions](UPGRADING.md) if you are upgrading from an older version of Protozero. -The build process will also build the Doxygen-based reference documentation -if you have [Doxygen](http://www.stack.nl/~dimitri/doxygen/) installed. Then -open `doc/html/index.html` in your browser to read it. +The build process will also build the Doxygen-based reference documentation if +you have Doxygen installed. Then open `doc/html/index.html` in your browser to +read it. ## Endianness diff --git a/third_party/protozero/UPGRADING.md b/third_party/protozero/UPGRADING.md index 9a5db8ee9..bf9040809 100644 --- a/third_party/protozero/UPGRADING.md +++ b/third_party/protozero/UPGRADING.md @@ -13,6 +13,11 @@ macro `PROTOZERO_STRICT_API` in which case Protozero will compile without the code used for backwards compatibilty. You will then get compile errors for older API usages. +## Upgrading from *v1.6* to *v1.7* + +* The `pbf_writer` class is now a typedef for `basic_pbf_writer` + If you have forward declared it in your code, it might have to change. + ## Upgrading from *v1.5* to *v1.6.0* * The `data_view` class moved from `types.hpp` into its own header file diff --git a/third_party/protozero/appveyor.yml b/third_party/protozero/appveyor.yml index 3c3dc7bce..4f3cb4a21 100644 --- a/third_party/protozero/appveyor.yml +++ b/third_party/protozero/appveyor.yml @@ -24,6 +24,9 @@ environment: autocrlf: false - config: RelWithDebInfo autocrlf: false + - config: Debug + autocrlf: false + platform: x86 #----------------------------------------------------------------------------- @@ -36,22 +39,32 @@ init: # halts: "msys2-runtime and catgets are in conflict. Remove catgets?" # See also: https://github.com/Alexpux/MSYS2-packages/issues/1141 install: - - if [%config%]==[MSYS2] ( - C:\msys64\usr\bin\pacman --noconfirm --sync --refresh --refresh --sysupgrade --sysupgrade --ask=20 - && C:\msys64\usr\bin\pacman -Rc --noconfirm mingw-w64-x86_64-gcc-libs + - if "%config%"=="MSYS2" ( + set "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%" && + pacman --noconfirm --sync --refresh --refresh --sysupgrade --sysupgrade --ask=20 && + pacman -Rc --noconfirm mingw-w64-x86_64-gcc-libs && + pacman -S --needed --noconfirm mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-doxygen mingw-w64-x86_64-protobuf ) build_script: - - if [%config%]==[MSYS2] ( - build-msys2.bat + - cd c:\projects\protozero + - mkdir build + - cd build + - if "%platform%"=="x64" ( + set vcvarsall_arg=amd64 ) else ( - build-appveyor.bat + set vcvarsall_arg=x86 + ) + - if "%config%"=="MSYS2" ( + cmake .. -LA -G "MSYS Makefiles" && + make VERBOSE=1 + ) else ( + "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall" %vcvarsall_arg% && + cmake .. -LA -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=%config% && + nmake VERBOSE=1 ) -# remove garbage VS messages -# http://help.appveyor.com/discussions/problems/4569-the-target-_convertpdbfiles-listed-in-a-beforetargets-attribute-at-c-does-not-exist-in-the-project-and-will-be-ignored -before_build: - - del "C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets" - +test_script: + - ctest --output-on-failure #----------------------------------------------------------------------------- diff --git a/third_party/protozero/build-appveyor.bat b/third_party/protozero/build-appveyor.bat deleted file mode 100644 index 76e848c29..000000000 --- a/third_party/protozero/build-appveyor.bat +++ /dev/null @@ -1,65 +0,0 @@ -@ECHO OFF -SETLOCAL -SET EL=0 - -ECHO ~~~~~~ %~f0 ~~~~~~ - -::show all available env vars -SET -ECHO cmake on AppVeyor -cmake -version - -ECHO activating VS cmd prompt && CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -SET protobuf_sdk=protozero-dep-protobuf-2.6.1.7z -IF EXIST %protobuf_sdk% (ECHO protobuf already downloaded) ELSE (ECHO downloading protobuf ... && powershell Invoke-WebRequest https://mapbox.s3.amazonaws.com/windows-builds/windows-build-deps/$env:protobuf_sdk -OutFile $pwd\$env:protobuf_sdk) -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -IF EXIST deps\protobuf (ECHO protobuf already extracted) ELSE (CALL 7z x -y %protobuf_sdk% | %windir%\system32\FIND "ing archive") -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -SET PATH=%~dp0deps\protobuf;%PATH% - -IF EXIST build ECHO deleting build dir... && RD /Q /S build -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -MKDIR build -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -CD build -ECHO config^: %config% - -::This will produce lots of LNK4099 warnings which can be ignored. -::Unfortunately they can't be disabled, see -::http://stackoverflow.com/questions/661606/visual-c-how-to-disable-specific-linker-warnings -SET CMAKE_CMD=cmake .. ^ --LA -G "Visual Studio 14 Win64" - -ECHO calling^: %CMAKE_CMD% -%CMAKE_CMD% -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -SET avlogger= -IF /I "%APPVEYOR%"=="True" SET avlogger=/logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" - -msbuild protozero.sln ^ -/p:Configuration=%config% ^ -/toolsversion:14.0 ^ -/p:Platform=x64 ^ -/p:PlatformToolset=v140 %avlogger% -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ctest --output-on-failure ^ --C %config% ^ -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -GOTO DONE - -:ERROR -ECHO ~~~~~~ ERROR %~f0 ~~~~~~ -SET EL=%ERRORLEVEL% - -:DONE -IF %EL% NEQ 0 ECHO. && ECHO !!! ERRORLEVEL^: %EL% !!! && ECHO. -ECHO ~~~~~~ DONE %~f0 ~~~~~~ - -EXIT /b %EL% diff --git a/third_party/protozero/build-local.bat b/third_party/protozero/build-local.bat deleted file mode 100644 index 62db254ac..000000000 --- a/third_party/protozero/build-local.bat +++ /dev/null @@ -1,29 +0,0 @@ -@ECHO OFF -SETLOCAL -SET EL=0 - -ECHO =========== %~f0 =========== - -SET VERBOSITY_MSBUILD=diagnostic -IF NOT "%1"=="" SET VERBOSITY_MSBUILD=%1 -SET platform=x64 -SET configuration=Release -CALL build-appveyor.bat %VERBOSITY_MSBUILD% -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -SET platform=x86 -SET configuration=Debug -CALL build-appveyor.bat %VERBOSITY_MSBUILD% -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -GOTO DONE - -:ERROR -ECHO =========== ERROR %~f0 =========== -ECHO ERRORLEVEL^: %ERRORLEVEL% -SET EL=%ERRORLEVEL% - -:DONE -ECHO =========== DONE %~f0 =========== - -EXIT /b %EL% diff --git a/third_party/protozero/build-msys2.bat b/third_party/protozero/build-msys2.bat deleted file mode 100644 index 1a02156b5..000000000 --- a/third_party/protozero/build-msys2.bat +++ /dev/null @@ -1,18 +0,0 @@ -echo "Adding MSYS2 to path..." -SET "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%" -echo %PATH% - -echo "Installing MSYS2 packages..." -bash -lc "pacman -S --needed --noconfirm mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-doxygen mingw-w64-x86_64-protobuf" - -echo "Generating makefiles" -mkdir build -cd build -cmake .. -LA -G "MSYS Makefiles" - -echo "Building" -make VERBOSE=1 - -echo "Testing" -ctest --output-on-failure - diff --git a/third_party/protozero/doc/Doxyfile.in b/third_party/protozero/doc/Doxyfile.in index 148190551..a23ad7f74 100644 --- a/third_party/protozero/doc/Doxyfile.in +++ b/third_party/protozero/doc/Doxyfile.in @@ -2046,7 +2046,7 @@ EXTERNAL_PAGES = YES # interpreter (i.e. the result of 'which perl'). # The default file (with absolute path) is: /usr/bin/perl. -PERL_PATH = /usr/bin/perl +#PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool @@ -2068,7 +2068,7 @@ CLASS_DIAGRAMS = YES # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. -MSCGEN_PATH = +#MSCGEN_PATH = # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The diff --git a/third_party/protozero/doc/advanced.md b/third_party/protozero/doc/advanced.md index f5a0e1120..d579538d0 100644 --- a/third_party/protozero/doc/advanced.md +++ b/third_party/protozero/doc/advanced.md @@ -269,3 +269,58 @@ still considerably cheaper than decoding the varints. You have to benchmark your use case to see whether the `reserve()` (or whatever you are using the `size()` for) is worth it. + +## Using a different buffer class than std::string + +Normally you are using the `pbf_writer` or `pbf_builder` classes which use a +`std::string` that you supply as their buffer for building the actual protocol +buffers message into. But you can use a different buffer implementation +instead. This might be useful if you want to use a fixed-size buffer for +instance. + +The `pbf_writer` and `pbf_builder` classes are actually only aliases for the +`basic_pbf_writer` and `basic_pbf_builder` template classes: + +```cpp +using pbf_writer = basic_pbf_writer; + +template +using pbf_builder = basic_pbf_builder; +``` + +If you want to use a different buffer type, use the `basic_*` form of the +class and use the buffer class as template parameter. When instantiating the +`basic_pbf_writer` or `basic_pbf_builder`, the only parameter to the +constructor must always be a reference to an object of the buffer class. + +```cpp +some_buffer_class buffer; +basic_pbf_writer writer{buffer}; +``` + +For this to work you must supply template specializations for some static +functions in the `protozero::buffer_customization` struct, see +`buffer_tmpl.hpp` for details. + +Protozero already supports two buffer types: +* `std::string` (to use include `protozero/buffer_string.hpp`) +* `std::vector` (to use include `protozero/buffer_vector.hpp`) + +There is a class `protozero::fixed_size_buffer_adaptor` you can use as adaptor +for any fixed-sized buffer you might have. Include `protozero/buffer_fixed.hpp` +to use it: + +```cpp +#include + +your_buffer_class some_buffer; +protozero::fixed_size_buffer_adaptor buffer_adaptor{some_buffer.data(), some_buffer.size()}; +basic_pbf_writer writer{buffer_adaptor}; +``` + +The buffer adaptor can be initialized with any container if it supports the +`data()` and `size()` member functions: + +```cpp +protozero::fixed_size_buffer_adaptor buffer_adaptor{some_buffer}; +``` diff --git a/third_party/protozero/include/protozero/basic_pbf_builder.hpp b/third_party/protozero/include/protozero/basic_pbf_builder.hpp new file mode 100644 index 000000000..0ede726fa --- /dev/null +++ b/third_party/protozero/include/protozero/basic_pbf_builder.hpp @@ -0,0 +1,266 @@ +#ifndef PROTOZERO_BASIC_PBF_BUILDER_HPP +#define PROTOZERO_BASIC_PBF_BUILDER_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +/** + * @file basic_pbf_builder.hpp + * + * @brief Contains the basic_pbf_builder template class. + */ + +#include "basic_pbf_writer.hpp" +#include "types.hpp" + +#include + +namespace protozero { + +/** + * The basic_pbf_builder is used to write PBF formatted messages into a buffer. + * It is based on the basic_pbf_writer class and has all the same methods. The + * difference is that while the pbf_writer class takes an integer tag, + * this template class takes a tag of the template type T. The idea is that + * T will be an enumeration value and this helps reduce the possibility of + * programming errors. + * + * Almost all methods in this class can throw an std::bad_alloc exception if + * the underlying buffer class wants to resize. + * + * Read the tutorial to understand how this class is used. In most cases you + * want to use the pbf_builder class which uses a std::string as buffer type. + */ +template +class basic_pbf_builder : public basic_pbf_writer { + + static_assert(std::is_same::type>::value, + "T must be enum with underlying type protozero::pbf_tag_type"); + +public: + + /// The type of messages this class will build. + using enum_type = T; + + basic_pbf_builder() = default; + + /** + * Create a builder using the given string as a data store. The object + * stores a reference to that string and adds all data to it. The string + * doesn't have to be empty. The pbf_message object will just append data. + */ + explicit basic_pbf_builder(TBuffer& data) noexcept : + basic_pbf_writer{data} { + } + + /** + * Construct a pbf_builder for a submessage from the pbf_message or + * pbf_writer of the parent message. + * + * @param parent_writer The parent pbf_message or pbf_writer + * @param tag Tag of the field that will be written + */ + template + basic_pbf_builder(basic_pbf_writer& parent_writer, P tag) noexcept : + basic_pbf_writer{parent_writer, pbf_tag_type(tag)} { + } + +/// @cond INTERNAL +#define PROTOZERO_WRITER_WRAP_ADD_SCALAR(name, type) \ + void add_##name(T tag, type value) { \ + basic_pbf_writer::add_##name(pbf_tag_type(tag), value); \ + } + + PROTOZERO_WRITER_WRAP_ADD_SCALAR(bool, bool) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(enum, int32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(int32, int32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(sint32, int32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(uint32, uint32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(int64, int64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(sint64, int64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(uint64, uint64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(fixed32, uint32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(sfixed32, int32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(fixed64, uint64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(sfixed64, int64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(float, float) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(double, double) + +#undef PROTOZERO_WRITER_WRAP_ADD_SCALAR +/// @endcond + + /** + * Add "bytes" field to data. + * + * @param tag Tag of the field + * @param value Pointer to value to be written + * @param size Number of bytes to be written + */ + void add_bytes(T tag, const char* value, std::size_t size) { + basic_pbf_writer::add_bytes(pbf_tag_type(tag), value, size); + } + + /** + * Add "bytes" field to data. + * + * @param tag Tag of the field + * @param value Value to be written + */ + void add_bytes(T tag, const data_view& value) { + basic_pbf_writer::add_bytes(pbf_tag_type(tag), value); + } + + /** + * Add "bytes" field to data. + * + * @param tag Tag of the field + * @param value Value to be written + */ + void add_bytes(T tag, const std::string& value) { + basic_pbf_writer::add_bytes(pbf_tag_type(tag), value); + } + + /** + * Add "bytes" field to data. Bytes from the value are written until + * a null byte is encountered. The null byte is not added. + * + * @param tag Tag of the field + * @param value Pointer to zero-delimited value to be written + */ + void add_bytes(T tag, const char* value) { + basic_pbf_writer::add_bytes(pbf_tag_type(tag), value); + } + + /** + * Add "bytes" field to data using vectored input. All the data in the + * 2nd and further arguments is "concatenated" with only a single copy + * into the final buffer. + * + * This will work with objects of any type supporting the data() and + * size() methods like std::string or protozero::data_view. + * + * Example: + * @code + * std::string data1 = "abc"; + * std::string data2 = "xyz"; + * builder.add_bytes_vectored(1, data1, data2); + * @endcode + * + * @tparam Ts List of types supporting data() and size() methods. + * @param tag Tag of the field + * @param values List of objects of types Ts with data to be appended. + */ + template + void add_bytes_vectored(T tag, Ts&&... values) { + basic_pbf_writer::add_bytes_vectored(pbf_tag_type(tag), std::forward(values)...); + } + + /** + * Add "string" field to data. + * + * @param tag Tag of the field + * @param value Pointer to value to be written + * @param size Number of bytes to be written + */ + void add_string(T tag, const char* value, std::size_t size) { + basic_pbf_writer::add_string(pbf_tag_type(tag), value, size); + } + + /** + * Add "string" field to data. + * + * @param tag Tag of the field + * @param value Value to be written + */ + void add_string(T tag, const data_view& value) { + basic_pbf_writer::add_string(pbf_tag_type(tag), value); + } + + /** + * Add "string" field to data. + * + * @param tag Tag of the field + * @param value Value to be written + */ + void add_string(T tag, const std::string& value) { + basic_pbf_writer::add_string(pbf_tag_type(tag), value); + } + + /** + * Add "string" field to data. Bytes from the value are written until + * a null byte is encountered. The null byte is not added. + * + * @param tag Tag of the field + * @param value Pointer to value to be written + */ + void add_string(T tag, const char* value) { + basic_pbf_writer::add_string(pbf_tag_type(tag), value); + } + + /** + * Add "message" field to data. + * + * @param tag Tag of the field + * @param value Pointer to message to be written + * @param size Length of the message + */ + void add_message(T tag, const char* value, std::size_t size) { + basic_pbf_writer::add_message(pbf_tag_type(tag), value, size); + } + + /** + * Add "message" field to data. + * + * @param tag Tag of the field + * @param value Value to be written. The value must be a complete message. + */ + void add_message(T tag, const data_view& value) { + basic_pbf_writer::add_message(pbf_tag_type(tag), value); + } + + /** + * Add "message" field to data. + * + * @param tag Tag of the field + * @param value Value to be written. The value must be a complete message. + */ + void add_message(T tag, const std::string& value) { + basic_pbf_writer::add_message(pbf_tag_type(tag), value); + } + +/// @cond INTERNAL +#define PROTOZERO_WRITER_WRAP_ADD_PACKED(name) \ + template \ + void add_packed_##name(T tag, InputIterator first, InputIterator last) { \ + basic_pbf_writer::add_packed_##name(pbf_tag_type(tag), first, last); \ + } + + PROTOZERO_WRITER_WRAP_ADD_PACKED(bool) + PROTOZERO_WRITER_WRAP_ADD_PACKED(enum) + PROTOZERO_WRITER_WRAP_ADD_PACKED(int32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(sint32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(uint32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(int64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(sint64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(uint64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(fixed32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(sfixed32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(fixed64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(sfixed64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(float) + PROTOZERO_WRITER_WRAP_ADD_PACKED(double) + +#undef PROTOZERO_WRITER_WRAP_ADD_PACKED +/// @endcond + +}; // class basic_pbf_builder + +} // end namespace protozero + +#endif // PROTOZERO_BASIC_PBF_BUILDER_HPP diff --git a/third_party/protozero/include/protozero/basic_pbf_writer.hpp b/third_party/protozero/include/protozero/basic_pbf_writer.hpp new file mode 100644 index 000000000..f167c4d1d --- /dev/null +++ b/third_party/protozero/include/protozero/basic_pbf_writer.hpp @@ -0,0 +1,1054 @@ +#ifndef PROTOZERO_BASIC_PBF_WRITER_HPP +#define PROTOZERO_BASIC_PBF_WRITER_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +/** + * @file basic_pbf_writer.hpp + * + * @brief Contains the basic_pbf_writer template class. + */ + +#include "buffer_tmpl.hpp" +#include "config.hpp" +#include "data_view.hpp" +#include "types.hpp" +#include "varint.hpp" + +#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace protozero { + +namespace detail { + + template class packed_field_varint; + template class packed_field_svarint; + template class packed_field_fixed; + +} // end namespace detail + +/** + * The basic_pbf_writer is used to write PBF formatted messages into a buffer. + * + * This uses TBuffer as the type for the underlaying buffer. In typical uses + * this is std::string, but you can use a different type that must support + * the right interface. Please see the documentation for details. + * + * Almost all methods in this class can throw an std::bad_alloc exception if + * the underlying buffer class wants to resize. + */ +template +class basic_pbf_writer { + + // A pointer to a buffer holding the data already written to the PBF + // message. For default constructed writers or writers that have been + // rolled back, this is a nullptr. + TBuffer* m_data = nullptr; + + // A pointer to a parent writer object if this is a submessage. If this + // is a top-level writer, it is a nullptr. + basic_pbf_writer* m_parent_writer = nullptr; + + // This is usually 0. If there is an open submessage, this is set in the + // parent to the rollback position, ie. the last position before the + // submessage was started. This is the position where the header of the + // submessage starts. + std::size_t m_rollback_pos = 0; + + // This is usually 0. If there is an open submessage, this is set in the + // parent to the position where the data of the submessage is written to. + std::size_t m_pos = 0; + + void add_varint(uint64_t value) { + protozero_assert(m_pos == 0 && "you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage"); + protozero_assert(m_data); + add_varint_to_buffer(m_data, value); + } + + void add_field(pbf_tag_type tag, pbf_wire_type type) { + protozero_assert(((tag > 0 && tag < 19000) || (tag > 19999 && tag <= ((1U << 29U) - 1))) && "tag out of range"); + const uint32_t b = (tag << 3U) | uint32_t(type); + add_varint(b); + } + + void add_tagged_varint(pbf_tag_type tag, uint64_t value) { + add_field(tag, pbf_wire_type::varint); + add_varint(value); + } + + template + void add_fixed(T value) { + protozero_assert(m_pos == 0 && "you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage"); + protozero_assert(m_data); +#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN + byteswap_inplace(&value); +#endif + buffer_customization::append(m_data, reinterpret_cast(&value), sizeof(T)); + } + + template + void add_packed_fixed(pbf_tag_type tag, It first, It last, std::input_iterator_tag /*unused*/) { + if (first == last) { + return; + } + + basic_pbf_writer sw{*this, tag}; + + while (first != last) { + sw.add_fixed(*first++); + } + } + + template + void add_packed_fixed(pbf_tag_type tag, It first, It last, std::forward_iterator_tag /*unused*/) { + if (first == last) { + return; + } + + const auto length = std::distance(first, last); + add_length_varint(tag, sizeof(T) * pbf_length_type(length)); + reserve(sizeof(T) * std::size_t(length)); + + while (first != last) { + add_fixed(*first++); + } + } + + template + void add_packed_varint(pbf_tag_type tag, It first, It last) { + if (first == last) { + return; + } + + basic_pbf_writer sw{*this, tag}; + + while (first != last) { + sw.add_varint(uint64_t(*first++)); + } + } + + template + void add_packed_svarint(pbf_tag_type tag, It first, It last) { + if (first == last) { + return; + } + + basic_pbf_writer sw{*this, tag}; + + while (first != last) { + sw.add_varint(encode_zigzag64(*first++)); + } + } + + // The number of bytes to reserve for the varint holding the length of + // a length-delimited field. The length has to fit into pbf_length_type, + // and a varint needs 8 bit for every 7 bit. + enum : int { + reserve_bytes = sizeof(pbf_length_type) * 8 / 7 + 1 + }; + + // If m_rollpack_pos is set to this special value, it means that when + // the submessage is closed, nothing needs to be done, because the length + // of the submessage has already been written correctly. + enum : std::size_t { + size_is_known = std::numeric_limits::max() + }; + + void open_submessage(pbf_tag_type tag, std::size_t size) { + protozero_assert(m_pos == 0); + protozero_assert(m_data); + if (size == 0) { + m_rollback_pos = buffer_customization::size(m_data); + add_field(tag, pbf_wire_type::length_delimited); + buffer_customization::append_zeros(m_data, std::size_t(reserve_bytes)); + } else { + m_rollback_pos = size_is_known; + add_length_varint(tag, pbf_length_type(size)); + reserve(size); + } + m_pos = buffer_customization::size(m_data); + } + + void rollback_submessage() { + protozero_assert(m_pos != 0); + protozero_assert(m_rollback_pos != size_is_known); + protozero_assert(m_data); + buffer_customization::resize(m_data, m_rollback_pos); + m_pos = 0; + } + + void commit_submessage() { + protozero_assert(m_pos != 0); + protozero_assert(m_rollback_pos != size_is_known); + protozero_assert(m_data); + const auto length = pbf_length_type(buffer_customization::size(m_data) - m_pos); + + protozero_assert(buffer_customization::size(m_data) >= m_pos - reserve_bytes); + const auto n = add_varint_to_buffer(buffer_customization::at_pos(m_data, m_pos - reserve_bytes), length); + + buffer_customization::erase_range(m_data, m_pos - reserve_bytes + n, m_pos); + m_pos = 0; + } + + void close_submessage() { + protozero_assert(m_data); + if (m_pos == 0 || m_rollback_pos == size_is_known) { + return; + } + if (buffer_customization::size(m_data) - m_pos == 0) { + rollback_submessage(); + } else { + commit_submessage(); + } + } + + void add_length_varint(pbf_tag_type tag, pbf_length_type length) { + add_field(tag, pbf_wire_type::length_delimited); + add_varint(length); + } + +public: + + /** + * Create a writer using the specified buffer as a data store. The + * basic_pbf_writer stores a pointer to that buffer and adds all data to + * it. The buffer doesn't have to be empty. The basic_pbf_writer will just + * append data. + */ + explicit basic_pbf_writer(TBuffer& buffer) noexcept : + m_data{&buffer} { + } + + /** + * Create a writer without a data store. In this form the writer can not + * be used! + */ + basic_pbf_writer() noexcept = default; + + /** + * Construct a basic_pbf_writer for a submessage from the basic_pbf_writer + * of the parent message. + * + * @param parent_writer The basic_pbf_writer + * @param tag Tag (field number) of the field that will be written + * @param size Optional size of the submessage in bytes (use 0 for unknown). + * Setting this allows some optimizations but is only possible in + * a few very specific cases. + */ + basic_pbf_writer(basic_pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size = 0) : + m_data{parent_writer.m_data}, + m_parent_writer{&parent_writer} { + m_parent_writer->open_submessage(tag, size); + } + + /// A basic_pbf_writer object can not be copied + basic_pbf_writer(const basic_pbf_writer&) = delete; + + /// A basic_pbf_writer object can not be copied + basic_pbf_writer& operator=(const basic_pbf_writer&) = delete; + + /** + * A basic_pbf_writer object can be moved. After this the other + * basic_pbf_writer will be invalid. + */ + basic_pbf_writer(basic_pbf_writer&& other) noexcept : + m_data{other.m_data}, + m_parent_writer{other.m_parent_writer}, + m_rollback_pos{other.m_rollback_pos}, + m_pos{other.m_pos} { + other.m_data = nullptr; + other.m_parent_writer = nullptr; + other.m_rollback_pos = 0; + other.m_pos = 0; + } + + /** + * A basic_pbf_writer object can be moved. After this the other + * basic_pbf_writer will be invalid. + */ + basic_pbf_writer& operator=(basic_pbf_writer&& other) noexcept { + m_data = other.m_data; + m_parent_writer = other.m_parent_writer; + m_rollback_pos = other.m_rollback_pos; + m_pos = other.m_pos; + other.m_data = nullptr; + other.m_parent_writer = nullptr; + other.m_rollback_pos = 0; + other.m_pos = 0; + return *this; + } + + ~basic_pbf_writer() noexcept { + try { + if (m_parent_writer != nullptr) { + m_parent_writer->close_submessage(); + } + } catch (...) { + // This try/catch is used to make the destructor formally noexcept. + // close_submessage() is not noexcept, but will not throw the way + // it is called here, so we are good. But to be paranoid, call... + std::terminate(); + } + } + + /** + * Check if this writer is valid. A writer is invalid if it was default + * constructed, moved from, or if commit() has been called on it. + * Otherwise it is valid. + */ + bool valid() const noexcept { + return m_data != nullptr; + } + + /** + * Swap the contents of this object with the other. + * + * @param other Other object to swap data with. + */ + void swap(basic_pbf_writer& other) noexcept { + using std::swap; + swap(m_data, other.m_data); + swap(m_parent_writer, other.m_parent_writer); + swap(m_rollback_pos, other.m_rollback_pos); + swap(m_pos, other.m_pos); + } + + /** + * Reserve size bytes in the underlying message store in addition to + * whatever the message store already holds. So unlike + * the `std::string::reserve()` method this is not an absolute size, + * but additional memory that should be reserved. + * + * @param size Number of bytes to reserve in underlying message store. + */ + void reserve(std::size_t size) { + protozero_assert(m_data); + buffer_customization::reserve_additional(m_data, size); + } + + /** + * Commit this submessage. This does the same as when the basic_pbf_writer + * goes out of scope and is destructed. + * + * @pre Must be a basic_pbf_writer of a submessage, ie one opened with the + * basic_pbf_writer constructor taking a parent message. + * @post The basic_pbf_writer is invalid and can't be used any more. + */ + void commit() { + protozero_assert(m_parent_writer && "you can't call commit() on a basic_pbf_writer without a parent"); + protozero_assert(m_pos == 0 && "you can't call commit() on a basic_pbf_writer that has an open nested submessage"); + m_parent_writer->close_submessage(); + m_parent_writer = nullptr; + m_data = nullptr; + } + + /** + * Cancel writing of this submessage. The complete submessage will be + * removed as if it was never created and no fields were added. + * + * @pre Must be a basic_pbf_writer of a submessage, ie one opened with the + * basic_pbf_writer constructor taking a parent message. + * @post The basic_pbf_writer is invalid and can't be used any more. + */ + void rollback() { + protozero_assert(m_parent_writer && "you can't call rollback() on a basic_pbf_writer without a parent"); + protozero_assert(m_pos == 0 && "you can't call rollback() on a basic_pbf_writer that has an open nested submessage"); + m_parent_writer->rollback_submessage(); + m_parent_writer = nullptr; + m_data = nullptr; + } + + ///@{ + /** + * @name Scalar field writer functions + */ + + /** + * Add "bool" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_bool(pbf_tag_type tag, bool value) { + add_field(tag, pbf_wire_type::varint); + protozero_assert(m_pos == 0 && "you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage"); + protozero_assert(m_data); + m_data->push_back(char(value)); + } + + /** + * Add "enum" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_enum(pbf_tag_type tag, int32_t value) { + add_tagged_varint(tag, uint64_t(value)); + } + + /** + * Add "int32" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_int32(pbf_tag_type tag, int32_t value) { + add_tagged_varint(tag, uint64_t(value)); + } + + /** + * Add "sint32" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_sint32(pbf_tag_type tag, int32_t value) { + add_tagged_varint(tag, encode_zigzag32(value)); + } + + /** + * Add "uint32" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_uint32(pbf_tag_type tag, uint32_t value) { + add_tagged_varint(tag, value); + } + + /** + * Add "int64" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_int64(pbf_tag_type tag, int64_t value) { + add_tagged_varint(tag, uint64_t(value)); + } + + /** + * Add "sint64" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_sint64(pbf_tag_type tag, int64_t value) { + add_tagged_varint(tag, encode_zigzag64(value)); + } + + /** + * Add "uint64" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_uint64(pbf_tag_type tag, uint64_t value) { + add_tagged_varint(tag, value); + } + + /** + * Add "fixed32" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_fixed32(pbf_tag_type tag, uint32_t value) { + add_field(tag, pbf_wire_type::fixed32); + add_fixed(value); + } + + /** + * Add "sfixed32" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_sfixed32(pbf_tag_type tag, int32_t value) { + add_field(tag, pbf_wire_type::fixed32); + add_fixed(value); + } + + /** + * Add "fixed64" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_fixed64(pbf_tag_type tag, uint64_t value) { + add_field(tag, pbf_wire_type::fixed64); + add_fixed(value); + } + + /** + * Add "sfixed64" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_sfixed64(pbf_tag_type tag, int64_t value) { + add_field(tag, pbf_wire_type::fixed64); + add_fixed(value); + } + + /** + * Add "float" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_float(pbf_tag_type tag, float value) { + add_field(tag, pbf_wire_type::fixed32); + add_fixed(value); + } + + /** + * Add "double" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_double(pbf_tag_type tag, double value) { + add_field(tag, pbf_wire_type::fixed64); + add_fixed(value); + } + + /** + * Add "bytes" field to data. + * + * @param tag Tag (field number) of the field + * @param value Pointer to value to be written + * @param size Number of bytes to be written + */ + void add_bytes(pbf_tag_type tag, const char* value, std::size_t size) { + protozero_assert(m_pos == 0 && "you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage"); + protozero_assert(m_data); + protozero_assert(size <= std::numeric_limits::max()); + add_length_varint(tag, pbf_length_type(size)); + buffer_customization::append(m_data, value, size); + } + + /** + * Add "bytes" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_bytes(pbf_tag_type tag, const data_view& value) { + add_bytes(tag, value.data(), value.size()); + } + + /** + * Add "bytes" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_bytes(pbf_tag_type tag, const std::string& value) { + add_bytes(tag, value.data(), value.size()); + } + + /** + * Add "bytes" field to data. Bytes from the value are written until + * a null byte is encountered. The null byte is not added. + * + * @param tag Tag (field number) of the field + * @param value Pointer to zero-delimited value to be written + */ + void add_bytes(pbf_tag_type tag, const char* value) { + add_bytes(tag, value, std::strlen(value)); + } + + /** + * Add "bytes" field to data using vectored input. All the data in the + * 2nd and further arguments is "concatenated" with only a single copy + * into the final buffer. + * + * This will work with objects of any type supporting the data() and + * size() methods like std::string or protozero::data_view. + * + * Example: + * @code + * std::string data1 = "abc"; + * std::string data2 = "xyz"; + * writer.add_bytes_vectored(1, data1, data2); + * @endcode + * + * @tparam Ts List of types supporting data() and size() methods. + * @param tag Tag (field number) of the field + * @param values List of objects of types Ts with data to be appended. + */ + template + void add_bytes_vectored(pbf_tag_type tag, Ts&&... values) { + protozero_assert(m_pos == 0 && "you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage"); + protozero_assert(m_data); + size_t sum_size = 0; + (void)std::initializer_list{sum_size += values.size()...}; + protozero_assert(sum_size <= std::numeric_limits::max()); + add_length_varint(tag, pbf_length_type(sum_size)); + buffer_customization::reserve_additional(m_data, sum_size); + (void)std::initializer_list{(buffer_customization::append(m_data, values.data(), values.size()), 0)...}; + } + + /** + * Add "string" field to data. + * + * @param tag Tag (field number) of the field + * @param value Pointer to value to be written + * @param size Number of bytes to be written + */ + void add_string(pbf_tag_type tag, const char* value, std::size_t size) { + add_bytes(tag, value, size); + } + + /** + * Add "string" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_string(pbf_tag_type tag, const data_view& value) { + add_bytes(tag, value.data(), value.size()); + } + + /** + * Add "string" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_string(pbf_tag_type tag, const std::string& value) { + add_bytes(tag, value.data(), value.size()); + } + + /** + * Add "string" field to data. Bytes from the value are written until + * a null byte is encountered. The null byte is not added. + * + * @param tag Tag (field number) of the field + * @param value Pointer to value to be written + */ + void add_string(pbf_tag_type tag, const char* value) { + add_bytes(tag, value, std::strlen(value)); + } + + /** + * Add "message" field to data. + * + * @param tag Tag (field number) of the field + * @param value Pointer to message to be written + * @param size Length of the message + */ + void add_message(pbf_tag_type tag, const char* value, std::size_t size) { + add_bytes(tag, value, size); + } + + /** + * Add "message" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written. The value must be a complete message. + */ + void add_message(pbf_tag_type tag, const data_view& value) { + add_bytes(tag, value.data(), value.size()); + } + + /** + * Add "message" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written. The value must be a complete message. + */ + void add_message(pbf_tag_type tag, const std::string& value) { + add_bytes(tag, value.data(), value.size()); + } + + ///@} + + ///@{ + /** + * @name Repeated packed field writer functions + */ + + /** + * Add "repeated packed bool" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to bool. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_varint(tag, first, last); + } + + /** + * Add "repeated packed enum" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to int32_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_varint(tag, first, last); + } + + /** + * Add "repeated packed int32" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to int32_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_varint(tag, first, last); + } + + /** + * Add "repeated packed sint32" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to int32_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_svarint(tag, first, last); + } + + /** + * Add "repeated packed uint32" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to uint32_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_uint32(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_varint(tag, first, last); + } + + /** + * Add "repeated packed int64" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to int64_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_varint(tag, first, last); + } + + /** + * Add "repeated packed sint64" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to int64_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_svarint(tag, first, last); + } + + /** + * Add "repeated packed uint64" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to uint64_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_varint(tag, first, last); + } + + /** + * Add a "repeated packed" fixed-size field to data. The following + * fixed-size fields are available: + * + * uint32_t -> repeated packed fixed32 + * int32_t -> repeated packed sfixed32 + * uint64_t -> repeated packed fixed64 + * int64_t -> repeated packed sfixed64 + * double -> repeated packed double + * float -> repeated packed float + * + * @tparam ValueType One of the following types: (u)int32/64_t, double, float. + * @tparam InputIterator A type satisfying the InputIterator concept. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_fixed(pbf_tag_type tag, InputIterator first, InputIterator last) { + static_assert(std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value, "Only some types are allowed"); + add_packed_fixed(tag, first, last, + typename std::iterator_traits::iterator_category{}); + } + + /** + * Add "repeated packed fixed32" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to uint32_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_fixed32(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_fixed(tag, first, last, + typename std::iterator_traits::iterator_category{}); + } + + /** + * Add "repeated packed sfixed32" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to int32_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_sfixed32(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_fixed(tag, first, last, + typename std::iterator_traits::iterator_category{}); + } + + /** + * Add "repeated packed fixed64" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to uint64_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_fixed64(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_fixed(tag, first, last, + typename std::iterator_traits::iterator_category{}); + } + + /** + * Add "repeated packed sfixed64" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to int64_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_sfixed64(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_fixed(tag, first, last, + typename std::iterator_traits::iterator_category{}); + } + + /** + * Add "repeated packed float" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to float. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_float(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_fixed(tag, first, last, + typename std::iterator_traits::iterator_category{}); + } + + /** + * Add "repeated packed double" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to double. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_double(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_fixed(tag, first, last, + typename std::iterator_traits::iterator_category{}); + } + + ///@} + + template friend class detail::packed_field_varint; + template friend class detail::packed_field_svarint; + template friend class detail::packed_field_fixed; + +}; // class basic_pbf_writer + +/** + * Swap two basic_pbf_writer objects. + * + * @param lhs First object. + * @param rhs Second object. + */ +template +inline void swap(basic_pbf_writer& lhs, basic_pbf_writer& rhs) noexcept { + lhs.swap(rhs); +} + +namespace detail { + + template + class packed_field { + + basic_pbf_writer m_writer{}; + + public: + + packed_field(const packed_field&) = delete; + packed_field& operator=(const packed_field&) = delete; + + packed_field(packed_field&&) noexcept = default; + packed_field& operator=(packed_field&&) noexcept = default; + + packed_field() = default; + + packed_field(basic_pbf_writer& parent_writer, pbf_tag_type tag) : + m_writer{parent_writer, tag} { + } + + packed_field(basic_pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size) : + m_writer{parent_writer, tag, size} { + } + + ~packed_field() noexcept = default; + + bool valid() const noexcept { + return m_writer.valid(); + } + + void commit() { + m_writer.commit(); + } + + void rollback() { + m_writer.rollback(); + } + + basic_pbf_writer& writer() noexcept { + return m_writer; + } + + }; // class packed_field + + template + class packed_field_fixed : public packed_field { + + public: + + packed_field_fixed() : + packed_field{} { + } + + template + packed_field_fixed(basic_pbf_writer& parent_writer, P tag) : + packed_field{parent_writer, static_cast(tag)} { + } + + template + packed_field_fixed(basic_pbf_writer& parent_writer, P tag, std::size_t size) : + packed_field{parent_writer, static_cast(tag), size * sizeof(T)} { + } + + void add_element(T value) { + this->writer().template add_fixed(value); + } + + }; // class packed_field_fixed + + template + class packed_field_varint : public packed_field { + + public: + + packed_field_varint() : + packed_field{} { + } + + template + packed_field_varint(basic_pbf_writer& parent_writer, P tag) : + packed_field{parent_writer, static_cast(tag)} { + } + + void add_element(T value) { + this->writer().add_varint(uint64_t(value)); + } + + }; // class packed_field_varint + + template + class packed_field_svarint : public packed_field { + + public: + + packed_field_svarint() : + packed_field{} { + } + + template + packed_field_svarint(basic_pbf_writer& parent_writer, P tag) : + packed_field{parent_writer, static_cast(tag)} { + } + + void add_element(T value) { + this->writer().add_varint(encode_zigzag64(value)); + } + + }; // class packed_field_svarint + +} // end namespace detail + +} // end namespace protozero + +#endif // PROTOZERO_BASIC_PBF_WRITER_HPP diff --git a/third_party/protozero/include/protozero/buffer_fixed.hpp b/third_party/protozero/include/protozero/buffer_fixed.hpp new file mode 100644 index 000000000..b2e6d1d27 --- /dev/null +++ b/third_party/protozero/include/protozero/buffer_fixed.hpp @@ -0,0 +1,222 @@ +#ifndef PROTOZERO_BUFFER_FIXED_HPP +#define PROTOZERO_BUFFER_FIXED_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +/** + * @file buffer_fixed.hpp + * + * @brief Contains the fixed_size_buffer_adaptor class. + */ + +#include "buffer_tmpl.hpp" +#include "config.hpp" + +#include +#include +#include +#include + +namespace protozero { + +/** + * This class can be used instead of std::string if you want to create a + * vector tile in a fixed-size buffer. Any operation that needs more space + * than is available will fail with a std::length_error exception. + */ +class fixed_size_buffer_adaptor { + + char* m_data; + std::size_t m_capacity; + std::size_t m_size = 0; + +public: + + /// @cond usual container typedefs not documented + + using size_type = std::size_t; + + using value_type = char; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + + using iterator = pointer; + using const_iterator = const_pointer; + + /// @endcond + + /** + * Constructor. + * + * @param data Pointer to some memory allocated for the buffer. + * @param capacity Number of bytes available. + */ + fixed_size_buffer_adaptor(char* data, std::size_t capacity) noexcept : + m_data(data), + m_capacity(capacity) { + } + + /** + * Constructor. + * + * @param container Some container class supporting the member functions + * data() and size(). + */ + template + explicit fixed_size_buffer_adaptor(T& container) : + m_data(container.data()), + m_capacity(container.size()) { + } + + /// Returns a pointer to the data in the buffer. + const char* data() const noexcept { + return m_data; + } + + /// Returns a pointer to the data in the buffer. + char* data() noexcept { + return m_data; + } + + /// The capacity this buffer was created with. + std::size_t capacity() const noexcept { + return m_capacity; + } + + /// The number of bytes used in the buffer. Always <= capacity(). + std::size_t size() const noexcept { + return m_size; + } + + /// Return iterator to beginning of data. + char* begin() noexcept { + return m_data; + } + + /// Return iterator to beginning of data. + const char* begin() const noexcept { + return m_data; + } + + /// Return iterator to beginning of data. + const char* cbegin() const noexcept { + return m_data; + } + + /// Return iterator to end of data. + char* end() noexcept { + return m_data + m_size; + } + + /// Return iterator to end of data. + const char* end() const noexcept { + return m_data + m_size; + } + + /// Return iterator to end of data. + const char* cend() const noexcept { + return m_data + m_size; + } + +/// @cond INTERNAL + + // Do not rely on anything beyond this point + + void append(const char* data, std::size_t count) { + if (m_size + count > m_capacity) { + throw std::length_error{"fixed size data store exhausted"}; + } + std::copy_n(data, count, m_data + m_size); + m_size += count; + } + + void append_zeros(std::size_t count) { + if (m_size + count > m_capacity) { + throw std::length_error{"fixed size data store exhausted"}; + } + std::fill_n(m_data + m_size, count, '\0'); + m_size += count; + } + + void resize(std::size_t size) { + protozero_assert(size < m_size); + if (size > m_capacity) { + throw std::length_error{"fixed size data store exhausted"}; + } + m_size = size; + } + + void erase_range(std::size_t from, std::size_t to) { + protozero_assert(from <= m_size); + protozero_assert(to <= m_size); + protozero_assert(from < to); + std::copy(m_data + to, m_data + m_size, m_data + from); + m_size -= (to - from); + } + + char* at_pos(std::size_t pos) { + protozero_assert(pos <= m_size); + return m_data + pos; + } + + void push_back(char ch) { + if (m_size >= m_capacity) { + throw std::length_error{"fixed size data store exhausted"}; + } + m_data[m_size++] = ch; + } +/// @endcond + +}; // class fixed_size_buffer_adaptor + +/// @cond INTERNAL +template <> +struct buffer_customization { + + static std::size_t size(const fixed_size_buffer_adaptor* buffer) noexcept { + return buffer->size(); + } + + static void append(fixed_size_buffer_adaptor* buffer, const char* data, std::size_t count) { + buffer->append(data, count); + } + + static void append_zeros(fixed_size_buffer_adaptor* buffer, std::size_t count) { + buffer->append_zeros(count); + } + + static void resize(fixed_size_buffer_adaptor* buffer, std::size_t size) { + buffer->resize(size); + } + + static void reserve_additional(fixed_size_buffer_adaptor* /*buffer*/, std::size_t /*size*/) { + /* nothing to be done for fixed-size buffers */ + } + + static void erase_range(fixed_size_buffer_adaptor* buffer, std::size_t from, std::size_t to) { + buffer->erase_range(from, to); + } + + static char* at_pos(fixed_size_buffer_adaptor* buffer, std::size_t pos) { + return buffer->at_pos(pos); + } + + static void push_back(fixed_size_buffer_adaptor* buffer, char ch) { + buffer->push_back(ch); + } + +}; +/// @endcond + +} // namespace protozero + +#endif // PROTOZERO_BUFFER_FIXED_HPP diff --git a/third_party/protozero/include/protozero/buffer_string.hpp b/third_party/protozero/include/protozero/buffer_string.hpp new file mode 100644 index 000000000..1f0f902a8 --- /dev/null +++ b/third_party/protozero/include/protozero/buffer_string.hpp @@ -0,0 +1,76 @@ +#ifndef PROTOZERO_BUFFER_STRING_HPP +#define PROTOZERO_BUFFER_STRING_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +/** + * @file buffer_string.hpp + * + * @brief Contains the customization points for buffer implementation based + * on std::string + */ + +#include "buffer_tmpl.hpp" + +#include +#include +#include + +namespace protozero { + +// Implementation of buffer customizations points for std::string + +/// @cond INTERNAL +template <> +struct buffer_customization { + + static std::size_t size(const std::string* buffer) noexcept { + return buffer->size(); + } + + static void append(std::string* buffer, const char* data, std::size_t count) { + buffer->append(data, count); + } + + static void append_zeros(std::string* buffer, std::size_t count) { + buffer->append(count, '\0'); + } + + static void resize(std::string* buffer, std::size_t size) { + protozero_assert(size < buffer->size()); + buffer->resize(size); + } + + static void reserve_additional(std::string* buffer, std::size_t size) { + buffer->reserve(buffer->size() + size); + } + + static void erase_range(std::string* buffer, std::size_t from, std::size_t to) { + protozero_assert(from <= buffer->size()); + protozero_assert(to <= buffer->size()); + protozero_assert(from <= to); + buffer->erase(std::next(buffer->begin(), from), std::next(buffer->begin(), to)); + } + + static char* at_pos(std::string* buffer, std::size_t pos) { + protozero_assert(pos <= buffer->size()); + return (&*buffer->begin()) + pos; + } + + static void push_back(std::string* buffer, char ch) { + buffer->push_back(ch); + } + +}; +/// @endcond + +} // namespace protozero + +#endif // PROTOZERO_BUFFER_STRING_HPP diff --git a/third_party/protozero/include/protozero/buffer_tmpl.hpp b/third_party/protozero/include/protozero/buffer_tmpl.hpp new file mode 100644 index 000000000..ac223996d --- /dev/null +++ b/third_party/protozero/include/protozero/buffer_tmpl.hpp @@ -0,0 +1,113 @@ +#ifndef PROTOZERO_BUFFER_TMPL_HPP +#define PROTOZERO_BUFFER_TMPL_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +/** + * @file buffer_tmpl.hpp + * + * @brief Contains the customization points for buffer implementations. + */ + +#include +#include +#include + +namespace protozero { + +// Implementation of buffer customizations points for std::string + +/// @cond INTERNAL +template +struct buffer_customization { + + /** + * Get the number of bytes currently used in the buffer. + * + * @param buffer Pointer to the buffer. + * @returns number of bytes used in the buffer. + */ + static std::size_t size(const std::string* buffer); + + /** + * Append count bytes from data to the buffer. + * + * @param buffer Pointer to the buffer. + * @param data Pointer to the data. + * @param count Number of bytes to be added to the buffer. + */ + static void append(std::string* buffer, const char* data, std::size_t count); + + /** + * Append count zero bytes to the buffer. + * + * @param buffer Pointer to the buffer. + * @param count Number of bytes to be added to the buffer. + */ + static void append_zeros(std::string* buffer, std::size_t count); + + /** + * Shrink the buffer to the specified size. The new size will always be + * smaller than the current size. + * + * @param buffer Pointer to the buffer. + * @param size New size of the buffer. + * + * @pre size < current size of buffer + */ + static void resize(std::string* buffer, std::size_t size); + + /** + * Reserve an additional size bytes for use in the buffer. This is used for + * variable-sized buffers to tell the buffer implementation that soon more + * memory will be used. The implementation can ignore this. + * + * @param buffer Pointer to the buffer. + * @param size Number of bytes to reserve. + */ + static void reserve_additional(std::string* buffer, std::size_t size); + + /** + * Delete data from the buffer. This must move back the data after the + * part being deleted and resize the buffer accordingly. + * + * @param buffer Pointer to the buffer. + * @param from Offset into the buffer where we want to erase from. + * @param to Offset into the buffer one past the last byte we want to erase. + * + * @pre from, to <= size of the buffer, from < to + */ + static void erase_range(std::string* buffer, std::size_t from, std::size_t to); + + /** + * Return a pointer to the memory at the specified position in the buffer. + * + * @param buffer Pointer to the buffer. + * @param pos The position in the buffer. + * @returns pointer to the memory in the buffer at the specified position. + * + * @pre pos <= size of the buffer + */ + static char* at_pos(std::string* buffer, std::size_t pos); + + /** + * Add a char to the buffer incrementing the number of chars in the buffer. + * + * @param buffer Pointer to the buffer. + * @param ch The character to add. + */ + static void push_back(std::string* buffer, char ch); + +}; +/// @endcond + +} // namespace protozero + +#endif // PROTOZERO_BUFFER_TMPL_HPP diff --git a/third_party/protozero/include/protozero/buffer_vector.hpp b/third_party/protozero/include/protozero/buffer_vector.hpp new file mode 100644 index 000000000..6a34b072e --- /dev/null +++ b/third_party/protozero/include/protozero/buffer_vector.hpp @@ -0,0 +1,76 @@ +#ifndef PROTOZERO_BUFFER_VECTOR_HPP +#define PROTOZERO_BUFFER_VECTOR_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +/** + * @file buffer_vector.hpp + * + * @brief Contains the customization points for buffer implementation based + * on std::vector + */ + +#include "buffer_tmpl.hpp" + +#include +#include +#include + +namespace protozero { + +// Implementation of buffer customizations points for std::vector + +/// @cond INTERNAL +template <> +struct buffer_customization> { + + static std::size_t size(const std::vector* buffer) noexcept { + return buffer->size(); + } + + static void append(std::vector* buffer, const char* data, std::size_t count) { + buffer->insert(buffer->end(), data, data + count); + } + + static void append_zeros(std::vector* buffer, std::size_t count) { + buffer->insert(buffer->end(), count, '\0'); + } + + static void resize(std::vector* buffer, std::size_t size) { + protozero_assert(size < buffer->size()); + buffer->resize(size); + } + + static void reserve_additional(std::vector* buffer, std::size_t size) { + buffer->reserve(buffer->size() + size); + } + + static void erase_range(std::vector* buffer, std::size_t from, std::size_t to) { + protozero_assert(from <= buffer->size()); + protozero_assert(to <= buffer->size()); + protozero_assert(from <= to); + buffer->erase(std::next(buffer->begin(), from), std::next(buffer->begin(), to)); + } + + static char* at_pos(std::vector* buffer, std::size_t pos) { + protozero_assert(pos <= buffer->size()); + return (&*buffer->begin()) + pos; + } + + static void push_back(std::vector* buffer, char ch) { + buffer->push_back(ch); + } + +}; +/// @endcond + +} // namespace protozero + +#endif // PROTOZERO_BUFFER_VECTOR_HPP diff --git a/third_party/protozero/include/protozero/byteswap.hpp b/third_party/protozero/include/protozero/byteswap.hpp index fd8a83a68..799d1795d 100644 --- a/third_party/protozero/include/protozero/byteswap.hpp +++ b/third_party/protozero/include/protozero/byteswap.hpp @@ -16,7 +16,7 @@ documentation. * @brief Contains functions to swap bytes in values (for different endianness). */ -#include +#include "config.hpp" #include @@ -27,10 +27,10 @@ inline uint32_t byteswap_impl(uint32_t value) noexcept { #ifdef PROTOZERO_USE_BUILTIN_BSWAP return __builtin_bswap32(value); #else - return ((value & 0xff000000) >> 24) | - ((value & 0x00ff0000) >> 8) | - ((value & 0x0000ff00) << 8) | - ((value & 0x000000ff) << 24); + return ((value & 0xff000000U) >> 24U) | + ((value & 0x00ff0000U) >> 8U) | + ((value & 0x0000ff00U) << 8U) | + ((value & 0x000000ffU) << 24U); #endif } @@ -38,46 +38,62 @@ inline uint64_t byteswap_impl(uint64_t value) noexcept { #ifdef PROTOZERO_USE_BUILTIN_BSWAP return __builtin_bswap64(value); #else - return ((value & 0xff00000000000000ULL) >> 56) | - ((value & 0x00ff000000000000ULL) >> 40) | - ((value & 0x0000ff0000000000ULL) >> 24) | - ((value & 0x000000ff00000000ULL) >> 8) | - ((value & 0x00000000ff000000ULL) << 8) | - ((value & 0x0000000000ff0000ULL) << 24) | - ((value & 0x000000000000ff00ULL) << 40) | - ((value & 0x00000000000000ffULL) << 56); + return ((value & 0xff00000000000000ULL) >> 56U) | + ((value & 0x00ff000000000000ULL) >> 40U) | + ((value & 0x0000ff0000000000ULL) >> 24U) | + ((value & 0x000000ff00000000ULL) >> 8U) | + ((value & 0x00000000ff000000ULL) << 8U) | + ((value & 0x0000000000ff0000ULL) << 24U) | + ((value & 0x000000000000ff00ULL) << 40U) | + ((value & 0x00000000000000ffULL) << 56U); #endif } +} // end namespace detail + +/// byteswap the data pointed to by ptr in-place. inline void byteswap_inplace(uint32_t* ptr) noexcept { - *ptr = byteswap_impl(*ptr); + *ptr = detail::byteswap_impl(*ptr); } +/// byteswap the data pointed to by ptr in-place. inline void byteswap_inplace(uint64_t* ptr) noexcept { - *ptr = byteswap_impl(*ptr); + *ptr = detail::byteswap_impl(*ptr); } +/// byteswap the data pointed to by ptr in-place. inline void byteswap_inplace(int32_t* ptr) noexcept { - auto bptr = reinterpret_cast(ptr); - *bptr = byteswap_impl(*bptr); + auto* bptr = reinterpret_cast(ptr); + *bptr = detail::byteswap_impl(*bptr); } +/// byteswap the data pointed to by ptr in-place. inline void byteswap_inplace(int64_t* ptr) noexcept { - auto bptr = reinterpret_cast(ptr); - *bptr = byteswap_impl(*bptr); + auto* bptr = reinterpret_cast(ptr); + *bptr = detail::byteswap_impl(*bptr); } +/// byteswap the data pointed to by ptr in-place. inline void byteswap_inplace(float* ptr) noexcept { - auto bptr = reinterpret_cast(ptr); - *bptr = byteswap_impl(*bptr); + auto* bptr = reinterpret_cast(ptr); + *bptr = detail::byteswap_impl(*bptr); } +/// byteswap the data pointed to by ptr in-place. inline void byteswap_inplace(double* ptr) noexcept { - auto bptr = reinterpret_cast(ptr); - *bptr = byteswap_impl(*bptr); + auto* bptr = reinterpret_cast(ptr); + *bptr = detail::byteswap_impl(*bptr); } +namespace detail { + + // Added for backwards compatibility with any code that might use this + // function (even if it shouldn't have). Will be removed in a later + // version of protozero. + using ::protozero::byteswap_inplace; + } // end namespace detail + } // end namespace protozero #endif // PROTOZERO_BYTESWAP_HPP diff --git a/third_party/protozero/include/protozero/data_view.hpp b/third_party/protozero/include/protozero/data_view.hpp index 952c91203..3ec87af34 100644 --- a/third_party/protozero/include/protozero/data_view.hpp +++ b/third_party/protozero/include/protozero/data_view.hpp @@ -16,7 +16,7 @@ documentation. * @brief Contains the implementation of the data_view class. */ -#include +#include "config.hpp" #include #include @@ -55,8 +55,8 @@ public: * @param length Length of the data. */ constexpr data_view(const char* ptr, std::size_t length) noexcept - : m_data(ptr), - m_size(length) { + : m_data{ptr}, + m_size{length} { } /** @@ -65,8 +65,8 @@ public: * @param str String with the data. */ data_view(const std::string& str) noexcept // NOLINT(google-explicit-constructor, hicpp-explicit-conversions) - : m_data(str.data()), - m_size(str.size()) { + : m_data{str.data()}, + m_size{str.size()} { } /** @@ -75,8 +75,8 @@ public: * @param ptr Pointer to the data. */ data_view(const char* ptr) noexcept // NOLINT(google-explicit-constructor, hicpp-explicit-conversions) - : m_data(ptr), - m_size(std::strlen(ptr)) { + : m_data{ptr}, + m_size{std::strlen(ptr)} { } /** @@ -141,8 +141,8 @@ public: * * @pre Must not be default constructed data_view. */ - int compare(data_view other) const { - protozero_assert(m_data && other.m_data); + int compare(data_view other) const noexcept { + assert(m_data && other.m_data); const int cmp = std::memcmp(data(), other.data(), std::min(size(), other.size())); if (cmp == 0) { diff --git a/third_party/protozero/include/protozero/iterators.hpp b/third_party/protozero/include/protozero/iterators.hpp index c1d7d8d69..ee8ef8ecf 100644 --- a/third_party/protozero/include/protozero/iterators.hpp +++ b/third_party/protozero/include/protozero/iterators.hpp @@ -16,8 +16,8 @@ documentation. * @brief Contains the iterators for access to packed repeated fields. */ -#include -#include +#include "config.hpp" +#include "varint.hpp" #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN # include @@ -56,7 +56,7 @@ public: * Default constructor. Create empty iterator_range. */ constexpr iterator_range() : - P(iterator{}, iterator{}) { + P{iterator{}, iterator{}} { } /** @@ -66,8 +66,8 @@ public: * @param last_iterator Iterator to end of range. */ constexpr iterator_range(iterator&& first_iterator, iterator&& last_iterator) : - P(std::forward(first_iterator), - std::forward(last_iterator)) { + P{std::forward(first_iterator), + std::forward(last_iterator)} { } /// Return iterator to beginning of range. @@ -164,6 +164,8 @@ class const_fixed_iterator { public: + /// @cond usual iterator functions not documented + using iterator_category = std::random_access_iterator_tag; using value_type = T; using difference_type = std::ptrdiff_t; @@ -173,7 +175,7 @@ public: const_fixed_iterator() noexcept = default; explicit const_fixed_iterator(const char* data) noexcept : - m_data(data) { + m_data{data} { } const_fixed_iterator(const const_fixed_iterator&) noexcept = default; @@ -184,11 +186,11 @@ public: ~const_fixed_iterator() noexcept = default; - value_type operator*() const { + value_type operator*() const noexcept { value_type result; std::memcpy(&result, m_data, sizeof(value_type)); #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN - detail::byteswap_inplace(&result); + byteswap_inplace(&result); #endif return result; } @@ -204,14 +206,6 @@ public: return tmp; } - bool operator==(const_fixed_iterator rhs) const noexcept { - return m_data == rhs.m_data; - } - - bool operator!=(const_fixed_iterator rhs) const noexcept { - return !(*this == rhs); - } - const_fixed_iterator& operator--() noexcept { m_data -= sizeof(value_type); return *this; @@ -223,6 +217,14 @@ public: return tmp; } + friend bool operator==(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept { + return lhs.m_data == rhs.m_data; + } + + friend bool operator!=(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept { + return !(lhs == rhs); + } + friend bool operator<(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept { return lhs.m_data < rhs.m_data; } @@ -237,7 +239,6 @@ public: friend bool operator>=(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept { return !(lhs < rhs); - } const_fixed_iterator& operator+=(difference_type val) noexcept { @@ -276,6 +277,8 @@ public: return *(*this + n); } + /// @endcond + }; // class const_fixed_iterator /** @@ -288,13 +291,15 @@ class const_varint_iterator { protected: /// Pointer to current iterator position - const char* m_data = nullptr; + const char* m_data = nullptr; // NOLINT(misc-non-private-member-variables-in-classes, cppcoreguidelines-non-private-member-variables-in-classes,-warnings-as-errors) /// Pointer to end iterator position - const char* m_end = nullptr; + const char* m_end = nullptr; // NOLINT(misc-non-private-member-variables-in-classes, cppcoreguidelines-non-private-member-variables-in-classes,-warnings-as-errors) public: + /// @cond usual iterator functions not documented + using iterator_category = std::forward_iterator_tag; using value_type = T; using difference_type = std::ptrdiff_t; @@ -302,19 +307,24 @@ public: using reference = value_type&; static difference_type distance(const_varint_iterator begin, const_varint_iterator end) noexcept { + // The "distance" between default initialized const_varint_iterator's + // is always 0. + if (!begin.m_data) { + return 0; + } // We know that each varint contains exactly one byte with the most // significant bit not set. We can use this to quickly figure out // how many varints there are without actually decoding the varints. return std::count_if(begin.m_data, end.m_data, [](char c) noexcept { - return (static_cast(c) & 0x80u) == 0; + return (static_cast(c) & 0x80U) == 0; }); } const_varint_iterator() noexcept = default; const_varint_iterator(const char* data, const char* end) noexcept : - m_data(data), - m_end(end) { + m_data{data}, + m_end{end} { } const_varint_iterator(const const_varint_iterator&) noexcept = default; @@ -326,16 +336,19 @@ public: ~const_varint_iterator() noexcept = default; value_type operator*() const { + protozero_assert(m_data); const char* d = m_data; // will be thrown away return static_cast(decode_varint(&d, m_end)); } const_varint_iterator& operator++() { + protozero_assert(m_data); skip_varint(&m_data, m_end); return *this; } const_varint_iterator operator++(int) { + protozero_assert(m_data); const const_varint_iterator tmp{*this}; ++(*this); return tmp; @@ -349,6 +362,8 @@ public: return !(*this == rhs); } + /// @endcond + }; // class const_varint_iterator /** @@ -360,6 +375,8 @@ class const_svarint_iterator : public const_varint_iterator { public: + /// @cond usual iterator functions not documented + using iterator_category = std::forward_iterator_tag; using value_type = T; using difference_type = std::ptrdiff_t; @@ -367,11 +384,11 @@ public: using reference = value_type&; const_svarint_iterator() noexcept : - const_varint_iterator() { + const_varint_iterator{} { } const_svarint_iterator(const char* data, const char* end) noexcept : - const_varint_iterator(data, end) { + const_varint_iterator{data, end} { } const_svarint_iterator(const const_svarint_iterator&) = default; @@ -383,21 +400,26 @@ public: ~const_svarint_iterator() = default; value_type operator*() const { + protozero_assert(this->m_data); const char* d = this->m_data; // will be thrown away return static_cast(decode_zigzag64(decode_varint(&d, this->m_end))); } const_svarint_iterator& operator++() { + protozero_assert(this->m_data); skip_varint(&this->m_data, this->m_end); return *this; } const_svarint_iterator operator++(int) { + protozero_assert(this->m_data); const const_svarint_iterator tmp{*this}; ++(*this); return tmp; } + /// @endcond + }; // class const_svarint_iterator } // end namespace protozero @@ -408,6 +430,8 @@ namespace std { // functions can't be partially specialized, we have to do this for // every value_type we are using. + /// @cond individual overloads do not need to be documented + template <> inline typename protozero::const_varint_iterator::difference_type distance>(protozero::const_varint_iterator first, // NOLINT(readability-inconsistent-declaration-parameter-name) @@ -450,6 +474,8 @@ namespace std { return protozero::const_svarint_iterator::distance(first, last); } + /// @endcond + } // end namespace std #endif // PROTOZERO_ITERATORS_HPP diff --git a/third_party/protozero/include/protozero/pbf_builder.hpp b/third_party/protozero/include/protozero/pbf_builder.hpp index 2e74b2fd9..71a2dec2b 100644 --- a/third_party/protozero/include/protozero/pbf_builder.hpp +++ b/third_party/protozero/include/protozero/pbf_builder.hpp @@ -16,249 +16,16 @@ documentation. * @brief Contains the pbf_builder template class. */ -#include -#include +#include "basic_pbf_builder.hpp" +#include "pbf_writer.hpp" -#include +#include namespace protozero { -/** - * The pbf_builder is used to write PBF formatted messages into a buffer. It - * is based on the pbf_writer class and has all the same methods. The - * difference is that while the pbf_writer class takes an integer tag, - * this template class takes a tag of the template type T. The idea is that - * T will be an enumeration value and this helps reduce the possibility of - * programming errors. - * - * Almost all methods in this class can throw an std::bad_alloc exception if - * the std::string used as a buffer wants to resize. - * - * Read the tutorial to understand how this class is used. - */ +/// Specialization of basic_pbf_builder using std::string as buffer type. template -class pbf_builder : public pbf_writer { - - static_assert(std::is_same::type>::value, - "T must be enum with underlying type protozero::pbf_tag_type"); - -public: - - /// The type of messages this class will build. - using enum_type = T; - - pbf_builder() = default; - - /** - * Create a builder using the given string as a data store. The object - * stores a reference to that string and adds all data to it. The string - * doesn't have to be empty. The pbf_message object will just append data. - */ - explicit pbf_builder(std::string& data) noexcept : - pbf_writer(data) { - } - - /** - * Construct a pbf_builder for a submessage from the pbf_message or - * pbf_writer of the parent message. - * - * @param parent_writer The parent pbf_message or pbf_writer - * @param tag Tag of the field that will be written - */ - template - pbf_builder(pbf_writer& parent_writer, P tag) noexcept : - pbf_writer(parent_writer, pbf_tag_type(tag)) { - } - -/// @cond INTERNAL -#define PROTOZERO_WRITER_WRAP_ADD_SCALAR(name, type) \ - void add_##name(T tag, type value) { \ - pbf_writer::add_##name(pbf_tag_type(tag), value); \ - } - - PROTOZERO_WRITER_WRAP_ADD_SCALAR(bool, bool) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(enum, int32_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(int32, int32_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(sint32, int32_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(uint32, uint32_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(int64, int64_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(sint64, int64_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(uint64, uint64_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(fixed32, uint32_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(sfixed32, int32_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(fixed64, uint64_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(sfixed64, int64_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(float, float) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(double, double) - -#undef PROTOZERO_WRITER_WRAP_ADD_SCALAR -/// @endcond - - /** - * Add "bytes" field to data. - * - * @param tag Tag of the field - * @param value Pointer to value to be written - * @param size Number of bytes to be written - */ - void add_bytes(T tag, const char* value, std::size_t size) { - pbf_writer::add_bytes(pbf_tag_type(tag), value, size); - } - - /** - * Add "bytes" field to data. - * - * @param tag Tag of the field - * @param value Value to be written - */ - void add_bytes(T tag, const data_view& value) { - pbf_writer::add_bytes(pbf_tag_type(tag), value); - } - - /** - * Add "bytes" field to data. - * - * @param tag Tag of the field - * @param value Value to be written - */ - void add_bytes(T tag, const std::string& value) { - pbf_writer::add_bytes(pbf_tag_type(tag), value); - } - - /** - * Add "bytes" field to data. Bytes from the value are written until - * a null byte is encountered. The null byte is not added. - * - * @param tag Tag of the field - * @param value Pointer to zero-delimited value to be written - */ - void add_bytes(T tag, const char* value) { - pbf_writer::add_bytes(pbf_tag_type(tag), value); - } - - /** - * Add "bytes" field to data using vectored input. All the data in the - * 2nd and further arguments is "concatenated" with only a single copy - * into the final buffer. - * - * This will work with objects of any type supporting the data() and - * size() methods like std::string or protozero::data_view. - * - * Example: - * @code - * std::string data1 = "abc"; - * std::string data2 = "xyz"; - * builder.add_bytes_vectored(1, data1, data2); - * @endcode - * - * @tparam Ts List of types supporting data() and size() methods. - * @param tag Tag of the field - * @param values List of objects of types Ts with data to be appended. - */ - template - void add_bytes_vectored(T tag, Ts&&... values) { - pbf_writer::add_bytes_vectored(pbf_tag_type(tag), std::forward(values)...); - } - - /** - * Add "string" field to data. - * - * @param tag Tag of the field - * @param value Pointer to value to be written - * @param size Number of bytes to be written - */ - void add_string(T tag, const char* value, std::size_t size) { - pbf_writer::add_string(pbf_tag_type(tag), value, size); - } - - /** - * Add "string" field to data. - * - * @param tag Tag of the field - * @param value Value to be written - */ - void add_string(T tag, const data_view& value) { - pbf_writer::add_string(pbf_tag_type(tag), value); - } - - /** - * Add "string" field to data. - * - * @param tag Tag of the field - * @param value Value to be written - */ - void add_string(T tag, const std::string& value) { - pbf_writer::add_string(pbf_tag_type(tag), value); - } - - /** - * Add "string" field to data. Bytes from the value are written until - * a null byte is encountered. The null byte is not added. - * - * @param tag Tag of the field - * @param value Pointer to value to be written - */ - void add_string(T tag, const char* value) { - pbf_writer::add_string(pbf_tag_type(tag), value); - } - - /** - * Add "message" field to data. - * - * @param tag Tag of the field - * @param value Pointer to message to be written - * @param size Length of the message - */ - void add_message(T tag, const char* value, std::size_t size) { - pbf_writer::add_message(pbf_tag_type(tag), value, size); - } - - /** - * Add "message" field to data. - * - * @param tag Tag of the field - * @param value Value to be written. The value must be a complete message. - */ - void add_message(T tag, const data_view& value) { - pbf_writer::add_message(pbf_tag_type(tag), value); - } - - /** - * Add "message" field to data. - * - * @param tag Tag of the field - * @param value Value to be written. The value must be a complete message. - */ - void add_message(T tag, const std::string& value) { - pbf_writer::add_message(pbf_tag_type(tag), value); - } - -/// @cond INTERNAL -#define PROTOZERO_WRITER_WRAP_ADD_PACKED(name) \ - template \ - void add_packed_##name(T tag, InputIterator first, InputIterator last) { \ - pbf_writer::add_packed_##name(pbf_tag_type(tag), first, last); \ - } - - PROTOZERO_WRITER_WRAP_ADD_PACKED(bool) - PROTOZERO_WRITER_WRAP_ADD_PACKED(enum) - PROTOZERO_WRITER_WRAP_ADD_PACKED(int32) - PROTOZERO_WRITER_WRAP_ADD_PACKED(sint32) - PROTOZERO_WRITER_WRAP_ADD_PACKED(uint32) - PROTOZERO_WRITER_WRAP_ADD_PACKED(int64) - PROTOZERO_WRITER_WRAP_ADD_PACKED(sint64) - PROTOZERO_WRITER_WRAP_ADD_PACKED(uint64) - PROTOZERO_WRITER_WRAP_ADD_PACKED(fixed32) - PROTOZERO_WRITER_WRAP_ADD_PACKED(sfixed32) - PROTOZERO_WRITER_WRAP_ADD_PACKED(fixed64) - PROTOZERO_WRITER_WRAP_ADD_PACKED(sfixed64) - PROTOZERO_WRITER_WRAP_ADD_PACKED(float) - PROTOZERO_WRITER_WRAP_ADD_PACKED(double) - -#undef PROTOZERO_WRITER_WRAP_ADD_PACKED -/// @endcond - -}; // class pbf_builder +using pbf_builder = basic_pbf_builder; } // end namespace protozero diff --git a/third_party/protozero/include/protozero/pbf_message.hpp b/third_party/protozero/include/protozero/pbf_message.hpp index 10040d5b4..d7fd8b5d0 100644 --- a/third_party/protozero/include/protozero/pbf_message.hpp +++ b/third_party/protozero/include/protozero/pbf_message.hpp @@ -16,8 +16,8 @@ documentation. * @brief Contains the pbf_message template class. */ -#include -#include +#include "pbf_reader.hpp" +#include "types.hpp" #include @@ -78,7 +78,7 @@ public: */ template pbf_message(Args&&... args) noexcept : // NOLINT(google-explicit-constructor, hicpp-explicit-conversions) - pbf_reader(std::forward(args)...) { + pbf_reader{std::forward(args)...} { } /** diff --git a/third_party/protozero/include/protozero/pbf_reader.hpp b/third_party/protozero/include/protozero/pbf_reader.hpp index 5f8ea0eca..92bfdee5e 100644 --- a/third_party/protozero/include/protozero/pbf_reader.hpp +++ b/third_party/protozero/include/protozero/pbf_reader.hpp @@ -16,12 +16,12 @@ documentation. * @brief Contains the pbf_reader class. */ -#include -#include -#include -#include -#include -#include +#include "config.hpp" +#include "data_view.hpp" +#include "exception.hpp" +#include "iterators.hpp" +#include "types.hpp" +#include "varint.hpp" #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN # include @@ -80,7 +80,7 @@ class pbf_reader { skip_bytes(sizeof(T)); std::memcpy(&result, data, sizeof(T)); #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN - detail::byteswap_inplace(&result); + byteswap_inplace(&result); #endif return result; } @@ -98,7 +98,8 @@ class pbf_reader { template T get_varint() { - return static_cast(decode_varint(&m_data, m_end)); + const auto val = static_cast(decode_varint(&m_data, m_end)); + return val; } template @@ -112,7 +113,7 @@ class pbf_reader { } void skip_bytes(pbf_length_type len) { - if (m_data + len > m_end) { + if (m_end - m_data < static_cast(len)) { throw end_of_buffer_exception{}; } m_data += len; @@ -151,8 +152,8 @@ public: * @post There is no current field. */ explicit pbf_reader(const data_view& view) noexcept - : m_data(view.data()), - m_end(view.data() + view.size()) { + : m_data{view.data()}, + m_end{view.data() + view.size()} { } /** @@ -166,8 +167,8 @@ public: * @post There is no current field. */ pbf_reader(const char* data, std::size_t size) noexcept - : m_data(data), - m_end(data + size) { + : m_data{data}, + m_end{data + size} { } #ifndef PROTOZERO_STRICT_API @@ -183,8 +184,8 @@ public: * @deprecated Use one of the other constructors. */ explicit pbf_reader(const std::pair& data) noexcept - : m_data(data.first), - m_end(data.first + data.second) { + : m_data{data.first}, + m_end{data.first + data.second} { } #endif @@ -199,8 +200,8 @@ public: * @post There is no current field. */ explicit pbf_reader(const std::string& data) noexcept - : m_data(data.data()), - m_end(data.data() + data.size()) { + : m_data{data.data()}, + m_end{data.data() + data.size()} { } /** @@ -242,7 +243,14 @@ public: * read. */ operator bool() const noexcept { // NOLINT(google-explicit-constructor, hicpp-explicit-conversions) - return m_data < m_end; + return m_data != m_end; + } + + /** + * Get a view of the not yet read data. + */ + data_view data() const noexcept { + return {m_data, static_cast(m_end - m_data)}; } /** @@ -279,7 +287,7 @@ public: } const auto value = get_varint(); - m_tag = pbf_tag_type(value >> 3u); + m_tag = pbf_tag_type(value >> 3U); // tags 0 and 19000 to 19999 are not allowed as per // https://developers.google.com/protocol-buffers/docs/proto#assigning-tags @@ -287,7 +295,7 @@ public: throw invalid_tag_exception{}; } - m_wire_type = pbf_wire_type(value & 0x07u); + m_wire_type = pbf_wire_type(value & 0x07U); switch (m_wire_type) { case pbf_wire_type::varint: case pbf_wire_type::fixed64: @@ -486,9 +494,9 @@ public: bool get_bool() { protozero_assert(tag() != 0 && "call next() before accessing field value"); protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); - const auto data = m_data; + const bool result = m_data[0] != 0; skip_varint(&m_data, m_end); - return data[0] != 0; + return result; } /** diff --git a/third_party/protozero/include/protozero/pbf_writer.hpp b/third_party/protozero/include/protozero/pbf_writer.hpp index 1abe9a38a..9a07bd5b9 100644 --- a/third_party/protozero/include/protozero/pbf_writer.hpp +++ b/third_party/protozero/include/protozero/pbf_writer.hpp @@ -16,1033 +16,60 @@ documentation. * @brief Contains the pbf_writer class. */ -#include -#include -#include -#include +#include "basic_pbf_writer.hpp" +#include "buffer_string.hpp" -#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN -# include -#endif - -#include #include -#include -#include -#include -#include #include -#include namespace protozero { -namespace detail { - - template class packed_field_varint; - template class packed_field_svarint; - template class packed_field_fixed; - -} // end namespace detail - /** - * The pbf_writer is used to write PBF formatted messages into a buffer. - * - * Almost all methods in this class can throw an std::bad_alloc exception if - * the std::string used as a buffer wants to resize. + * Specialization of basic_pbf_writer using std::string as buffer type. */ -class pbf_writer { - - // A pointer to a string buffer holding the data already written to the - // PBF message. For default constructed writers or writers that have been - // rolled back, this is a nullptr. - std::string* m_data = nullptr; - - // A pointer to a parent writer object if this is a submessage. If this - // is a top-level writer, it is a nullptr. - pbf_writer* m_parent_writer = nullptr; - - // This is usually 0. If there is an open submessage, this is set in the - // parent to the rollback position, ie. the last position before the - // submessage was started. This is the position where the header of the - // submessage starts. - std::size_t m_rollback_pos = 0; - - // This is usually 0. If there is an open submessage, this is set in the - // parent to the position where the data of the submessage is written to. - std::size_t m_pos = 0; - - void add_varint(uint64_t value) { - protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); - protozero_assert(m_data); - write_varint(std::back_inserter(*m_data), value); - } - - void add_field(pbf_tag_type tag, pbf_wire_type type) { - protozero_assert(((tag > 0 && tag < 19000) || (tag > 19999 && tag <= ((1u << 29u) - 1))) && "tag out of range"); - const uint32_t b = (tag << 3u) | uint32_t(type); - add_varint(b); - } - - void add_tagged_varint(pbf_tag_type tag, uint64_t value) { - add_field(tag, pbf_wire_type::varint); - add_varint(value); - } - - template - void add_fixed(T value) { - protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); - protozero_assert(m_data); -#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN - detail::byteswap_inplace(&value); -#endif - m_data->append(reinterpret_cast(&value), sizeof(T)); - } - - template - void add_packed_fixed(pbf_tag_type tag, It first, It last, std::input_iterator_tag /*unused*/) { - if (first == last) { - return; - } - - pbf_writer sw{*this, tag}; - - while (first != last) { - sw.add_fixed(*first++); - } - } - - template - void add_packed_fixed(pbf_tag_type tag, It first, It last, std::forward_iterator_tag /*unused*/) { - if (first == last) { - return; - } - - const auto length = std::distance(first, last); - add_length_varint(tag, sizeof(T) * pbf_length_type(length)); - reserve(sizeof(T) * std::size_t(length)); - - while (first != last) { - add_fixed(*first++); - } - } - - template - void add_packed_varint(pbf_tag_type tag, It first, It last) { - if (first == last) { - return; - } - - pbf_writer sw{*this, tag}; - - while (first != last) { - sw.add_varint(uint64_t(*first++)); - } - } - - template - void add_packed_svarint(pbf_tag_type tag, It first, It last) { - if (first == last) { - return; - } - - pbf_writer sw{*this, tag}; - - while (first != last) { - sw.add_varint(encode_zigzag64(*first++)); - } - } - - // The number of bytes to reserve for the varint holding the length of - // a length-delimited field. The length has to fit into pbf_length_type, - // and a varint needs 8 bit for every 7 bit. - enum constant_reserve_bytes : int { - reserve_bytes = sizeof(pbf_length_type) * 8 / 7 + 1 - }; - - // If m_rollpack_pos is set to this special value, it means that when - // the submessage is closed, nothing needs to be done, because the length - // of the submessage has already been written correctly. - enum constant_size_is_known : std::size_t { - size_is_known = std::numeric_limits::max() - }; - - void open_submessage(pbf_tag_type tag, std::size_t size) { - protozero_assert(m_pos == 0); - protozero_assert(m_data); - if (size == 0) { - m_rollback_pos = m_data->size(); - add_field(tag, pbf_wire_type::length_delimited); - m_data->append(std::size_t(reserve_bytes), '\0'); - } else { - m_rollback_pos = size_is_known; - add_length_varint(tag, pbf_length_type(size)); - reserve(size); - } - m_pos = m_data->size(); - } - - void rollback_submessage() { - protozero_assert(m_pos != 0); - protozero_assert(m_rollback_pos != size_is_known); - protozero_assert(m_data); - m_data->resize(m_rollback_pos); - m_pos = 0; - } - - void commit_submessage() { - protozero_assert(m_pos != 0); - protozero_assert(m_rollback_pos != size_is_known); - protozero_assert(m_data); - const auto length = pbf_length_type(m_data->size() - m_pos); - - protozero_assert(m_data->size() >= m_pos - reserve_bytes); - const auto n = write_varint(m_data->begin() + int64_t(m_pos) - reserve_bytes, length); - - m_data->erase(m_data->begin() + int64_t(m_pos) - reserve_bytes + n, m_data->begin() + int64_t(m_pos)); - m_pos = 0; - } - - void close_submessage() { - protozero_assert(m_data); - if (m_pos == 0 || m_rollback_pos == size_is_known) { - return; - } - if (m_data->size() - m_pos == 0) { - rollback_submessage(); - } else { - commit_submessage(); - } - } - - void add_length_varint(pbf_tag_type tag, pbf_length_type length) { - add_field(tag, pbf_wire_type::length_delimited); - add_varint(length); - } - -public: - - /** - * Create a writer using the given string as a data store. The pbf_writer - * stores a reference to that string and adds all data to it. The string - * doesn't have to be empty. The pbf_writer will just append data. - */ - explicit pbf_writer(std::string& data) noexcept : - m_data(&data) { - } - - /** - * Create a writer without a data store. In this form the writer can not - * be used! - */ - pbf_writer() noexcept = default; - - /** - * Construct a pbf_writer for a submessage from the pbf_writer of the - * parent message. - * - * @param parent_writer The pbf_writer - * @param tag Tag (field number) of the field that will be written - * @param size Optional size of the submessage in bytes (use 0 for unknown). - * Setting this allows some optimizations but is only possible in - * a few very specific cases. - */ - pbf_writer(pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size=0) : - m_data(parent_writer.m_data), - m_parent_writer(&parent_writer) { - m_parent_writer->open_submessage(tag, size); - } - - /// A pbf_writer object can not be copied - pbf_writer(const pbf_writer&) = delete; - - /// A pbf_writer object can not be copied - pbf_writer& operator=(const pbf_writer&) = delete; - - /** - * A pbf_writer object can be moved. After this the other pbf_writer will - * be invalid. - */ - pbf_writer(pbf_writer&& other) noexcept : - m_data(other.m_data), - m_parent_writer(other.m_parent_writer), - m_rollback_pos(other.m_rollback_pos), - m_pos(other.m_pos) { - other.m_data = nullptr; - other.m_parent_writer = nullptr; - other.m_rollback_pos = 0; - other.m_pos = 0; - } - - /** - * A pbf_writer object can be moved. After this the other pbf_writer will - * be invalid. - */ - pbf_writer& operator=(pbf_writer&& other) noexcept { - m_data = other.m_data; - m_parent_writer = other.m_parent_writer; - m_rollback_pos = other.m_rollback_pos; - m_pos = other.m_pos; - other.m_data = nullptr; - other.m_parent_writer = nullptr; - other.m_rollback_pos = 0; - other.m_pos = 0; - return *this; - } - - ~pbf_writer() { - if (m_parent_writer != nullptr) { - m_parent_writer->close_submessage(); - } - } - - /** - * Check if this writer is valid. A writer is invalid if it was default - * constructed, moved from, or if commit() has been called on it. - * Otherwise it is valid. - */ - bool valid() const noexcept { - return m_data != nullptr; - } - - /** - * Swap the contents of this object with the other. - * - * @param other Other object to swap data with. - */ - void swap(pbf_writer& other) noexcept { - using std::swap; - swap(m_data, other.m_data); - swap(m_parent_writer, other.m_parent_writer); - swap(m_rollback_pos, other.m_rollback_pos); - swap(m_pos, other.m_pos); - } - - /** - * Reserve size bytes in the underlying message store in addition to - * whatever the message store already holds. So unlike - * the `std::string::reserve()` method this is not an absolute size, - * but additional memory that should be reserved. - * - * @param size Number of bytes to reserve in underlying message store. - */ - void reserve(std::size_t size) { - protozero_assert(m_data); - m_data->reserve(m_data->size() + size); - } - - /** - * Commit this submessage. This does the same as when the pbf_writer - * goes out of scope and is destructed. - * - * @pre Must be a pbf_writer of a submessage, ie one opened with the - * pbf_writer constructor taking a parent message. - * @post The pbf_writer is invalid and can't be used any more. - */ - void commit() { - protozero_assert(m_parent_writer && "you can't call commit() on a pbf_writer without a parent"); - protozero_assert(m_pos == 0 && "you can't call commit() on a pbf_writer that has an open nested submessage"); - m_parent_writer->close_submessage(); - m_parent_writer = nullptr; - m_data = nullptr; - } - - /** - * Cancel writing of this submessage. The complete submessage will be - * removed as if it was never created and no fields were added. - * - * @pre Must be a pbf_writer of a submessage, ie one opened with the - * pbf_writer constructor taking a parent message. - * @post The pbf_writer is invalid and can't be used any more. - */ - void rollback() { - protozero_assert(m_parent_writer && "you can't call rollback() on a pbf_writer without a parent"); - protozero_assert(m_pos == 0 && "you can't call rollback() on a pbf_writer that has an open nested submessage"); - m_parent_writer->rollback_submessage(); - m_parent_writer = nullptr; - m_data = nullptr; - } - - ///@{ - /** - * @name Scalar field writer functions - */ - - /** - * Add "bool" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_bool(pbf_tag_type tag, bool value) { - add_field(tag, pbf_wire_type::varint); - protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); - protozero_assert(m_data); - m_data->append(1, char(value)); - } - - /** - * Add "enum" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_enum(pbf_tag_type tag, int32_t value) { - add_tagged_varint(tag, uint64_t(value)); - } - - /** - * Add "int32" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_int32(pbf_tag_type tag, int32_t value) { - add_tagged_varint(tag, uint64_t(value)); - } - - /** - * Add "sint32" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_sint32(pbf_tag_type tag, int32_t value) { - add_tagged_varint(tag, encode_zigzag32(value)); - } - - /** - * Add "uint32" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_uint32(pbf_tag_type tag, uint32_t value) { - add_tagged_varint(tag, value); - } - - /** - * Add "int64" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_int64(pbf_tag_type tag, int64_t value) { - add_tagged_varint(tag, uint64_t(value)); - } - - /** - * Add "sint64" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_sint64(pbf_tag_type tag, int64_t value) { - add_tagged_varint(tag, encode_zigzag64(value)); - } - - /** - * Add "uint64" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_uint64(pbf_tag_type tag, uint64_t value) { - add_tagged_varint(tag, value); - } - - /** - * Add "fixed32" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_fixed32(pbf_tag_type tag, uint32_t value) { - add_field(tag, pbf_wire_type::fixed32); - add_fixed(value); - } - - /** - * Add "sfixed32" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_sfixed32(pbf_tag_type tag, int32_t value) { - add_field(tag, pbf_wire_type::fixed32); - add_fixed(value); - } - - /** - * Add "fixed64" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_fixed64(pbf_tag_type tag, uint64_t value) { - add_field(tag, pbf_wire_type::fixed64); - add_fixed(value); - } - - /** - * Add "sfixed64" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_sfixed64(pbf_tag_type tag, int64_t value) { - add_field(tag, pbf_wire_type::fixed64); - add_fixed(value); - } - - /** - * Add "float" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_float(pbf_tag_type tag, float value) { - add_field(tag, pbf_wire_type::fixed32); - add_fixed(value); - } - - /** - * Add "double" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_double(pbf_tag_type tag, double value) { - add_field(tag, pbf_wire_type::fixed64); - add_fixed(value); - } - - /** - * Add "bytes" field to data. - * - * @param tag Tag (field number) of the field - * @param value Pointer to value to be written - * @param size Number of bytes to be written - */ - void add_bytes(pbf_tag_type tag, const char* value, std::size_t size) { - protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); - protozero_assert(m_data); - protozero_assert(size <= std::numeric_limits::max()); - add_length_varint(tag, pbf_length_type(size)); - m_data->append(value, size); - } - - /** - * Add "bytes" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_bytes(pbf_tag_type tag, const data_view& value) { - add_bytes(tag, value.data(), value.size()); - } - - /** - * Add "bytes" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_bytes(pbf_tag_type tag, const std::string& value) { - add_bytes(tag, value.data(), value.size()); - } - - /** - * Add "bytes" field to data. Bytes from the value are written until - * a null byte is encountered. The null byte is not added. - * - * @param tag Tag (field number) of the field - * @param value Pointer to zero-delimited value to be written - */ - void add_bytes(pbf_tag_type tag, const char* value) { - add_bytes(tag, value, std::strlen(value)); - } - - /** - * Add "bytes" field to data using vectored input. All the data in the - * 2nd and further arguments is "concatenated" with only a single copy - * into the final buffer. - * - * This will work with objects of any type supporting the data() and - * size() methods like std::string or protozero::data_view. - * - * Example: - * @code - * std::string data1 = "abc"; - * std::string data2 = "xyz"; - * writer.add_bytes_vectored(1, data1, data2); - * @endcode - * - * @tparam Ts List of types supporting data() and size() methods. - * @param tag Tag (field number) of the field - * @param values List of objects of types Ts with data to be appended. - */ - template - void add_bytes_vectored(pbf_tag_type tag, Ts&&... values) { - protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); - protozero_assert(m_data); - size_t sum_size = 0; - (void)std::initializer_list{sum_size += values.size()...}; - protozero_assert(sum_size <= std::numeric_limits::max()); - add_length_varint(tag, pbf_length_type(sum_size)); - m_data->reserve(m_data->size() + sum_size); - (void)std::initializer_list{(m_data->append(values.data(), values.size()), 0)...}; - } - - /** - * Add "string" field to data. - * - * @param tag Tag (field number) of the field - * @param value Pointer to value to be written - * @param size Number of bytes to be written - */ - void add_string(pbf_tag_type tag, const char* value, std::size_t size) { - add_bytes(tag, value, size); - } - - /** - * Add "string" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_string(pbf_tag_type tag, const data_view& value) { - add_bytes(tag, value.data(), value.size()); - } - - /** - * Add "string" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_string(pbf_tag_type tag, const std::string& value) { - add_bytes(tag, value.data(), value.size()); - } - - /** - * Add "string" field to data. Bytes from the value are written until - * a null byte is encountered. The null byte is not added. - * - * @param tag Tag (field number) of the field - * @param value Pointer to value to be written - */ - void add_string(pbf_tag_type tag, const char* value) { - add_bytes(tag, value, std::strlen(value)); - } - - /** - * Add "message" field to data. - * - * @param tag Tag (field number) of the field - * @param value Pointer to message to be written - * @param size Length of the message - */ - void add_message(pbf_tag_type tag, const char* value, std::size_t size) { - add_bytes(tag, value, size); - } - - /** - * Add "message" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written. The value must be a complete message. - */ - void add_message(pbf_tag_type tag, const data_view& value) { - add_bytes(tag, value.data(), value.size()); - } - - /** - * Add "message" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written. The value must be a complete message. - */ - void add_message(pbf_tag_type tag, const std::string& value) { - add_bytes(tag, value.data(), value.size()); - } - - ///@} - - ///@{ - /** - * @name Repeated packed field writer functions - */ - - /** - * Add "repeated packed bool" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to bool. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_varint(tag, first, last); - } - - /** - * Add "repeated packed enum" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to int32_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_varint(tag, first, last); - } - - /** - * Add "repeated packed int32" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to int32_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_varint(tag, first, last); - } - - /** - * Add "repeated packed sint32" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to int32_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_svarint(tag, first, last); - } - - /** - * Add "repeated packed uint32" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to uint32_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_uint32(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_varint(tag, first, last); - } - - /** - * Add "repeated packed int64" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to int64_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_varint(tag, first, last); - } - - /** - * Add "repeated packed sint64" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to int64_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_svarint(tag, first, last); - } - - /** - * Add "repeated packed uint64" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to uint64_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_varint(tag, first, last); - } - - /** - * Add "repeated packed fixed32" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to uint32_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_fixed32(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_fixed(tag, first, last, - typename std::iterator_traits::iterator_category()); - } - - /** - * Add "repeated packed sfixed32" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to int32_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_sfixed32(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_fixed(tag, first, last, - typename std::iterator_traits::iterator_category()); - } - - /** - * Add "repeated packed fixed64" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to uint64_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_fixed64(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_fixed(tag, first, last, - typename std::iterator_traits::iterator_category()); - } - - /** - * Add "repeated packed sfixed64" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to int64_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_sfixed64(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_fixed(tag, first, last, - typename std::iterator_traits::iterator_category()); - } - - /** - * Add "repeated packed float" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to float. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_float(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_fixed(tag, first, last, - typename std::iterator_traits::iterator_category()); - } - - /** - * Add "repeated packed double" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to double. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_double(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_fixed(tag, first, last, - typename std::iterator_traits::iterator_category()); - } - - ///@} - - template friend class detail::packed_field_varint; - template friend class detail::packed_field_svarint; - template friend class detail::packed_field_fixed; - -}; // class pbf_writer - -/** - * Swap two pbf_writer objects. - * - * @param lhs First object. - * @param rhs Second object. - */ -inline void swap(pbf_writer& lhs, pbf_writer& rhs) noexcept { - lhs.swap(rhs); -} - -namespace detail { - - class packed_field { - - protected: - - pbf_writer m_writer{}; - - public: - - packed_field(const packed_field&) = delete; - packed_field& operator=(const packed_field&) = delete; - - packed_field(packed_field&&) noexcept = default; - packed_field& operator=(packed_field&&) noexcept = default; - - packed_field() = default; - - packed_field(pbf_writer& parent_writer, pbf_tag_type tag) : - m_writer(parent_writer, tag) { - } - - packed_field(pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size) : - m_writer(parent_writer, tag, size) { - } - - ~packed_field() noexcept = default; - - bool valid() const noexcept { - return m_writer.valid(); - } - - void commit() { - m_writer.commit(); - } - - void rollback() { - m_writer.rollback(); - } - - }; // class packed_field - - template - class packed_field_fixed : public packed_field { - - public: - - packed_field_fixed() : - packed_field() { - } - - template - packed_field_fixed(pbf_writer& parent_writer, P tag) : - packed_field(parent_writer, static_cast(tag)) { - } - - template - packed_field_fixed(pbf_writer& parent_writer, P tag, std::size_t size) : - packed_field(parent_writer, static_cast(tag), size * sizeof(T)) { - } - - void add_element(T value) { - m_writer.add_fixed(value); - } - - }; // class packed_field_fixed - - template - class packed_field_varint : public packed_field { - - public: - - packed_field_varint() : - packed_field() { - } - - template - packed_field_varint(pbf_writer& parent_writer, P tag) : - packed_field(parent_writer, static_cast(tag)) { - } - - void add_element(T value) { - m_writer.add_varint(uint64_t(value)); - } - - }; // class packed_field_varint - - template - class packed_field_svarint : public packed_field { - - public: - - packed_field_svarint() : - packed_field() { - } - - template - packed_field_svarint(pbf_writer& parent_writer, P tag) : - packed_field(parent_writer, static_cast(tag)) { - } - - void add_element(T value) { - m_writer.add_varint(encode_zigzag64(value)); - } - - }; // class packed_field_svarint - -} // end namespace detail +using pbf_writer = basic_pbf_writer; /// Class for generating packed repeated bool fields. -using packed_field_bool = detail::packed_field_varint; +using packed_field_bool = detail::packed_field_varint; /// Class for generating packed repeated enum fields. -using packed_field_enum = detail::packed_field_varint; +using packed_field_enum = detail::packed_field_varint; /// Class for generating packed repeated int32 fields. -using packed_field_int32 = detail::packed_field_varint; +using packed_field_int32 = detail::packed_field_varint; /// Class for generating packed repeated sint32 fields. -using packed_field_sint32 = detail::packed_field_svarint; +using packed_field_sint32 = detail::packed_field_svarint; /// Class for generating packed repeated uint32 fields. -using packed_field_uint32 = detail::packed_field_varint; +using packed_field_uint32 = detail::packed_field_varint; /// Class for generating packed repeated int64 fields. -using packed_field_int64 = detail::packed_field_varint; +using packed_field_int64 = detail::packed_field_varint; /// Class for generating packed repeated sint64 fields. -using packed_field_sint64 = detail::packed_field_svarint; +using packed_field_sint64 = detail::packed_field_svarint; /// Class for generating packed repeated uint64 fields. -using packed_field_uint64 = detail::packed_field_varint; +using packed_field_uint64 = detail::packed_field_varint; /// Class for generating packed repeated fixed32 fields. -using packed_field_fixed32 = detail::packed_field_fixed; +using packed_field_fixed32 = detail::packed_field_fixed; /// Class for generating packed repeated sfixed32 fields. -using packed_field_sfixed32 = detail::packed_field_fixed; +using packed_field_sfixed32 = detail::packed_field_fixed; /// Class for generating packed repeated fixed64 fields. -using packed_field_fixed64 = detail::packed_field_fixed; +using packed_field_fixed64 = detail::packed_field_fixed; /// Class for generating packed repeated sfixed64 fields. -using packed_field_sfixed64 = detail::packed_field_fixed; +using packed_field_sfixed64 = detail::packed_field_fixed; /// Class for generating packed repeated float fields. -using packed_field_float = detail::packed_field_fixed; +using packed_field_float = detail::packed_field_fixed; /// Class for generating packed repeated double fields. -using packed_field_double = detail::packed_field_fixed; +using packed_field_double = detail::packed_field_fixed; } // end namespace protozero diff --git a/third_party/protozero/include/protozero/types.hpp b/third_party/protozero/include/protozero/types.hpp index b5241274e..3aefddfb5 100644 --- a/third_party/protozero/include/protozero/types.hpp +++ b/third_party/protozero/include/protozero/types.hpp @@ -16,7 +16,7 @@ documentation. * @brief Contains the declaration of low-level types used in the pbf format. */ -#include +#include "config.hpp" #include #include @@ -53,7 +53,7 @@ enum class pbf_wire_type : uint32_t { */ template constexpr inline uint32_t tag_and_type(T tag, pbf_wire_type wire_type) noexcept { - return (static_cast(static_cast(tag)) << 3u) | static_cast(wire_type); + return (static_cast(static_cast(tag)) << 3U) | static_cast(wire_type); } /** diff --git a/third_party/protozero/include/protozero/varint.hpp b/third_party/protozero/include/protozero/varint.hpp index dd79a6ef9..b4648a442 100644 --- a/third_party/protozero/include/protozero/varint.hpp +++ b/third_party/protozero/include/protozero/varint.hpp @@ -16,7 +16,8 @@ documentation. * @brief Contains low-level varint and zigzag encoding and decoding functions. */ -#include +#include "buffer_tmpl.hpp" +#include "exception.hpp" #include @@ -31,30 +32,30 @@ namespace detail { // from https://github.com/facebook/folly/blob/master/folly/Varint.h inline uint64_t decode_varint_impl(const char** data, const char* end) { - const auto begin = reinterpret_cast(*data); - const auto iend = reinterpret_cast(end); + const auto* begin = reinterpret_cast(*data); + const auto* iend = reinterpret_cast(end); const int8_t* p = begin; uint64_t val = 0; if (iend - begin >= max_varint_length) { // fast path do { - int64_t b; - b = *p++; val = uint64_t((b & 0x7fu) ); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 7u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 14u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 21u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 28u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 35u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 42u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 49u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 56u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x01u) << 63u); if (b >= 0) { break; } + int64_t b = *p++; + val = ((uint64_t(b) & 0x7fU) ); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 7U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 14U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 21U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 28U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 35U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 42U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 49U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 56U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x01U) << 63U); if (b >= 0) { break; } throw varint_too_long_exception{}; } while (false); } else { unsigned int shift = 0; while (p != iend && *p < 0) { - val |= uint64_t(*p++ & 0x7fu) << shift; + val |= (uint64_t(*p++) & 0x7fU) << shift; shift += 7; } if (p == iend) { @@ -88,7 +89,7 @@ namespace detail { */ inline uint64_t decode_varint(const char** data, const char* end) { // If this is a one-byte varint, decode it here. - if (end != *data && ((**data & 0x80u) == 0)) { + if (end != *data && ((static_cast(**data) & 0x80U) == 0)) { const auto val = static_cast(**data); ++(*data); return val; @@ -110,15 +111,15 @@ inline uint64_t decode_varint(const char** data, const char* end) { * before the end of the varint. */ inline void skip_varint(const char** data, const char* end) { - const auto begin = reinterpret_cast(*data); - const auto iend = reinterpret_cast(end); + const auto* begin = reinterpret_cast(*data); + const auto* iend = reinterpret_cast(end); const int8_t* p = begin; while (p != iend && *p < 0) { ++p; } - if (p >= begin + max_varint_length) { + if (p - begin >= max_varint_length) { throw varint_too_long_exception{}; } @@ -140,17 +141,73 @@ inline void skip_varint(const char** data, const char* end) { * @param value The integer that will be encoded. * @returns the number of bytes written * @throws Any exception thrown by increment or dereference operator on data. + * @deprecated Use add_varint_to_buffer() instead. */ template inline int write_varint(T data, uint64_t value) { int n = 1; - while (value >= 0x80u) { - *data++ = char((value & 0x7fu) | 0x80u); - value >>= 7u; + while (value >= 0x80U) { + *data++ = char((value & 0x7fU) | 0x80U); + value >>= 7U; + ++n; + } + *data = char(value); + + return n; +} + +/** + * Varint encode a 64 bit integer. + * + * @tparam TBuffer A buffer type. + * @param buffer Output buffer the varint will be written to. + * @param value The integer that will be encoded. + * @returns the number of bytes written + * @throws Any exception thrown by calling the buffer_push_back() function. + */ +template +inline void add_varint_to_buffer(TBuffer* buffer, uint64_t value) { + while (value >= 0x80U) { + buffer_customization::push_back(buffer, char((value & 0x7fU) | 0x80U)); + value >>= 7U; + } + buffer_customization::push_back(buffer, char(value)); +} + +/** + * Varint encode a 64 bit integer. + * + * @param data Where to add the varint. There must be enough space available! + * @param value The integer that will be encoded. + * @returns the number of bytes written + */ +inline int add_varint_to_buffer(char* data, uint64_t value) noexcept { + int n = 1; + + while (value >= 0x80U) { + *data++ = char((value & 0x7fU) | 0x80U); + value >>= 7U; + ++n; + } + *data = char(value); + + return n; +} + +/** + * Get the length of the varint the specified value would produce. + * + * @param value The integer to be encoded. + * @returns the number of bytes the varint would have if we created it. + */ +inline int length_of_varint(uint64_t value) noexcept { + int n = 1; + + while (value >= 0x80U) { + value >>= 7U; ++n; } - *data++ = char(value); return n; } @@ -159,28 +216,28 @@ inline int write_varint(T data, uint64_t value) { * ZigZag encodes a 32 bit integer. */ inline constexpr uint32_t encode_zigzag32(int32_t value) noexcept { - return (static_cast(value) << 1u) ^ (static_cast(value >> 31u)); + return (static_cast(value) << 1U) ^ static_cast(-static_cast(static_cast(value) >> 31U)); } /** * ZigZag encodes a 64 bit integer. */ inline constexpr uint64_t encode_zigzag64(int64_t value) noexcept { - return (static_cast(value) << 1u) ^ (static_cast(value >> 63u)); + return (static_cast(value) << 1U) ^ static_cast(-static_cast(static_cast(value) >> 63U)); } /** * Decodes a 32 bit ZigZag-encoded integer. */ inline constexpr int32_t decode_zigzag32(uint32_t value) noexcept { - return static_cast(value >> 1u) ^ -static_cast(value & 1u); + return static_cast((value >> 1U) ^ static_cast(-static_cast(value & 1U))); } /** * Decodes a 64 bit ZigZag-encoded integer. */ inline constexpr int64_t decode_zigzag64(uint64_t value) noexcept { - return static_cast(value >> 1u) ^ -static_cast(value & 1u); + return static_cast((value >> 1U) ^ static_cast(-static_cast(value & 1U))); } } // end namespace protozero diff --git a/third_party/protozero/include/protozero/version.hpp b/third_party/protozero/include/protozero/version.hpp index 32a494f4b..9a0e4cc9f 100644 --- a/third_party/protozero/include/protozero/version.hpp +++ b/third_party/protozero/include/protozero/version.hpp @@ -20,15 +20,15 @@ documentation. #define PROTOZERO_VERSION_MAJOR 1 /// The minor version number -#define PROTOZERO_VERSION_MINOR 6 +#define PROTOZERO_VERSION_MINOR 7 /// The patch number -#define PROTOZERO_VERSION_PATCH 2 +#define PROTOZERO_VERSION_PATCH 0 /// The complete version number #define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH) /// Version number as string -#define PROTOZERO_VERSION_STRING "1.6.2" +#define PROTOZERO_VERSION_STRING "1.7.0" #endif // PROTOZERO_VERSION_HPP diff --git a/third_party/protozero/test/catch/catch.hpp b/third_party/protozero/test/catch/catch.hpp index 6b5129d60..6beb0eadb 100644 --- a/third_party/protozero/test/catch/catch.hpp +++ b/third_party/protozero/test/catch/catch.hpp @@ -1,17 +1,21 @@ /* - * Catch v1.12.0 - * Generated: 2018-01-11 21:56:34.893972 + * Catch v2.12.1 + * Generated: 2020-04-21 19:29:20.964532 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp -#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 12 +#define CATCH_VERSION_PATCH 1 #ifdef __clang__ # pragma clang system_header @@ -19,36 +23,66 @@ # pragma GCC system_header #endif -// #included from: internal/catch_suppress_warnings.h +// start catch_suppress_warnings.h #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(push) # pragma warning(disable: 161 1682) # else // __ICC -# pragma clang diagnostic ignored "-Wglobal-constructors" -# pragma clang diagnostic ignored "-Wvariadic-macros" -# pragma clang diagnostic ignored "-Wc99-extensions" -# pragma clang diagnostic ignored "-Wunused-variable" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" -# pragma clang diagnostic ignored "-Wc++98-compat" -# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" # pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ -# pragma GCC diagnostic ignored "-Wvariadic-macros" -# pragma GCC diagnostic ignored "-Wunused-variable" -# pragma GCC diagnostic ignored "-Wparentheses" + // Because REQUIREs trigger GCC's -Wparentheses, and because still + // supported version of g++ have only buggy support for _Pragmas, + // Wparentheses have to be suppressed globally. +# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details # pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wpadded" #endif +// end catch_suppress_warnings.h #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS #endif +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) +// start catch_platform.h + +#ifdef __APPLE__ +# include +# if TARGET_OS_OSX == 1 +# define CATCH_PLATFORM_MAC +# elif TARGET_OS_IPHONE == 1 +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h + #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED @@ -56,93 +90,110 @@ # endif #endif -// #included from: internal/catch_notimplemented_exception.h -#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED +// start catch_user_interfaces.h -// #included from: catch_common.h -#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED +namespace Catch { + unsigned int rngSeed(); +} -// #included from: catch_compiler_capabilities.h -#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h -// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler // The following features are defined: // -// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? -// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? -// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods -// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? -// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported -// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? -// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? -// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) -// CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported? -// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported? - -// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? - -// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too // **************** // In general each macro has a _NO_ form -// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. -// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 - #ifdef __cplusplus -# if __cplusplus >= 201103L -# define CATCH_CPP11_OR_GREATER +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define CATCH_CPP14_OR_GREATER # endif -# if __cplusplus >= 201402L -# define CATCH_CPP14_OR_GREATER +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER # endif #endif -#ifdef __clang__ +#if defined(__cpp_lib_uncaught_exceptions) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif -# if __has_feature(cxx_nullptr) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +// We have to avoid both ICC and Clang, because they try to mask themselves +// as gcc, and we want only GCC in this block +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) + +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) + +#endif + +#if defined(__clang__) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + +// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug +// which results in calls to destructors being emitted for each temporary, +// without a matching initialization. In practice, this can result in something +// like `std::string::~string` being called on an uninitialized value. +// +// For example, this code will likely segfault under IBM XL: +// ``` +// REQUIRE(std::string("12") + "34" == "1234") +// ``` +// +// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. +# if !defined(__ibmxl__) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg) */ # endif -# if __has_feature(cxx_noexcept) -# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -# endif +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") -# if defined(CATCH_CPP11_OR_GREATER) -# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ - _Pragma( "clang diagnostic pop" ) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic pop" ) -# endif +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) #endif // __clang__ +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + //////////////////////////////////////////////////////////////////////////////// // We know some environments not to support full POSIX signals -#if defined(__CYGWIN__) || defined(__QNX__) - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# endif - +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS #endif #ifdef __OS400__ @@ -150,6 +201,25 @@ # define CATCH_CONFIG_COLOUR_NONE #endif +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + //////////////////////////////////////////////////////////////////////////////// // Cygwin #ifdef __CYGWIN__ @@ -157,219 +227,248 @@ // Required for some versions of Cygwin to declare gettimeofday // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin # define _BSD_SOURCE +// some versions of cygwin (most) do not support std::to_string. Use the libstd check. +// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 +# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING + +# endif #endif // __CYGWIN__ -//////////////////////////////////////////////////////////////////////////////// -// Borland -#ifdef __BORLANDC__ - -#endif // __BORLANDC__ - -//////////////////////////////////////////////////////////////////////////////// -// EDG -#ifdef __EDG_VERSION__ - -#endif // __EDG_VERSION__ - -//////////////////////////////////////////////////////////////////////////////// -// Digital Mars -#ifdef __DMC__ - -#endif // __DMC__ - -//////////////////////////////////////////////////////////////////////////////// -// GCC -#ifdef __GNUC__ - -# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# endif - -// - otherwise more recent versions define __cplusplus >= 201103L -// and will get picked up below - -#endif // __GNUC__ - //////////////////////////////////////////////////////////////////////////////// // Visual C++ -#ifdef _MSC_VER +#if defined(_MSC_VER) -#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) -#if (_MSC_VER >= 1600) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR -#endif +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif -#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) -#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE -#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS -#endif +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif + +// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ +// _MSVC_TRADITIONAL == 0 means new conformant preprocessor +// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor +# if !defined(__clang__) // Handle Clang masquerading for msvc +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif // MSVC_TRADITIONAL +# endif // __clang__ #endif // _MSC_VER +#if defined(_REENTRANT) || defined(_MSC_VER) +// Enable async processing, as -pthread is specified or no additional linking is required +# define CATCH_INTERNAL_CONFIG_USE_ASYNC +#endif // _MSC_VER + //////////////////////////////////////////////////////////////////////////////// - -// Use variadic macros if the compiler supports them -#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ - ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ - ( defined __GNUC__ && __GNUC__ >= 3 ) || \ - ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) - -#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS - +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED #endif -// Use __COUNTER__ if the compiler supports it -#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \ - ( defined __GNUC__ && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 )) ) || \ - ( defined __clang__ && __clang_major__ >= 3 ) +//////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ -// Use of __COUNTER__ is suppressed during code analysis in CLion/AppCode 2017.2.x and former, -// because __COUNTER__ is not properly handled by it. -// This does not affect compilation -#if ( !defined __JETBRAINS_IDE__ || __JETBRAINS_IDE__ >= 20170300L ) +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) #define CATCH_INTERNAL_CONFIG_COUNTER #endif -#endif - //////////////////////////////////////////////////////////////////////////////// -// C++ language feature support -// catch all support for C++11 -#if defined(CATCH_CPP11_OR_GREATER) - -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM -# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE -# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE -# endif - -# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS -# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS -# endif - -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) -# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG -# endif - -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) -# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE -# endif -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) -# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR -# endif -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) -# define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE -# endif -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) -# define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS -# endif - -#endif // __cplusplus >= 201103L - -// Now set the actual defines based on the above + anything the user has configured -#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_NULLPTR +// RTX is a special version of Windows that is real time. +// This means that it is detected as Windows, but does not provide +// the same set of capabilities as real Windows does. +#if defined(UNDER_RTSS) || defined(RTX64_BUILD) + #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH + #define CATCH_INTERNAL_CONFIG_NO_ASYNC + #define CATCH_CONFIG_COLOUR_NONE #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_NOEXCEPT -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_GENERATED_METHODS -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_IS_ENUM -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_TUPLE -#endif -#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) -# define CATCH_CONFIG_VARIADIC_MACROS -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_LONG_LONG -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_OVERRIDE -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_UNIQUE_PTR + +#if !defined(_GLIBCXX_USE_C99_MATH_TR1) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER #endif + +// Various stdlib support checks that require __has_include +#if defined(__has_include) + // Check if string_view is available and usable + #if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif + + // Check if optional is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if byte is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) + #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) # define CATCH_CONFIG_COUNTER #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_SHUFFLE -#endif -# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_TYPE_TRAITS -# endif -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) # define CATCH_CONFIG_WINDOWS_SEH #endif // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_CONFIG_POSIX_SIGNALS #endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# define CATCH_CONFIG_POLYFILL_ISNAN +#endif + +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) +# define CATCH_CONFIG_USE_ASYNC +#endif + +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS #endif -#if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS #endif -// noexcept support: -#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) -# define CATCH_NOEXCEPT noexcept -# define CATCH_NOEXCEPT_IS(x) noexcept(x) +// The goal of this macro is to avoid evaluation of the arguments, but +// still have the compiler warn on problems inside... +#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) +#endif + +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) #else -# define CATCH_NOEXCEPT throw() -# define CATCH_NOEXCEPT_IS(x) +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) #endif -// nullptr support -#ifdef CATCH_CONFIG_CPP11_NULLPTR -# define CATCH_NULL nullptr -#else -# define CATCH_NULL NULL -#endif - -// override support -#ifdef CATCH_CONFIG_CPP11_OVERRIDE -# define CATCH_OVERRIDE override -#else -# define CATCH_OVERRIDE -#endif - -// unique_ptr support -#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR -# define CATCH_AUTO_PTR( T ) std::unique_ptr -#else -# define CATCH_AUTO_PTR( T ) std::auto_ptr +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #endif +// end catch_compiler_capabilities.h #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #ifdef CATCH_CONFIG_COUNTER @@ -378,95 +477,48 @@ # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #endif -#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr -#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) +#include +#include +#include -#include -#include +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); namespace Catch { - struct IConfig; - struct CaseSensitive { enum Choice { Yes, No }; }; class NonCopyable { -#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; NonCopyable& operator = ( NonCopyable && ) = delete; -#else - NonCopyable( NonCopyable const& info ); - NonCopyable& operator = ( NonCopyable const& ); -#endif protected: - NonCopyable() {} + NonCopyable(); virtual ~NonCopyable(); }; - class SafeBool { - public: - typedef void (SafeBool::*type)() const; - - static type makeSafe( bool value ) { - return value ? &SafeBool::trueValue : 0; - } - private: - void trueValue() const {} - }; - - template - void deleteAll( ContainerT& container ) { - typename ContainerT::const_iterator it = container.begin(); - typename ContainerT::const_iterator itEnd = container.end(); - for(; it != itEnd; ++it ) - delete *it; - } - template - void deleteAllValues( AssociativeContainerT& container ) { - typename AssociativeContainerT::const_iterator it = container.begin(); - typename AssociativeContainerT::const_iterator itEnd = container.end(); - for(; it != itEnd; ++it ) - delete it->second; - } - - bool startsWith( std::string const& s, std::string const& prefix ); - bool startsWith( std::string const& s, char prefix ); - bool endsWith( std::string const& s, std::string const& suffix ); - bool endsWith( std::string const& s, char suffix ); - bool contains( std::string const& s, std::string const& infix ); - void toLowerInPlace( std::string& s ); - std::string toLower( std::string const& s ); - std::string trim( std::string const& str ); - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); - - struct pluralise { - pluralise( std::size_t count, std::string const& label ); - - friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); - - std::size_t m_count; - std::string m_label; - }; - struct SourceLineInfo { - SourceLineInfo(); - SourceLineInfo( char const* _file, std::size_t _line ); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - SourceLineInfo(SourceLineInfo const& other) = default; - SourceLineInfo( SourceLineInfo && ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo& operator = ( SourceLineInfo && ) = default; -# endif - bool empty() const; - bool operator == ( SourceLineInfo const& other ) const; - bool operator < ( SourceLineInfo const& other ) const; + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo( SourceLineInfo&& ) noexcept = default; + SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; + + bool empty() const noexcept { return file[0] == '\0'; } + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; char const* file; std::size_t line; @@ -474,24 +526,17 @@ namespace Catch { std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - // This is just here to avoid compiler warnings with macro constants and boolean literals - inline bool isTrue( bool value ){ return value; } - inline bool alwaysTrue() { return true; } - inline bool alwaysFalse() { return false; } - - void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); - - void seedRng( IConfig const& config ); - unsigned int rngSeed(); + // Bring in operator<< from global namespace into Catch namespace + // This is necessary because the overload of operator<< above makes + // lookup stop at namespace Catch + using ::operator<<; // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as // >> stuff +StreamEndStop struct StreamEndStop { - std::string operator+() { - return std::string(); - } + std::string operator+() const; }; template T const& operator + ( T const& value, StreamEndStop ) { @@ -499,180 +544,28 @@ namespace Catch { } } -#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) -#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +// end catch_common.h namespace Catch { - class NotImplementedException : public std::exception - { - public: - NotImplementedException( SourceLineInfo const& lineInfo ); - - virtual ~NotImplementedException() CATCH_NOEXCEPT {} - - virtual const char* what() const CATCH_NOEXCEPT; - - private: - std::string m_what; - SourceLineInfo m_lineInfo; + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); }; } // end namespace Catch -/////////////////////////////////////////////////////////////////////////////// -#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION -// #included from: internal/catch_context.h -#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h -// #included from: catch_interfaces_generators.h -#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED - -#include - -namespace Catch { - - struct IGeneratorInfo { - virtual ~IGeneratorInfo(); - virtual bool moveNext() = 0; - virtual std::size_t getCurrentIndex() const = 0; - }; - - struct IGeneratorsForTest { - virtual ~IGeneratorsForTest(); - - virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; - virtual bool moveNext() = 0; - }; - - IGeneratorsForTest* createGeneratorsForTest(); - -} // end namespace Catch - -// #included from: catch_ptr.hpp -#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -namespace Catch { - - // An intrusive reference counting smart pointer. - // T must implement addRef() and release() methods - // typically implementing the IShared interface - template - class Ptr { - public: - Ptr() : m_p( CATCH_NULL ){} - Ptr( T* p ) : m_p( p ){ - if( m_p ) - m_p->addRef(); - } - Ptr( Ptr const& other ) : m_p( other.m_p ){ - if( m_p ) - m_p->addRef(); - } - ~Ptr(){ - if( m_p ) - m_p->release(); - } - void reset() { - if( m_p ) - m_p->release(); - m_p = CATCH_NULL; - } - Ptr& operator = ( T* p ){ - Ptr temp( p ); - swap( temp ); - return *this; - } - Ptr& operator = ( Ptr const& other ){ - Ptr temp( other ); - swap( temp ); - return *this; - } - void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } - T* get() const{ return m_p; } - T& operator*() const { return *m_p; } - T* operator->() const { return m_p; } - bool operator !() const { return m_p == CATCH_NULL; } - operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } - - private: - T* m_p; - }; - - struct IShared : NonCopyable { - virtual ~IShared(); - virtual void addRef() const = 0; - virtual void release() const = 0; - }; - - template - struct SharedImpl : T { - - SharedImpl() : m_rc( 0 ){} - - virtual void addRef() const { - ++m_rc; - } - virtual void release() const { - if( --m_rc == 0 ) - delete this; - } - - mutable unsigned int m_rc; - }; - -} // end namespace Catch - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -namespace Catch { - - class TestCase; - class Stream; - struct IResultCapture; - struct IRunner; - struct IGeneratorsForTest; - struct IConfig; - - struct IContext - { - virtual ~IContext(); - - virtual IResultCapture* getResultCapture() = 0; - virtual IRunner* getRunner() = 0; - virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; - virtual bool advanceGeneratorsForCurrentTest() = 0; - virtual Ptr getConfig() const = 0; - }; - - struct IMutableContext : IContext - { - virtual ~IMutableContext(); - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setRunner( IRunner* runner ) = 0; - virtual void setConfig( Ptr const& config ) = 0; - }; - - IContext& getCurrentContext(); - IMutableContext& getCurrentMutableContext(); - void cleanUpContext(); - Stream createStream( std::string const& streamName ); - -} - -// #included from: internal/catch_test_registry.hpp -#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED - -// #included from: catch_interfaces_testcase.h -#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED +// start catch_interfaces_testcase.h #include @@ -680,10 +573,9 @@ namespace Catch { class TestSpec; - struct ITestCase : IShared { + struct ITestInvoker { virtual void invoke () const = 0; - protected: - virtual ~ITestCase(); + virtual ~ITestInvoker(); }; class TestCase; @@ -695,167 +587,769 @@ namespace Catch { virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); } +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include +#include +#include +#include + +namespace Catch { + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. + class StringRef { + public: + using size_type = std::size_t; + using const_iterator = const char*; + + private: + static constexpr char const* const s_empty = ""; + + char const* m_start = s_empty; + size_type m_size = 0; + + public: // construction + constexpr StringRef() noexcept = default; + + StringRef( char const* rawChars ) noexcept; + + constexpr StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + explicit operator std::string() const { + return std::string(m_start, m_size); + } + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); + } + + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } + + public: // named queries + constexpr auto empty() const noexcept -> bool { + return m_size == 0; + } + constexpr auto size() const noexcept -> size_type { + return m_size; + } + + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception + auto c_str() const -> char const*; + + public: // substrings and searches + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; + + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; + + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } + + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + }; + + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } +} // namespace Catch + +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} + +// end catch_stringref.h +// start catch_preprocessor.hpp + + +#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ +#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) + +#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ +// MSVC needs more evaluations +#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#else +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#endif + +#define CATCH_REC_END(...) +#define CATCH_REC_OUT + +#define CATCH_EMPTY() +#define CATCH_DEFER(id) id CATCH_EMPTY() + +#define CATCH_REC_GET_END2() 0, CATCH_REC_END +#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 +#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 +#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT +#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) + +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) + +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) + +// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, +// and passes userdata as the first parameter to each invocation, +// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) +#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif + +#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ +#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) + +#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#else +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) + +#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) +#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) +#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) + +#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define INTERNAL_CATCH_TYPE_GEN\ + template struct TypeList {};\ + template\ + constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ + template class...> struct TemplateTypeList{};\ + template class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ + template\ + struct append;\ + template\ + struct rewrap;\ + template class, typename...>\ + struct create;\ + template class, typename>\ + struct convert;\ + \ + template \ + struct append { using type = T; };\ + template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ + struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ + template< template class L1, typename...E1, typename...Rest>\ + struct append, TypeList, Rest...> { using type = L1; };\ + \ + template< template class Container, template class List, typename...elems>\ + struct rewrap, List> { using type = TypeList>; };\ + template< template class Container, template class List, class...Elems, typename...Elements>\ + struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ + \ + template