[osrm] 02/22: Imported Upstream version 5.0.0~rc1+ds
Sebastiaan Couwenberg
sebastic at moszumanska.debian.org
Fri Apr 29 22:44:12 UTC 2016
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository osrm.
commit 1d9c10ad08ef3e47f6395fc4ec9300058592a35c
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Fri Apr 29 23:13:06 2016 +0200
Imported Upstream version 5.0.0~rc1+ds
---
.cncc.style | 14 +
.eslintrc | 28 +
.gitignore | 9 +
.travis.yml | 139 +-
CHANGELOG.md | 17 +
CMakeLists.txt | 332 +-
Doxyfile.in | 1 +
Gemfile | 7 -
Gemfile.lock | 35 -
LICENCE.TXT | 2 +-
Rakefile | 190 -
algorithms/bfs_components.hpp | 174 -
algorithms/coordinate_calculation.cpp | 273 -
algorithms/coordinate_calculation.hpp | 82 -
algorithms/douglas_peucker.cpp | 164 -
algorithms/douglas_peucker.hpp | 81 -
algorithms/geospatial_query.hpp | 180 -
algorithms/graph_compressor.hpp | 62 -
algorithms/object_encoder.hpp | 89 -
algorithms/polyline_compressor.cpp | 128 -
algorithms/polyline_compressor.hpp | 51 -
algorithms/polyline_formatter.cpp | 56 -
algorithms/route_name_extraction.hpp | 162 -
appveyor-build.bat | 50 +-
appveyor.yml | 11 +-
benchmarks/static_rtree.cpp | 152 -
build-local.bat | 3 +-
cmake/CPackDebianConfig.cmake | 15 +-
cmake/FindLua52.cmake | 2 +-
cmake/FindSTXXL.cmake | 2 +-
cmake/FingerPrint-Config.cmake | 12 +-
cmake/cmake_options_script.py | 10 +-
cmake/cmake_uninstall.cmake.in | 21 +
cmake/pkgconfig.in | 6 +-
cmake/postinst.in | 2 -
config/cucumber.yml | 9 -
contractor/contractor_options.cpp | 142 -
contractor/processing_chain.cpp | 441 -
contractor/processing_chain.hpp | 84 -
cucumber.js | 11 +
data_structures/compressed_edge_container.hpp | 69 -
data_structures/coordinate.cpp | 87 -
data_structures/edge_based_node.hpp | 113 -
data_structures/external_memory_node.cpp | 66 -
data_structures/external_memory_node.hpp | 57 -
data_structures/fixed_point_number.hpp | 216 -
data_structures/hilbert_value.cpp | 100 -
data_structures/hilbert_value.hpp | 49 -
data_structures/import_edge.cpp | 113 -
data_structures/import_edge.hpp | 108 -
data_structures/internal_route_result.hpp | 87 -
data_structures/lru_cache.hpp | 97 -
data_structures/matrix_graph_wrapper.hpp | 70 -
data_structures/node_based_graph.hpp | 103 -
data_structures/node_id.hpp | 41 -
data_structures/original_edge_data.hpp | 63 -
data_structures/phantom_node.cpp | 105 -
data_structures/phantom_node.hpp | 162 -
data_structures/query_node.hpp | 85 -
data_structures/rectangle.hpp | 203 -
data_structures/route_parameters.cpp | 179 -
data_structures/search_engine.hpp | 69 -
data_structures/search_engine_data.cpp | 93 -
data_structures/search_engine_data.hpp | 61 -
data_structures/segment_information.hpp | 80 -
data_structures/static_kdtree.hpp | 260 -
data_structures/turn_instructions.hpp | 105 -
data_structures/upper_bound.hpp | 77 -
data_structures/xor_fast_hash.hpp | 115 -
data_structures/xor_fast_hash_storage.hpp | 101 -
descriptors/description_factory.cpp | 249 -
descriptors/description_factory.hpp | 96 -
descriptors/descriptor_base.hpp | 87 -
descriptors/gpx_descriptor.hpp | 94 -
descriptors/json_descriptor.hpp | 403 -
docker/Dockerfile | 2 -
example/CMakeLists.txt | 33 +
example/cmake/FindLibOSRM.cmake | 65 +
example/cmake/FindTBB.cmake | 283 +
example/example.cpp | 85 +
extract.cpp | 89 -
extractor/edge_based_graph_factory.cpp | 702 --
extractor/edge_based_graph_factory.hpp | 142 -
extractor/extraction_node.hpp | 38 -
extractor/extraction_way.hpp | 129 -
extractor/extractor_options.cpp | 230 -
extractor/first_and_last_segment_of_way.hpp | 89 -
extractor/restriction_parser.hpp | 77 -
extractor/scripting_environment.cpp | 175 -
extractor/scripting_environment.hpp | 60 -
extractor/speed_profile.hpp | 16 -
features/bicycle/area.feature | 85 +-
features/bicycle/bridge.feature | 32 +-
features/bicycle/ferry.feature | 22 +-
features/bicycle/maxspeed.feature | 6 +-
features/bicycle/mode.feature | 118 +-
features/bicycle/names.feature | 8 +-
features/bicycle/oneway.feature | 10 +-
features/bicycle/pushing.feature | 46 +-
features/bicycle/ref.feature | 10 +-
features/bicycle/restrictions.feature | 94 +-
features/bicycle/roundabout.feature | 14 +-
features/bicycle/stop_area.feature | 8 +-
features/bicycle/turn_penalty.feature | 16 +-
features/car/advisory.feature | 38 +-
features/car/bridge.feature | 28 +-
features/car/ferry.feature | 38 +-
features/car/link.feature | 30 +-
features/car/maxspeed.feature | 18 +-
features/car/mode.feature | 18 +-
features/car/names.feature | 8 +-
features/car/oneway.feature | 10 +-
features/car/restrictions.feature | 120 +-
features/car/roundabout.feature | 14 +-
features/car/shuttle_train.feature | 20 +-
features/car/traffic.feature | 47 +
features/foot/area.feature | 78 +-
features/foot/ferry.feature | 24 +-
features/foot/names.feature | 8 +-
features/foot/ref.feature | 10 +-
features/foot/restrictions.feature | 94 +-
features/foot/roundabout.feature | 18 +-
features/guidance/motorway.feature | 202 +
features/guidance/roundabout.feature | 173 +
.../options/{prepare => contract}/files.feature | 15 +-
.../options/{prepare => contract}/help.feature | 32 +-
.../options/{prepare => contract}/invalid.feature | 6 +-
.../options/{prepare => contract}/version.feature | 10 +-
features/options/extract/help.feature | 6 -
features/options/routed/files.feature | 10 +-
features/options/routed/help.feature | 27 -
features/options/routed/invalid.feature | 3 +-
features/raster/weights.feature | 65 +-
features/step_definitions/data.js | 273 +
features/step_definitions/data.rb | 192 -
features/step_definitions/distance_matrix.js | 81 +
features/step_definitions/distance_matrix.rb | 66 -
features/step_definitions/hooks.js | 30 +
features/step_definitions/matching.js | 174 +
features/step_definitions/matching.rb | 124 -
features/step_definitions/nearest.js | 53 +
features/step_definitions/nearest.rb | 51 -
features/step_definitions/options.js | 69 +
features/step_definitions/options.rb | 57 -
features/step_definitions/requests.js | 60 +
features/step_definitions/requests.rb | 46 -
features/step_definitions/routability.js | 120 +
features/step_definitions/routability.rb | 78 -
features/step_definitions/routing.js | 16 +
features/step_definitions/routing.rb | 165 -
features/step_definitions/timestamp.js | 13 +
features/step_definitions/timestamp.rb | 7 -
features/step_definitions/trip.js | 141 +
features/step_definitions/trip.rb | 121 -
features/support/build_osm.js | 165 +
features/support/config.js | 115 +
features/support/config.rb | 16 -
features/support/data.js | 340 +
features/support/data.rb | 325 -
features/support/data_classes.js | 85 +
features/support/env.js | 125 +
features/support/env.rb | 98 -
features/support/exception_classes.js | 132 +
features/support/exceptions.js | 15 +
features/support/exceptions.rb | 62 -
features/support/file.rb | 34 -
features/support/fuzzy.js | 5 +
features/support/fuzzy.rb | 32 -
features/support/hash.js | 37 +
features/support/hash.rb | 63 -
features/support/hooks.js | 37 +
features/support/hooks.rb | 35 -
features/support/http.js | 51 +
features/support/http.rb | 37 -
features/support/launch.js | 5 +
features/support/launch.rb | 137 -
features/support/launch_classes.js | 163 +
features/support/log.js | 90 +
features/support/log.rb | 88 -
features/support/osm_parser.rb | 25 -
features/support/osmlib.rb | 14 -
features/support/route.js | 166 +
features/support/route.rb | 181 -
features/support/run.js | 40 +
features/support/run.rb | 28 -
features/support/shared_steps.js | 202 +
features/support/shortcuts.rb | 3 -
features/support/table_patch.js | 11 +
features/testbot/64bit.feature | 4 +-
features/testbot/alternative.feature | 16 +-
features/testbot/alternative_loop.feature | 29 +
features/testbot/bad.feature | 8 +-
features/testbot/basic.feature | 170 +-
features/testbot/bearing.feature | 150 +-
features/testbot/bearing_param.feature | 44 +-
features/testbot/compression.feature | 6 +-
features/testbot/datastore.feature | 8 +-
features/testbot/distance.feature | 136 +-
features/testbot/distance_matrix.feature | 100 +-
features/testbot/duration.feature | 18 +-
features/testbot/example.feature | 30 +-
features/testbot/fastest.feature | 12 +-
features/testbot/ferry.feature | 76 +-
features/testbot/fixed.feature | 4 +-
features/testbot/geometry.feature | 8 +-
features/testbot/graph.feature | 8 +-
features/testbot/load.feature | 18 +-
features/testbot/loop.feature | 24 +-
features/testbot/matching.feature | 31 +
features/testbot/matching_turns.feature | 121 -
features/testbot/mode.feature | 171 +-
features/testbot/oneway.feature | 44 +-
features/testbot/opposite.feature | 6 +-
features/testbot/origin.feature | 24 +-
features/testbot/penalty.feature | 46 +-
features/testbot/planetary.feature | 12 +-
features/testbot/post.feature | 83 -
features/testbot/projection.feature | 20 +-
features/testbot/protobuffer.feature | 156 -
features/testbot/roundabout.feature | 60 +-
features/testbot/snap.feature | 98 +-
features/testbot/speed.feature | 6 +-
features/testbot/status.feature | 52 +-
features/testbot/time.feature | 134 +-
features/testbot/trip.feature | 15 +
features/testbot/turn_angles.feature | 74 +
features/testbot/turns.feature | 140 +-
features/testbot/utf.feature | 8 +-
features/testbot/uturn.feature | 16 +-
features/testbot/via.feature | 147 +-
features/timestamp/timestamp.feature | 11 -
include/contractor/contractor.hpp | 96 +
.../contractor/contractor_config.hpp | 55 +-
.../contractor}/crc32_processor.hpp | 34 +-
.../contractor/graph_contractor.hpp | 560 +-
.../contractor}/query_edge.hpp | 36 +-
include/engine/api/base_api.hpp | 64 +
include/engine/api/base_parameters.hpp | 90 +
include/engine/api/json_factory.hpp | 81 +
include/engine/api/match_api.hpp | 119 +
.../engine/api/match_parameters.hpp | 78 +-
include/engine/api/nearest_api.hpp | 57 +
.../engine/api/nearest_parameters.hpp | 45 +-
include/engine/api/route_api.hpp | 190 +
include/engine/api/route_parameters.hpp | 96 +
include/engine/api/table_api.hpp | 133 +
include/engine/api/table_parameters.hpp | 110 +
.../engine/api/tile_parameters.hpp | 66 +-
include/engine/api/trip_api.hpp | 111 +
.../engine/api/trip_parameters.hpp | 33 +-
include/engine/base64.hpp | 141 +
.../engine/bearing.hpp | 29 +-
include/engine/datafacade/datafacade_base.hpp | 153 +
include/engine/datafacade/internal_datafacade.hpp | 658 ++
include/engine/datafacade/shared_datafacade.hpp | 717 ++
include/engine/douglas_peucker.hpp | 60 +
include/engine/engine.hpp | 88 +
.../engine_config.hpp} | 39 +-
include/engine/geospatial_query.hpp | 467 +
include/engine/guidance/assemble_geometry.hpp | 81 +
include/engine/guidance/assemble_leg.hpp | 169 +
include/engine/guidance/assemble_overview.hpp | 24 +
include/engine/guidance/assemble_route.hpp | 22 +
include/engine/guidance/assemble_steps.hpp | 157 +
include/engine/guidance/leg_geometry.hpp | 54 +
include/engine/guidance/post_processing.hpp | 44 +
include/engine/guidance/route.hpp | 20 +
include/engine/guidance/route_leg.hpp | 29 +
include/engine/guidance/route_step.hpp | 40 +
include/engine/guidance/step_maneuver.hpp | 45 +
include/engine/guidance/toolkit.hpp | 63 +
include/engine/hint.hpp | 81 +
include/engine/internal_route_result.hpp | 63 +
.../engine/map_matching}/bayes_classifier.hpp | 47 +-
.../engine/map_matching}/hidden_markov_model.hpp | 86 +-
.../engine/map_matching/matching_confidence.hpp | 58 +
include/engine/map_matching/sub_matching.hpp | 25 +
include/engine/phantom_node.hpp | 214 +
include/engine/plugins/match.hpp | 48 +
include/engine/plugins/nearest.hpp | 26 +
include/engine/plugins/plugin_base.hpp | 284 +
include/engine/plugins/table.hpp | 35 +
include/engine/plugins/tile.hpp | 35 +
include/engine/plugins/trip.hpp | 54 +
include/engine/plugins/viaroute.hpp | 47 +
include/engine/polyline_compressor.hpp | 31 +
.../routing_algorithms}/alternative_path.hpp | 187 +-
.../routing_algorithms}/direct_shortest_path.hpp | 104 +-
.../engine/routing_algorithms}/many_to_many.hpp | 171 +-
.../engine/routing_algorithms}/map_matching.hpp | 260 +-
include/engine/routing_algorithms/routing_base.hpp | 906 ++
.../engine/routing_algorithms}/shortest_path.hpp | 343 +-
include/engine/search_engine_data.hpp | 42 +
.../engine/status.hpp | 24 +-
.../engine/trip}/trip_brute_force.hpp | 46 +-
.../engine/trip}/trip_farthest_insertion.hpp | 62 +-
.../engine/trip}/trip_nearest_neighbour.hpp | 47 +-
include/engine/trip/trip_tabu_search.hpp | 41 +
include/extractor/compressed_edge_container.hpp | 57 +
include/extractor/edge_based_edge.hpp | 80 +
include/extractor/edge_based_graph_factory.hpp | 134 +
include/extractor/edge_based_node.hpp | 76 +
include/extractor/external_memory_node.hpp | 56 +
.../extractor}/extraction_containers.hpp | 53 +-
.../extractor}/extraction_helper_functions.hpp | 54 +-
include/extractor/extraction_node.hpp | 19 +
include/extractor/extraction_way.hpp | 58 +
{extractor => include/extractor}/extractor.hpp | 45 +-
.../extractor}/extractor_callbacks.hpp | 51 +-
.../extractor/extractor_config.hpp | 64 +-
.../extractor/first_and_last_segment_of_way.hpp | 60 +
include/extractor/graph_compressor.hpp | 38 +
include/extractor/guidance/classification_data.hpp | 67 +
include/extractor/guidance/discrete_angle.hpp | 19 +
include/extractor/guidance/toolkit.hpp | 404 +
include/extractor/guidance/turn_analysis.hpp | 202 +
include/extractor/guidance/turn_classification.hpp | 123 +
include/extractor/guidance/turn_instruction.hpp | 127 +
.../extractor}/internal_extractor_edge.hpp | 90 +-
include/extractor/node_based_edge.hpp | 143 +
include/extractor/original_edge_data.hpp | 42 +
include/extractor/profile_properties.hpp | 48 +
include/extractor/query_node.hpp | 51 +
.../extractor}/raster_source.hpp | 49 +-
.../extractor}/restriction.hpp | 38 +-
.../extractor}/restriction_map.hpp | 57 +-
include/extractor/restriction_parser.hpp | 58 +
include/extractor/scripting_environment.hpp | 54 +
{algorithms => include/extractor}/tarjan_scc.hpp | 62 +-
.../extractor}/travel_mode.hpp | 28 +-
.../tribool.hpp => include/osrm/bearing.hpp | 18 +-
include/osrm/coordinate.hpp | 47 +-
.../osrm/engine_config.hpp | 16 +-
include/osrm/json_container.hpp | 75 +-
.../osrm/match_parameters.hpp | 18 +-
.../osrm/nearest_parameters.hpp | 18 +-
include/osrm/osrm.hpp | 116 +-
.../osrm/osrm_fwd.hpp | 44 +-
include/osrm/route_parameters.hpp | 94 +-
util/fingerprint.cpp => include/osrm/status.hpp | 15 +-
.../osrm/storage_config.hpp | 16 +-
include/osrm/strong_typedef.hpp | 68 -
.../osrm/table_parameters.hpp | 18 +-
.../osrm/tile_parameters.hpp | 18 +-
.../osrm/trip_parameters.hpp | 18 +-
include/server/api/base_parameters_grammar.hpp | 108 +
include/server/api/match_parameter_grammar.hpp | 88 +
include/server/api/nearest_parameter_grammar.hpp | 48 +
include/server/api/parameters_parser.hpp | 49 +
include/server/api/parsed_url.hpp | 27 +
include/server/api/route_parameters_grammar.hpp | 96 +
include/server/api/table_parameter_grammar.hpp | 61 +
include/server/api/tile_parameter_grammar.hpp | 59 +
include/server/api/trip_parameter_grammar.hpp | 81 +
include/server/api/url_parser.hpp | 29 +
include/server/connection.hpp | 72 +
include/server/http/compression_type.hpp | 21 +
include/server/http/header.hpp | 34 +
include/server/http/reply.hpp | 45 +
include/server/http/request.hpp | 26 +
include/server/request_handler.hpp | 37 +
include/server/request_parser.hpp | 76 +
{server => include/server}/server.hpp | 60 +-
include/server/service/base_service.hpp | 39 +
include/server/service/match_service.hpp | 33 +
include/server/service/nearest_service.hpp | 33 +
include/server/service/route_service.hpp | 33 +
include/server/service/table_service.hpp | 33 +
include/server/service/tile_service.hpp | 33 +
include/server/service/trip_service.hpp | 33 +
include/server/service/utils.hpp | 29 +
include/server/service_handler.hpp | 41 +
include/storage/shared_barriers.hpp | 39 +
include/storage/shared_datatype.hpp | 136 +
.../storage/shared_memory.hpp | 128 +-
include/storage/storage.hpp | 26 +
include/storage/storage_config.hpp | 44 +
include/util/assert.hpp | 20 +
{util => include/util}/bearing.hpp | 34 +-
{data_structures => include/util}/binary_heap.hpp | 41 +-
include/util/cast.hpp | 49 +
include/util/container.hpp | 20 +
include/util/coordinate.hpp | 187 +
include/util/coordinate_calculation.hpp | 92 +
.../util}/deallocating_vector.hpp | 58 +-
{util => include/util}/dist_table_wrapper.hpp | 36 +-
.../util}/dynamic_graph.hpp | 63 +-
include/util/exception.hpp | 30 +
include/util/fingerprint.hpp | 39 +
{util => include/util}/fingerprint_impl.hpp.in | 47 +-
include/util/for_each_pair.hpp | 45 +
{util => include/util}/graph_loader.hpp | 79 +-
{util => include/util}/graph_utils.hpp | 26 +-
include/util/hilbert_value.hpp | 18 +
include/util/integer_range.hpp | 58 +
include/util/io.hpp | 127 +
.../util}/iso_8601_duration_parser.hpp | 34 +-
include/{osrm => util}/json_container.hpp | 74 +-
include/util/json_deep_compare.hpp | 158 +
include/util/json_logger.hpp | 62 +
{util => include/util}/json_renderer.hpp | 46 +-
include/util/json_util.hpp | 58 +
include/util/lua_util.hpp | 54 +
{util => include/util}/make_unique.hpp | 32 +-
include/util/matrix_graph_wrapper.hpp | 51 +
include/util/name_table.hpp | 31 +
include/util/node_based_graph.hpp | 95 +
{data_structures => include/util}/percent.hpp | 34 +-
{data_structures => include/util}/range_table.hpp | 52 +-
include/util/rectangle.hpp | 182 +
.../util}/shared_memory_vector_wrapper.hpp | 69 +-
include/util/simple_logger.hpp | 55 +
{data_structures => include/util}/static_graph.hpp | 65 +-
{data_structures => include/util}/static_rtree.hpp | 380 +-
include/util/std_hash.hpp | 41 +
{util => include/util}/string_util.hpp | 36 +-
include/util/strong_typedef.hpp | 84 +
{util => include/util}/timing_util.hpp | 34 +-
{util => include/util}/trigonometry_table.hpp | 64 +-
typedefs.h => include/util/typedefs.hpp | 35 +-
include/util/version.hpp.in | 10 +
include/util/viewport.hpp | 51 +
include/util/xor_fast_hash.hpp | 71 +
include/util/xor_fast_hash_storage.hpp | 84 +
library/osrm_impl.cpp | 183 -
library/osrm_impl.hpp | 71 -
package.json | 39 +
plugins/distance_table.hpp | 247 -
plugins/hello_world.hpp | 106 -
plugins/match.hpp | 417 -
plugins/nearest.hpp | 128 -
plugins/plugin_base.hpp | 136 -
plugins/timestamp.hpp | 62 -
plugins/trip.hpp | 398 -
plugins/viaroute.hpp | 215 -
prepare.cpp | 109 -
profiles/bicycle.lua | 81 +-
profiles/car.lua | 58 +-
profiles/foot.lua | 23 +-
profiles/rasterbot.lua | 11 +-
.../{rasterbot-interp.lua => rasterbotinterp.lua} | 11 +-
profiles/testbot.lua | 37 +-
routed.cpp | 198 -
routing_algorithms/routing_base.hpp | 687 --
scripts/check_taginfo.py | 51 +
scripts/format.sh | 22 +
scripts/install_node.sh | 9 +
scripts/modernize.sh | 15 +-
scripts/tidy.sh | 10 +-
scripts/update_depdendencies.sh | 4 +-
server/api_grammar.hpp | 122 -
server/connection.hpp | 95 -
server/data_structures/datafacade_base.hpp | 126 -
server/data_structures/internal_datafacade.hpp | 469 -
server/data_structures/shared_barriers.hpp | 60 -
server/data_structures/shared_datafacade.hpp | 503 -
server/data_structures/shared_datatype.hpp | 196 -
server/http/header.hpp | 54 -
server/http/reply.hpp | 65 -
server/http/request.hpp | 48 -
server/request_handler.cpp | 177 -
server/request_handler.hpp | 59 -
server/request_parser.cpp | 393 -
server/request_parser.hpp | 98 -
src/benchmarks/static_rtree.cpp | 115 +
src/contractor/contractor.cpp | 686 ++
src/engine/api/json_factory.cpp | 230 +
src/engine/douglas_peucker.cpp | 100 +
src/engine/engine.cpp | 190 +
src/engine/engine_config.cpp | 27 +
src/engine/guidance/assemble_overview.cpp | 103 +
src/engine/guidance/assemble_route.cpp | 30 +
src/engine/guidance/assemble_steps.cpp | 82 +
src/engine/guidance/post_processing.cpp | 494 +
src/engine/hint.cpp | 59 +
src/engine/plugins/match.cpp | 197 +
src/engine/plugins/nearest.cpp | 49 +
src/engine/plugins/table.cpp | 76 +
src/engine/plugins/tile.cpp | 455 +
src/engine/plugins/trip.cpp | 245 +
src/engine/plugins/viaroute.cpp | 129 +
src/engine/polyline_compressor.cpp | 128 +
src/engine/search_engine_data.cpp | 80 +
.../extractor}/compressed_edge_container.cpp | 140 +-
src/extractor/edge_based_graph_factory.cpp | 481 +
.../extractor}/extraction_containers.cpp | 284 +-
{extractor => src/extractor}/extractor.cpp | 368 +-
.../extractor}/extractor_callbacks.cpp | 125 +-
{algorithms => src/extractor}/graph_compressor.cpp | 101 +-
src/extractor/guidance/classification_data.cpp | 53 +
src/extractor/guidance/turn_analysis.cpp | 2313 ++++
.../extractor}/raster_source.cpp | 91 +-
.../extractor}/restriction_map.cpp | 43 +-
.../extractor}/restriction_parser.cpp | 469 +-
src/extractor/scripting_environment.cpp | 184 +
src/osrm/osrm.cpp | 54 +
src/server/api/parameters_parser.cpp | 86 +
src/server/api/url_parser.cpp | 88 +
{server => src/server}/connection.cpp | 63 +-
{server => src/server}/http/reply.cpp | 45 +-
src/server/request_handler.cpp | 151 +
src/server/request_parser.cpp | 299 +
src/server/service/match_service.cpp | 73 +
src/server/service/nearest_service.cpp | 72 +
src/server/service/route_service.cpp | 69 +
src/server/service/table_service.cpp | 90 +
src/server/service/tile_service.cpp | 51 +
src/server/service/trip_service.cpp | 73 +
src/server/service_handler.cpp | 54 +
datastore.cpp => src/storage/storage.cpp | 464 +-
src/storage/storage_config.cpp | 38 +
{tools => src/tools}/.gitignore | 0
src/tools/components.cpp | 233 +
src/tools/contract.cpp | 159 +
src/tools/extract.cpp | 160 +
src/tools/io-benchmark.cpp | 325 +
src/tools/routed.cpp | 348 +
src/tools/springclean.cpp | 82 +
src/tools/store.cpp | 104 +
src/tools/unlock_all_mutexes.cpp | 20 +
src/util/assert.cpp | 29 +
src/util/coordinate.cpp | 100 +
src/util/coordinate_calculation.cpp | 325 +
src/util/exception.cpp | 21 +
src/util/fingerprint.cpp | 2 +
src/util/hilbert_value.cpp | 84 +
src/util/name_table.cpp | 62 +
{util => src/util}/simple_logger.cpp | 36 +-
taginfo.json | 147 +-
test/data/Makefile | 29 +
test/data/data.md5sum | 1 +
third_party/variant/.clang-format | 89 +
third_party/variant/.gitignore | 3 +
third_party/variant/.travis.yml | 133 +-
third_party/variant/.ycm_extra_conf.py | 40 +
third_party/variant/Jamroot | 8 +-
third_party/variant/LICENSE_1_0.txt | 23 +
third_party/variant/Makefile | 44 +-
third_party/variant/README.md | 92 +-
third_party/variant/doc/other_implementations.md | 15 +
third_party/variant/doc/standards_effort.md | 28 +
third_party/variant/optional.hpp | 39 +-
third_party/variant/recursive_wrapper.hpp | 133 +-
third_party/variant/scripts/build-appveyor.bat | 2 +-
third_party/variant/scripts/linux.sh | 59 -
third_party/variant/scripts/osx.sh | 20 -
.../scripts/run_compilation_failure_tests.sh | 50 +
third_party/variant/test/bench_variant.cpp | 52 +-
third_party/variant/test/binary_visitor_test.cpp | 40 +-
.../variant/test/boost_variant_hello_world.cpp | 7 +-
third_party/variant/test/catch.hpp | 8683 --------------
.../compilation_failure/default_constructor.cpp | 22 +
.../test/compilation_failure/empty_typelist.cpp | 11 +
.../variant/test/compilation_failure/equality.cpp | 11 +
.../variant/test/compilation_failure/get_type.cpp | 10 +
.../variant/test/compilation_failure/is_type.cpp | 10 +
.../mutating_visitor_on_const.cpp | 24 +
.../test/compilation_failure/no-reference.cpp | 9 +
third_party/variant/test/include/catch.hpp | 11613 +++++++++++++++++++
third_party/variant/test/optional_unit.cpp | 82 -
.../variant/test/our_variant_hello_world.cpp | 20 +
.../variant/test/recursive_wrapper_test.cpp | 67 +-
.../variant/test/reference_wrapper_test.cpp | 42 +-
third_party/variant/test/t/binary_visitor_1.cpp | 7 +
third_party/variant/test/t/binary_visitor_2.cpp | 7 +
third_party/variant/test/t/binary_visitor_3.cpp | 7 +
third_party/variant/test/t/binary_visitor_4.cpp | 7 +
third_party/variant/test/t/binary_visitor_5.cpp | 7 +
third_party/variant/test/t/binary_visitor_6.cpp | 7 +
third_party/variant/test/t/binary_visitor_impl.hpp | 204 +
third_party/variant/test/t/issue21.cpp | 48 +
third_party/variant/test/t/mutating_visitor.cpp | 36 +
third_party/variant/test/t/optional.cpp | 102 +
third_party/variant/test/t/recursive_wrapper.cpp | 158 +
third_party/variant/test/t/sizeof.cpp | 52 +
third_party/variant/test/t/unary_visitor.cpp | 127 +
third_party/variant/test/t/variant.cpp | 570 +
third_party/variant/test/unique_ptr_test.cpp | 68 +-
third_party/variant/test/unit.cpp | 314 +-
third_party/variant/test/variant_hello_world.cpp | 22 -
third_party/variant/variant.gyp | 20 +-
third_party/variant/variant.hpp | 635 +-
third_party/variant/variant_io.hpp | 32 +-
third_party/variant/vcbuild.bat | 8 -
tools/check-hsgr.cpp | 112 -
tools/components.cpp | 257 -
tools/io-benchmark.cpp | 348 -
tools/simpleclient.cpp | 97 -
tools/springclean.cpp | 102 -
tools/unlock_all_mutexes.cpp | 51 -
unit_tests/algorithms/douglas_peucker.cpp | 104 -
unit_tests/algorithms/duration_parsing.cpp | 64 -
unit_tests/algorithms/geometry_string.cpp | 74 -
unit_tests/algorithms/string_util.cpp | 65 -
unit_tests/data_structures/coordinate.cpp | 50 -
unit_tests/data_structures/dynamic_graph.cpp | 93 -
unit_tests/data_structures/static_rtree.cpp | 480 -
unit_tests/engine/base64.cpp | 80 +
unit_tests/engine/douglas_peucker.cpp | 109 +
unit_tests/engine/geometry_string.cpp | 45 +
unit_tests/engine/guidance_assembly.cpp | 20 +
unit_tests/engine_tests.cpp | 7 +
.../compressed_edge_container.cpp | 7 +-
.../{algorithms => extractor}/graph_compressor.cpp | 125 +-
.../raster_source.cpp | 44 +-
unit_tests/extractor_tests.cpp | 7 +
unit_tests/library/args.hpp | 16 +
unit_tests/library/coordinates.hpp | 28 +
unit_tests/library/equal_json.hpp | 27 +
unit_tests/library/fixture.hpp | 21 +
unit_tests/library/limits.cpp | 139 +
unit_tests/library/match.cpp | 37 +
unit_tests/library/nearest.cpp | 116 +
unit_tests/library/route.cpp | 232 +
unit_tests/library/table.cpp | 37 +
unit_tests/library/tile.cpp | 31 +
unit_tests/library/trip.cpp | 37 +
unit_tests/library_tests.cpp | 7 +
unit_tests/mocks/mock_datafacade.hpp | 178 +
unit_tests/server/parameters_parser.cpp | 330 +
unit_tests/server/url_parser.cpp | 102 +
unit_tests/server_tests.cpp | 7 +
unit_tests/util/bearing.cpp | 37 +-
.../{data_structures => util}/binary_heap.cpp | 34 +-
unit_tests/util/coordinate_calculation.cpp | 191 +
unit_tests/util/duration_parsing.cpp | 40 +
unit_tests/util/dynamic_graph.cpp | 66 +
unit_tests/util/io.cpp | 42 +
.../{data_structures => util}/range_table.cpp | 38 +-
unit_tests/util/rectangle.cpp | 107 +
.../{data_structures => util}/static_graph.cpp | 53 +-
unit_tests/util/static_rtree.cpp | 456 +
unit_tests/util/string_util.cpp | 41 +
unit_tests/util/viewport.cpp | 25 +
unit_tests/util_tests.cpp | 27 -
util/cast.hpp | 69 -
util/compute_angle.cpp | 54 -
util/compute_angle.hpp | 42 -
util/container.hpp | 111 -
util/datastore_options.hpp | 282 -
util/debug_geometry.hpp | 198 -
util/fingerprint.hpp | 61 -
util/ini_file.hpp | 51 -
util/integer_range.hpp | 80 -
util/json_util.hpp | 103 -
util/lua_util.hpp | 65 -
util/matching_debug_info.hpp | 155 -
util/mercator.cpp | 40 -
util/mercator.hpp | 38 -
util/osrm_exception.cpp | 43 -
util/routed_options.hpp | 284 -
util/simple_logger.hpp | 74 -
util/std_hash.hpp | 72 -
util/version.hpp.in | 37 -
util/xml_renderer.hpp | 137 -
655 files changed, 47552 insertions(+), 36007 deletions(-)
diff --git a/.cncc.style b/.cncc.style
new file mode 100644
index 0000000..bdece58
--- /dev/null
+++ b/.cncc.style
@@ -0,0 +1,14 @@
+# Kind-specific patterns to check AST nodes against. Both python-clang and
+# libclang docs explain CursorKind, with differences in detail. See also:
+# - https://github.com/llvm-mirror/clang/blob/aca4fe314a55cacae29e1548cb7bfd2119c6df4c/bindings/python/clang/cindex.py#L599
+# - http://clang.llvm.org/doxygen/group__CINDEX.html#gaaccc432245b4cd9f2d470913f9ef0013
+# - https://docs.python.org/2/library/re.html#regular-expression-syntax
+
+class_decl: '^([A-Z]+[a-z]+)+$'
+struct_decl: '^([A-Z]+[a-z]+)+$'
+field_decl: '^[a-z_]+$'
+var_decl: '^[a-z]+[a-z0-9_]*$'
+parm_decl: '^[a-z]*[a-z0-9_]*$'
+namespace: '^[a-z_]*$'
+cxx_method: '^([A-Z]+[a-z]+)+$'
+function_decl: '^[a-z]+([A-Z]+[a-z]+)*$'
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..d6d517d
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,28 @@
+{
+ "rules": {
+ "indent": [
+ 2,
+ 4
+ ],
+ "quotes": [
+ 1,
+ "single"
+ ],
+ "linebreak-style": [
+ 2,
+ "unix"
+ ],
+ "semi": [
+ 2,
+ "always"
+ ],
+ "no-console": [
+ 1
+ ]
+ },
+ "env": {
+ "es6": true,
+ "node": true
+ },
+ "extends": "eslint:recommended"
+}
diff --git a/.gitignore b/.gitignore
index 21608e3..83f572d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,6 +40,8 @@ Thumbs.db
# build related files #
#######################
/build/
+/example/build/
+/test/data/monaco*
/cmake/postinst
# Eclipse related files #
@@ -73,8 +75,15 @@ stxxl.errlog
###################
/sandbox/
+# Test related files #
+######################
/test/profile.lua
+/test/cache
+/test/speeds.csv
+node_modules
# Deprecated config file #
##########################
/server.ini
+
+*.swp
diff --git a/.travis.yml b/.travis.yml
index c065949..553cf56 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,9 @@
-language: cpp
+#language: cpp
+# This makes travis use the thin image which boots faster
+language: generic
+
+
+# sudo:required is needed for trusty images
sudo: required
dist: trusty
@@ -11,67 +16,86 @@ branches:
- develop
matrix:
+ fast_finish: true
+
include:
- # 1/ Linux Clang Builds
+ # Debug Builds
+ - os: linux
+ compiler: gcc
+ addons: &gcc5
+ apt:
+ sources: ['ubuntu-toolchain-r-test']
+ packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+ env: COMPILER='g++-5' BUILD_TYPE='Debug'
- os: linux
- compiler: clang
- addons: &clang38
+ compiler: gcc
+ addons: &gcc48
apt:
- sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
- packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
- env: COMPILER='clang++-3.8' BUILD_TYPE='Release'
+ sources: ['ubuntu-toolchain-r-test']
+ packages: ['g++-4.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+ env: COMPILER='g++-4.8' BUILD_TYPE='Debug'
- os: linux
compiler: clang
addons: &clang38
apt:
sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
- packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
- env: COMPILER='clang++-3.8' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
+ packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+ env: COMPILER='clang++-3.8' BUILD_TYPE='Debug' RUN_CLANG_FORMAT=ON
- - os: linux
+ - os: osx
+ osx_image: xcode7.3
compiler: clang
- addons: *clang38
- env: COMPILER='clang++-3.8' BUILD_TYPE='Debug'
+ env: COMPILER='clang++' BUILD_TYPE='Debug'
-
- # 2/ Linux GCC Builds
+ # Release Builds
- os: linux
compiler: gcc
- addons: &gcc48
+ addons: &gcc5
apt:
sources: ['ubuntu-toolchain-r-test']
- packages: ['g++-4.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
- env: COMPILER='g++-4.8' BUILD_TYPE='Release'
+ packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+ env: COMPILER='g++-5' BUILD_TYPE='Release'
- os: linux
compiler: gcc
- addons: *gcc48
- env: COMPILER='g++-4.8' BUILD_TYPE='Debug'
-
+ addons: &gcc48
+ apt:
+ sources: ['ubuntu-toolchain-r-test']
+ packages: ['g++-4.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+ env: COMPILER='g++-4.8' BUILD_TYPE='Release'
- os: linux
- compiler: gcc
- addons: &gcc5
+ compiler: clang
+ addons: &clang38
apt:
- sources: ['ubuntu-toolchain-r-test']
- packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
- env: COMPILER='g++-5' BUILD_TYPE='Release'
+ sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
+ packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+ env: COMPILER='clang++-3.8' BUILD_TYPE='Release'
+ - os: osx
+ osx_image: xcode7.3
+ compiler: clang
+ env: COMPILER='clang++' BUILD_TYPE='Release'
+
+ # Shared Library
- os: linux
compiler: gcc
addons: &gcc5
apt:
sources: ['ubuntu-toolchain-r-test']
- packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'rubygems-integration', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+ packages: ['g++-5', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
env: COMPILER='g++-5' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
- os: linux
- compiler: gcc
- addons: *gcc5
- env: COMPILER='g++-5' BUILD_TYPE='Debug'
+ compiler: clang
+ addons: &clang38
+ apt:
+ sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
+ packages: ['clang-3.8', 'libbz2-dev', 'libstxxl-dev', 'libstxxl1', 'libxml2-dev', 'libzip-dev', 'lua5.1', 'liblua5.1-0-dev', 'libtbb-dev', 'libgdal-dev', 'libluabind-dev', 'libboost-all-dev']
+ env: COMPILER='clang++-3.8' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
# Disabled until tests all pass on OSX:
@@ -95,20 +119,13 @@ matrix:
#- os: osx
# osx_image: xcode7
# compiler: clang
- # env: COMPILER='clang++' BUILD_TYPE='Debug'
-
- #- os: osx
- # osx_image: xcode7
- # compiler: clang
- # env: COMPILER='clang++' BUILD_TYPE='Release'
-
- #- os: osx
- # osx_image: xcode7
- # compiler: clang
# env: COMPILER='clang++' BUILD_TYPE='Release' BUILD_SHARED_LIBS=ON
+before_install:
+ - source ./scripts/install_node.sh 4
install:
+ - npm install
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
- mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR}
- |
@@ -117,30 +134,44 @@ install:
mkdir cmake && travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
- OSMOSIS_URL="http://bretth.dev.openstreetmap.org/osmosis-build/osmosis-latest.tgz"
- mkdir osmosis && travis_retry wget --quiet -O - ${OSMOSIS_URL} | tar -xz -C osmosis
- export PATH=${DEPS_DIR}/osmosis/bin:${PATH}
-
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
- brew install cmake boost libzip libstxxl libxml2 lua51 luabind tbb GDAL osmosis
+ # implicit deps, but seem to be installed by default with recent images: libxml2 GDAL boost
+ brew install cmake libzip libstxxl lua51 luabind tbb md5sha1sum
fi
before_script:
- cd ${TRAVIS_BUILD_DIR}
- - rvm use 1.9.3
- - gem install bundler
- - bundle install
- - mkdir build && cd build
+ - |
+ if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
+ ./scripts/check_taginfo.py taginfo.json profiles/car.lua
+ fi
+ - mkdir build && pushd build
- export CXX=${COMPILER}
- - export OSRM_PORT=5000 OSRM_TIMEOUT=60
- - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS:-OFF} -DBUILD_TOOLS=1
+ - export OSRM_PORT=5000 OSRM_TIMEOUT=6000
+ - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS:-OFF} -DBUILD_TOOLS=1 -DENABLE_CCACHE=0
script:
- make --jobs=2
- make tests --jobs=2
- make benchmarks
- - ./algorithm-tests
- - ./datastructure-tests
+ - sudo make install
+ - |
+ if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
+ sudo ldconfig
+ fi
+ - ./extractor-tests
+ - ./engine-tests
- ./util-tests
- - cd ..
- - cucumber -p verify
+ - popd
+ - npm test
+ - make -C test/data
+ - ./build/library-tests test/data/monaco.osrm
+ - mkdir example/build && pushd example/build
+ - cmake ..
+ - make
+ - ./osrm-example ../../test/data/monaco.osrm
+ - popd
+ - |
+ if [ -n "$RUN_CLANG_FORMAT" ]; then
+ ./scripts/format.sh || true # we don't want to fail just yet
+ fi
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..168b5ad
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,17 @@
+# 5.0.0 RC1
+ - Renamed osrm-prepare into osrm-contract
+ - osrm-contract does not need a profile parameter anymore
+ - New public HTTP API, find documentation [here](https://github.com/Project-OSRM/osrm-backend/wiki/New-Server-api)
+ - POST support is discontinued, please use library bindings for more complex requests
+ - Removed timestamp plugin
+ - Coordinate order is now Longitude,Latitude
+ - Cucumber tests now based on Javascript (run with `npm test`)
+ - Profile API changed:
+ - `forward_mode` and `backward_mode` now need to be selected from a pre-defined list
+ - Global profile properties are now stored in a global `properties` element. This includes:
+ - `properties.traffic_signal_penalty`
+ - `properties.use_turn_restrictions`
+ - `properties.u_turn_penalty`
+ - `properties.allow_u_turn_at_via`
+
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b8fecc5..3ca9c8a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,8 +7,8 @@ This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. P
endif()
project(OSRM C CXX)
-set(OSRM_VERSION_MAJOR 4)
-set(OSRM_VERSION_MINOR 9)
+set(OSRM_VERSION_MAJOR 5)
+set(OSRM_VERSION_MINOR 0)
set(OSRM_VERSION_PATCH 0)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
@@ -29,15 +29,15 @@ if(WIN32 AND MSVC_VERSION LESS 1800)
message(FATAL_ERROR "Building with Microsoft compiler needs Visual Studio 2013 or later (Express version works too)")
endif()
+option(ENABLE_CCACHE "Speed up incremental rebuilds via ccache" ON)
option(ENABLE_JSON_LOGGING "Adds additional JSON debug logging to the response" OFF)
-option(DEBUG_GEOMETRY "Enables an option to dump GeoJSON of the final routing graph" OFF)
option(BUILD_TOOLS "Build OSRM tools" OFF)
+option(BUILD_COMPONENTS "Build OSRM tools" ON)
+option(ENABLE_ASSERTIONS OFF)
-include_directories(${CMAKE_CURRENT_SOURCE_DIR})
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
-include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/)
+include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include/)
+include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/)
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/)
-include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include/)
add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND}
"-DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR}"
@@ -46,74 +46,61 @@ add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND}
COMMENT "Configuring revision fingerprint"
VERBATIM)
-add_custom_target(tests DEPENDS datastructure-tests algorithm-tests util-tests)
+add_custom_target(tests DEPENDS engine-tests extractor-tests util-tests server-tests library-tests)
add_custom_target(benchmarks DEPENDS rtree-bench)
set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework)
configure_file(
- ${CMAKE_CURRENT_SOURCE_DIR}/util/version.hpp.in
- ${CMAKE_CURRENT_BINARY_DIR}/util/version.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/util/version.hpp.in
+ ${CMAKE_CURRENT_BINARY_DIR}/include/util/version.hpp
)
-file(GLOB ExtractorGlob extractor/*.cpp data_structures/hilbert_value.cpp)
-file(GLOB ImporterGlob data_structures/import_edge.cpp data_structures/external_memory_node.cpp data_structures/raster_source.cpp)
-add_library(IMPORT OBJECT ${ImporterGlob})
-add_library(LOGGER OBJECT util/simple_logger.cpp)
-add_library(PHANTOMNODE OBJECT data_structures/phantom_node.cpp)
-add_library(RASTERSOURCE OBJECT data_structures/raster_source.cpp)
-add_library(EXCEPTION OBJECT util/osrm_exception.cpp)
-add_library(MERCATOR OBJECT util/mercator.cpp)
-add_library(ANGLE OBJECT util/compute_angle.cpp)
-
-set(ExtractorSources extract.cpp ${ExtractorGlob})
-add_executable(osrm-extract ${ExtractorSources} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR> $<TARGET_OBJECTS:COMPRESSEDEDGE> $<TARGET_OBJECTS:GRAPHCOMPRESSOR> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:ANGLE>)
-
-add_library(RESTRICTION OBJECT data_structures/restriction_map.cpp)
-add_library(COMPRESSEDEDGE OBJECT data_structures/compressed_edge_container.cpp)
-add_library(GRAPHCOMPRESSOR OBJECT algorithms/graph_compressor.cpp)
-
-file(GLOB PrepareGlob contractor/*.cpp data_structures/hilbert_value.cpp {RestrictionMapGlob})
-set(PrepareSources prepare.cpp ${PrepareGlob})
-add_executable(osrm-prepare ${PrepareSources} $<TARGET_OBJECTS:ANGLE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR> $<TARGET_OBJECTS:COMPRESSEDEDGE> $<TARGET_OBJECTS:GRAPHCOMPRESSOR>)
-
-file(GLOB ServerGlob server/*.cpp)
-file(GLOB DescriptorGlob descriptors/*.cpp)
-file(GLOB DatastructureGlob data_structures/search_engine_data.cpp data_structures/route_parameters.cpp util/bearing.cpp)
-file(GLOB CoordinateGlob data_structures/coordinate.cpp algorithms/coordinate_calculation.cpp)
-file(GLOB AlgorithmGlob algorithms/polyline_compressor.cpp algorithms/polyline_formatter.cpp algorithms/douglas_peucker.cpp)
-file(GLOB HttpGlob server/http/*.cpp)
-file(GLOB LibOSRMGlob library/*.cpp)
-file(GLOB DataStructureTestsGlob unit_tests/data_structures/*.cpp data_structures/hilbert_value.cpp)
-file(GLOB AlgorithmTestsGlob unit_tests/algorithms/*.cpp algorithms/graph_compressor.cpp)
+file(GLOB UtilGlob src/util/*.cpp)
+file(GLOB ExtractorGlob src/extractor/*.cpp src/extractor/*/*.cpp)
+file(GLOB ContractorGlob src/contractor/*.cpp)
+file(GLOB StorageGlob src/storage/*.cpp)
+file(GLOB ServerGlob src/server/*.cpp src/server/**/*.cpp)
+file(GLOB EngineGlob src/engine/*.cpp src/engine/**/*.cpp)
+file(GLOB ExtractorTestsGlob unit_tests/extractor/*.cpp)
+file(GLOB EngineTestsGlob unit_tests/engine/*.cpp)
file(GLOB UtilTestsGlob unit_tests/util/*.cpp)
-
-set(
- OSRMSources
- ${LibOSRMGlob}
- ${DescriptorGlob}
- ${DatastructureGlob}
- ${AlgorithmGlob}
- ${HttpGlob}
-)
-
-add_library(COORDINATE OBJECT ${CoordinateGlob})
-add_library(OSRM ${OSRMSources} $<TARGET_OBJECTS:ANGLE> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR> $<TARGET_OBJECTS:IMPORT>)
-
-add_library(FINGERPRINT OBJECT util/fingerprint.cpp)
-add_dependencies(FINGERPRINT FingerPrintConfigure)
-add_dependencies(OSRM FingerPrintConfigure)
-set_target_properties(FINGERPRINT PROPERTIES LINKER_LANGUAGE CXX)
-
-add_executable(osrm-routed routed.cpp ${ServerGlob} $<TARGET_OBJECTS:EXCEPTION>)
-add_executable(osrm-datastore datastore.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
+file(GLOB ServerTestsGlob unit_tests/server/*.cpp)
+file(GLOB LibraryTestsGlob unit_tests/library/*.cpp)
+file(GLOB IOTestsGlob unit_tests/io/*.cpp)
+
+add_library(UTIL OBJECT ${UtilGlob})
+add_library(EXTRACTOR OBJECT ${ExtractorGlob})
+add_library(CONTRACTOR OBJECT ${ContractorGlob})
+add_library(STORAGE OBJECT ${StorageGlob})
+add_library(ENGINE OBJECT ${EngineGlob})
+add_library(SERVER OBJECT ${ServerGlob})
+
+add_dependencies(UTIL FingerPrintConfigure)
+set_target_properties(UTIL PROPERTIES LINKER_LANGUAGE CXX)
+
+add_executable(osrm-extract src/tools/extract.cpp)
+add_executable(osrm-contract src/tools/contract.cpp)
+add_executable(osrm-routed src/tools/routed.cpp $<TARGET_OBJECTS:SERVER> $<TARGET_OBJECTS:UTIL>)
+add_executable(osrm-datastore src/tools/store.cpp $<TARGET_OBJECTS:UTIL>)
+add_library(osrm src/osrm/osrm.cpp $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:UTIL> $<TARGET_OBJECTS:STORAGE>)
+add_library(osrm_extract $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:UTIL>)
+add_library(osrm_contract $<TARGET_OBJECTS:CONTRACTOR> $<TARGET_OBJECTS:UTIL>)
+add_library(osrm_store $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:UTIL>)
# Unit tests
-add_executable(datastructure-tests EXCLUDE_FROM_ALL unit_tests/datastructure_tests.cpp ${DataStructureTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR> $<TARGET_OBJECTS:COMPRESSEDEDGE> $<TARGET_OBJECTS:GRAPHCOMPRESSOR> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:RASTERSOURCE>)
-add_executable(algorithm-tests EXCLUDE_FROM_ALL unit_tests/algorithm_tests.cpp ${AlgorithmTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:COMPRESSEDEDGE>)
-add_executable(util-tests EXCLUDE_FROM_ALL unit_tests/util_tests.cpp ${UtilTestsGlob})
+add_executable(engine-tests EXCLUDE_FROM_ALL unit_tests/engine_tests.cpp ${EngineTestsGlob} $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:UTIL>)
+add_executable(extractor-tests EXCLUDE_FROM_ALL unit_tests/extractor_tests.cpp ${ExtractorTestsGlob} $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:UTIL>)
+add_executable(util-tests EXCLUDE_FROM_ALL unit_tests/util_tests.cpp ${UtilTestsGlob} $<TARGET_OBJECTS:UTIL>)
+add_executable(server-tests EXCLUDE_FROM_ALL unit_tests/server_tests.cpp ${ServerTestsGlob} $<TARGET_OBJECTS:UTIL> $<TARGET_OBJECTS:SERVER>)
+add_executable(library-tests EXCLUDE_FROM_ALL unit_tests/library_tests.cpp ${LibraryTestsGlob})
# Benchmarks
-add_executable(rtree-bench EXCLUDE_FROM_ALL benchmarks/static_rtree.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
+add_executable(rtree-bench EXCLUDE_FROM_ALL src/benchmarks/static_rtree.cpp $<TARGET_OBJECTS:UTIL>)
+
+target_include_directories(engine-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/unit_tests)
+target_include_directories(util-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/unit_tests)
+target_include_directories(library-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/)
+target_include_directories(rtree-bench PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/unit_tests)
# Check the release mode
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
@@ -121,6 +108,7 @@ if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
endif()
if(CMAKE_BUILD_TYPE MATCHES Debug)
message(STATUS "Configuring OSRM in debug mode")
+ set(ENABLE_ASSERTIONS ON)
if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-inline -fno-omit-frame-pointer")
@@ -175,7 +163,7 @@ endif()
# Configuring compilers
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=2 -D_FORTIFY_SOURCE=2 -fPIC")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=2 -D_FORTIFY_SOURCE=2 -fPIC -fcolor-diagnostics")
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
set(COLOR_FLAG "-fdiagnostics-color=auto")
check_cxx_compiler_flag("-fdiagnostics-color=auto" HAS_COLOR_FLAG)
@@ -185,7 +173,6 @@ elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
# using GCC
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wuninitialized -Wunreachable-code -Wstrict-overflow=1 -D_FORTIFY_SOURCE=2 ${COLOR_FLAG} -fPIC")
if(WIN32) # using mingw
- add_definitions(-D_USE_MATH_DEFINES) # define M_PI, M_1_PI etc.
add_definitions(-DWIN32)
set(OPTIONAL_SOCKET_LIBS ws2_32 wsock32)
endif()
@@ -195,9 +182,10 @@ elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel")
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
# using Visual Studio C++
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} date_time chrono zlib)
+ add_definitions(-DBOOST_LIB_DIAGNOSTIC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-DNOMINMAX) # avoid min and max macros that can break compilation
- add_definitions(-D_USE_MATH_DEFINES) # define M_PI
+ add_definitions(-D_USE_MATH_DEFINES) #needed for M_PI with cmath.h
add_definitions(-D_WIN32_WINNT=0x0501)
add_definitions(-DXML_STATIC)
find_library(ws2_32_LIBRARY_PATH ws2_32)
@@ -245,76 +233,45 @@ if(APPLE)
endif()
if(UNIX AND NOT APPLE)
- target_link_libraries(osrm-prepare rt)
- target_link_libraries(osrm-datastore rt)
- target_link_libraries(OSRM rt)
+ set(MAYBE_RT_LIBRARY rt)
endif()
-#Check Boost
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/cmake")
+set(OSMIUM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include")
+find_package(Osmium REQUIRED COMPONENTS io)
+include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS})
+
+
find_package(Boost 1.49.0 COMPONENTS ${BOOST_COMPONENTS} REQUIRED)
-if(NOT Boost_FOUND)
- message(FATAL_ERROR "Fatal error: Boost (version >= 1.49.0) required.\n")
+if(NOT WIN32)
+ add_definitions(-DBOOST_TEST_DYN_LINK)
endif()
+add_definitions(-DBOOST_SPIRIT_USE_PHOENIX_V3 -DBOOST_RESULT_OF_USE_DECLTYPE)
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
-target_link_libraries(OSRM ${Boost_LIBRARIES})
-target_link_libraries(osrm-extract ${Boost_LIBRARIES})
-target_link_libraries(osrm-prepare ${Boost_LIBRARIES})
-target_link_libraries(osrm-routed ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
-target_link_libraries(osrm-datastore ${Boost_LIBRARIES})
-target_link_libraries(datastructure-tests ${Boost_LIBRARIES})
-target_link_libraries(algorithm-tests ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
-target_link_libraries(util-tests ${Boost_LIBRARIES})
-target_link_libraries(rtree-bench ${Boost_LIBRARIES})
-
find_package(Threads REQUIRED)
-target_link_libraries(osrm-extract ${CMAKE_THREAD_LIBS_INIT})
-target_link_libraries(osrm-datastore ${CMAKE_THREAD_LIBS_INIT})
-target_link_libraries(osrm-prepare ${CMAKE_THREAD_LIBS_INIT})
-target_link_libraries(OSRM ${CMAKE_THREAD_LIBS_INIT})
-target_link_libraries(datastructure-tests ${CMAKE_THREAD_LIBS_INIT})
-target_link_libraries(algorithm-tests ${CMAKE_THREAD_LIBS_INIT})
-target_link_libraries(rtree-bench ${CMAKE_THREAD_LIBS_INIT})
find_package(TBB REQUIRED)
+include_directories(SYSTEM ${TBB_INCLUDE_DIR})
if(WIN32 AND CMAKE_BUILD_TYPE MATCHES Debug)
set(TBB_LIBRARIES ${TBB_DEBUG_LIBRARIES})
endif()
-target_link_libraries(osrm-datastore ${TBB_LIBRARIES})
-target_link_libraries(osrm-extract ${TBB_LIBRARIES})
-target_link_libraries(osrm-prepare ${TBB_LIBRARIES})
-target_link_libraries(osrm-routed ${TBB_LIBRARIES})
-target_link_libraries(datastructure-tests ${TBB_LIBRARIES})
-target_link_libraries(algorithm-tests ${TBB_LIBRARIES})
-target_link_libraries(rtree-bench ${TBB_LIBRARIES})
-include_directories(SYSTEM ${TBB_INCLUDE_DIR})
find_package( Luabind REQUIRED )
include(check_luabind)
-
include_directories(SYSTEM ${LUABIND_INCLUDE_DIR})
-target_link_libraries(osrm-extract ${LUABIND_LIBRARY})
-target_link_libraries(osrm-prepare ${LUABIND_LIBRARY})
+set(USED_LUA_LIBRARIES ${LUA_LIBRARY})
if(LUAJIT_FOUND)
- target_link_libraries(osrm-extract ${LUAJIT_LIBRARIES})
- target_link_libraries(osrm-prepare ${LUAJIT_LIBRARIES})
-else()
- target_link_libraries(osrm-extract ${LUA_LIBRARY})
- target_link_libraries(osrm-prepare ${LUA_LIBRARY})
+ set(USED_LUA_LIBRARIES, LUAJIT_LIBRARIES)
endif()
include_directories(SYSTEM ${LUA_INCLUDE_DIR})
find_package(EXPAT REQUIRED)
include_directories(SYSTEM ${EXPAT_INCLUDE_DIRS})
-target_link_libraries(osrm-extract ${EXPAT_LIBRARIES})
find_package(STXXL REQUIRED)
include_directories(SYSTEM ${STXXL_INCLUDE_DIR})
-target_link_libraries(OSRM ${STXXL_LIBRARY})
-target_link_libraries(osrm-extract ${STXXL_LIBRARY})
-target_link_libraries(osrm-prepare ${STXXL_LIBRARY})
-target_link_libraries(datastructure-tests ${STXXL_LIBRARY})
set(OpenMP_FIND_QUIETLY ON)
find_package(OpenMP)
@@ -325,91 +282,144 @@ endif()
find_package(BZip2 REQUIRED)
include_directories(SYSTEM ${BZIP_INCLUDE_DIRS})
-target_link_libraries(osrm-extract ${BZIP2_LIBRARIES})
find_package(ZLIB REQUIRED)
include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS})
-target_link_libraries(osrm-extract ${ZLIB_LIBRARY})
-target_link_libraries(osrm-routed ${ZLIB_LIBRARY})
if (ENABLE_JSON_LOGGING)
message(STATUS "Enabling json logging")
add_definitions(-DENABLE_JSON_LOGGING)
endif()
-if (DEBUG_GEOMETRY)
- message(STATUS "Enabling final edge weight GeoJSON output option")
- add_definitions(-DDEBUG_GEOMETRY)
-endif()
-
-if(BUILD_TOOLS)
- message(STATUS "Activating OSRM internal tools")
+# Binaries
+target_link_libraries(osrm-datastore osrm_store ${Boost_LIBRARIES})
+target_link_libraries(osrm-extract osrm_extract ${Boost_LIBRARIES})
+target_link_libraries(osrm-contract osrm_contract ${Boost_LIBRARIES})
+target_link_libraries(osrm-routed osrm ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} ${ZLIB_LIBRARY})
+
+set(EXTRACTOR_LIBRARIES
+ ${BZIP2_LIBRARIES}
+ ${Boost_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${EXPAT_LIBRARIES}
+ ${LUABIND_LIBRARY}
+ ${USED_LUA_LIBRARIES}
+ ${OSMIUM_LIBRARIES}
+ ${STXXL_LIBRARY}
+ ${TBB_LIBRARIES}
+ ${ZLIB_LIBRARY})
+set(CONTRACTOR_LIBRARIES
+ ${Boost_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${LUABIND_LIBRARY}
+ ${USED_LUA_LIBRARIES}
+ ${STXXL_LIBRARY}
+ ${TBB_LIBRARIES}
+ ${MAYBE_RT_LIBRARY})
+set(ENGINE_LIBRARIES
+ ${Boost_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${STXXL_LIBRARY}
+ ${TBB_LIBRARIES}
+ ${MAYBE_RT_LIBRARY})
+set(STORAGE_LIBRARIES
+ ${Boost_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${TBB_LIBRARIES}
+ ${MAYBE_RT_LIBRARY})
+set(UTIL_LIBRARIES
+ ${Boost_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${STXXL_LIBRARY}
+ ${TBB_LIBRARIES})
+# Libraries
+target_link_libraries(osrm ${ENGINE_LIBRARIES})
+target_link_libraries(osrm_contract ${CONTRACTOR_LIBRARIES})
+target_link_libraries(osrm_extract ${EXTRACTOR_LIBRARIES})
+target_link_libraries(osrm_store ${STORAGE_LIBRARIES})
+# Tests
+target_link_libraries(engine-tests ${ENGINE_LIBRARIES})
+target_link_libraries(server-tests osrm ${Boost_LIBRARIES})
+target_link_libraries(extractor-tests ${EXTRACTOR_LIBRARIES})
+target_link_libraries(rtree-bench ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${TBB_LIBRARIES})
+target_link_libraries(util-tests ${UTIL_LIBRARIES})
+target_link_libraries(library-tests osrm ${Boost_LIBRARIES})
+
+if(BUILD_COMPONENTS)
find_package(GDAL)
if(GDAL_FOUND)
- add_executable(osrm-components tools/components.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
+ add_executable(osrm-components src/tools/components.cpp $<TARGET_OBJECTS:UTIL>)
target_link_libraries(osrm-components ${TBB_LIBRARIES})
include_directories(SYSTEM ${GDAL_INCLUDE_DIR})
target_link_libraries(osrm-components ${GDAL_LIBRARIES} ${Boost_LIBRARIES})
install(TARGETS osrm-components DESTINATION bin)
else()
- message(FATAL_ERROR "libgdal and/or development headers not found")
+ message(WARNING "libgdal and/or development headers not found")
endif()
- add_executable(osrm-cli tools/simpleclient.cpp $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:COORDINATE>)
- target_link_libraries(osrm-cli ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
- target_link_libraries(osrm-cli ${TBB_LIBRARIES})
- add_executable(osrm-io-benchmark tools/io-benchmark.cpp $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER>)
+endif()
+
+if(BUILD_TOOLS)
+ message(STATUS "Activating OSRM internal tools")
+ add_executable(osrm-io-benchmark src/tools/io-benchmark.cpp $<TARGET_OBJECTS:UTIL>)
target_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES})
- add_executable(osrm-unlock-all tools/unlock_all_mutexes.cpp $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION>)
+ add_executable(osrm-unlock-all src/tools/unlock_all_mutexes.cpp $<TARGET_OBJECTS:UTIL>)
target_link_libraries(osrm-unlock-all ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
if(UNIX AND NOT APPLE)
target_link_libraries(osrm-unlock-all rt)
endif()
- add_executable(osrm-check-hsgr tools/check-hsgr.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:IMPORT>)
- target_link_libraries(osrm-check-hsgr ${Boost_LIBRARIES} ${TBB_LIBRARIES})
- add_executable(osrm-springclean tools/springclean.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION>)
+ add_executable(osrm-springclean src/tools/springclean.cpp $<TARGET_OBJECTS:UTIL>)
target_link_libraries(osrm-springclean ${Boost_LIBRARIES})
- install(TARGETS osrm-cli DESTINATION bin)
install(TARGETS osrm-io-benchmark DESTINATION bin)
install(TARGETS osrm-unlock-all DESTINATION bin)
- install(TARGETS osrm-check-hsgr DESTINATION bin)
install(TARGETS osrm-springclean DESTINATION bin)
endif()
-file(GLOB InstallGlob include/osrm/*.hpp)
-file(GLOB VariantGlob third_party/variant/*.hpp)
+if (ENABLE_ASSERTIONS)
+ message(STATUS "Enabling assertions")
+ add_definitions(-DBOOST_ENABLE_ASSERT_HANDLER)
+endif()
# Add RPATH info to executables so that when they are run after being installed
# (i.e., from /usr/local/bin/) the linker can find library dependencies. For
# more info see http://www.cmake.org/Wiki/CMake_RPATH_handling
set_property(TARGET osrm-extract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
-set_property(TARGET osrm-prepare PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
+set_property(TARGET osrm-contract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
set_property(TARGET osrm-datastore PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
set_property(TARGET osrm-routed PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
-install(FILES ${InstallGlob} DESTINATION include/osrm)
+file(GLOB VariantGlob third_party/variant/*.hpp)
+file(GLOB LibraryGlob include/osrm/*.hpp)
+file(GLOB ParametersGlob include/engine/api/*_parameters.hpp)
+set(EngineHeader include/engine/status.hpp include/engine/engine_config.hpp include/engine/hint.hpp include/engine/bearing.hpp include/engine/phantom_node.hpp)
+set(UtilHeader include/util/coordinate.hpp include/util/json_container.hpp include/util/typedefs.hpp include/util/strong_typedef.hpp)
+set(ExtractorHeader include/extractor/extractor.hpp include/extractor/extractor_config.hpp include/extractor/travel_mode.hpp)
+set(ContractorHeader include/contractor/contractor.hpp include/contractor/contractor_config.hpp)
+set(StorageHeader include/storage/storage.hpp include/storage/storage_config.hpp)
+install(FILES ${EngineHeader} DESTINATION include/osrm/engine)
+install(FILES ${UtilHeader} DESTINATION include/osrm/util)
+install(FILES ${StorageHeader} DESTINATION include/osrm/storage)
+install(FILES ${ExtractorHeader} DESTINATION include/osrm/extractor)
+install(FILES ${ContractorHeader} DESTINATION include/osrm/contractor)
+install(FILES ${LibraryGlob} DESTINATION include/osrm)
+install(FILES ${ParametersGlob} DESTINATION include/osrm/engine/api)
install(FILES ${VariantGlob} DESTINATION include/variant)
install(TARGETS osrm-extract DESTINATION bin)
-install(TARGETS osrm-prepare DESTINATION bin)
+install(TARGETS osrm-contract DESTINATION bin)
install(TARGETS osrm-datastore DESTINATION bin)
install(TARGETS osrm-routed DESTINATION bin)
-install(TARGETS OSRM DESTINATION lib)
-
-list(GET Boost_LIBRARIES 1 BOOST_LIBRARY_FIRST)
-get_filename_component(BOOST_LIBRARY_LISTING "${BOOST_LIBRARY_FIRST}" PATH)
-set(BOOST_LIBRARY_LISTING "-L${BOOST_LIBRARY_LISTING}")
-foreach(lib ${Boost_LIBRARIES})
- get_filename_component(BOOST_LIBRARY_NAME "${lib}" NAME_WE)
- string(REPLACE "lib" "" BOOST_LIBRARY_NAME ${BOOST_LIBRARY_NAME})
- set(BOOST_LIBRARY_LISTING "${BOOST_LIBRARY_LISTING} -l${BOOST_LIBRARY_NAME}")
-endforeach()
-list(GET TBB_LIBRARIES 1 TBB_LIBRARY_FIRST)
-get_filename_component(TBB_LIBRARY_LISTING "${TBB_LIBRARY_FIRST}" PATH)
-set(TBB_LIBRARY_LISTING "-L${TBB_LIBRARY_LISTING}")
-foreach(lib ${TBB_LIBRARIES})
- get_filename_component(TBB_LIBRARY_NAME "${lib}" NAME_WE)
- string(REPLACE "lib" "" TBB_LIBRARY_NAME ${TBB_LIBRARY_NAME})
- set(TBB_LIBRARY_LISTING "${TBB_LIBRARY_LISTING} -l${TBB_LIBRARY_NAME}")
+install(TARGETS osrm DESTINATION lib)
+install(TARGETS osrm_extract DESTINATION lib)
+install(TARGETS osrm_contract DESTINATION lib)
+install(TARGETS osrm_store DESTINATION lib)
+
+list(GET ENGINE_LIBRARIES 1 ENGINE_LIBRARY_FIRST)
+foreach(lib ${ENGINE_LIBRARIES})
+ get_filename_component(ENGINE_LIBRARY_PATH "${ENGINE_LIBRARY_FIRST}" PATH)
+ get_filename_component(ENGINE_LIBRARY_NAME "${lib}" NAME_WE)
+ string(REPLACE "lib" "" ENGINE_LIBRARY_NAME ${ENGINE_LIBRARY_NAME})
+ string(REPLACE "-l" "" ENGINE_LIBRARY_NAME ${ENGINE_LIBRARY_NAME})
+ set(ENGINE_LIBRARY_LISTING "${ENGINE_LIBRARY_LISTING} -L${ENGINE_LIBRARY_PATH} -l${ENGINE_LIBRARY_NAME}")
endforeach()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
@@ -432,11 +442,21 @@ COMMENT "Generating API documentation with Doxygen" VERBATIM
endif()
# prefix compilation with ccache by default if available and on clang or gcc
-if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
+if(ENABLE_CCACHE AND (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU"))
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
+ message(STATUS "Using ccache to speed up incremental builds")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
set(ENV{CCACHE_CPP2} "true")
endif()
endif()
+
+# uninstall target
+configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake"
+ IMMEDIATE @ONLY)
+
+add_custom_target(uninstall
+ COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
diff --git a/Doxyfile.in b/Doxyfile.in
index 5842f6b..dd51b16 100644
--- a/Doxyfile.in
+++ b/Doxyfile.in
@@ -18,6 +18,7 @@ RECURSIVE = YES
EXCLUDE = @CMAKE_CURRENT_SOURCE_DIR@/third_party \
@CMAKE_CURRENT_SOURCE_DIR@/build \
+ @CMAKE_CURRENT_SOURCE_DIR@/node_modules \
@CMAKE_CURRENT_SOURCE_DIR@/unit_tests \
@CMAKE_CURRENT_SOURCE_DIR@/benchmarks \
@CMAKE_CURRENT_SOURCE_DIR@/features
diff --git a/Gemfile b/Gemfile
deleted file mode 100644
index 31d044b..0000000
--- a/Gemfile
+++ /dev/null
@@ -1,7 +0,0 @@
-source "http://rubygems.org"
-
-gem "cucumber"
-gem "rake"
-gem "osmlib-base"
-gem "sys-proctable"
-gem "rspec-expectations"
diff --git a/Gemfile.lock b/Gemfile.lock
deleted file mode 100644
index 3363e92..0000000
--- a/Gemfile.lock
+++ /dev/null
@@ -1,35 +0,0 @@
-GEM
- remote: http://rubygems.org/
- specs:
- builder (3.2.2)
- cucumber (2.0.0)
- builder (>= 2.1.2)
- cucumber-core (~> 1.1.3)
- diff-lcs (>= 1.1.3)
- gherkin (~> 2.12)
- multi_json (>= 1.7.5, < 2.0)
- multi_test (>= 0.1.2)
- cucumber-core (1.1.3)
- gherkin (~> 2.12.0)
- diff-lcs (1.2.5)
- gherkin (2.12.2)
- multi_json (~> 1.3)
- multi_json (1.11.0)
- multi_test (0.1.2)
- osmlib-base (0.1.4)
- rake (10.4.2)
- rspec-expectations (3.2.1)
- diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.2.0)
- rspec-support (3.2.2)
- sys-proctable (0.9.8)
-
-PLATFORMS
- ruby
-
-DEPENDENCIES
- cucumber
- osmlib-base
- rake
- rspec-expectations
- sys-proctable
diff --git a/LICENCE.TXT b/LICENCE.TXT
index c77e5cd..143580e 100644
--- a/LICENCE.TXT
+++ b/LICENCE.TXT
@@ -1,4 +1,4 @@
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/Rakefile b/Rakefile
deleted file mode 100644
index 1c848bb..0000000
--- a/Rakefile
+++ /dev/null
@@ -1,190 +0,0 @@
-require 'OSM/StreamParser'
-require 'socket'
-require 'digest/sha1'
-require 'cucumber/rake/task'
-require 'sys/proctable'
-
-BUILD_FOLDER = 'build'
-DATA_FOLDER = 'sandbox'
-PROFILE = 'bicycle'
-OSRM_PORT = 5000
-PROFILES_FOLDER = '../profiles'
-
-Cucumber::Rake::Task.new do |t|
- t.cucumber_opts = %w{--format pretty}
-end
-
-areas = {
- :kbh => { :country => 'denmark', :bbox => 'top=55.6972 left=12.5222 right=12.624 bottom=55.6376' },
- :frd => { :country => 'denmark', :bbox => 'top=55.7007 left=12.4765 bottom=55.6576 right=12.5698' },
- :regh => { :country => 'denmark', :bbox => 'top=56.164 left=11.792 bottom=55.403 right=12.731' },
- :denmark => { :country => 'denmark', :bbox => nil },
- :skaane => { :country => 'sweden', :bbox => 'top=56.55 left=12.4 bottom=55.3 right=14.6' }
-}
-
-
-
-osm_data_area_name = ARGV[1] ? ARGV[1].to_s.to_sym : :kbh
-raise "Unknown data area." unless areas[osm_data_area_name]
-osm_data_country = areas[osm_data_area_name][:country]
-osm_data_area_bbox = areas[osm_data_area_name][:bbox]
-
-
-task osm_data_area_name.to_sym {} #define empty task to prevent rake from whining. will break if area has same name as a task
-
-
-def each_process name, &block
- Sys::ProcTable.ps do |process|
- if process.comm.strip == name.strip && process.state != 'zombie'
- yield process.pid.to_i, process.state.strip
- end
- end
-end
-
-def up?
- find_pid('osrm-routed') != nil
-end
-
-def find_pid name
- each_process(name) { |pid,state| return pid.to_i }
- return nil
-end
-
-def wait_for_shutdown name
- timeout = 10
- (timeout*10).times do
- return if find_pid(name) == nil
- sleep 0.1
- end
- raise "*** Could not terminate #{name}."
-end
-
-
-desc "Rebuild and run tests."
-task :default => [:build]
-
-desc "Build using CMake."
-task :build do
- if Dir.exists? BUILD_FOLDER
- Dir.chdir BUILD_FOLDER do
- system "make"
- end
- else
- system "mkdir build; cd build; cmake ..; make"
- end
-end
-
-desc "Setup config files."
-task :setup do
-end
-
-desc "Download OSM data."
-task :download do
- Dir.mkdir "#{DATA_FOLDER}" unless File.exist? "#{DATA_FOLDER}"
- puts "Downloading..."
- puts "curl http://download.geofabrik.de/europe/#{osm_data_country}-latest.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
- raise "Error while downloading data." unless system "curl http://download.geofabrik.de/europe/#{osm_data_country}-latest.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
- if osm_data_area_bbox
- puts "Cropping and converting to protobuffer..."
- raise "Error while cropping data." unless system "osmosis --read-pbf file=#{DATA_FOLDER}/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=#{DATA_FOLDER}/#{osm_data_area_name}.osm.pbf omitmetadata=true"
- end
-end
-
-desc "Crop OSM data"
-task :crop do
- if osm_data_area_bbox
- raise "Error while cropping data." unless system "osmosis --read-pbf file=#{DATA_FOLDER}/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=#{DATA_FOLDER}/#{osm_data_area_name}.osm.pbf omitmetadata=true"
- end
-end
-
-desc "Reprocess OSM data."
-task :process => [:extract,:prepare] do
-end
-
-desc "Extract OSM data."
-task :extract do
- Dir.chdir DATA_FOLDER do
- raise "Error while extracting data." unless system "../#{BUILD_FOLDER}/osrm-extract #{osm_data_area_name}.osm.pbf --profile ../profiles/#{PROFILE}.lua"
- end
-end
-
-desc "Prepare OSM data."
-task :prepare do
- Dir.chdir DATA_FOLDER do
- raise "Error while preparing data." unless system "../#{BUILD_FOLDER}/osrm-prepare #{osm_data_area_name}.osrm --profile ../profiles/#{PROFILE}.lua"
- end
-end
-
-desc "Delete preprocessing files."
-task :clean do
- File.delete *Dir.glob("#{DATA_FOLDER}/*.osrm")
- File.delete *Dir.glob("#{DATA_FOLDER}/*.osrm.*")
-end
-
-desc "Run all cucumber test"
-task :test do
- system "cucumber"
- puts
-end
-
-desc "Run the routing server in the terminal. Press Ctrl-C to stop."
-task :run do
- Dir.chdir DATA_FOLDER do
- system "../#{BUILD_FOLDER}/osrm-routed #{osm_data_area_name}.osrm --port #{OSRM_PORT}"
- end
-end
-
-desc "Launch the routing server in the background. Use rake:down to stop it."
-task :up do
- Dir.chdir DATA_FOLDER do
- abort("Already up.") if up?
- pipe = IO.popen("../#{BUILD_FOLDER}/osrm-routed #{osm_data_area_name}.osrm --port #{OSRM_PORT} 1>>osrm-routed.log 2>>osrm-routed.log")
- timeout = 5
- (timeout*10).times do
- begin
- socket = TCPSocket.new('localhost', OSRM_PORT)
- socket.puts 'ping'
- rescue Errno::ECONNREFUSED
- sleep 0.1
- end
- end
- end
-end
-
-desc "Stop the routing server."
-task :down do
- pid = find_pid 'osrm-routed'
- if pid
- Process.kill 'TERM', pid
- else
- puts "Already down."
- end
-end
-
-desc "Kill all osrm-extract, osrm-prepare and osrm-routed processes."
-task :kill do
- each_process('osrm-routed') { |pid,state| Process.kill 'KILL', pid }
- each_process('osrm-prepare') { |pid,state| Process.kill 'KILL', pid }
- each_process('osrm-extract') { |pid,state| Process.kill 'KILL', pid }
- wait_for_shutdown 'osrm-routed'
- wait_for_shutdown 'osrm-prepare'
- wait_for_shutdown 'osrm-extract'
-end
-
-desc "Get PIDs of all osrm-extract, osrm-prepare and osrm-routed processes."
-task :pid do
- each_process 'osrm-routed' do |pid,state|
- puts "#{pid}\t#{state}"
- end
-end
-
-desc "Stop, reprocess and restart."
-task :update => [:down,:process,:up] do
-end
-
-
-desc "Remove test cache files."
-task :sweep do
- system "rm test/cache/*"
-end
-
diff --git a/algorithms/bfs_components.hpp b/algorithms/bfs_components.hpp
deleted file mode 100644
index b3f5364..0000000
--- a/algorithms/bfs_components.hpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef BFS_COMPONENTS_HPP_
-#define BFS_COMPONENTS_HPP_
-
-#include "../typedefs.h"
-#include "../data_structures/restriction_map.hpp"
-
-#include <queue>
-#include <unordered_set>
-
-// Explores the components of the given graph while respecting turn restrictions
-// and barriers.
-template <typename GraphT> class BFSComponentExplorer
-{
- public:
- BFSComponentExplorer(const GraphT &dynamic_graph,
- const RestrictionMap &restrictions,
- const std::unordered_set<NodeID> &barrier_nodes)
- : m_graph(dynamic_graph), m_restriction_map(restrictions), m_barrier_nodes(barrier_nodes)
- {
- BOOST_ASSERT(m_graph.GetNumberOfNodes() > 0);
- }
-
- /*!
- * Returns the size of the component that the node belongs to.
- */
- unsigned int GetComponentSize(const NodeID node) const
- {
- BOOST_ASSERT(node < m_component_index_list.size());
-
- return m_component_index_size[m_component_index_list[node]];
- }
-
- unsigned int GetNumberOfComponents() { return m_component_index_size.size(); }
-
- /*!
- * Computes the component sizes.
- */
- void run()
- {
- std::queue<std::pair<NodeID, NodeID>> bfs_queue;
- unsigned current_component = 0;
-
- BOOST_ASSERT(m_component_index_list.empty());
- BOOST_ASSERT(m_component_index_size.empty());
-
- unsigned num_nodes = m_graph.GetNumberOfNodes();
-
- m_component_index_list.resize(num_nodes, std::numeric_limits<unsigned>::max());
-
- BOOST_ASSERT(num_nodes > 0);
-
- // put unexplorered node with parent pointer into queue
- for (NodeID node = 0; node < num_nodes; ++node)
- {
- if (std::numeric_limits<unsigned>::max() == m_component_index_list[node])
- {
- unsigned size = ExploreComponent(bfs_queue, node, current_component);
-
- // push size into vector
- m_component_index_size.emplace_back(size);
- ++current_component;
- }
- }
- }
-
- private:
- /*!
- * Explores the current component that starts at node using BFS.
- */
- unsigned ExploreComponent(std::queue<std::pair<NodeID, NodeID>> &bfs_queue,
- NodeID node,
- unsigned current_component)
- {
- /*
- Graphical representation of variables:
-
- u v w
- *---------->*---------->*
- e2
- */
-
- bfs_queue.emplace(node, node);
- // mark node as read
- m_component_index_list[node] = current_component;
-
- unsigned current_component_size = 1;
-
- while (!bfs_queue.empty())
- {
- // fetch element from BFS queue
- std::pair<NodeID, NodeID> current_queue_item = bfs_queue.front();
- bfs_queue.pop();
-
- const NodeID v = current_queue_item.first; // current node
- const NodeID u = current_queue_item.second; // parent
- // increment size counter of current component
- ++current_component_size;
- if (m_barrier_nodes.find(v) != m_barrier_nodes.end())
- {
- continue;
- }
- const NodeID to_node_of_only_restriction =
- m_restriction_map.CheckForEmanatingIsOnlyTurn(u, v);
-
- for (auto e2 : m_graph.GetAdjacentEdgeRange(v))
- {
- const NodeID w = m_graph.GetTarget(e2);
-
- if (to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
- w != to_node_of_only_restriction)
- {
- // At an only_-restriction but not at the right turn
- continue;
- }
-
- if (u != w)
- {
- // only add an edge if turn is not a U-turn except
- // when it is at the end of a dead-end street.
- if (!m_restriction_map.CheckIfTurnIsRestricted(u, v, w))
- {
- // only add an edge if turn is not prohibited
- if (std::numeric_limits<unsigned>::max() == m_component_index_list[w])
- {
- // insert next (node, parent) only if w has
- // not yet been explored
- // mark node as read
- m_component_index_list[w] = current_component;
- bfs_queue.emplace(w, v);
- }
- }
- }
- }
- }
-
- return current_component_size;
- }
-
- std::vector<unsigned> m_component_index_list;
- std::vector<NodeID> m_component_index_size;
-
- const GraphT &m_graph;
- const RestrictionMap &m_restriction_map;
- const std::unordered_set<NodeID> &m_barrier_nodes;
-};
-
-#endif // BFS_COMPONENTS_HPP_
diff --git a/algorithms/coordinate_calculation.cpp b/algorithms/coordinate_calculation.cpp
deleted file mode 100644
index ff7626e..0000000
--- a/algorithms/coordinate_calculation.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "coordinate_calculation.hpp"
-
-#include "../util/mercator.hpp"
-#include "../util/string_util.hpp"
-
-#include <boost/assert.hpp>
-
-#include <osrm/coordinate.hpp>
-
-#include <cmath>
-
-#include <limits>
-
-namespace
-{
-constexpr static const float RAD = 0.017453292519943295769236907684886f;
-// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
-// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
-constexpr static const float earth_radius = 6372797.560856f;
-}
-
-namespace coordinate_calculation
-{
-
-double haversine_distance(const int lat1,
- const int lon1,
- const int lat2,
- const int lon2)
-{
- BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
- BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
- BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
- BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
- const double lt1 = lat1 / COORDINATE_PRECISION;
- const double ln1 = lon1 / COORDINATE_PRECISION;
- const double lt2 = lat2 / COORDINATE_PRECISION;
- const double ln2 = lon2 / COORDINATE_PRECISION;
- const double dlat1 = lt1 * (RAD);
-
- const double dlong1 = ln1 * (RAD);
- const double dlat2 = lt2 * (RAD);
- const double dlong2 = ln2 * (RAD);
-
- const double dLong = dlong1 - dlong2;
- const double dLat = dlat1 - dlat2;
-
- const double aHarv = std::pow(std::sin(dLat / 2.0), 2.0) +
- std::cos(dlat1) * std::cos(dlat2) * std::pow(std::sin(dLong / 2.), 2);
- const double cHarv = 2. * std::atan2(std::sqrt(aHarv), std::sqrt(1.0 - aHarv));
- return earth_radius * cHarv;
-}
-
-double haversine_distance(const FixedPointCoordinate &coordinate_1,
- const FixedPointCoordinate &coordinate_2)
-{
- return haversine_distance(coordinate_1.lat, coordinate_1.lon, coordinate_2.lat,
- coordinate_2.lon);
-}
-
-float great_circle_distance(const FixedPointCoordinate &coordinate_1,
- const FixedPointCoordinate &coordinate_2)
-{
- return great_circle_distance(coordinate_1.lat, coordinate_1.lon, coordinate_2.lat,
- coordinate_2.lon);
-}
-
-float great_circle_distance(const int lat1,
- const int lon1,
- const int lat2,
- const int lon2)
-{
- BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
- BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
- BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
- BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
-
- const float float_lat1 = (lat1 / COORDINATE_PRECISION) * RAD;
- const float float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD;
- const float float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD;
- const float float_lon2 = (lon2 / COORDINATE_PRECISION) * RAD;
-
- const float x_value = (float_lon2 - float_lon1) * std::cos((float_lat1 + float_lat2) / 2.f);
- const float y_value = float_lat2 - float_lat1;
- return std::hypot(x_value, y_value) * earth_radius;
-}
-
-float perpendicular_distance(const FixedPointCoordinate &source_coordinate,
- const FixedPointCoordinate &target_coordinate,
- const FixedPointCoordinate &query_location)
-{
- float ratio;
- FixedPointCoordinate nearest_location;
-
- return perpendicular_distance(source_coordinate, target_coordinate, query_location,
- nearest_location, ratio);
-}
-
-float perpendicular_distance(const FixedPointCoordinate &segment_source,
- const FixedPointCoordinate &segment_target,
- const FixedPointCoordinate &query_location,
- FixedPointCoordinate &nearest_location,
- float &ratio)
-{
- return perpendicular_distance_from_projected_coordinate(
- segment_source, segment_target, query_location,
- {mercator::lat2y(query_location.lat / COORDINATE_PRECISION),
- query_location.lon / COORDINATE_PRECISION},
- nearest_location, ratio);
-}
-
-float perpendicular_distance_from_projected_coordinate(
- const FixedPointCoordinate &source_coordinate,
- const FixedPointCoordinate &target_coordinate,
- const FixedPointCoordinate &query_location,
- const std::pair<double, double> &projected_coordinate)
-{
- float ratio;
- FixedPointCoordinate nearest_location;
-
- return perpendicular_distance_from_projected_coordinate(source_coordinate, target_coordinate,
- query_location, projected_coordinate,
- nearest_location, ratio);
-}
-
-float perpendicular_distance_from_projected_coordinate(
- const FixedPointCoordinate &segment_source,
- const FixedPointCoordinate &segment_target,
- const FixedPointCoordinate &query_location,
- const std::pair<double, double> &projected_coordinate,
- FixedPointCoordinate &nearest_location,
- float &ratio)
-{
- BOOST_ASSERT(query_location.is_valid());
-
- // initialize values
- const double x = projected_coordinate.first;
- const double y = projected_coordinate.second;
- const double a = mercator::lat2y(segment_source.lat / COORDINATE_PRECISION);
- const double b = segment_source.lon / COORDINATE_PRECISION;
- const double c = mercator::lat2y(segment_target.lat / COORDINATE_PRECISION);
- const double d = segment_target.lon / COORDINATE_PRECISION;
- double p, q /*,mX*/, nY;
- if (std::abs(a - c) > std::numeric_limits<double>::epsilon())
- {
- const double m = (d - b) / (c - a); // slope
- // Projection of (x,y) on line joining (a,b) and (c,d)
- p = ((x + (m * y)) + (m * m * a - m * b)) / (1.f + m * m);
- q = b + m * (p - a);
- }
- else
- {
- p = c;
- q = y;
- }
- nY = (d * p - c * q) / (a * d - b * c);
-
- // discretize the result to coordinate precision. it's a hack!
- if (std::abs(nY) < (1.f / COORDINATE_PRECISION))
- {
- nY = 0.f;
- }
-
- // compute ratio
- ratio =
- static_cast<float>((p - nY * a) / c); // These values are actually n/m+n and m/m+n , we need
- // not calculate the explicit values of m an n as we
- // are just interested in the ratio
- if (std::isnan(ratio))
- {
- ratio = (segment_target == query_location ? 1.f : 0.f);
- }
- else if (std::abs(ratio) <= std::numeric_limits<float>::epsilon())
- {
- ratio = 0.f;
- }
- else if (std::abs(ratio - 1.f) <= std::numeric_limits<float>::epsilon())
- {
- ratio = 1.f;
- }
-
- // compute nearest location
- BOOST_ASSERT(!std::isnan(ratio));
- if (ratio <= 0.f)
- {
- nearest_location = segment_source;
- }
- else if (ratio >= 1.f)
- {
- nearest_location = segment_target;
- }
- else
- {
- // point lies in between
- nearest_location.lat = static_cast<int>(mercator::y2lat(p) * COORDINATE_PRECISION);
- nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
- }
- BOOST_ASSERT(nearest_location.is_valid());
-
- const float approximate_distance =
- great_circle_distance(query_location, nearest_location);
- BOOST_ASSERT(0.f <= approximate_distance);
- return approximate_distance;
-}
-
-void lat_or_lon_to_string(const int value, std::string &output)
-{
- char buffer[12];
- buffer[11] = 0; // zero termination
- output = printInt<11, 6>(buffer, value);
-}
-
-float deg_to_rad(const float degree)
-{
- return degree * (static_cast<float>(M_PI) / 180.f);
-}
-
-float rad_to_deg(const float radian)
-{
- return radian * (180.f * static_cast<float>(M_1_PI));
-}
-
-float bearing(const FixedPointCoordinate &first_coordinate,
- const FixedPointCoordinate &second_coordinate)
-{
- const float lon_diff =
- second_coordinate.lon / COORDINATE_PRECISION - first_coordinate.lon / COORDINATE_PRECISION;
- const float lon_delta = deg_to_rad(lon_diff);
- const float lat1 = deg_to_rad(first_coordinate.lat / COORDINATE_PRECISION);
- const float lat2 = deg_to_rad(second_coordinate.lat / COORDINATE_PRECISION);
- const float y = std::sin(lon_delta) * std::cos(lat2);
- const float x =
- std::cos(lat1) * std::sin(lat2) - std::sin(lat1) * std::cos(lat2) * std::cos(lon_delta);
- float result = rad_to_deg(std::atan2(y, x));
- while (result < 0.f)
- {
- result += 360.f;
- }
-
- while (result >= 360.f)
- {
- result -= 360.f;
- }
- return result;
-}
-
-}
diff --git a/algorithms/coordinate_calculation.hpp b/algorithms/coordinate_calculation.hpp
deleted file mode 100644
index 80ec7c2..0000000
--- a/algorithms/coordinate_calculation.hpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef COORDINATE_CALCULATION
-#define COORDINATE_CALCULATION
-
-struct FixedPointCoordinate;
-
-#include <string>
-#include <utility>
-
-namespace coordinate_calculation
-{
- double
- haversine_distance(const int lat1, const int lon1, const int lat2, const int lon2);
-
- double haversine_distance(const FixedPointCoordinate &first_coordinate,
- const FixedPointCoordinate &second_coordinate);
-
- float great_circle_distance(const FixedPointCoordinate &first_coordinate,
- const FixedPointCoordinate &second_coordinate);
-
- float great_circle_distance(const int lat1, const int lon1, const int lat2, const int lon2);
-
- void lat_or_lon_to_string(const int value, std::string &output);
-
- float perpendicular_distance(const FixedPointCoordinate &segment_source,
- const FixedPointCoordinate &segment_target,
- const FixedPointCoordinate &query_location);
-
- float perpendicular_distance(const FixedPointCoordinate &segment_source,
- const FixedPointCoordinate &segment_target,
- const FixedPointCoordinate &query_location,
- FixedPointCoordinate &nearest_location,
- float &ratio);
-
- float perpendicular_distance_from_projected_coordinate(
- const FixedPointCoordinate &segment_source,
- const FixedPointCoordinate &segment_target,
- const FixedPointCoordinate &query_location,
- const std::pair<double, double> &projected_coordinate);
-
- float perpendicular_distance_from_projected_coordinate(
- const FixedPointCoordinate &segment_source,
- const FixedPointCoordinate &segment_target,
- const FixedPointCoordinate &query_location,
- const std::pair<double, double> &projected_coordinate,
- FixedPointCoordinate &nearest_location,
- float &ratio);
-
- float deg_to_rad(const float degree);
- float rad_to_deg(const float radian);
-
- float bearing(const FixedPointCoordinate &first_coordinate,
- const FixedPointCoordinate &second_coordinate);
-}
-
-#endif // COORDINATE_CALCULATION
diff --git a/algorithms/douglas_peucker.cpp b/algorithms/douglas_peucker.cpp
deleted file mode 100644
index 280c90f..0000000
--- a/algorithms/douglas_peucker.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "douglas_peucker.hpp"
-
-#include "../data_structures/segment_information.hpp"
-
-#include <boost/assert.hpp>
-#include <osrm/coordinate.hpp>
-
-#include <cmath>
-#include <algorithm>
-#include <iterator>
-
-namespace
-{
-struct CoordinatePairCalculator
-{
- CoordinatePairCalculator() = delete;
- CoordinatePairCalculator(const FixedPointCoordinate &coordinate_a,
- const FixedPointCoordinate &coordinate_b)
- {
- // initialize distance calculator with two fixed coordinates a, b
- const float RAD = 0.017453292519943295769236907684886f;
- first_lat = (coordinate_a.lat / COORDINATE_PRECISION) * RAD;
- first_lon = (coordinate_a.lon / COORDINATE_PRECISION) * RAD;
- second_lat = (coordinate_b.lat / COORDINATE_PRECISION) * RAD;
- second_lon = (coordinate_b.lon / COORDINATE_PRECISION) * RAD;
- }
-
- int operator()(FixedPointCoordinate &other) const
- {
- // set third coordinate c
- const float RAD = 0.017453292519943295769236907684886f;
- const float earth_radius = 6372797.560856f;
- const float float_lat1 = (other.lat / COORDINATE_PRECISION) * RAD;
- const float float_lon1 = (other.lon / COORDINATE_PRECISION) * RAD;
-
- // compute distance (a,c)
- const float x_value_1 = (first_lon - float_lon1) * cos((float_lat1 + first_lat) / 2.f);
- const float y_value_1 = first_lat - float_lat1;
- const float dist1 = std::hypot(x_value_1, y_value_1) * earth_radius;
-
- // compute distance (b,c)
- const float x_value_2 = (second_lon - float_lon1) * cos((float_lat1 + second_lat) / 2.f);
- const float y_value_2 = second_lat - float_lat1;
- const float dist2 = std::hypot(x_value_2, y_value_2) * earth_radius;
-
- // return the minimum
- return static_cast<int>(std::min(dist1, dist2));
- }
-
- float first_lat;
- float first_lon;
- float second_lat;
- float second_lon;
-};
-}
-
-void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level)
-{
- Run(std::begin(input_geometry), std::end(input_geometry), zoom_level);
-}
-
-void DouglasPeucker::Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level)
-{
- const auto size = std::distance(begin, end);
- if (size < 2)
- {
- return;
- }
-
- begin->necessary = true;
- std::prev(end)->necessary = true;
-
- {
- BOOST_ASSERT_MSG(zoom_level < DOUGLAS_PEUCKER_THRESHOLDS.size(), "unsupported zoom level");
- auto left_border = begin;
- auto right_border = std::next(begin);
- // Sweep over array and identify those ranges that need to be checked
- do
- {
- // traverse list until new border element found
- if (right_border->necessary)
- {
- // sanity checks
- BOOST_ASSERT(left_border->necessary);
- BOOST_ASSERT(right_border->necessary);
- recursion_stack.emplace(left_border, right_border);
- left_border = right_border;
- }
- ++right_border;
- } while (right_border != end);
- }
-
- // mark locations as 'necessary' by divide-and-conquer
- while (!recursion_stack.empty())
- {
- // pop next element
- const GeometryRange pair = recursion_stack.top();
- recursion_stack.pop();
- // sanity checks
- BOOST_ASSERT_MSG(pair.first->necessary, "left border must be necessary");
- BOOST_ASSERT_MSG(pair.second->necessary, "right border must be necessary");
- BOOST_ASSERT_MSG(std::distance(pair.second, end) > 0, "right border outside of geometry");
- BOOST_ASSERT_MSG(std::distance(pair.first, pair.second) >= 0,
- "left border on the wrong side");
-
- int max_int_distance = 0;
- auto farthest_entry_it = pair.second;
- const CoordinatePairCalculator dist_calc(pair.first->location, pair.second->location);
-
- // sweep over range to find the maximum
- for (auto it = std::next(pair.first); it != pair.second; ++it)
- {
- const int distance = dist_calc(it->location);
- // found new feasible maximum?
- if (distance > max_int_distance && distance > DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
- {
- farthest_entry_it = it;
- max_int_distance = distance;
- }
- }
-
- // check if maximum violates a zoom level dependent threshold
- if (max_int_distance > DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
- {
- // mark idx as necessary
- farthest_entry_it->necessary = true;
- if (1 < std::distance(pair.first, farthest_entry_it))
- {
- recursion_stack.emplace(pair.first, farthest_entry_it);
- }
- if (1 < std::distance(farthest_entry_it, pair.second))
- {
- recursion_stack.emplace(farthest_entry_it, pair.second);
- }
- }
- }
-}
diff --git a/algorithms/douglas_peucker.hpp b/algorithms/douglas_peucker.hpp
deleted file mode 100644
index da02982..0000000
--- a/algorithms/douglas_peucker.hpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef DOUGLAS_PEUCKER_HPP_
-#define DOUGLAS_PEUCKER_HPP_
-
-#include "../data_structures/segment_information.hpp"
-
-#include <array>
-#include <stack>
-#include <utility>
-#include <vector>
-
-/* This class object computes the bitvector of indicating generalized input
- * points according to the (Ramer-)Douglas-Peucker algorithm.
- *
- * Input is vector of pairs. Each pair consists of the point information and a
- * bit indicating if the points is present in the generalization.
- * Note: points may also be pre-selected*/
-
-static const std::array<int, 19> DOUGLAS_PEUCKER_THRESHOLDS{{
- 512440, // z0
- 256720, // z1
- 122560, // z2
- 56780, // z3
- 28800, // z4
- 14400, // z5
- 7200, // z6
- 3200, // z7
- 2400, // z8
- 1000, // z9
- 600, // z10
- 120, // z11
- 60, // z12
- 45, // z13
- 36, // z14
- 20, // z15
- 8, // z16
- 6, // z17
- 4 // z18
-}};
-
-class DouglasPeucker
-{
- public:
- using RandomAccessIt = std::vector<SegmentInformation>::iterator;
-
- using GeometryRange = std::pair<RandomAccessIt, RandomAccessIt>;
- // Stack to simulate the recursion
- std::stack<GeometryRange> recursion_stack;
-
- public:
- void Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level);
- void Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level);
-};
-
-#endif /* DOUGLAS_PEUCKER_HPP_ */
diff --git a/algorithms/geospatial_query.hpp b/algorithms/geospatial_query.hpp
deleted file mode 100644
index 96b4fc5..0000000
--- a/algorithms/geospatial_query.hpp
+++ /dev/null
@@ -1,180 +0,0 @@
-#ifndef GEOSPATIAL_QUERY_HPP
-#define GEOSPATIAL_QUERY_HPP
-
-#include "coordinate_calculation.hpp"
-#include "../typedefs.h"
-#include "../data_structures/phantom_node.hpp"
-#include "../util/bearing.hpp"
-
-#include <osrm/coordinate.hpp>
-
-#include <vector>
-#include <memory>
-#include <algorithm>
-
-// Implements complex queries on top of an RTree and builds PhantomNodes from it.
-//
-// Only holds a weak reference on the RTree!
-template <typename RTreeT> class GeospatialQuery
-{
- using EdgeData = typename RTreeT::EdgeData;
- using CoordinateList = typename RTreeT::CoordinateList;
-
- public:
- GeospatialQuery(RTreeT &rtree_, std::shared_ptr<CoordinateList> coordinates_)
- : rtree(rtree_), coordinates(coordinates_)
- {
- }
-
- // Returns nearest PhantomNodes in the given bearing range within max_distance.
- // Does not filter by small/big component!
- std::vector<PhantomNodeWithDistance>
- NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate,
- const float max_distance,
- const int bearing = 0,
- const int bearing_range = 180)
- {
- auto results =
- rtree.Nearest(input_coordinate,
- [this, bearing, bearing_range, max_distance](const EdgeData &data)
- {
- return checkSegmentBearing(data, bearing, bearing_range);
- },
- [max_distance](const std::size_t, const float min_dist)
- {
- return min_dist > max_distance;
- });
-
- return MakePhantomNodes(input_coordinate, results);
- }
-
- // Returns max_results nearest PhantomNodes in the given bearing range.
- // Does not filter by small/big component!
- std::vector<PhantomNodeWithDistance>
- NearestPhantomNodes(const FixedPointCoordinate &input_coordinate,
- const unsigned max_results,
- const int bearing = 0,
- const int bearing_range = 180)
- {
- auto results = rtree.Nearest(input_coordinate,
- [this, bearing, bearing_range](const EdgeData &data)
- {
- return checkSegmentBearing(data, bearing, bearing_range);
- },
- [max_results](const std::size_t num_results, const float)
- {
- return num_results >= max_results;
- });
-
- return MakePhantomNodes(input_coordinate, results);
- }
-
- // Returns the nearest phantom node. If this phantom node is not from a big component
- // a second phantom node is return that is the nearest coordinate in a big component.
- std::pair<PhantomNode, PhantomNode>
- NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate,
- const int bearing = 0,
- const int bearing_range = 180)
- {
- bool has_small_component = false;
- bool has_big_component = false;
- auto results = rtree.Nearest(
- input_coordinate,
- [this, bearing, bearing_range, &has_big_component,
- &has_small_component](const EdgeData &data)
- {
- auto use_segment =
- (!has_small_component || (!has_big_component && !data.component.is_tiny));
- auto use_directions = std::make_pair(use_segment, use_segment);
-
- if (use_segment)
- {
- use_directions = checkSegmentBearing(data, bearing, bearing_range);
- if (use_directions.first || use_directions.second)
- {
- has_big_component = has_big_component || !data.component.is_tiny;
- has_small_component = has_small_component || data.component.is_tiny;
- }
- }
-
- return use_directions;
- },
- [&has_big_component](const std::size_t num_results, const float)
- {
- return num_results > 0 && has_big_component;
- });
-
- if (results.size() == 0)
- {
- return std::make_pair(PhantomNode{}, PhantomNode{});
- }
-
- BOOST_ASSERT(results.size() > 0);
- return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
- MakePhantomNode(input_coordinate, results.back()).phantom_node);
- }
-
- private:
- std::vector<PhantomNodeWithDistance>
- MakePhantomNodes(const FixedPointCoordinate &input_coordinate,
- const std::vector<EdgeData> &results) const
- {
- std::vector<PhantomNodeWithDistance> distance_and_phantoms(results.size());
- std::transform(results.begin(), results.end(), distance_and_phantoms.begin(),
- [this, &input_coordinate](const EdgeData &data)
- {
- return MakePhantomNode(input_coordinate, data);
- });
- return distance_and_phantoms;
- }
-
- PhantomNodeWithDistance MakePhantomNode(const FixedPointCoordinate &input_coordinate,
- const EdgeData &data) const
- {
- FixedPointCoordinate point_on_segment;
- float ratio;
- const auto current_perpendicular_distance = coordinate_calculation::perpendicular_distance(
- coordinates->at(data.u), coordinates->at(data.v), input_coordinate, point_on_segment,
- ratio);
-
- auto transformed =
- PhantomNodeWithDistance { PhantomNode{data, point_on_segment}, current_perpendicular_distance };
-
- ratio = std::min(1.f, std::max(0.f, ratio));
-
- if (SPECIAL_NODEID != transformed.phantom_node.forward_node_id)
- {
- transformed.phantom_node.forward_weight *= ratio;
- }
- if (SPECIAL_NODEID != transformed.phantom_node.reverse_node_id)
- {
- transformed.phantom_node.reverse_weight *= 1.f - ratio;
- }
- return transformed;
- }
-
- std::pair<bool, bool> checkSegmentBearing(const EdgeData &segment,
- const float filter_bearing,
- const float filter_bearing_range)
- {
- const float forward_edge_bearing =
- coordinate_calculation::bearing(coordinates->at(segment.u), coordinates->at(segment.v));
-
- const float backward_edge_bearing = (forward_edge_bearing + 180) > 360
- ? (forward_edge_bearing - 180)
- : (forward_edge_bearing + 180);
-
- const bool forward_bearing_valid =
- bearing::CheckInBounds(forward_edge_bearing, filter_bearing, filter_bearing_range) &&
- segment.forward_edge_based_node_id != SPECIAL_NODEID;
- const bool backward_bearing_valid =
- bearing::CheckInBounds(backward_edge_bearing, filter_bearing, filter_bearing_range) &&
- segment.reverse_edge_based_node_id != SPECIAL_NODEID;
- return std::make_pair(forward_bearing_valid, backward_bearing_valid);
- }
-
- RTreeT &rtree;
- const std::shared_ptr<CoordinateList> coordinates;
-};
-
-#endif
diff --git a/algorithms/graph_compressor.hpp b/algorithms/graph_compressor.hpp
deleted file mode 100644
index 8096a92..0000000
--- a/algorithms/graph_compressor.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-#ifndef GEOMETRY_COMPRESSOR_HPP
-#define GEOMETRY_COMPRESSOR_HPP
-
-#include "../typedefs.h"
-
-#include "../extractor/speed_profile.hpp"
-#include "../data_structures/node_based_graph.hpp"
-
-#include <memory>
-#include <unordered_set>
-
-class CompressedEdgeContainer;
-class RestrictionMap;
-
-class GraphCompressor
-{
- using EdgeData = NodeBasedDynamicGraph::EdgeData;
-
-public:
- GraphCompressor(SpeedProfileProperties speed_profile);
-
- void Compress(const std::unordered_set<NodeID>& barrier_nodes,
- const std::unordered_set<NodeID>& traffic_lights,
- RestrictionMap& restriction_map,
- NodeBasedDynamicGraph& graph,
- CompressedEdgeContainer& geometry_compressor);
-private:
-
- void PrintStatistics(unsigned original_number_of_nodes,
- unsigned original_number_of_edges,
- const NodeBasedDynamicGraph& graph) const;
-
- SpeedProfileProperties speed_profile;
-};
-
-#endif
diff --git a/algorithms/object_encoder.hpp b/algorithms/object_encoder.hpp
deleted file mode 100644
index 581b396..0000000
--- a/algorithms/object_encoder.hpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef OBJECT_ENCODER_HPP
-#define OBJECT_ENCODER_HPP
-
-#include <boost/assert.hpp>
-#include <boost/archive/iterators/base64_from_binary.hpp>
-#include <boost/archive/iterators/binary_from_base64.hpp>
-#include <boost/archive/iterators/transform_width.hpp>
-
-#include <algorithm>
-#include <iterator>
-#include <string>
-#include <vector>
-
-struct ObjectEncoder
-{
- using base64_t = boost::archive::iterators::base64_from_binary<
- boost::archive::iterators::transform_width<const char *, 6, 8>>;
-
- using binary_t = boost::archive::iterators::transform_width<
- boost::archive::iterators::binary_from_base64<std::string::const_iterator>,
- 8,
- 6>;
-
- template <class ObjectT> static void EncodeToBase64(const ObjectT &object, std::string &encoded)
- {
- const char *char_ptr_to_object = reinterpret_cast<const char *>(&object);
- std::vector<unsigned char> data(sizeof(object));
- std::copy(char_ptr_to_object, char_ptr_to_object + sizeof(ObjectT), data.begin());
-
- unsigned char number_of_padded_chars = 0; // is in {0,1,2};
- while (data.size() % 3 != 0)
- {
- ++number_of_padded_chars;
- data.push_back(0x00);
- }
-
- BOOST_ASSERT_MSG(0 == data.size() % 3, "base64 input data size is not a multiple of 3!");
- encoded.resize(sizeof(ObjectT));
- encoded.assign(base64_t(&data[0]),
- base64_t(&data[0] + (data.size() - number_of_padded_chars)));
- std::replace(begin(encoded), end(encoded), '+', '-');
- std::replace(begin(encoded), end(encoded), '/', '_');
- }
-
- template <class ObjectT> static void DecodeFromBase64(const std::string &input, ObjectT &object)
- {
- try
- {
- std::string encoded(input);
- std::replace(begin(encoded), end(encoded), '-', '+');
- std::replace(begin(encoded), end(encoded), '_', '/');
-
- std::copy(binary_t(encoded.begin()), binary_t(encoded.begin() + encoded.length()),
- reinterpret_cast<char *>(&object));
- }
- catch (...)
- {
- }
- }
-};
-
-#endif /* OBJECT_ENCODER_HPP */
diff --git a/algorithms/polyline_compressor.cpp b/algorithms/polyline_compressor.cpp
deleted file mode 100644
index 0db75dc..0000000
--- a/algorithms/polyline_compressor.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "polyline_compressor.hpp"
-#include "../data_structures/segment_information.hpp"
-
-#include <osrm/coordinate.hpp>
-
-std::string PolylineCompressor::encode_vector(std::vector<int> &numbers) const
-{
- std::string output;
- const auto end = numbers.size();
- for (std::size_t i = 0; i < end; ++i)
- {
- numbers[i] <<= 1;
- if (numbers[i] < 0)
- {
- numbers[i] = ~(numbers[i]);
- }
- }
- for (const int number : numbers)
- {
- output += encode_number(number);
- }
- return output;
-}
-
-std::string PolylineCompressor::encode_number(int number_to_encode) const
-{
- std::string output;
- while (number_to_encode >= 0x20)
- {
- const int next_value = (0x20 | (number_to_encode & 0x1f)) + 63;
- output += static_cast<char>(next_value);
- number_to_encode >>= 5;
- }
-
- number_to_encode += 63;
- output += static_cast<char>(number_to_encode);
- return output;
-}
-
-std::string
-PolylineCompressor::get_encoded_string(const std::vector<SegmentInformation> &polyline) const
-{
- if (polyline.empty())
- {
- return {};
- }
-
- std::vector<int> delta_numbers;
- delta_numbers.reserve((polyline.size() - 1) * 2);
- FixedPointCoordinate previous_coordinate = {0, 0};
- for (const auto &segment : polyline)
- {
- if (segment.necessary)
- {
- const int lat_diff = segment.location.lat - previous_coordinate.lat;
- const int lon_diff = segment.location.lon - previous_coordinate.lon;
- delta_numbers.emplace_back(lat_diff);
- delta_numbers.emplace_back(lon_diff);
- previous_coordinate = segment.location;
- }
- }
- return encode_vector(delta_numbers);
-}
-
-std::vector<FixedPointCoordinate> PolylineCompressor::decode_string(const std::string &geometry_string) const
-{
- std::vector<FixedPointCoordinate> new_coordinates;
- int index = 0, len = geometry_string.size();
- int lat = 0, lng = 0;
-
- while (index < len)
- {
- int b, shift = 0, result = 0;
- do
- {
- b = geometry_string.at(index++) - 63;
- result |= (b & 0x1f) << shift;
- shift += 5;
- } while (b >= 0x20);
- int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
- lat += dlat;
-
- shift = 0;
- result = 0;
- do
- {
- b = geometry_string.at(index++) - 63;
- result |= (b & 0x1f) << shift;
- shift += 5;
- } while (b >= 0x20);
- int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
- lng += dlng;
-
- FixedPointCoordinate p;
- p.lat = COORDINATE_PRECISION * (((double) lat / 1E6));
- p.lon = COORDINATE_PRECISION * (((double) lng / 1E6));
- new_coordinates.push_back(p);
- }
-
- return new_coordinates;
-}
diff --git a/algorithms/polyline_compressor.hpp b/algorithms/polyline_compressor.hpp
deleted file mode 100644
index a148200..0000000
--- a/algorithms/polyline_compressor.hpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef POLYLINECOMPRESSOR_H_
-#define POLYLINECOMPRESSOR_H_
-
-struct SegmentInformation;
-
-#include <osrm/coordinate.hpp>
-
-#include <string>
-#include <vector>
-
-class PolylineCompressor
-{
- private:
- std::string encode_vector(std::vector<int> &numbers) const;
-
- std::string encode_number(const int number_to_encode) const;
-
- public:
- std::string get_encoded_string(const std::vector<SegmentInformation> &polyline) const;
-
- std::vector<FixedPointCoordinate> decode_string(const std::string &geometry_string) const;
-};
-
-#endif /* POLYLINECOMPRESSOR_H_ */
diff --git a/algorithms/polyline_formatter.cpp b/algorithms/polyline_formatter.cpp
deleted file mode 100644
index 670a612..0000000
--- a/algorithms/polyline_formatter.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "polyline_formatter.hpp"
-
-#include "polyline_compressor.hpp"
-#include "../data_structures/segment_information.hpp"
-
-#include <osrm/coordinate.hpp>
-
-osrm::json::String
-PolylineFormatter::printEncodedString(const std::vector<SegmentInformation> &polyline) const
-{
- return osrm::json::String(PolylineCompressor().get_encoded_string(polyline));
-}
-
-osrm::json::Array
-PolylineFormatter::printUnencodedString(const std::vector<SegmentInformation> &polyline) const
-{
- osrm::json::Array json_geometry_array;
- for (const auto &segment : polyline)
- {
- if (segment.necessary)
- {
- osrm::json::Array json_coordinate;
- json_coordinate.values.push_back(segment.location.lat / COORDINATE_PRECISION);
- json_coordinate.values.push_back(segment.location.lon / COORDINATE_PRECISION);
- json_geometry_array.values.push_back(json_coordinate);
- }
- }
- return json_geometry_array;
-}
diff --git a/algorithms/route_name_extraction.hpp b/algorithms/route_name_extraction.hpp
deleted file mode 100644
index 00dae89..0000000
--- a/algorithms/route_name_extraction.hpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef EXTRACT_ROUTE_NAMES_H
-#define EXTRACT_ROUTE_NAMES_H
-
-#include <boost/assert.hpp>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-struct RouteNames
-{
- std::string shortest_path_name_1;
- std::string shortest_path_name_2;
- std::string alternative_path_name_1;
- std::string alternative_path_name_2;
-};
-
-// construct routes names
-template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
-{
- private:
- SegmentT PickNextLongestSegment(const std::vector<SegmentT> &segment_list,
- const unsigned blocked_name_id) const
- {
- SegmentT result_segment;
- result_segment.length = 0;
-
- for (const SegmentT &segment : segment_list)
- {
- if (segment.name_id != blocked_name_id && segment.length > result_segment.length &&
- segment.name_id != 0)
- {
- result_segment = segment;
- }
- }
- return result_segment;
- }
-
- public:
- RouteNames operator()(std::vector<SegmentT> &shortest_path_segments,
- std::vector<SegmentT> &alternative_path_segments,
- const DataFacadeT *facade) const
- {
- RouteNames route_names;
-
- SegmentT shortest_segment_1, shortest_segment_2;
- SegmentT alternative_segment_1, alternative_segment_2;
-
- auto length_comperator = [](const SegmentT &a, const SegmentT &b)
- {
- return a.length > b.length;
- };
- auto name_id_comperator = [](const SegmentT &a, const SegmentT &b)
- {
- return a.name_id < b.name_id;
- };
-
- if (shortest_path_segments.empty())
- {
- return route_names;
- }
-
- // pick the longest segment for the shortest path.
- std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), length_comperator);
- shortest_segment_1 = shortest_path_segments[0];
- if (!alternative_path_segments.empty())
- {
- std::sort(alternative_path_segments.begin(), alternative_path_segments.end(),
- length_comperator);
-
- // also pick the longest segment for the alternative path
- alternative_segment_1 = alternative_path_segments[0];
- }
-
- // compute the set difference (for shortest path) depending on names between shortest and
- // alternative
- std::vector<SegmentT> shortest_path_set_difference(shortest_path_segments.size());
- std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), name_id_comperator);
- std::sort(alternative_path_segments.begin(), alternative_path_segments.end(),
- name_id_comperator);
- std::set_difference(shortest_path_segments.begin(), shortest_path_segments.end(),
- alternative_path_segments.begin(), alternative_path_segments.end(),
- shortest_path_set_difference.begin(), name_id_comperator);
-
- std::sort(shortest_path_set_difference.begin(), shortest_path_set_difference.end(),
- length_comperator);
- shortest_segment_2 =
- PickNextLongestSegment(shortest_path_set_difference, shortest_segment_1.name_id);
-
- // compute the set difference (for alternative path) depending on names between shortest and
- // alternative
- // vectors are still sorted, no need to do again
- BOOST_ASSERT(std::is_sorted(shortest_path_segments.begin(), shortest_path_segments.end(),
- name_id_comperator));
- BOOST_ASSERT(std::is_sorted(alternative_path_segments.begin(),
- alternative_path_segments.end(), name_id_comperator));
-
- std::vector<SegmentT> alternative_path_set_difference(alternative_path_segments.size());
- std::set_difference(alternative_path_segments.begin(), alternative_path_segments.end(),
- shortest_path_segments.begin(), shortest_path_segments.end(),
- alternative_path_set_difference.begin(), name_id_comperator);
-
- std::sort(alternative_path_set_difference.begin(), alternative_path_set_difference.end(),
- length_comperator);
-
- if (!alternative_path_segments.empty())
- {
- alternative_segment_2 = PickNextLongestSegment(alternative_path_set_difference,
- alternative_segment_1.name_id);
- }
-
- // move the segments into the order in which they occur.
- if (shortest_segment_1.position > shortest_segment_2.position)
- {
- std::swap(shortest_segment_1, shortest_segment_2);
- }
- if (alternative_segment_1.position > alternative_segment_2.position)
- {
- std::swap(alternative_segment_1, alternative_segment_2);
- }
-
- // fetching names for the selected segments
- route_names.shortest_path_name_1 = facade->get_name_for_id(shortest_segment_1.name_id);
- route_names.shortest_path_name_2 = facade->get_name_for_id(shortest_segment_2.name_id);
-
- route_names.alternative_path_name_1 =
- facade->get_name_for_id(alternative_segment_1.name_id);
- route_names.alternative_path_name_2 =
- facade->get_name_for_id(alternative_segment_2.name_id);
-
- return route_names;
- }
-};
-
-#endif // EXTRACT_ROUTE_NAMES_H
diff --git a/appveyor-build.bat b/appveyor-build.bat
index a1e9603..568998b 100644
--- a/appveyor-build.bat
+++ b/appveyor-build.bat
@@ -8,16 +8,39 @@ SET PROJECT_DIR=%CD%
ECHO PROJECT_DIR^: %PROJECT_DIR%
ECHO NUMBER_OF_PROCESSORS^: %NUMBER_OF_PROCESSORS%
ECHO cmake^: && cmake --version
+IF %ERRORLEVEL% NEQ 0 ECHO CMAKE not found GOTO ERROR
+
+FOR /F %%G IN ("--version") DO cmake %%G 2>&1 | findstr /C:"3.5.0" > nul && goto CMAKE_NOT_OK
+GOTO CMAKE_OK
+
+:CMAKE_NOT_OK
+ECHO CMAKE NOT OK - downloading new CMake
+IF NOT EXIST cm.zip powershell Invoke-WebRequest https://cmake.org/files/v3.5/cmake-3.5.1-win32-x86.zip -OutFile $env:PROJECT_DIR\cm.zip
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+IF NOT EXIST cmake-3.5.1-win32-x86 7z -y x cm.zip | %windir%\system32\FIND "ing archive"
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+SET PATH=%PROJECT_DIR%\cmake-3.5.1-win32-x86\bin;%PATH%
+
+:CMAKE_OK
+ECHO CMAKE_OK
+cmake --version
ECHO activating VS command prompt ...
SET PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH%
CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
ECHO platform^: %platform%
+
+ECHO cl.exe version
+cl
+ECHO msbuild version
+msbuild /version
+
:: HARDCODE "x64" as it is uppercase on AppVeyor and download from S3 is case sensitive
SET DEPSPKG=osrm-deps-win-x64-14.0.7z
:: local development
+ECHO.
ECHO LOCAL_DEV^: %LOCAL_DEV%
IF NOT DEFINED LOCAL_DEV SET LOCAL_DEV=0
IF DEFINED LOCAL_DEV IF %LOCAL_DEV% EQU 1 IF EXIST %DEPSPKG% ECHO skipping deps download && GOTO SKIPDL
@@ -33,27 +56,39 @@ IF %ERRORLEVEL% NEQ 0 GOTO ERROR
IF EXIST osrm-deps ECHO deleting osrm-deps... && RD /S /Q osrm-deps
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-IF EXIST build ECHO deletings build dir... && RD /S /Q build
+IF EXIST build ECHO deleting build dir... && RD /S /Q build
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
7z -y x %DEPSPKG% | %windir%\system32\FIND "ing archive"
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+::tree osrm-deps
+
MKDIR build
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
cd build
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-SET OSRMDEPSDIR=%PROJECT_DIR%\osrm-deps
+SET OSRMDEPSDIR=%PROJECT_DIR%/osrm-deps
set PREFIX=%OSRMDEPSDIR%/libs
set BOOST_ROOT=%OSRMDEPSDIR%/boost
+set BOOST_LIBRARYDIR=%BOOST_ROOT%/lib
set TBB_INSTALL_DIR=%OSRMDEPSDIR%/tbb
set TBB_ARCH_PLATFORM=intel64/vc14
+ECHO OSRMDEPSDIR ^: %OSRMDEPSDIR%
+ECHO PREFIX ^: %PREFIX%
+ECHO BOOST_ROOT ^: %BOOST_ROOT%
+ECHO BOOST_LIBRARYDIR ^: %BOOST_LIBRARYDIR%
+ECHO TBB_INSTALL_DIR ^: %TBB_INSTALL_DIR%
+ECHO TBB_ARCH_PLATFORM ^: %TBB_ARCH_PLATFORM%
+
+
ECHO calling cmake ....
cmake .. ^
-G "Visual Studio 14 2015 Win64" ^
-DBOOST_ROOT=%BOOST_ROOT% ^
+-DBOOST_LIBRARYDIR=%BOOST_LIBRARYDIR% ^
-DBoost_ADDITIONAL_VERSIONS=1.58 ^
-DBoost_USE_MULTITHREADED=ON ^
-DBoost_USE_STATIC_LIBS=ON ^
@@ -81,11 +116,14 @@ IF %ERRORLEVEL% NEQ 0 GOTO ERROR
SET PATH=%PROJECT_DIR%\osrm-deps\libs\bin;%PATH%
-ECHO running datastructure-tests.exe ...
-%Configuration%\datastructure-tests.exe
+ECHO running engine-tests.exe ...
+%Configuration%\engine-tests.exe
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+ECHO running extractor-tests.exe ...
+%Configuration%\extractor-tests.exe
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-ECHO running algorithm-tests.exe ...
-%Configuration%\algorithm-tests.exe
+ECHO running util-tests.exe ...
+%Configuration%\util-tests.exe
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
IF NOT "%APPVEYOR_REPO_BRANCH%"=="develop" GOTO DONE
diff --git a/appveyor.yml b/appveyor.yml
index b8fb979..b7e09ef 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -25,6 +25,11 @@ artifacts:
# - path: osrm_Debug.zip
# name: osrm_Debug.zip
+branches:
+ only:
+ - master
+ - develop
+
deploy:
provider: FTP
server:
@@ -36,9 +41,3 @@ deploy:
folder: /
enable_ssl: true
active_mode: false
-
-# notifications:
-# - provider: HipChat
-# auth_token:
-# secure: boLE7BjcahdIUxv9jkN7U3F8iOASF+MkhtctlVoWJoo=
-# room: Directions
diff --git a/benchmarks/static_rtree.cpp b/benchmarks/static_rtree.cpp
deleted file mode 100644
index ebe055c..0000000
--- a/benchmarks/static_rtree.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "../data_structures/query_node.hpp"
-#include "../data_structures/static_rtree.hpp"
-#include "../data_structures/edge_based_node.hpp"
-#include "../algorithms/geospatial_query.hpp"
-#include "../util/timing_util.hpp"
-
-#include <osrm/coordinate.hpp>
-
-#include <random>
-#include <iostream>
-
-// Choosen by a fair W20 dice roll (this value is completely arbitrary)
-constexpr unsigned RANDOM_SEED = 13;
-constexpr int32_t WORLD_MIN_LAT = -90 * COORDINATE_PRECISION;
-constexpr int32_t WORLD_MAX_LAT = 90 * COORDINATE_PRECISION;
-constexpr int32_t WORLD_MIN_LON = -180 * COORDINATE_PRECISION;
-constexpr int32_t WORLD_MAX_LON = 180 * COORDINATE_PRECISION;
-
-using RTreeLeaf = EdgeBasedNode;
-using FixedPointCoordinateListPtr = std::shared_ptr<std::vector<FixedPointCoordinate>>;
-using BenchStaticRTree = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>;
-using BenchQuery = GeospatialQuery<BenchStaticRTree>;
-
-FixedPointCoordinateListPtr LoadCoordinates(const boost::filesystem::path &nodes_file)
-{
- boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
-
- QueryNode current_node;
- unsigned coordinate_count = 0;
- nodes_input_stream.read((char *)&coordinate_count, sizeof(unsigned));
- auto coords = std::make_shared<std::vector<FixedPointCoordinate>>(coordinate_count);
- for (unsigned i = 0; i < coordinate_count; ++i)
- {
- nodes_input_stream.read((char *)¤t_node, sizeof(QueryNode));
- coords->at(i) = FixedPointCoordinate(current_node.lat, current_node.lon);
- BOOST_ASSERT((std::abs(coords->at(i).lat) >> 30) == 0);
- BOOST_ASSERT((std::abs(coords->at(i).lon) >> 30) == 0);
- }
- nodes_input_stream.close();
- return coords;
-}
-
-template <typename QueryT>
-void BenchmarkQuery(const std::vector<FixedPointCoordinate> &queries,
- const std::string& name,
- QueryT query)
-{
- std::cout << "Running " << name << " with " << queries.size() << " coordinates: " << std::flush;
-
- TIMER_START(query);
- for (const auto &q : queries)
- {
- auto result = query(q);
- }
- TIMER_STOP(query);
-
- std::cout << "Took " << TIMER_SEC(query) << " seconds "
- << "(" << TIMER_MSEC(query) << "ms"
- << ") -> " << TIMER_MSEC(query) / queries.size() << " ms/query "
- << "(" << TIMER_MSEC(query) << "ms"
- << ")" << std::endl;
-}
-
-void Benchmark(BenchStaticRTree &rtree, BenchQuery &geo_query, unsigned num_queries)
-{
- std::mt19937 mt_rand(RANDOM_SEED);
- std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
- std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
- std::vector<FixedPointCoordinate> queries;
- for (unsigned i = 0; i < num_queries; i++)
- {
- queries.emplace_back(lat_udist(mt_rand), lon_udist(mt_rand));
- }
-
- BenchmarkQuery(queries, "raw RTree queries (1 result)", [&rtree](const FixedPointCoordinate &q)
- {
- return rtree.Nearest(q, 1);
- });
- BenchmarkQuery(queries, "raw RTree queries (10 results)",
- [&rtree](const FixedPointCoordinate &q)
- {
- return rtree.Nearest(q, 10);
- });
-
- BenchmarkQuery(queries, "big component alternative queries",
- [&geo_query](const FixedPointCoordinate &q)
- {
- return geo_query.NearestPhantomNodeWithAlternativeFromBigComponent(q);
- });
- BenchmarkQuery(queries, "max distance 1000", [&geo_query](const FixedPointCoordinate &q)
- {
- return geo_query.NearestPhantomNodesInRange(q, 1000);
- });
- BenchmarkQuery(queries, "PhantomNode query (1 result)", [&geo_query](const FixedPointCoordinate &q)
- {
- return geo_query.NearestPhantomNodes(q, 1);
- });
- BenchmarkQuery(queries, "PhantomNode query (10 result)", [&geo_query](const FixedPointCoordinate &q)
- {
- return geo_query.NearestPhantomNodes(q, 10);
- });
-}
-
-int main(int argc, char **argv)
-{
- if (argc < 4)
- {
- std::cout << "./rtree-bench file.ramIndex file.fileIndx file.nodes"
- << "\n";
- return 1;
- }
-
- const char *ramPath = argv[1];
- const char *filePath = argv[2];
- const char *nodesPath = argv[3];
-
- auto coords = LoadCoordinates(nodesPath);
-
- BenchStaticRTree rtree(ramPath, filePath, coords);
- BenchQuery query(rtree, coords);
-
- Benchmark(rtree, query, 10000);
-
- return 0;
-}
diff --git a/build-local.bat b/build-local.bat
index b26c415..a90c0aa 100644
--- a/build-local.bat
+++ b/build-local.bat
@@ -11,7 +11,8 @@ SET CONFIGURATION=Release
FOR /F "tokens=*" %%i in ('git rev-parse --abbrev-ref HEAD') do SET APPVEYOR_REPO_BRANCH=%%i
ECHO APPVEYOR_REPO_BRANCH^: %APPVEYOR_REPO_BRANCH%
-SET PATH=C:\mb\windows-builds-64\tmp-bin\cmake-3.4.0-win32-x86\bin;%PATH%
+::SET PATH=C:\mb\windows-builds-64\tmp-bin\cmake-3.5.0-win32-x86\bin;%PATH%
+SET PATH=C:\mb\windows-builds-64\tmp-bin\cmake-3.5.1-win32-x86\bin;%PATH%
SET PATH=C:\Program Files\7-Zip;%PATH%
powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted -Force
diff --git a/cmake/CPackDebianConfig.cmake b/cmake/CPackDebianConfig.cmake
index bd434ee..13216dd 100644
--- a/cmake/CPackDebianConfig.cmake
+++ b/cmake/CPackDebianConfig.cmake
@@ -7,15 +7,13 @@ INCLUDE(FindDebArch)
SET(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md")
SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENCE.TXT")
SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CPACK_RESOURCE_FILE_README}")
-SET(CPACK_PACKAGE_VERSION_MAJOR "0")
-SET(CPACK_PACKAGE_VERSION_MINOR "4")
-SET(CPACK_PACKAGE_VERSION_PATCH "3")
-
-SET(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+SET(CPACK_PACKAGE_UPSTREAM_VERSION "${OSRM_VERSION_MAJOR}.${OSRM_VERSION_MINOR}.${OSRM_VERSION_PATCH}")
+SET(CPACK_PACKAGE_DEBIAN_REVISION "1")
+SET(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_UPSTREAM_VERSION}-${CPACK_PACKAGE_DEBIAN_REVISION}")
string(TOLOWER "${CMAKE_PROJECT_NAME}" LOWER_PROJECT_NAME)
SET(CPACK_PACKAGE_FILE_NAME "${LOWER_PROJECT_NAME}_${CPACK_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
-SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${LOWER_PROJECT_NAME}_${CPACK_PACKAGE_VERSION}_orig")
+SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${LOWER_PROJECT_NAME}_${CPACK_PACKAGE_UPSTREAM_VERSION}_orig")
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Open Source Routing Machine (OSRM).")
SET(CPACK_PACKAGE_DESCRIPTION "Open Source Routing Machine (OSRM) is a routing engine.")
@@ -27,7 +25,7 @@ SET(CPACK_INCLUDE_TOPLEVEL_DIRECTORY "FALSE")
SET(CPACK_GENERATOR "DEB")
SET(CPACK_DEBIAN_PACKAGE_NAME "${CPACK_PACKAGE_NAME}${VERSION_SUFFIX}")
-SET(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}${CPACK_PACKAGE_REVISION}")
+SET(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}")
SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Dennis Luxen <info at project-osrm.org>")
SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
SET(CPACK_DEBIAN_PACKAGE_SECTION "devel")
@@ -38,7 +36,6 @@ SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6-dev, libbz2-1.0, libstxxl1, libxml2,
file(GLOB_RECURSE ProfileGlob ${CMAKE_SOURCE_DIR}/profiles/*)
install(FILES ${ProfileGlob} DESTINATION "share/doc/${LOWER_PROJECT_NAME}/profiles")
-CONFIGURE_FILE (${CMAKE_SOURCE_DIR}/cmake/postinst.in postinst)
-set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_BINARY_DIR}/postinst;${CMAKE_CURRENT_BINARY_DIR}/copyright;")
+set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_BINARY_DIR}/copyright;")
MESSAGE(STATUS "Debian Package: ${CPACK_DEBIAN_PACKAGE_NAME} (${CPACK_DEBIAN_PACKAGE_VERSION}) [${CPACK_PACKAGE_FILE_NAME}.deb]")
diff --git a/cmake/FindLua52.cmake b/cmake/FindLua52.cmake
index d17fbf6..4aeaf94 100644
--- a/cmake/FindLua52.cmake
+++ b/cmake/FindLua52.cmake
@@ -14,7 +14,7 @@
#=============================================================================
# Copyright 2007-2009 Kitware, Inc.
-# Copyright 2013 for Project-OSRM, Lua5.1 => Lua5.2
+# Copyright 2016 for Project-OSRM, Lua5.1 => Lua5.2
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
diff --git a/cmake/FindSTXXL.cmake b/cmake/FindSTXXL.cmake
index 76a2722..473fb6a 100644
--- a/cmake/FindSTXXL.cmake
+++ b/cmake/FindSTXXL.cmake
@@ -24,7 +24,7 @@ FIND_PATH(STXXL_INCLUDE_DIR stxxl.h
)
FIND_LIBRARY(STXXL_LIBRARY
- NAMES stxxl
+ NAMES stxxl stxxl_debug
HINTS
$ENV{STXXL_DIR}
PATH_SUFFIXES lib64 lib
diff --git a/cmake/FingerPrint-Config.cmake b/cmake/FingerPrint-Config.cmake
index d36b622..0672b34 100644
--- a/cmake/FingerPrint-Config.cmake
+++ b/cmake/FingerPrint-Config.cmake
@@ -1,10 +1,10 @@
-set(OLDFILE ${OUTPUT_DIR}/util/fingerprint_impl.hpp)
+set(OLDFILE ${OUTPUT_DIR}/include/util/fingerprint_impl.hpp)
set(NEWFILE ${OLDFILE}.tmp)
-set(INFILE ${SOURCE_DIR}/util/fingerprint_impl.hpp.in)
-file(MD5 ${SOURCE_DIR}/prepare.cpp MD5PREPARE)
-file(MD5 ${SOURCE_DIR}/data_structures/static_rtree.hpp MD5RTREE)
-file(MD5 ${SOURCE_DIR}/util/graph_loader.hpp MD5GRAPH)
-file(MD5 ${SOURCE_DIR}/server/data_structures/internal_datafacade.hpp MD5OBJECTS)
+set(INFILE ${SOURCE_DIR}/include/util/fingerprint_impl.hpp.in)
+file(MD5 ${SOURCE_DIR}/src/tools/contract.cpp MD5PREPARE)
+file(MD5 ${SOURCE_DIR}/include/util/static_rtree.hpp MD5RTREE)
+file(MD5 ${SOURCE_DIR}/include/util/graph_loader.hpp MD5GRAPH)
+file(MD5 ${SOURCE_DIR}/include/engine/datafacade/internal_datafacade.hpp MD5OBJECTS)
CONFIGURE_FILE(${INFILE} ${NEWFILE})
diff --git a/cmake/cmake_options_script.py b/cmake/cmake_options_script.py
index 52e943e..8d30604 100644
--- a/cmake/cmake_options_script.py
+++ b/cmake/cmake_options_script.py
@@ -32,13 +32,11 @@ cache_file = "%s/cached_options.txt" % (scriptpath)
db = None
if os.access(cache_file, os.R_OK) == 0:
db = load_db(sys.argv[1])
- f = open(cache_file, "wb")
- pickle.dump(db, f)
- f.close()
+ with open(cache_file, "wb") as f:
+ pickle.dump(db, f)
else:
- f = open(cache_file)
- db = pickle.load(f)
- f.close()
+ with open(cache_file) as f:
+ db = pickle.load(f)
if db and sys.argv[2] in db:
for option in db[sys.argv[2]]:
diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in
new file mode 100644
index 0000000..2037e36
--- /dev/null
+++ b/cmake/cmake_uninstall.cmake.in
@@ -0,0 +1,21 @@
+if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+ message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+string(REGEX REPLACE "\n" ";" files "${files}")
+foreach(file ${files})
+ message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
+ if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+ exec_program(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ if(NOT "${rm_retval}" STREQUAL 0)
+ message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
+ endif(NOT "${rm_retval}" STREQUAL 0)
+ else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+ message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
+ endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+endforeach(file)
diff --git a/cmake/pkgconfig.in b/cmake/pkgconfig.in
index 16263bf..92fe403 100644
--- a/cmake/pkgconfig.in
+++ b/cmake/pkgconfig.in
@@ -1,11 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
-includedir=${prefix}/include
+includedir=${prefix}/include ${prefix}/include/osrm
libdir=${prefix}/lib
Name: libOSRM
Description: Project OSRM library
Version: v at OSRM_VERSION_MAJOR@. at OSRM_VERSION_MINOR@. at OSRM_VERSION_PATCH@
Requires:
-Libs: -L${libdir} -lOSRM
-Libs.private: @BOOST_LIBRARY_LISTING@ @TBB_LIBRARY_LISTING@
+Libs: -L${libdir} -losrm
+Libs.private: @ENGINE_LIBRARY_LISTING@
Cflags: -I${includedir}
diff --git a/cmake/postinst.in b/cmake/postinst.in
deleted file mode 100644
index 92f2fde..0000000
--- a/cmake/postinst.in
+++ /dev/null
@@ -1,2 +0,0 @@
-#/usr/bin/env bash
-ln -s /usr/share/doc/@CMAKE_PROJECT_NAME@/profiles/car.lua @CMAKE_INSTALL_PREFIX@/profile.lua
diff --git a/config/cucumber.yml b/config/cucumber.yml
deleted file mode 100644
index 2cdea36..0000000
--- a/config/cucumber.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-# config/cucumber.yml
-##YAML Template
----
-default: --require features --tags ~@todo --tags ~@bug --tag ~@stress
-verify: --require features --tags ~@todo --tags ~@bug --tags ~@stress -f progress
-jenkins: --require features --tags ~@todo --tags ~@bug --tags ~@stress --tags ~@options -f progress
-bugs: --require features --tags @bug
-todo: --require features --tags @todo
-all: --require features
diff --git a/contractor/contractor_options.cpp b/contractor/contractor_options.cpp
deleted file mode 100644
index d483465..0000000
--- a/contractor/contractor_options.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "contractor_options.hpp"
-
-#include "util/version.hpp"
-#include "../util/simple_logger.hpp"
-
-#include <boost/filesystem.hpp>
-#include <boost/program_options.hpp>
-
-#include <tbb/task_scheduler_init.h>
-
-return_code
-ContractorOptions::ParseArguments(int argc, char *argv[], ContractorConfig &contractor_config)
-{
- // declare a group of options that will be allowed only on command line
- boost::program_options::options_description generic_options("Options");
- generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
- "config,c", boost::program_options::value<boost::filesystem::path>(&contractor_config.config_file_path)
- ->default_value("contractor.ini"),
- "Path to a configuration file.");
-
- // declare a group of options that will be allowed both on command line and in config file
- boost::program_options::options_description config_options("Configuration");
- config_options.add_options()(
- "profile,p",
- boost::program_options::value<boost::filesystem::path>(&contractor_config.profile_path)
- ->default_value("profile.lua"),
- "Path to LUA routing profile")(
- "threads,t",
- boost::program_options::value<unsigned int>(&contractor_config.requested_num_threads)
- ->default_value(tbb::task_scheduler_init::default_num_threads()),
- "Number of threads to use")(
- "core,k", boost::program_options::value<double>(&contractor_config.core_factor)
- ->default_value(1.0),"Percentage of the graph (in vertices) to contract [0..1]")(
- "segment-speed-file", boost::program_options::value<std::string>(&contractor_config.segment_speed_lookup_path),
- "Lookup file containing nodeA,nodeB,speed data to adjust edge weights")(
- "level-cache,o",
- boost::program_options::value<bool>(&contractor_config.use_cached_priority)->default_value(false),
- "Use .level file to retain the contaction level for each node from the last run.");
-
-#ifdef DEBUG_GEOMETRY
- config_options.add_options()(
- "debug-geometry", boost::program_options::value<std::string>(&contractor_config.debug_geometry_path)
- ,"Write out edge-weight debugging geometry data in GeoJSON format to this file");
-#endif
-
- // hidden options, will be allowed both on command line and in config file, but will not be
- // shown to the user
- boost::program_options::options_description hidden_options("Hidden options");
- hidden_options.add_options()(
- "input,i", boost::program_options::value<boost::filesystem::path>(&contractor_config.osrm_input_path),
- "Input file in .osm, .osm.bz2 or .osm.pbf format");
-
- // positional option
- boost::program_options::positional_options_description positional_options;
- positional_options.add("input", 1);
-
- // combine above options for parsing
- boost::program_options::options_description cmdline_options;
- cmdline_options.add(generic_options).add(config_options).add(hidden_options);
-
- boost::program_options::options_description config_file_options;
- config_file_options.add(config_options).add(hidden_options);
-
- boost::program_options::options_description visible_options(
- "Usage: " + boost::filesystem::basename(argv[0]) + " <input.osrm> [options]");
- visible_options.add(generic_options).add(config_options);
-
- // parse command line options
- boost::program_options::variables_map option_variables;
- boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
- .options(cmdline_options)
- .positional(positional_options)
- .run(),
- option_variables);
-
- const auto &temp_config_path = option_variables["config"].as<boost::filesystem::path>();
- if (boost::filesystem::is_regular_file(temp_config_path))
- {
- boost::program_options::store(boost::program_options::parse_config_file<char>(
- temp_config_path.string().c_str(), cmdline_options, true),
- option_variables);
- }
-
- if (option_variables.count("version"))
- {
- SimpleLogger().Write() << OSRM_VERSION;
- return return_code::exit;
- }
-
- if (option_variables.count("help"))
- {
- SimpleLogger().Write() << "\n" << visible_options;
- return return_code::exit;
- }
-
- boost::program_options::notify(option_variables);
-
- if (!option_variables.count("input"))
- {
- SimpleLogger().Write() << "\n" << visible_options;
- return return_code::fail;
- }
-
- return return_code::ok;
-}
-
-void ContractorOptions::GenerateOutputFilesNames(ContractorConfig &contractor_config)
-{
- contractor_config.level_output_path = contractor_config.osrm_input_path.string() + ".level";
- contractor_config.core_output_path = contractor_config.osrm_input_path.string() + ".core";
- contractor_config.graph_output_path = contractor_config.osrm_input_path.string() + ".hsgr";
- contractor_config.edge_based_graph_path = contractor_config.osrm_input_path.string() + ".ebg";
- contractor_config.edge_segment_lookup_path = contractor_config.osrm_input_path.string() + ".edge_segment_lookup";
- contractor_config.edge_penalty_path = contractor_config.osrm_input_path.string() + ".edge_penalties";
-}
diff --git a/contractor/processing_chain.cpp b/contractor/processing_chain.cpp
deleted file mode 100644
index 2bd5350..0000000
--- a/contractor/processing_chain.cpp
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "processing_chain.hpp"
-#include "contractor.hpp"
-
-#include "contractor.hpp"
-
-#include "../data_structures/deallocating_vector.hpp"
-
-#include "../algorithms/crc32_processor.hpp"
-#include "../util/graph_loader.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/lua_util.hpp"
-#include "../util/osrm_exception.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/string_util.hpp"
-#include "../util/timing_util.hpp"
-#include "../typedefs.h"
-
-#include <fast-cpp-csv-parser/csv.h>
-
-#include <boost/filesystem/fstream.hpp>
-#include <boost/program_options.hpp>
-
-#include <tbb/parallel_sort.h>
-
-#include <chrono>
-#include <memory>
-#include <string>
-#include <thread>
-#include <vector>
-
-#include "../util/debug_geometry.hpp"
-
-Prepare::~Prepare() {}
-
-int Prepare::Run()
-{
-#ifdef WIN32
-#pragma message("Memory consumption on Windows can be higher due to different bit packing")
-#else
- static_assert(sizeof(NodeBasedEdge) == 20,
- "changing NodeBasedEdge type has influence on memory consumption!");
- static_assert(sizeof(EdgeBasedEdge) == 16,
- "changing EdgeBasedEdge type has influence on memory consumption!");
-#endif
-
- if (config.core_factor > 1.0 || config.core_factor < 0)
- {
- throw osrm::exception("Core factor must be between 0.0 to 1.0 (inclusive)");
- }
-
- TIMER_START(preparing);
-
- // Create a new lua state
-
- SimpleLogger().Write() << "Loading edge-expanded graph representation";
-
- DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
-
- size_t max_edge_id = LoadEdgeExpandedGraph(
- config.edge_based_graph_path, edge_based_edge_list, config.edge_segment_lookup_path,
- config.edge_penalty_path, config.segment_speed_lookup_path);
-
- // Contracting the edge-expanded graph
-
- TIMER_START(contraction);
- std::vector<bool> is_core_node;
- std::vector<float> node_levels;
- if (config.use_cached_priority)
- {
- ReadNodeLevels(node_levels);
- }
- DeallocatingVector<QueryEdge> contracted_edge_list;
- ContractGraph(max_edge_id, edge_based_edge_list, contracted_edge_list, is_core_node,
- node_levels);
- TIMER_STOP(contraction);
-
- SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
-
- std::size_t number_of_used_edges = WriteContractedGraph(max_edge_id, contracted_edge_list);
- WriteCoreNodeMarker(std::move(is_core_node));
- if (!config.use_cached_priority)
- {
- WriteNodeLevels(std::move(node_levels));
- }
-
- TIMER_STOP(preparing);
-
- SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
- SimpleLogger().Write() << "Contraction: " << ((max_edge_id + 1) / TIMER_SEC(contraction))
- << " nodes/sec and " << number_of_used_edges / TIMER_SEC(contraction)
- << " edges/sec";
-
- SimpleLogger().Write() << "finished preprocessing";
-
- return 0;
-}
-
-namespace std
-{
-
-template <> struct hash<std::pair<OSMNodeID, OSMNodeID>>
-{
- std::size_t operator()(const std::pair<OSMNodeID, OSMNodeID> &k) const
- {
- return OSMNodeID_to_uint64_t(k.first) ^ (OSMNodeID_to_uint64_t(k.second) << 12);
- }
-};
-}
-
-std::size_t Prepare::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
- DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
- const std::string &edge_segment_lookup_filename,
- const std::string &edge_penalty_filename,
- const std::string &segment_speed_filename)
-{
- SimpleLogger().Write() << "Opening " << edge_based_graph_filename;
- boost::filesystem::ifstream input_stream(edge_based_graph_filename, std::ios::binary);
-
- const bool update_edge_weights = segment_speed_filename != "";
-
- boost::filesystem::ifstream edge_segment_input_stream;
- boost::filesystem::ifstream edge_fixed_penalties_input_stream;
-
- if (update_edge_weights)
- {
- edge_segment_input_stream.open(edge_segment_lookup_filename, std::ios::binary);
- edge_fixed_penalties_input_stream.open(edge_penalty_filename, std::ios::binary);
- if (!edge_segment_input_stream || !edge_fixed_penalties_input_stream)
- {
- throw osrm::exception("Could not load .edge_segment_lookup or .edge_penalties, did you "
- "run osrm-extract with '--generate-edge-lookup'?");
- }
- }
-
- const FingerPrint fingerprint_valid = FingerPrint::GetValid();
- FingerPrint fingerprint_loaded;
- input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
- fingerprint_loaded.TestPrepare(fingerprint_valid);
-
- size_t number_of_edges = 0;
- size_t max_edge_id = SPECIAL_EDGEID;
- input_stream.read((char *)&number_of_edges, sizeof(size_t));
- input_stream.read((char *)&max_edge_id, sizeof(size_t));
-
- edge_based_edge_list.resize(number_of_edges);
- SimpleLogger().Write() << "Reading " << number_of_edges << " edges from the edge based graph";
-
- std::unordered_map<std::pair<OSMNodeID, OSMNodeID>, unsigned> segment_speed_lookup;
-
- if (update_edge_weights)
- {
- SimpleLogger().Write() << "Segment speed data supplied, will update edge weights from "
- << segment_speed_filename;
- io::CSVReader<3> csv_in(segment_speed_filename);
- csv_in.set_header("from_node", "to_node", "speed");
- uint64_t from_node_id;
- uint64_t to_node_id;
- unsigned speed;
- while (csv_in.read_row(from_node_id, to_node_id, speed))
- {
- segment_speed_lookup[std::make_pair(OSMNodeID(from_node_id), OSMNodeID(to_node_id))] = speed;
- }
- }
-
- DEBUG_GEOMETRY_START(config);
-
- // TODO: can we read this in bulk? DeallocatingVector isn't necessarily
- // all stored contiguously
- for (; number_of_edges > 0; --number_of_edges)
- {
- EdgeBasedEdge inbuffer;
- input_stream.read((char *) &inbuffer, sizeof(EdgeBasedEdge));
-
- if (update_edge_weights)
- {
- // Processing-time edge updates
- unsigned fixed_penalty;
- edge_fixed_penalties_input_stream.read(reinterpret_cast<char *>(&fixed_penalty),
- sizeof(fixed_penalty));
-
- int new_weight = 0;
-
- unsigned num_osm_nodes = 0;
- edge_segment_input_stream.read(reinterpret_cast<char *>(&num_osm_nodes),
- sizeof(num_osm_nodes));
- OSMNodeID previous_osm_node_id;
- edge_segment_input_stream.read(reinterpret_cast<char *>(&previous_osm_node_id),
- sizeof(previous_osm_node_id));
- OSMNodeID this_osm_node_id;
- double segment_length;
- int segment_weight;
- --num_osm_nodes;
- for (; num_osm_nodes != 0; --num_osm_nodes)
- {
- edge_segment_input_stream.read(reinterpret_cast<char *>(&this_osm_node_id),
- sizeof(this_osm_node_id));
- edge_segment_input_stream.read(reinterpret_cast<char *>(&segment_length),
- sizeof(segment_length));
- edge_segment_input_stream.read(reinterpret_cast<char *>(&segment_weight),
- sizeof(segment_weight));
-
- auto speed_iter = segment_speed_lookup.find(
- std::make_pair(previous_osm_node_id, this_osm_node_id));
- if (speed_iter != segment_speed_lookup.end())
- {
- // This sets the segment weight using the same formula as the
- // EdgeBasedGraphFactory for consistency. The *why* of this formula
- // is lost in the annals of time.
- int new_segment_weight =
- std::max(1, static_cast<int>(std::floor(
- (segment_length * 10.) / (speed_iter->second / 3.6) + .5)));
- new_weight += new_segment_weight;
-
- DEBUG_GEOMETRY_EDGE(
- new_segment_weight,
- segment_length,
- previous_osm_node_id,
- this_osm_node_id);
- }
- else
- {
- // If no lookup found, use the original weight value for this segment
- new_weight += segment_weight;
-
- DEBUG_GEOMETRY_EDGE(
- segment_weight,
- segment_length,
- previous_osm_node_id,
- this_osm_node_id);
- }
-
- previous_osm_node_id = this_osm_node_id;
- }
-
- inbuffer.weight = fixed_penalty + new_weight;
- }
-
- edge_based_edge_list.emplace_back(std::move(inbuffer));
- }
-
- DEBUG_GEOMETRY_STOP();
- SimpleLogger().Write() << "Done reading edges";
- return max_edge_id;
-}
-
-void Prepare::ReadNodeLevels(std::vector<float> &node_levels) const
-{
- boost::filesystem::ifstream order_input_stream(config.level_output_path, std::ios::binary);
-
- unsigned level_size;
- order_input_stream.read((char *)&level_size, sizeof(unsigned));
- node_levels.resize(level_size);
- order_input_stream.read((char *)node_levels.data(), sizeof(float) * node_levels.size());
-}
-
-void Prepare::WriteNodeLevels(std::vector<float> &&in_node_levels) const
-{
- std::vector<float> node_levels(std::move(in_node_levels));
-
- boost::filesystem::ofstream order_output_stream(config.level_output_path, std::ios::binary);
-
- unsigned level_size = node_levels.size();
- order_output_stream.write((char *)&level_size, sizeof(unsigned));
- order_output_stream.write((char *)node_levels.data(), sizeof(float) * node_levels.size());
-}
-
-void Prepare::WriteCoreNodeMarker(std::vector<bool> &&in_is_core_node) const
-{
- std::vector<bool> is_core_node(std::move(in_is_core_node));
- std::vector<char> unpacked_bool_flags(std::move(is_core_node.size()));
- for (auto i = 0u; i < is_core_node.size(); ++i)
- {
- unpacked_bool_flags[i] = is_core_node[i] ? 1 : 0;
- }
-
- boost::filesystem::ofstream core_marker_output_stream(config.core_output_path,
- std::ios::binary);
- unsigned size = unpacked_bool_flags.size();
- core_marker_output_stream.write((char *)&size, sizeof(unsigned));
- core_marker_output_stream.write((char *)unpacked_bool_flags.data(),
- sizeof(char) * unpacked_bool_flags.size());
-}
-
-std::size_t Prepare::WriteContractedGraph(unsigned max_node_id,
- const DeallocatingVector<QueryEdge> &contracted_edge_list)
-{
- // Sorting contracted edges in a way that the static query graph can read some in in-place.
- tbb::parallel_sort(contracted_edge_list.begin(), contracted_edge_list.end());
- const unsigned contracted_edge_count = contracted_edge_list.size();
- SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
- << " edges";
-
- const FingerPrint fingerprint = FingerPrint::GetValid();
- boost::filesystem::ofstream hsgr_output_stream(config.graph_output_path, std::ios::binary);
- hsgr_output_stream.write((char *)&fingerprint, sizeof(FingerPrint));
- const unsigned max_used_node_id = [&contracted_edge_list]
- {
- unsigned tmp_max = 0;
- for (const QueryEdge &edge : contracted_edge_list)
- {
- BOOST_ASSERT(SPECIAL_NODEID != edge.source);
- BOOST_ASSERT(SPECIAL_NODEID != edge.target);
- tmp_max = std::max(tmp_max, edge.source);
- tmp_max = std::max(tmp_max, edge.target);
- }
- return tmp_max;
- }();
-
- SimpleLogger().Write(logDEBUG) << "input graph has " << (max_node_id + 1) << " nodes";
- SimpleLogger().Write(logDEBUG) << "contracted graph has " << (max_used_node_id + 1) << " nodes";
-
- std::vector<StaticGraph<EdgeData>::NodeArrayEntry> node_array;
- // make sure we have at least one sentinel
- node_array.resize(max_node_id + 2);
-
- SimpleLogger().Write() << "Building node array";
- StaticGraph<EdgeData>::EdgeIterator edge = 0;
- StaticGraph<EdgeData>::EdgeIterator position = 0;
- StaticGraph<EdgeData>::EdgeIterator last_edge;
-
- // initializing 'first_edge'-field of nodes:
- for (const auto node : osrm::irange(0u, max_used_node_id + 1))
- {
- last_edge = edge;
- while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node))
- {
- ++edge;
- }
- node_array[node].first_edge = position; //=edge
- position += edge - last_edge; // remove
- }
-
- for (const auto sentinel_counter :
- osrm::irange<unsigned>(max_used_node_id + 1, node_array.size()))
- {
- // sentinel element, guarded against underflow
- node_array[sentinel_counter].first_edge = contracted_edge_count;
- }
-
- SimpleLogger().Write() << "Serializing node array";
-
- RangebasedCRC32 crc32_calculator;
- const unsigned edges_crc32 = crc32_calculator(contracted_edge_list);
- SimpleLogger().Write() << "Writing CRC32: " << edges_crc32;
-
- const unsigned node_array_size = node_array.size();
- // serialize crc32, aka checksum
- hsgr_output_stream.write((char *)&edges_crc32, sizeof(unsigned));
- // serialize number of nodes
- hsgr_output_stream.write((char *)&node_array_size, sizeof(unsigned));
- // serialize number of edges
- hsgr_output_stream.write((char *)&contracted_edge_count, sizeof(unsigned));
- // serialize all nodes
- if (node_array_size > 0)
- {
- hsgr_output_stream.write((char *)&node_array[0],
- sizeof(StaticGraph<EdgeData>::NodeArrayEntry) * node_array_size);
- }
-
- // serialize all edges
- SimpleLogger().Write() << "Building edge array";
- int number_of_used_edges = 0;
-
- StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
- for (const auto edge : osrm::irange<std::size_t>(0, contracted_edge_list.size()))
- {
- // no eigen loops
- BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target);
- current_edge.target = contracted_edge_list[edge].target;
- current_edge.data = contracted_edge_list[edge].data;
-
- // every target needs to be valid
- BOOST_ASSERT(current_edge.target <= max_used_node_id);
-#ifndef NDEBUG
- if (current_edge.data.distance <= 0)
- {
- SimpleLogger().Write(logWARNING) << "Edge: " << edge
- << ",source: " << contracted_edge_list[edge].source
- << ", target: " << contracted_edge_list[edge].target
- << ", dist: " << current_edge.data.distance;
-
- SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node "
- << contracted_edge_list[edge].source << "/"
- << node_array.size() - 1;
- return 1;
- }
-#endif
- hsgr_output_stream.write((char *)¤t_edge,
- sizeof(StaticGraph<EdgeData>::EdgeArrayEntry));
-
- ++number_of_used_edges;
- }
-
- return number_of_used_edges;
-}
-
-/**
- \brief Build contracted graph.
- */
-void Prepare::ContractGraph(const unsigned max_edge_id,
- DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
- DeallocatingVector<QueryEdge> &contracted_edge_list,
- std::vector<bool> &is_core_node,
- std::vector<float> &inout_node_levels) const
-{
- std::vector<float> node_levels;
- node_levels.swap(inout_node_levels);
-
- Contractor contractor(max_edge_id + 1, edge_based_edge_list, std::move(node_levels));
- contractor.Run(config.core_factor);
- contractor.GetEdges(contracted_edge_list);
- contractor.GetCoreMarker(is_core_node);
- contractor.GetNodeLevels(inout_node_levels);
-}
diff --git a/contractor/processing_chain.hpp b/contractor/processing_chain.hpp
deleted file mode 100644
index 0eb6555..0000000
--- a/contractor/processing_chain.hpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef PROCESSING_CHAIN_HPP
-#define PROCESSING_CHAIN_HPP
-
-#include "contractor.hpp"
-#include "contractor_options.hpp"
-#include "../data_structures/query_edge.hpp"
-#include "../data_structures/static_graph.hpp"
-#include "../data_structures/deallocating_vector.hpp"
-#include "../data_structures/node_based_graph.hpp"
-
-struct SpeedProfileProperties;
-struct EdgeBasedNode;
-struct lua_State;
-
-#include <boost/filesystem.hpp>
-
-#include <vector>
-
-/**
- \brief class of 'prepare' utility.
- */
-class Prepare
-{
- public:
- using EdgeData = QueryEdge::EdgeData;
-
- explicit Prepare(ContractorConfig contractor_config) : config(std::move(contractor_config)) {}
- Prepare(const Prepare &) = delete;
- ~Prepare();
-
- int Run();
-
- protected:
- void ContractGraph(const unsigned max_edge_id,
- DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
- DeallocatingVector<QueryEdge> &contracted_edge_list,
- std::vector<bool> &is_core_node,
- std::vector<float> &node_levels) const;
- void WriteCoreNodeMarker(std::vector<bool> &&is_core_node) const;
- void WriteNodeLevels(std::vector<float> &&node_levels) const;
- void ReadNodeLevels(std::vector<float> &contraction_order) const;
- std::size_t WriteContractedGraph(unsigned number_of_edge_based_nodes,
- const DeallocatingVector<QueryEdge> &contracted_edge_list);
- void FindComponents(unsigned max_edge_id,
- const DeallocatingVector<EdgeBasedEdge> &edges,
- std::vector<EdgeBasedNode> &nodes) const;
-
- private:
- ContractorConfig config;
- std::size_t LoadEdgeExpandedGraph(const std::string &edge_based_graph_path,
- DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
- const std::string &edge_segment_lookup_path,
- const std::string &edge_penalty_path,
- const std::string &segment_speed_path);
-};
-
-#endif // PROCESSING_CHAIN_HPP
diff --git a/cucumber.js b/cucumber.js
new file mode 100644
index 0000000..c16104c
--- /dev/null
+++ b/cucumber.js
@@ -0,0 +1,11 @@
+module.exports = {
+ default: '--require features --tags ~@todo --tags ~@bug --tags ~@stress --tags ~@guidance',
+ verify: '--require features --tags ~@todo --tags ~@bug --tags ~@stress -f progress --tags ~@guidance',
+ jenkins: '--require features --tags ~@todo --tags ~@bug --tags ~@stress --tags ~@options -f progress',
+ bugs: '--require features --tags @bug',
+ todo: '--require features --tags @todo',
+ all: '--require features'
+}
+
+
+
diff --git a/data_structures/compressed_edge_container.hpp b/data_structures/compressed_edge_container.hpp
deleted file mode 100644
index 5d94ee6..0000000
--- a/data_structures/compressed_edge_container.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef GEOMETRY_COMPRESSOR_HPP_
-#define GEOMETRY_COMPRESSOR_HPP_
-
-#include "../typedefs.h"
-
-#include <unordered_map>
-
-#include <string>
-#include <vector>
-
-class CompressedEdgeContainer
-{
- public:
- using CompressedNode = std::pair<NodeID, EdgeWeight>;
- using EdgeBucket = std::vector<CompressedNode>;
-
- CompressedEdgeContainer();
- void CompressEdge(const EdgeID surviving_edge_id,
- const EdgeID removed_edge_id,
- const NodeID via_node_id,
- const NodeID target_node,
- const EdgeWeight weight1,
- const EdgeWeight weight2);
-
- bool HasEntryForID(const EdgeID edge_id) const;
- void PrintStatistics() const;
- void SerializeInternalVector(const std::string &path) const;
- unsigned GetPositionForID(const EdgeID edge_id) const;
- const EdgeBucket& GetBucketReference(const EdgeID edge_id) const;
- NodeID GetFirstEdgeTargetID(const EdgeID edge_id) const;
- NodeID GetLastEdgeSourceID(const EdgeID edge_id) const;
-
- private:
- int free_list_maximum = 0;
-
- void IncreaseFreeList();
- std::vector<EdgeBucket> m_compressed_geometries;
- std::vector<unsigned> m_free_list;
- std::unordered_map<EdgeID, unsigned> m_edge_id_to_list_index_map;
-};
-
-#endif // GEOMETRY_COMPRESSOR_HPP_
diff --git a/data_structures/coordinate.cpp b/data_structures/coordinate.cpp
deleted file mode 100644
index 208f3eb..0000000
--- a/data_structures/coordinate.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "../algorithms/coordinate_calculation.hpp"
-
-#ifndef NDEBUG
-#include "../util/simple_logger.hpp"
-#endif
-#include <osrm/coordinate.hpp>
-
-#ifndef NDEBUG
-#include <bitset>
-#endif
-#include <iostream>
-#include <limits>
-
-FixedPointCoordinate::FixedPointCoordinate()
- : lat(std::numeric_limits<int>::min()), lon(std::numeric_limits<int>::min())
-{
-}
-
-FixedPointCoordinate::FixedPointCoordinate(int lat, int lon) : lat(lat), lon(lon)
-{
-#ifndef NDEBUG
- if (0 != (std::abs(lat) >> 30))
- {
- std::bitset<32> y_coordinate_vector(lat);
- SimpleLogger().Write(logDEBUG) << "broken lat: " << lat
- << ", bits: " << y_coordinate_vector;
- }
- if (0 != (std::abs(lon) >> 30))
- {
- std::bitset<32> x_coordinate_vector(lon);
- SimpleLogger().Write(logDEBUG) << "broken lon: " << lon
- << ", bits: " << x_coordinate_vector;
- }
-#endif
-}
-
-bool FixedPointCoordinate::is_valid() const
-{
- if (lat > 90 * COORDINATE_PRECISION || lat < -90 * COORDINATE_PRECISION ||
- lon > 180 * COORDINATE_PRECISION || lon < -180 * COORDINATE_PRECISION)
- {
- return false;
- }
- return true;
-}
-
-bool FixedPointCoordinate::operator==(const FixedPointCoordinate &other) const
-{
- return lat == other.lat && lon == other.lon;
-}
-
-void FixedPointCoordinate::output(std::ostream &out) const
-{
- out << "(" << lat / COORDINATE_PRECISION << "," << lon / COORDINATE_PRECISION << ")";
-}
-
-float FixedPointCoordinate::bearing(const FixedPointCoordinate &other) const
-{
- return coordinate_calculation::bearing(other, *this);
-}
diff --git a/data_structures/edge_based_node.hpp b/data_structures/edge_based_node.hpp
deleted file mode 100644
index 8efbf01..0000000
--- a/data_structures/edge_based_node.hpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef EDGE_BASED_NODE_HPP
-#define EDGE_BASED_NODE_HPP
-
-#include "../data_structures/travel_mode.hpp"
-#include "../typedefs.h"
-
-#include <boost/assert.hpp>
-
-#include <osrm/coordinate.hpp>
-
-#include <limits>
-
-/// This is what StaticRTree serialized and stores on disk
-/// It is generated in EdgeBasedGraphFactory.
-struct EdgeBasedNode
-{
- EdgeBasedNode()
- : forward_edge_based_node_id(SPECIAL_NODEID), reverse_edge_based_node_id(SPECIAL_NODEID),
- u(SPECIAL_NODEID), v(SPECIAL_NODEID), name_id(0),
- forward_weight(INVALID_EDGE_WEIGHT >> 1), reverse_weight(INVALID_EDGE_WEIGHT >> 1),
- forward_offset(0), reverse_offset(0), packed_geometry_id(SPECIAL_EDGEID),
- component{INVALID_COMPONENTID, false}, fwd_segment_position(std::numeric_limits<unsigned short>::max()),
- forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
- backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
- {
- }
-
- explicit EdgeBasedNode(NodeID forward_edge_based_node_id,
- NodeID reverse_edge_based_node_id,
- NodeID u,
- NodeID v,
- unsigned name_id,
- int forward_weight,
- int reverse_weight,
- int forward_offset,
- int reverse_offset,
- unsigned packed_geometry_id,
- bool is_tiny_component,
- unsigned component_id,
- unsigned short fwd_segment_position,
- TravelMode forward_travel_mode,
- TravelMode backward_travel_mode)
- : forward_edge_based_node_id(forward_edge_based_node_id),
- reverse_edge_based_node_id(reverse_edge_based_node_id), u(u), v(v), name_id(name_id),
- forward_weight(forward_weight), reverse_weight(reverse_weight),
- forward_offset(forward_offset), reverse_offset(reverse_offset),
- packed_geometry_id(packed_geometry_id), component{component_id, is_tiny_component},
- fwd_segment_position(fwd_segment_position), forward_travel_mode(forward_travel_mode),
- backward_travel_mode(backward_travel_mode)
- {
- BOOST_ASSERT((forward_edge_based_node_id != SPECIAL_NODEID) ||
- (reverse_edge_based_node_id != SPECIAL_NODEID));
- }
-
- static inline FixedPointCoordinate Centroid(const FixedPointCoordinate &a,
- const FixedPointCoordinate &b)
- {
- FixedPointCoordinate centroid;
- // The coordinates of the midpoint are given by:
- centroid.lat = (a.lat + b.lat) / 2;
- centroid.lon = (a.lon + b.lon) / 2;
- return centroid;
- }
-
- bool IsCompressed() const { return packed_geometry_id != SPECIAL_EDGEID; }
-
- NodeID forward_edge_based_node_id; // needed for edge-expanded graph
- NodeID reverse_edge_based_node_id; // needed for edge-expanded graph
- NodeID u; // indices into the coordinates array
- NodeID v; // indices into the coordinates array
- unsigned name_id; // id of the edge name
- int forward_weight; // weight of the edge
- int reverse_weight; // weight in the other direction (may be different)
- int forward_offset; // prefix sum of the weight up the edge TODO: short must suffice
- int reverse_offset; // prefix sum of the weight from the edge TODO: short must suffice
- unsigned packed_geometry_id; // if set, then the edge represents a packed geometry
- struct {
- unsigned id : 31;
- bool is_tiny : 1;
- } component;
- unsigned short fwd_segment_position; // segment id in a compressed geometry
- TravelMode forward_travel_mode : 4;
- TravelMode backward_travel_mode : 4;
-};
-
-#endif // EDGE_BASED_NODE_HPP
diff --git a/data_structures/external_memory_node.cpp b/data_structures/external_memory_node.cpp
deleted file mode 100644
index d144f52..0000000
--- a/data_structures/external_memory_node.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "external_memory_node.hpp"
-#include "query_node.hpp"
-
-#include <limits>
-
-ExternalMemoryNode::ExternalMemoryNode(
- int lat, int lon, OSMNodeID node_id, bool barrier, bool traffic_lights)
- : QueryNode(lat, lon, node_id), barrier(barrier), traffic_lights(traffic_lights)
-{
-}
-
-ExternalMemoryNode::ExternalMemoryNode() : barrier(false), traffic_lights(false) {}
-
-ExternalMemoryNode ExternalMemoryNode::min_value()
-{
- return ExternalMemoryNode(0, 0, MIN_OSM_NODEID, false, false);
-}
-
-ExternalMemoryNode ExternalMemoryNode::max_value()
-{
- return ExternalMemoryNode(std::numeric_limits<int>::max(), std::numeric_limits<int>::max(),
- MAX_OSM_NODEID, false, false);
-}
-
-bool ExternalMemoryNodeSTXXLCompare::operator()(const ExternalMemoryNode &left,
- const ExternalMemoryNode &right) const
-{
- return left.node_id < right.node_id;
-}
-
-ExternalMemoryNodeSTXXLCompare::value_type ExternalMemoryNodeSTXXLCompare::max_value()
-{
- return ExternalMemoryNode::max_value();
-}
-
-ExternalMemoryNodeSTXXLCompare::value_type ExternalMemoryNodeSTXXLCompare::min_value()
-{
- return ExternalMemoryNode::min_value();
-}
diff --git a/data_structures/external_memory_node.hpp b/data_structures/external_memory_node.hpp
deleted file mode 100644
index a48d1a1..0000000
--- a/data_structures/external_memory_node.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef EXTERNAL_MEMORY_NODE_HPP_
-#define EXTERNAL_MEMORY_NODE_HPP_
-
-#include "query_node.hpp"
-
-#include "../typedefs.h"
-
-struct ExternalMemoryNode : QueryNode
-{
- ExternalMemoryNode(int lat, int lon, OSMNodeID id, bool barrier, bool traffic_light);
-
- ExternalMemoryNode();
-
- static ExternalMemoryNode min_value();
-
- static ExternalMemoryNode max_value();
-
- bool barrier;
- bool traffic_lights;
-};
-
-struct ExternalMemoryNodeSTXXLCompare
-{
- using value_type = ExternalMemoryNode;
- bool operator()(const ExternalMemoryNode &left, const ExternalMemoryNode &right) const;
- value_type max_value();
- value_type min_value();
-};
-
-#endif /* EXTERNAL_MEMORY_NODE_HPP_ */
diff --git a/data_structures/fixed_point_number.hpp b/data_structures/fixed_point_number.hpp
deleted file mode 100644
index c7ed257..0000000
--- a/data_structures/fixed_point_number.hpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef FIXED_POINT_NUMBER_HPP
-#define FIXED_POINT_NUMBER_HPP
-
-#include <cmath>
-#include <cstdint>
-
-#include <iostream>
-#include <limits>
-#include <type_traits>
-#include <utility>
-
-namespace osrm
-{
-
-// implements an binary based fixed point number type
-template <unsigned FractionalBitSize,
- bool use_64_bits = false,
- bool is_unsigned = false,
- bool truncate_results = false>
-class FixedPointNumber
-{
- static_assert(FractionalBitSize > 0, "FractionalBitSize must be greater than 0");
- static_assert(FractionalBitSize <= 32, "FractionalBitSize must at most 32");
-
- typename std::conditional<use_64_bits, int64_t, int32_t>::type m_fixed_point_state;
- constexpr static const decltype(m_fixed_point_state) PRECISION = 1 << FractionalBitSize;
-
- // state signage encapsulates whether the state should either represent a
- // signed or an unsigned floating point number
- using state_signage =
- typename std::conditional<is_unsigned,
- typename std::make_unsigned<decltype(m_fixed_point_state)>::type,
- decltype(m_fixed_point_state)>::type;
-
- public:
- FixedPointNumber() : m_fixed_point_state(0) {}
-
- // the type is either initialized with a floating point value or an
- // integral state. Anything else will throw at compile-time.
- template <class T>
- constexpr FixedPointNumber(const T &&input) noexcept
- : m_fixed_point_state(static_cast<decltype(m_fixed_point_state)>(
- std::round(std::forward<const T>(input) * PRECISION)))
- {
- static_assert(
- std::is_floating_point<T>::value || std::is_integral<T>::value,
- "FixedPointNumber needs to be initialized with floating point or integral value");
- }
-
- // get max value
- template <typename T,
- typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
- constexpr static auto max() noexcept -> T
- {
- return static_cast<T>(std::numeric_limits<state_signage>::max()) / PRECISION;
- }
-
- // get min value
- template <typename T,
- typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
- constexpr static auto min() noexcept -> T
- {
- return static_cast<T>(1) / PRECISION;
- }
-
- // get lowest value
- template <typename T,
- typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
- constexpr static auto lowest() noexcept -> T
- {
- return static_cast<T>(std::numeric_limits<state_signage>::min()) / PRECISION;
- }
-
- // cast to floating point type T, return value
- template <typename T,
- typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
- explicit operator const T() const noexcept
- {
- // casts to external type (signed or unsigned) and then to float
- return static_cast<T>(static_cast<state_signage>(m_fixed_point_state)) / PRECISION;
- }
-
- // warn about cast to integral type T, its disabled for good reason
- template <typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
- explicit operator T() const
- {
- static_assert(std::is_integral<T>::value,
- "casts to integral types have been disabled on purpose");
- }
-
- // compare, ie. sort fixed-point numbers
- bool operator<(const FixedPointNumber &other) const noexcept
- {
- return m_fixed_point_state < other.m_fixed_point_state;
- }
-
- // equality, ie. sort fixed-point numbers
- bool operator==(const FixedPointNumber &other) const noexcept
- {
- return m_fixed_point_state == other.m_fixed_point_state;
- }
-
- bool operator!=(const FixedPointNumber &other) const { return !(*this == other); }
- bool operator>(const FixedPointNumber &other) const { return other < *this; }
- bool operator<=(const FixedPointNumber &other) const { return !(other < *this); }
- bool operator>=(const FixedPointNumber &other) const { return !(*this < other); }
-
- // arithmetic operators
- FixedPointNumber operator+(const FixedPointNumber &other) const noexcept
- {
- FixedPointNumber tmp = *this;
- tmp.m_fixed_point_state += other.m_fixed_point_state;
- return tmp;
- }
-
- FixedPointNumber &operator+=(const FixedPointNumber &other) noexcept
- {
- this->m_fixed_point_state += other.m_fixed_point_state;
- return *this;
- }
-
- FixedPointNumber operator-(const FixedPointNumber &other) const noexcept
- {
- FixedPointNumber tmp = *this;
- tmp.m_fixed_point_state -= other.m_fixed_point_state;
- return tmp;
- }
-
- FixedPointNumber &operator-=(const FixedPointNumber &other) noexcept
- {
- this->m_fixed_point_state -= other.m_fixed_point_state;
- return *this;
- }
-
- FixedPointNumber operator*(const FixedPointNumber &other) const noexcept
- {
- int64_t temp = this->m_fixed_point_state;
- temp *= other.m_fixed_point_state;
-
- // rounding!
- if (!truncate_results)
- {
- temp = temp + ((temp & 1 << (FractionalBitSize - 1)) << 1);
- }
- temp >>= FractionalBitSize;
- FixedPointNumber tmp;
- tmp.m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
- return tmp;
- }
-
- FixedPointNumber &operator*=(const FixedPointNumber &other) noexcept
- {
- int64_t temp = this->m_fixed_point_state;
- temp *= other.m_fixed_point_state;
-
- // rounding!
- if (!truncate_results)
- {
- temp = temp + ((temp & 1 << (FractionalBitSize - 1)) << 1);
- }
- temp >>= FractionalBitSize;
- this->m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
- return *this;
- }
-
- FixedPointNumber operator/(const FixedPointNumber &other) const noexcept
- {
- int64_t temp = this->m_fixed_point_state;
- temp <<= FractionalBitSize;
- temp /= static_cast<int64_t>(other.m_fixed_point_state);
- FixedPointNumber tmp;
- tmp.m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
- return tmp;
- }
-
- FixedPointNumber &operator/=(const FixedPointNumber &other) noexcept
- {
- int64_t temp = this->m_fixed_point_state;
- temp <<= FractionalBitSize;
- temp /= static_cast<int64_t>(other.m_fixed_point_state);
- FixedPointNumber tmp;
- this->m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
- return *this;
- }
-};
-
-static_assert(4 == sizeof(FixedPointNumber<1>), "FP19 has wrong size != 4");
-}
-#endif // FIXED_POINT_NUMBER_HPP
diff --git a/data_structures/hilbert_value.cpp b/data_structures/hilbert_value.cpp
deleted file mode 100644
index d0d61e6..0000000
--- a/data_structures/hilbert_value.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "hilbert_value.hpp"
-
-#include <osrm/coordinate.hpp>
-
-uint64_t HilbertCode::operator()(const FixedPointCoordinate ¤t_coordinate) const
-{
- unsigned location[2];
- location[0] = current_coordinate.lat + static_cast<int>(90 * COORDINATE_PRECISION);
- location[1] = current_coordinate.lon + static_cast<int>(180 * COORDINATE_PRECISION);
-
- TransposeCoordinate(location);
- return BitInterleaving(location[0], location[1]);
-}
-
-uint64_t HilbertCode::BitInterleaving(const uint32_t latitude, const uint32_t longitude) const
-{
- uint64_t result = 0;
- for (int8_t index = 31; index >= 0; --index)
- {
- result |= (latitude >> index) & 1;
- result <<= 1;
- result |= (longitude >> index) & 1;
- if (0 != index)
- {
- result <<= 1;
- }
- }
- return result;
-}
-
-void HilbertCode::TransposeCoordinate(uint32_t *X) const
-{
- uint32_t M = 1u << (32 - 1), P, Q, t;
- int i;
- // Inverse undo
- for (Q = M; Q > 1; Q >>= 1)
- {
- P = Q - 1;
- for (i = 0; i < 2; ++i)
- {
-
- const bool condition = (X[i] & Q);
- if (condition)
- {
- X[0] ^= P; // invert
- }
- else
- {
- t = (X[0] ^ X[i]) & P;
- X[0] ^= t;
- X[i] ^= t;
- }
- } // exchange
- }
- // Gray encode
- for (i = 1; i < 2; ++i)
- {
- X[i] ^= X[i - 1];
- }
- t = 0;
- for (Q = M; Q > 1; Q >>= 1)
- {
- const bool condition = (X[2 - 1] & Q);
- if (condition)
- {
- t ^= Q - 1;
- }
- } // check if this for loop is wrong
- for (i = 0; i < 2; ++i)
- {
- X[i] ^= t;
- }
-}
diff --git a/data_structures/hilbert_value.hpp b/data_structures/hilbert_value.hpp
deleted file mode 100644
index 7b8bffa..0000000
--- a/data_structures/hilbert_value.hpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef HILBERT_VALUE_HPP
-#define HILBERT_VALUE_HPP
-
-#include <cstdint>
-
-// computes a 64 bit value that corresponds to the hilbert space filling curve
-
-struct FixedPointCoordinate;
-
-class HilbertCode
-{
- public:
- uint64_t operator()(const FixedPointCoordinate ¤t_coordinate) const;
- HilbertCode() {}
- HilbertCode(const HilbertCode &) = delete;
-
- private:
- inline uint64_t BitInterleaving(const uint32_t a, const uint32_t b) const;
- inline void TransposeCoordinate(uint32_t *X) const;
-};
-
-#endif /* HILBERT_VALUE_HPP */
diff --git a/data_structures/import_edge.cpp b/data_structures/import_edge.cpp
deleted file mode 100644
index bf2829d..0000000
--- a/data_structures/import_edge.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "import_edge.hpp"
-
-#include "travel_mode.hpp"
-#include "../typedefs.h"
-
-bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const
-{
- if (source == other.source)
- {
- if (target == other.target)
- {
- if (weight == other.weight)
- {
- return forward && backward && ((!other.forward) || (!other.backward));
- }
- return weight < other.weight;
- }
- return target < other.target;
- }
- return source < other.source;
-}
-
-NodeBasedEdge::NodeBasedEdge()
- : source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), forward(false),
- backward(false), roundabout(false),
- access_restricted(false), startpoint(true), is_split(false), travel_mode(false)
-{
-}
-
-NodeBasedEdge::NodeBasedEdge(NodeID source,
- NodeID target,
- NodeID name_id,
- EdgeWeight weight,
- bool forward,
- bool backward,
- bool roundabout,
- bool access_restricted,
- bool startpoint,
- TravelMode travel_mode,
- bool is_split)
- : source(source), target(target), name_id(name_id), weight(weight), forward(forward),
- backward(backward), roundabout(roundabout),
- access_restricted(access_restricted), startpoint(startpoint), is_split(is_split), travel_mode(travel_mode)
-{
-}
-
-bool EdgeBasedEdge::operator<(const EdgeBasedEdge &other) const
-{
- if (source == other.source)
- {
- if (target == other.target)
- {
- if (weight == other.weight)
- {
- return forward && backward && ((!other.forward) || (!other.backward));
- }
- return weight < other.weight;
- }
- return target < other.target;
- }
- return source < other.source;
-}
-
-template <class EdgeT>
-EdgeBasedEdge::EdgeBasedEdge(const EdgeT &other)
- : source(other.source), target(other.target), edge_id(other.data.via),
- weight(other.data.distance), forward(other.data.forward), backward(other.data.backward)
-{
-}
-
-/** Default constructor. target and weight are set to 0.*/
-EdgeBasedEdge::EdgeBasedEdge()
- : source(0), target(0), edge_id(0), weight(0), forward(false), backward(false)
-{
-}
-
-EdgeBasedEdge::EdgeBasedEdge(const NodeID source,
- const NodeID target,
- const NodeID edge_id,
- const EdgeWeight weight,
- const bool forward,
- const bool backward)
- : source(source), target(target), edge_id(edge_id), weight(weight), forward(forward),
- backward(backward)
-{
-}
diff --git a/data_structures/import_edge.hpp b/data_structures/import_edge.hpp
deleted file mode 100644
index 449ded2..0000000
--- a/data_structures/import_edge.hpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef IMPORT_EDGE_HPP
-#define IMPORT_EDGE_HPP
-
-#include "../data_structures/travel_mode.hpp"
-#include "../typedefs.h"
-
-struct NodeBasedEdge
-{
- bool operator<(const NodeBasedEdge &e) const;
-
- NodeBasedEdge();
- explicit NodeBasedEdge(NodeID source,
- NodeID target,
- NodeID name_id,
- EdgeWeight weight,
- bool forward,
- bool backward,
- bool roundabout,
- bool access_restricted,
- bool startpoint,
- TravelMode travel_mode,
- bool is_split);
-
- NodeID source;
- NodeID target;
- NodeID name_id;
- EdgeWeight weight;
- bool forward : 1;
- bool backward : 1;
- bool roundabout : 1;
- bool access_restricted : 1;
- bool startpoint : 1;
- bool is_split : 1;
- TravelMode travel_mode : 4;
-};
-
-struct NodeBasedEdgeWithOSM : NodeBasedEdge
-{
- explicit NodeBasedEdgeWithOSM(OSMNodeID source,
- OSMNodeID target,
- NodeID name_id,
- EdgeWeight weight,
- bool forward,
- bool backward,
- bool roundabout,
- bool access_restricted,
- bool startpoint,
- TravelMode travel_mode,
- bool is_split)
- : NodeBasedEdge(SPECIAL_NODEID, SPECIAL_NODEID, name_id, weight, forward, backward, roundabout, access_restricted, startpoint, travel_mode, is_split),
- osm_source_id(source), osm_target_id(target) {}
-
- OSMNodeID osm_source_id;
- OSMNodeID osm_target_id;
-};
-
-struct EdgeBasedEdge
-{
-
- public:
- bool operator<(const EdgeBasedEdge &e) const;
-
- template <class EdgeT> explicit EdgeBasedEdge(const EdgeT &myEdge);
-
- EdgeBasedEdge();
-
- explicit EdgeBasedEdge(const NodeID source,
- const NodeID target,
- const NodeID edge_id,
- const EdgeWeight weight,
- const bool forward,
- const bool backward);
- NodeID source;
- NodeID target;
- NodeID edge_id;
- EdgeWeight weight : 30;
- bool forward : 1;
- bool backward : 1;
-};
-
-#endif /* IMPORT_EDGE_HPP */
diff --git a/data_structures/internal_route_result.hpp b/data_structures/internal_route_result.hpp
deleted file mode 100644
index 068b63a..0000000
--- a/data_structures/internal_route_result.hpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef RAW_ROUTE_DATA_H
-#define RAW_ROUTE_DATA_H
-
-#include "../data_structures/phantom_node.hpp"
-#include "../data_structures/travel_mode.hpp"
-#include "../data_structures/turn_instructions.hpp"
-#include "../typedefs.h"
-
-#include <osrm/coordinate.hpp>
-
-#include <vector>
-
-struct PathData
-{
- PathData()
- : node(SPECIAL_NODEID), name_id(INVALID_EDGE_WEIGHT), segment_duration(INVALID_EDGE_WEIGHT),
- turn_instruction(TurnInstruction::NoTurn), travel_mode(TRAVEL_MODE_INACCESSIBLE)
- {
- }
-
- PathData(NodeID node,
- unsigned name_id,
- TurnInstruction turn_instruction,
- EdgeWeight segment_duration,
- TravelMode travel_mode)
- : node(node), name_id(name_id), segment_duration(segment_duration),
- turn_instruction(turn_instruction), travel_mode(travel_mode)
- {
- }
- NodeID node;
- unsigned name_id;
- EdgeWeight segment_duration;
- TurnInstruction turn_instruction;
- TravelMode travel_mode : 4;
-};
-
-struct InternalRouteResult
-{
- std::vector<std::vector<PathData>> unpacked_path_segments;
- std::vector<PathData> unpacked_alternative;
- std::vector<PhantomNodes> segment_end_coordinates;
- std::vector<bool> source_traversed_in_reverse;
- std::vector<bool> target_traversed_in_reverse;
- std::vector<bool> alt_source_traversed_in_reverse;
- std::vector<bool> alt_target_traversed_in_reverse;
- int shortest_path_length;
- int alternative_path_length;
-
- bool is_via_leg(const std::size_t leg) const
- {
- return (leg != unpacked_path_segments.size() - 1);
- }
-
- InternalRouteResult()
- : shortest_path_length(INVALID_EDGE_WEIGHT), alternative_path_length(INVALID_EDGE_WEIGHT)
- {
- }
-};
-
-#endif // RAW_ROUTE_DATA_H
diff --git a/data_structures/lru_cache.hpp b/data_structures/lru_cache.hpp
deleted file mode 100644
index 155ab1e..0000000
--- a/data_structures/lru_cache.hpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef LRUCACHE_HPP
-#define LRUCACHE_HPP
-
-#include <list>
-#include <unordered_map>
-
-template <typename KeyT, typename ValueT> class LRUCache
-{
- private:
- struct CacheEntry
- {
- CacheEntry(KeyT k, ValueT v) : key(k), value(v) {}
- KeyT key;
- ValueT value;
- };
- unsigned capacity;
- std::list<CacheEntry> itemsInCache;
- std::unordered_map<KeyT, typename std::list<CacheEntry>::iterator> positionMap;
-
- public:
- explicit LRUCache(unsigned c) : capacity(c) {}
-
- bool Holds(KeyT key)
- {
- if (positionMap.find(key) != positionMap.end())
- {
- return true;
- }
- return false;
- }
-
- void Insert(const KeyT key, ValueT &value)
- {
- itemsInCache.push_front(CacheEntry(key, value));
- positionMap.insert(std::make_pair(key, itemsInCache.begin()));
- if (itemsInCache.size() > capacity)
- {
- positionMap.erase(itemsInCache.back().key);
- itemsInCache.pop_back();
- }
- }
-
- void Insert(const KeyT key, ValueT value)
- {
- itemsInCache.push_front(CacheEntry(key, value));
- positionMap.insert(std::make_pair(key, itemsInCache.begin()));
- if (itemsInCache.size() > capacity)
- {
- positionMap.erase(itemsInCache.back().key);
- itemsInCache.pop_back();
- }
- }
-
- bool Fetch(const KeyT key, ValueT &result)
- {
- if (Holds(key))
- {
- CacheEntry e = *(positionMap.find(key)->second);
- result = e.value;
-
- // move to front
- itemsInCache.splice(itemsInCache.begin(), itemsInCache, positionMap.find(key)->second);
- positionMap.find(key)->second = itemsInCache.begin();
- return true;
- }
- return false;
- }
- unsigned Size() const { return itemsInCache.size(); }
-};
-#endif // LRUCACHE_HPP
diff --git a/data_structures/matrix_graph_wrapper.hpp b/data_structures/matrix_graph_wrapper.hpp
deleted file mode 100644
index f8b3e65..0000000
--- a/data_structures/matrix_graph_wrapper.hpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef MATRIX_GRAPH_WRAPPER_H
-#define MATRIX_GRAPH_WRAPPER_H
-
-#include <vector>
-#include <cstddef>
-#include <iterator>
-
-#include "../typedefs.h"
-
-// This Wrapper provides all methods that are needed for TarjanSCC, when the graph is given in a
-// matrix representation (e.g. as output from a distance table call)
-
-template <typename T> class MatrixGraphWrapper
-{
- public:
- MatrixGraphWrapper(std::vector<T> table, const std::size_t number_of_nodes)
- : table_(std::move(table)), number_of_nodes_(number_of_nodes){};
-
- std::size_t GetNumberOfNodes() const { return number_of_nodes_; }
-
- std::vector<T> GetAdjacentEdgeRange(const NodeID node) const
- {
-
- std::vector<T> edges;
- // find all valid adjacent edges and move to vector `edges`
- for (std::size_t i = 0; i < number_of_nodes_; ++i)
- {
- if (*(std::begin(table_) + node * number_of_nodes_ + i) != INVALID_EDGE_WEIGHT)
- {
- edges.push_back(i);
- }
- }
- return edges;
- }
-
- EdgeWeight GetTarget(const EdgeWeight edge) const { return edge; }
-
- private:
- const std::vector<T> table_;
- const std::size_t number_of_nodes_;
-};
-
-#endif // MATRIX_GRAPH_WRAPPER_H
diff --git a/data_structures/node_based_graph.hpp b/data_structures/node_based_graph.hpp
deleted file mode 100644
index e58cfce..0000000
--- a/data_structures/node_based_graph.hpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef NODE_BASED_GRAPH_HPP
-#define NODE_BASED_GRAPH_HPP
-
-#include "dynamic_graph.hpp"
-#include "import_edge.hpp"
-#include "../util/graph_utils.hpp"
-
-#include <tbb/parallel_sort.h>
-
-#include <memory>
-
-struct NodeBasedEdgeData
-{
- NodeBasedEdgeData()
- : distance(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID),
- name_id(std::numeric_limits<unsigned>::max()), access_restricted(false),
- reversed(false), roundabout(false), travel_mode(TRAVEL_MODE_INACCESSIBLE)
- {
- }
-
- NodeBasedEdgeData(int distance, unsigned edge_id, unsigned name_id,
- bool access_restricted, bool reversed,
- bool roundabout, bool startpoint, TravelMode travel_mode)
- : distance(distance), edge_id(edge_id), name_id(name_id),
- access_restricted(access_restricted), reversed(reversed),
- roundabout(roundabout), startpoint(startpoint), travel_mode(travel_mode)
- {
- }
-
- int distance;
- unsigned edge_id;
- unsigned name_id;
- bool access_restricted : 1;
- bool reversed : 1;
- bool roundabout : 1;
- bool startpoint : 1;
- TravelMode travel_mode : 4;
-
- bool IsCompatibleTo(const NodeBasedEdgeData &other) const
- {
- return (reversed == other.reversed) && (name_id == other.name_id) &&
- (travel_mode == other.travel_mode);
- }
-};
-
-using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
-
-/// Factory method to create NodeBasedDynamicGraph from NodeBasedEdges
-/// Since DynamicGraph expects directed edges, we need to insert
-/// two edges for undirected edges.
-inline std::shared_ptr<NodeBasedDynamicGraph>
-NodeBasedDynamicGraphFromEdges(std::size_t number_of_nodes, const std::vector<NodeBasedEdge> &input_edge_list)
-{
- auto edges_list = directedEdgesFromCompressed<NodeBasedDynamicGraph::InputEdge>(input_edge_list,
- [](NodeBasedDynamicGraph::InputEdge& output_edge, const NodeBasedEdge& input_edge)
- {
- output_edge.data.distance = static_cast<int>(input_edge.weight);
- BOOST_ASSERT(output_edge.data.distance > 0);
-
- output_edge.data.roundabout = input_edge.roundabout;
- output_edge.data.name_id = input_edge.name_id;
- output_edge.data.access_restricted = input_edge.access_restricted;
- output_edge.data.travel_mode = input_edge.travel_mode;
- output_edge.data.startpoint = input_edge.startpoint;
- }
- );
-
- tbb::parallel_sort(edges_list.begin(), edges_list.end());
-
- auto graph = std::make_shared<NodeBasedDynamicGraph>(
- static_cast<NodeBasedDynamicGraph::NodeIterator>(number_of_nodes), edges_list);
-
- return graph;
-}
-
-#endif // NODE_BASED_GRAPH_HPP
diff --git a/data_structures/node_id.hpp b/data_structures/node_id.hpp
deleted file mode 100644
index 0671a4d..0000000
--- a/data_structures/node_id.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef NODE_ID_HPP
-#define NODE_ID_HPP
-
-#include "../typedefs.h"
-
-struct Cmp
-{
- using value_type = OSMNodeID;
- bool operator()(const value_type left, const value_type right) const { return left < right; }
- value_type max_value() { return MAX_OSM_NODEID; }
- value_type min_value() { return MIN_OSM_NODEID; }
-};
-
-#endif // NODE_ID_HPP
diff --git a/data_structures/original_edge_data.hpp b/data_structures/original_edge_data.hpp
deleted file mode 100644
index cbbc1b2..0000000
--- a/data_structures/original_edge_data.hpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef ORIGINAL_EDGE_DATA_HPP
-#define ORIGINAL_EDGE_DATA_HPP
-
-#include "travel_mode.hpp"
-#include "turn_instructions.hpp"
-#include "../typedefs.h"
-
-#include <limits>
-
-struct OriginalEdgeData
-{
- explicit OriginalEdgeData(NodeID via_node,
- unsigned name_id,
- TurnInstruction turn_instruction,
- bool compressed_geometry,
- TravelMode travel_mode)
- : via_node(via_node), name_id(name_id), turn_instruction(turn_instruction),
- compressed_geometry(compressed_geometry), travel_mode(travel_mode)
- {
- }
-
- OriginalEdgeData()
- : via_node(std::numeric_limits<unsigned>::max()),
- name_id(std::numeric_limits<unsigned>::max()), turn_instruction(TurnInstruction::NoTurn),
- compressed_geometry(false), travel_mode(TRAVEL_MODE_INACCESSIBLE)
- {
- }
-
- NodeID via_node;
- unsigned name_id;
- TurnInstruction turn_instruction;
- bool compressed_geometry;
- TravelMode travel_mode;
-};
-
-#endif // ORIGINAL_EDGE_DATA_HPP
diff --git a/data_structures/phantom_node.cpp b/data_structures/phantom_node.cpp
deleted file mode 100644
index 95c5bbb..0000000
--- a/data_structures/phantom_node.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "phantom_node.hpp"
-
-#include "../typedefs.h"
-#include "travel_mode.hpp"
-
-#include <osrm/coordinate.hpp>
-
-#include <limits>
-
-PhantomNode::PhantomNode(NodeID forward_node_id,
- NodeID reverse_node_id,
- unsigned name_id,
- int forward_weight,
- int reverse_weight,
- int forward_offset,
- int reverse_offset,
- unsigned packed_geometry_id,
- bool is_tiny_component,
- unsigned component_id,
- FixedPointCoordinate &location,
- unsigned short fwd_segment_position,
- TravelMode forward_travel_mode,
- TravelMode backward_travel_mode)
- : forward_node_id(forward_node_id), reverse_node_id(reverse_node_id), name_id(name_id),
- forward_weight(forward_weight), reverse_weight(reverse_weight),
- forward_offset(forward_offset), reverse_offset(reverse_offset),
- packed_geometry_id(packed_geometry_id), component{component_id, is_tiny_component}, location(location),
- fwd_segment_position(fwd_segment_position), forward_travel_mode(forward_travel_mode),
- backward_travel_mode(backward_travel_mode)
-{
-}
-
-PhantomNode::PhantomNode()
- : forward_node_id(SPECIAL_NODEID), reverse_node_id(SPECIAL_NODEID),
- name_id(std::numeric_limits<unsigned>::max()), forward_weight(INVALID_EDGE_WEIGHT),
- reverse_weight(INVALID_EDGE_WEIGHT), forward_offset(0), reverse_offset(0),
- packed_geometry_id(SPECIAL_EDGEID), component{INVALID_COMPONENTID, false},
- fwd_segment_position(0), forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
- backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
-{
-}
-
-int PhantomNode::GetForwardWeightPlusOffset() const
-{
- if (SPECIAL_NODEID == forward_node_id)
- {
- return 0;
- }
- return forward_offset + forward_weight;
-}
-
-int PhantomNode::GetReverseWeightPlusOffset() const
-{
- if (SPECIAL_NODEID == reverse_node_id)
- {
- return 0;
- }
- return reverse_offset + reverse_weight;
-}
-
-bool PhantomNode::is_bidirected() const
-{
- return (forward_node_id != SPECIAL_NODEID) && (reverse_node_id != SPECIAL_NODEID);
-}
-
-bool PhantomNode::is_compressed() const { return (forward_offset != 0) || (reverse_offset != 0); }
-
-bool PhantomNode::is_valid(const unsigned number_of_nodes) const
-{
- return location.is_valid() &&
- ((forward_node_id < number_of_nodes) || (reverse_node_id < number_of_nodes)) &&
- ((forward_weight != INVALID_EDGE_WEIGHT) || (reverse_weight != INVALID_EDGE_WEIGHT)) &&
- (component.id != INVALID_COMPONENTID) && (name_id != INVALID_NAMEID);
-}
-
-bool PhantomNode::is_valid() const { return location.is_valid() && (name_id != INVALID_NAMEID); }
-
-bool PhantomNode::operator==(const PhantomNode &other) const { return location == other.location; }
diff --git a/data_structures/phantom_node.hpp b/data_structures/phantom_node.hpp
deleted file mode 100644
index b12c4fe..0000000
--- a/data_structures/phantom_node.hpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef PHANTOM_NODES_H
-#define PHANTOM_NODES_H
-
-#include "travel_mode.hpp"
-#include "../typedefs.h"
-
-#include <osrm/coordinate.hpp>
-
-#include <iostream>
-#include <utility>
-#include <vector>
-
-struct PhantomNode
-{
- PhantomNode(NodeID forward_node_id,
- NodeID reverse_node_id,
- unsigned name_id,
- int forward_weight,
- int reverse_weight,
- int forward_offset,
- int reverse_offset,
- unsigned packed_geometry_id,
- bool is_tiny_component,
- unsigned component_id,
- FixedPointCoordinate &location,
- unsigned short fwd_segment_position,
- TravelMode forward_travel_mode,
- TravelMode backward_travel_mode);
-
- PhantomNode();
-
- template <class OtherT> PhantomNode(const OtherT &other, const FixedPointCoordinate &foot_point)
- {
- forward_node_id = other.forward_edge_based_node_id;
- reverse_node_id = other.reverse_edge_based_node_id;
- name_id = other.name_id;
-
- forward_weight = other.forward_weight;
- reverse_weight = other.reverse_weight;
-
- forward_offset = other.forward_offset;
- reverse_offset = other.reverse_offset;
-
- packed_geometry_id = other.packed_geometry_id;
-
- component.id = other.component.id;
- component.is_tiny = other.component.is_tiny;
-
- location = foot_point;
- fwd_segment_position = other.fwd_segment_position;
-
- forward_travel_mode = other.forward_travel_mode;
- backward_travel_mode = other.backward_travel_mode;
- }
-
- NodeID forward_node_id;
- NodeID reverse_node_id;
- unsigned name_id;
- int forward_weight;
- int reverse_weight;
- int forward_offset;
- int reverse_offset;
- unsigned packed_geometry_id;
- struct ComponentType {
- uint32_t id : 31;
- bool is_tiny : 1;
- } component;
-// bit-fields are broken on Windows
-#ifndef _MSC_VER
- static_assert(sizeof(ComponentType) == 4, "ComponentType needs to 4 bytes big");
-#endif
- FixedPointCoordinate location;
- unsigned short fwd_segment_position;
- // note 4 bits would suffice for each,
- // but the saved byte would be padding anyway
- TravelMode forward_travel_mode;
- TravelMode backward_travel_mode;
-
- int GetForwardWeightPlusOffset() const;
-
- int GetReverseWeightPlusOffset() const;
-
- bool is_bidirected() const;
-
- bool is_compressed() const;
-
- bool is_valid(const unsigned numberOfNodes) const;
-
- bool is_valid() const;
-
- bool operator==(const PhantomNode &other) const;
-};
-
-#ifndef _MSC_VER
-static_assert(sizeof(PhantomNode) == 48, "PhantomNode has more padding then expected");
-#endif
-
-using PhantomNodePair = std::pair<PhantomNode, PhantomNode>;
-
-struct PhantomNodeWithDistance
-{
- PhantomNode phantom_node;
- double distance;
-};
-
-struct PhantomNodes
-{
- PhantomNode source_phantom;
- PhantomNode target_phantom;
-};
-
-inline std::ostream &operator<<(std::ostream &out, const PhantomNodes &pn)
-{
- out << "source_coord: " << pn.source_phantom.location << "\n";
- out << "target_coord: " << pn.target_phantom.location << std::endl;
- return out;
-}
-
-inline std::ostream &operator<<(std::ostream &out, const PhantomNode &pn)
-{
- out << "node1: " << pn.forward_node_id << ", "
- << "node2: " << pn.reverse_node_id << ", "
- << "name: " << pn.name_id << ", "
- << "fwd-w: " << pn.forward_weight << ", "
- << "rev-w: " << pn.reverse_weight << ", "
- << "fwd-o: " << pn.forward_offset << ", "
- << "rev-o: " << pn.reverse_offset << ", "
- << "geom: " << pn.packed_geometry_id << ", "
- << "comp: " << pn.component.is_tiny << " / " << pn.component.id << ", "
- << "pos: " << pn.fwd_segment_position << ", "
- << "loc: " << pn.location;
- return out;
-}
-
-#endif // PHANTOM_NODES_H
diff --git a/data_structures/query_node.hpp b/data_structures/query_node.hpp
deleted file mode 100644
index 0f32a53..0000000
--- a/data_structures/query_node.hpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef QUERY_NODE_HPP
-#define QUERY_NODE_HPP
-
-#include "../typedefs.h"
-
-#include <boost/assert.hpp>
-
-#include <osrm/coordinate.hpp>
-
-#include <limits>
-
-struct QueryNode
-{
- using key_type = OSMNodeID; // type of NodeID
- using value_type = int; // type of lat,lons
-
- explicit QueryNode(int lat, int lon, OSMNodeID node_id) : lat(lat), lon(lon), node_id(node_id) {}
- QueryNode()
- : lat(std::numeric_limits<int>::max()), lon(std::numeric_limits<int>::max()),
- node_id(SPECIAL_OSM_NODEID)
- {
- }
-
- int lat;
- int lon;
- OSMNodeID node_id;
-
- static QueryNode min_value()
- {
- return QueryNode(static_cast<int>(-90 * COORDINATE_PRECISION),
- static_cast<int>(-180 * COORDINATE_PRECISION),
- MIN_OSM_NODEID);
- }
-
- static QueryNode max_value()
- {
- return QueryNode(static_cast<int>(90 * COORDINATE_PRECISION),
- static_cast<int>(180 * COORDINATE_PRECISION),
- MAX_OSM_NODEID);
- }
-
- value_type operator[](const std::size_t n) const
- {
- switch (n)
- {
- case 1:
- return lat;
- case 0:
- return lon;
- default:
- break;
- }
- BOOST_ASSERT_MSG(false, "should not happen");
- return std::numeric_limits<int>::lowest();
- }
-};
-
-#endif // QUERY_NODE_HPP
diff --git a/data_structures/rectangle.hpp b/data_structures/rectangle.hpp
deleted file mode 100644
index 7f6704a..0000000
--- a/data_structures/rectangle.hpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef RECTANGLE_HPP
-#define RECTANGLE_HPP
-
-#include "../algorithms/coordinate_calculation.hpp"
-
-#include <boost/assert.hpp>
-
-#include <osrm/coordinate.hpp>
-
-#include <algorithm>
-#include <cstdint>
-#include <limits>
-
-// TODO: Make template type, add tests
-struct RectangleInt2D
-{
- RectangleInt2D()
- : min_lon(std::numeric_limits<int32_t>::max()),
- max_lon(std::numeric_limits<int32_t>::min()),
- min_lat(std::numeric_limits<int32_t>::max()), max_lat(std::numeric_limits<int32_t>::min())
- {
- }
-
- int32_t min_lon, max_lon;
- int32_t min_lat, max_lat;
-
- void MergeBoundingBoxes(const RectangleInt2D &other)
- {
- min_lon = std::min(min_lon, other.min_lon);
- max_lon = std::max(max_lon, other.max_lon);
- min_lat = std::min(min_lat, other.min_lat);
- max_lat = std::max(max_lat, other.max_lat);
- BOOST_ASSERT(min_lat != std::numeric_limits<int32_t>::min());
- BOOST_ASSERT(min_lon != std::numeric_limits<int32_t>::min());
- BOOST_ASSERT(max_lat != std::numeric_limits<int32_t>::min());
- BOOST_ASSERT(max_lon != std::numeric_limits<int32_t>::min());
- }
-
- FixedPointCoordinate Centroid() const
- {
- FixedPointCoordinate centroid;
- // The coordinates of the midpoints are given by:
- // x = (x1 + x2) /2 and y = (y1 + y2) /2.
- centroid.lon = (min_lon + max_lon) / 2;
- centroid.lat = (min_lat + max_lat) / 2;
- return centroid;
- }
-
- bool Intersects(const RectangleInt2D &other) const
- {
- FixedPointCoordinate upper_left(other.max_lat, other.min_lon);
- FixedPointCoordinate upper_right(other.max_lat, other.max_lon);
- FixedPointCoordinate lower_right(other.min_lat, other.max_lon);
- FixedPointCoordinate lower_left(other.min_lat, other.min_lon);
-
- return (Contains(upper_left) || Contains(upper_right) || Contains(lower_right) ||
- Contains(lower_left));
- }
-
- float GetMinDist(const FixedPointCoordinate &location) const
- {
- const bool is_contained = Contains(location);
- if (is_contained)
- {
- return 0.0f;
- }
-
- enum Direction
- {
- INVALID = 0,
- NORTH = 1,
- SOUTH = 2,
- EAST = 4,
- NORTH_EAST = 5,
- SOUTH_EAST = 6,
- WEST = 8,
- NORTH_WEST = 9,
- SOUTH_WEST = 10
- };
-
- Direction d = INVALID;
- if (location.lat > max_lat)
- d = (Direction)(d | NORTH);
- else if (location.lat < min_lat)
- d = (Direction)(d | SOUTH);
- if (location.lon > max_lon)
- d = (Direction)(d | EAST);
- else if (location.lon < min_lon)
- d = (Direction)(d | WEST);
-
- BOOST_ASSERT(d != INVALID);
-
- float min_dist = std::numeric_limits<float>::max();
- switch (d)
- {
- case NORTH:
- min_dist = coordinate_calculation::great_circle_distance(
- location, FixedPointCoordinate(max_lat, location.lon));
- break;
- case SOUTH:
- min_dist = coordinate_calculation::great_circle_distance(
- location, FixedPointCoordinate(min_lat, location.lon));
- break;
- case WEST:
- min_dist = coordinate_calculation::great_circle_distance(
- location, FixedPointCoordinate(location.lat, min_lon));
- break;
- case EAST:
- min_dist = coordinate_calculation::great_circle_distance(
- location, FixedPointCoordinate(location.lat, max_lon));
- break;
- case NORTH_EAST:
- min_dist = coordinate_calculation::great_circle_distance(
- location, FixedPointCoordinate(max_lat, max_lon));
- break;
- case NORTH_WEST:
- min_dist = coordinate_calculation::great_circle_distance(
- location, FixedPointCoordinate(max_lat, min_lon));
- break;
- case SOUTH_EAST:
- min_dist = coordinate_calculation::great_circle_distance(
- location, FixedPointCoordinate(min_lat, max_lon));
- break;
- case SOUTH_WEST:
- min_dist = coordinate_calculation::great_circle_distance(
- location, FixedPointCoordinate(min_lat, min_lon));
- break;
- default:
- break;
- }
-
- BOOST_ASSERT(min_dist < std::numeric_limits<float>::max());
-
- return min_dist;
- }
-
- float GetMinMaxDist(const FixedPointCoordinate &location) const
- {
- float min_max_dist = std::numeric_limits<float>::max();
- // Get minmax distance to each of the four sides
- const FixedPointCoordinate upper_left(max_lat, min_lon);
- const FixedPointCoordinate upper_right(max_lat, max_lon);
- const FixedPointCoordinate lower_right(min_lat, max_lon);
- const FixedPointCoordinate lower_left(min_lat, min_lon);
-
- min_max_dist = std::min(
- min_max_dist,
- std::max(coordinate_calculation::great_circle_distance(location, upper_left),
- coordinate_calculation::great_circle_distance(location, upper_right)));
-
- min_max_dist = std::min(
- min_max_dist,
- std::max(coordinate_calculation::great_circle_distance(location, upper_right),
- coordinate_calculation::great_circle_distance(location, lower_right)));
-
- min_max_dist =
- std::min(min_max_dist,
- std::max(coordinate_calculation::great_circle_distance(location, lower_right),
- coordinate_calculation::great_circle_distance(location, lower_left)));
-
- min_max_dist =
- std::min(min_max_dist,
- std::max(coordinate_calculation::great_circle_distance(location, lower_left),
- coordinate_calculation::great_circle_distance(location, upper_left)));
- return min_max_dist;
- }
-
- bool Contains(const FixedPointCoordinate &location) const
- {
- const bool lats_contained = (location.lat >= min_lat) && (location.lat <= max_lat);
- const bool lons_contained = (location.lon >= min_lon) && (location.lon <= max_lon);
- return lats_contained && lons_contained;
- }
-};
-
-#endif
diff --git a/data_structures/route_parameters.cpp b/data_structures/route_parameters.cpp
deleted file mode 100644
index 61789bb..0000000
--- a/data_structures/route_parameters.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include <boost/fusion/container/vector.hpp>
-#include <boost/fusion/sequence/intrinsic.hpp>
-#include <boost/fusion/include/at_c.hpp>
-#include <boost/spirit/include/qi.hpp>
-
-#include <osrm/route_parameters.hpp>
-
-#include "../algorithms/polyline_compressor.hpp"
-
-RouteParameters::RouteParameters()
- : zoom_level(18), print_instructions(false), alternate_route(true), geometry(true),
- compression(true), deprecatedAPI(false), uturn_default(false), classify(false),
- matching_beta(5), gps_precision(5), check_sum(-1), num_results(1)
-{
-}
-
-void RouteParameters::setZoomLevel(const short level)
-{
- if (18 >= level && 0 <= level)
- {
- zoom_level = level;
- }
-}
-
-void RouteParameters::setNumberOfResults(const short number)
-{
- if (number > 0 && number <= 100)
- {
- num_results = number;
- }
-}
-
-void RouteParameters::setAlternateRouteFlag(const bool flag) { alternate_route = flag; }
-
-void RouteParameters::setUTurn(const bool flag)
-{
- // the API grammar should make sure this never happens
- BOOST_ASSERT(!uturns.empty());
- uturns.back() = flag;
-}
-
-void RouteParameters::setAllUTurns(const bool flag)
-{
- // if the flag flips the default, then we erase everything.
- if (flag)
- {
- uturn_default = flag;
- uturns.clear();
- uturns.resize(coordinates.size(), uturn_default);
- }
-}
-
-void RouteParameters::setDeprecatedAPIFlag(const std::string &) { deprecatedAPI = true; }
-
-void RouteParameters::setChecksum(const unsigned sum) { check_sum = sum; }
-
-void RouteParameters::setInstructionFlag(const bool flag) { print_instructions = flag; }
-
-void RouteParameters::setService(const std::string &service_string) { service = service_string; }
-
-void RouteParameters::setClassify(const bool flag) { classify = flag; }
-
-void RouteParameters::setMatchingBeta(const double beta) { matching_beta = beta; }
-
-void RouteParameters::setGPSPrecision(const double precision) { gps_precision = precision; }
-
-void RouteParameters::setOutputFormat(const std::string &format) { output_format = format; }
-
-void RouteParameters::setJSONpParameter(const std::string ¶meter)
-{
- jsonp_parameter = parameter;
-}
-
-void RouteParameters::addHint(const std::string &hint)
-{
- hints.resize(coordinates.size());
- if (!hints.empty())
- {
- hints.back() = hint;
- }
-}
-
-void RouteParameters::addTimestamp(const unsigned timestamp)
-{
- timestamps.resize(coordinates.size());
- if (!timestamps.empty())
- {
- timestamps.back() = timestamp;
- }
-}
-
-void RouteParameters::addBearing(
- const boost::fusion::vector<int, boost::optional<int>> &received_bearing,
- boost::spirit::qi::unused_type /* unused */, bool& pass)
-{
- pass = false;
- const int bearing = boost::fusion::at_c<0>(received_bearing);
- const boost::optional<int> range = boost::fusion::at_c<1>(received_bearing);
- if (bearing < 0 || bearing > 359) return;
- if (range && (*range < 0 || *range > 180)) return;
- bearings.emplace_back(std::make_pair(bearing,range));
- pass = true;
-}
-
-void RouteParameters::setLanguage(const std::string &language_string)
-{
- language = language_string;
-}
-
-void RouteParameters::setGeometryFlag(const bool flag) { geometry = flag; }
-
-void RouteParameters::setCompressionFlag(const bool flag) { compression = flag; }
-
-void RouteParameters::addCoordinate(
- const boost::fusion::vector<double, double> &received_coordinates)
-{
- coordinates.emplace_back(
- static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<0>(received_coordinates)),
- static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<1>(received_coordinates)));
- is_source.push_back(true);
- is_destination.push_back(true);
- uturns.push_back(uturn_default);
-}
-
-void RouteParameters::addDestination(
- const boost::fusion::vector<double, double> &received_coordinates)
-{
- coordinates.emplace_back(
- static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<0>(received_coordinates)),
- static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<1>(received_coordinates)));
- is_source.push_back(false);
- is_destination.push_back(true);
- uturns.push_back(uturn_default);
-}
-
-void RouteParameters::addSource(
- const boost::fusion::vector<double, double> &received_coordinates)
-{
- coordinates.emplace_back(
- static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<0>(received_coordinates)),
- static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<1>(received_coordinates)));
- is_source.push_back(true);
- is_destination.push_back(false);
- uturns.push_back(uturn_default);
-}
-
-void RouteParameters::getCoordinatesFromGeometry(const std::string &geometry_string)
-{
- PolylineCompressor pc;
- coordinates = pc.decode_string(geometry_string);
-}
-
diff --git a/data_structures/search_engine.hpp b/data_structures/search_engine.hpp
deleted file mode 100644
index 5af734e..0000000
--- a/data_structures/search_engine.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef SEARCH_ENGINE_HPP
-#define SEARCH_ENGINE_HPP
-
-#include "search_engine_data.hpp"
-#include "../routing_algorithms/alternative_path.hpp"
-#include "../routing_algorithms/many_to_many.hpp"
-#include "../routing_algorithms/map_matching.hpp"
-#include "../routing_algorithms/shortest_path.hpp"
-#include "../routing_algorithms/direct_shortest_path.hpp"
-
-#include <type_traits>
-
-template <class DataFacadeT> class SearchEngine
-{
- private:
- DataFacadeT *facade;
- SearchEngineData engine_working_data;
-
- public:
- ShortestPathRouting<DataFacadeT> shortest_path;
- DirectShortestPathRouting<DataFacadeT> direct_shortest_path;
- AlternativeRouting<DataFacadeT> alternative_path;
- ManyToManyRouting<DataFacadeT> distance_table;
- MapMatching<DataFacadeT> map_matching;
-
- explicit SearchEngine(DataFacadeT *facade)
- : facade(facade),
- shortest_path(facade, engine_working_data),
- direct_shortest_path(facade, engine_working_data),
- alternative_path(facade, engine_working_data),
- distance_table(facade, engine_working_data),
- map_matching(facade, engine_working_data)
- {
- static_assert(!std::is_pointer<DataFacadeT>::value, "don't instantiate with ptr type");
- static_assert(std::is_object<DataFacadeT>::value,
- "don't instantiate with void, function, or reference");
- }
-
- ~SearchEngine() {}
-};
-
-#endif // SEARCH_ENGINE_HPP
diff --git a/data_structures/search_engine_data.cpp b/data_structures/search_engine_data.cpp
deleted file mode 100644
index 3282a0c..0000000
--- a/data_structures/search_engine_data.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "search_engine_data.hpp"
-
-#include "binary_heap.hpp"
-
-void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes)
-{
- if (forward_heap_1.get())
- {
- forward_heap_1->Clear();
- }
- else
- {
- forward_heap_1.reset(new QueryHeap(number_of_nodes));
- }
-
- if (reverse_heap_1.get())
- {
- reverse_heap_1->Clear();
- }
- else
- {
- reverse_heap_1.reset(new QueryHeap(number_of_nodes));
- }
-}
-
-void SearchEngineData::InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes)
-{
- if (forward_heap_2.get())
- {
- forward_heap_2->Clear();
- }
- else
- {
- forward_heap_2.reset(new QueryHeap(number_of_nodes));
- }
-
- if (reverse_heap_2.get())
- {
- reverse_heap_2->Clear();
- }
- else
- {
- reverse_heap_2.reset(new QueryHeap(number_of_nodes));
- }
-}
-
-void SearchEngineData::InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes)
-{
- if (forward_heap_3.get())
- {
- forward_heap_3->Clear();
- }
- else
- {
- forward_heap_3.reset(new QueryHeap(number_of_nodes));
- }
-
- if (reverse_heap_3.get())
- {
- reverse_heap_3->Clear();
- }
- else
- {
- reverse_heap_3.reset(new QueryHeap(number_of_nodes));
- }
-}
diff --git a/data_structures/search_engine_data.hpp b/data_structures/search_engine_data.hpp
deleted file mode 100644
index 8c1c161..0000000
--- a/data_structures/search_engine_data.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef SEARCH_ENGINE_DATA_HPP
-#define SEARCH_ENGINE_DATA_HPP
-
-#include <boost/thread/tss.hpp>
-
-#include "../typedefs.h"
-#include "binary_heap.hpp"
-
-struct HeapData
-{
- NodeID parent;
- /* explicit */ HeapData(NodeID p) : parent(p) {}
-};
-
-struct SearchEngineData
-{
- using QueryHeap = BinaryHeap<NodeID, NodeID, int, HeapData, UnorderedMapStorage<NodeID, int>>;
- using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
-
- static SearchEngineHeapPtr forward_heap_1;
- static SearchEngineHeapPtr reverse_heap_1;
- static SearchEngineHeapPtr forward_heap_2;
- static SearchEngineHeapPtr reverse_heap_2;
- static SearchEngineHeapPtr forward_heap_3;
- static SearchEngineHeapPtr reverse_heap_3;
-
- void InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes);
-
- void InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes);
-
- void InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes);
-};
-
-#endif // SEARCH_ENGINE_DATA_HPP
diff --git a/data_structures/segment_information.hpp b/data_structures/segment_information.hpp
deleted file mode 100644
index d9cdc81..0000000
--- a/data_structures/segment_information.hpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef SEGMENT_INFORMATION_HPP
-#define SEGMENT_INFORMATION_HPP
-
-#include "turn_instructions.hpp"
-
-#include "../data_structures/travel_mode.hpp"
-#include "../typedefs.h"
-
-#include <osrm/coordinate.hpp>
-#include <utility>
-
-// Struct fits everything in one cache line
-struct SegmentInformation
-{
- FixedPointCoordinate location;
- NodeID name_id;
- EdgeWeight duration;
- float length;
- short pre_turn_bearing; // more than enough [0..3600] fits into 12 bits
- short post_turn_bearing;
- TurnInstruction turn_instruction;
- TravelMode travel_mode;
- bool necessary;
- bool is_via_location;
-
- explicit SegmentInformation(FixedPointCoordinate location,
- const NodeID name_id,
- const EdgeWeight duration,
- const float length,
- const TurnInstruction turn_instruction,
- const bool necessary,
- const bool is_via_location,
- const TravelMode travel_mode)
- : location(std::move(location)), name_id(name_id), duration(duration), length(length),
- pre_turn_bearing(0), post_turn_bearing(0), turn_instruction(turn_instruction), travel_mode(travel_mode),
- necessary(necessary), is_via_location(is_via_location)
- {
- }
-
- explicit SegmentInformation(FixedPointCoordinate location,
- const NodeID name_id,
- const EdgeWeight duration,
- const float length,
- const TurnInstruction turn_instruction,
- const TravelMode travel_mode)
- : location(std::move(location)), name_id(name_id), duration(duration), length(length),
- pre_turn_bearing(0), post_turn_bearing(0), turn_instruction(turn_instruction), travel_mode(travel_mode),
- necessary(turn_instruction != TurnInstruction::NoTurn), is_via_location(false)
- {
- }
-};
-
-#endif /* SEGMENT_INFORMATION_HPP */
diff --git a/data_structures/static_kdtree.hpp b/data_structures/static_kdtree.hpp
deleted file mode 100644
index 1e65dc8..0000000
--- a/data_structures/static_kdtree.hpp
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-// KD Tree coded by Christian Vetter, Monav Project
-
-#ifndef STATICKDTREE_HPP
-#define STATICKDTREE_HPP
-
-#include <boost/assert.hpp>
-#include <vector>
-#include <algorithm>
-#include <stack>
-#include <limits>
-
-namespace KDTree
-{
-
-#define KDTREE_BASESIZE (8)
-
-template <unsigned k, typename T> class BoundingBox
-{
- public:
- BoundingBox()
- {
- for (unsigned dim = 0; dim < k; ++dim)
- {
- min[dim] = std::numeric_limits<T>::min();
- max[dim] = std::numeric_limits<T>::max();
- }
- }
-
- T min[k];
- T max[k];
-};
-
-struct NoData
-{
-};
-
-template <unsigned k, typename T> class EuclidianMetric
-{
- public:
- double operator()(const T left[k], const T right[k])
- {
- double result = 0;
- for (unsigned i = 0; i < k; ++i)
- {
- double temp = (double)left[i] - (double)right[i];
- result += temp * temp;
- }
- return result;
- }
-
- double operator()(const BoundingBox<k, T> &box, const T point[k])
- {
- T nearest[k];
- for (unsigned dim = 0; dim < k; ++dim)
- {
- if (point[dim] < box.min[dim])
- nearest[dim] = box.min[dim];
- else if (point[dim] > box.max[dim])
- nearest[dim] = box.max[dim];
- else
- nearest[dim] = point[dim];
- }
- return operator()(point, nearest);
- }
-};
-
-template <unsigned k, typename T, typename Data = NoData, typename Metric = EuclidianMetric<k, T>>
-class StaticKDTree
-{
- public:
- struct InputPoint
- {
- T coordinates[k];
- Data data;
- bool operator==(const InputPoint &right)
- {
- for (int i = 0; i < k; i++)
- {
- if (coordinates[i] != right.coordinates[i])
- return false;
- }
- return true;
- }
- };
-
- explicit StaticKDTree(std::vector<InputPoint> *points)
- {
- BOOST_ASSERT(k > 0);
- BOOST_ASSERT(points->size() > 0);
- size = points->size();
- kdtree = new InputPoint[size];
- for (Iterator i = 0; i != size; ++i)
- {
- kdtree[i] = points->at(i);
- for (unsigned dim = 0; dim < k; ++dim)
- {
- if (kdtree[i].coordinates[dim] < boundingBox.min[dim])
- boundingBox.min[dim] = kdtree[i].coordinates[dim];
- if (kdtree[i].coordinates[dim] > boundingBox.max[dim])
- boundingBox.max[dim] = kdtree[i].coordinates[dim];
- }
- }
- std::stack<Tree> s;
- s.push(Tree(0, size, 0));
- while (!s.empty())
- {
- Tree tree = s.top();
- s.pop();
-
- if (tree.right - tree.left < KDTREE_BASESIZE)
- continue;
-
- Iterator middle = tree.left + (tree.right - tree.left) / 2;
- std::nth_element(kdtree + tree.left, kdtree + middle, kdtree + tree.right,
- Less(tree.dimension));
- s.push(Tree(tree.left, middle, (tree.dimension + 1) % k));
- s.push(Tree(middle + 1, tree.right, (tree.dimension + 1) % k));
- }
- }
-
- ~StaticKDTree() { delete[] kdtree; }
-
- bool NearestNeighbor(InputPoint *result, const InputPoint &point)
- {
- Metric distance;
- bool found = false;
- double nearestDistance = std::numeric_limits<T>::max();
- std::stack<NNTree> s;
- s.push(NNTree(0, size, 0, boundingBox));
- while (!s.empty())
- {
- NNTree tree = s.top();
- s.pop();
-
- if (distance(tree.box, point.coordinates) >= nearestDistance)
- continue;
-
- if (tree.right - tree.left < KDTREE_BASESIZE)
- {
- for (unsigned i = tree.left; i < tree.right; i++)
- {
- double newDistance = distance(kdtree[i].coordinates, point.coordinates);
- if (newDistance < nearestDistance)
- {
- nearestDistance = newDistance;
- *result = kdtree[i];
- found = true;
- }
- }
- continue;
- }
-
- Iterator middle = tree.left + (tree.right - tree.left) / 2;
-
- double newDistance = distance(kdtree[middle].coordinates, point.coordinates);
- if (newDistance < nearestDistance)
- {
- nearestDistance = newDistance;
- *result = kdtree[middle];
- found = true;
- }
-
- Less comperator(tree.dimension);
- if (!comperator(point, kdtree[middle]))
- {
- NNTree first(middle + 1, tree.right, (tree.dimension + 1) % k, tree.box);
- NNTree second(tree.left, middle, (tree.dimension + 1) % k, tree.box);
- first.box.min[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
- second.box.max[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
- s.push(second);
- s.push(first);
- }
- else
- {
- NNTree first(middle + 1, tree.right, (tree.dimension + 1) % k, tree.box);
- NNTree second(tree.left, middle, (tree.dimension + 1) % k, tree.box);
- first.box.min[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
- second.box.max[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
- s.push(first);
- s.push(second);
- }
- }
- return found;
- }
-
- private:
- using Iterator = unsigned;
- struct Tree
- {
- Iterator left;
- Iterator right;
- unsigned dimension;
- Tree() {}
- Tree(Iterator l, Iterator r, unsigned d) : left(l), right(r), dimension(d) {}
- };
- struct NNTree
- {
- Iterator left;
- Iterator right;
- unsigned dimension;
- BoundingBox<k, T> box;
- NNTree() {}
- NNTree(Iterator l, Iterator r, unsigned d, const BoundingBox<k, T> &b)
- : left(l), right(r), dimension(d), box(b)
- {
- }
- };
- class Less
- {
- public:
- explicit Less(unsigned d)
- {
- dimension = d;
- BOOST_ASSERT(dimension < k);
- }
-
- bool operator()(const InputPoint &left, const InputPoint &right)
- {
- BOOST_ASSERT(dimension < k);
- return left.coordinates[dimension] < right.coordinates[dimension];
- }
-
- private:
- unsigned dimension;
- };
-
- BoundingBox<k, T> boundingBox;
- InputPoint *kdtree;
- Iterator size;
-};
-}
-
-#endif // STATICKDTREE_HPP
diff --git a/data_structures/turn_instructions.hpp b/data_structures/turn_instructions.hpp
deleted file mode 100644
index 1ca065f..0000000
--- a/data_structures/turn_instructions.hpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef TURN_INSTRUCTIONS_HPP
-#define TURN_INSTRUCTIONS_HPP
-
-enum class TurnInstruction : unsigned char
-{
- NoTurn = 0,
- GoStraight,
- TurnSlightRight,
- TurnRight,
- TurnSharpRight,
- UTurn,
- TurnSharpLeft,
- TurnLeft,
- TurnSlightLeft,
- ReachViaLocation,
- HeadOn,
- EnterRoundAbout,
- LeaveRoundAbout,
- StayOnRoundAbout,
- StartAtEndOfStreet,
- ReachedYourDestination,
- EnterAgainstAllowedDirection,
- LeaveAgainstAllowedDirection,
- InverseAccessRestrictionFlag = 127,
- AccessRestrictionFlag = 128,
- AccessRestrictionPenalty = 129
-};
-
-struct TurnInstructionsClass
-{
- TurnInstructionsClass() = delete;
- TurnInstructionsClass(const TurnInstructionsClass &) = delete;
-
- static inline TurnInstruction GetTurnDirectionOfInstruction(const double angle)
- {
- if (angle >= 23 && angle < 67)
- {
- return TurnInstruction::TurnSharpRight;
- }
- if (angle >= 67 && angle < 113)
- {
- return TurnInstruction::TurnRight;
- }
- if (angle >= 113 && angle < 158)
- {
- return TurnInstruction::TurnSlightRight;
- }
- if (angle >= 158 && angle < 202)
- {
- return TurnInstruction::GoStraight;
- }
- if (angle >= 202 && angle < 248)
- {
- return TurnInstruction::TurnSlightLeft;
- }
- if (angle >= 248 && angle < 292)
- {
- return TurnInstruction::TurnLeft;
- }
- if (angle >= 292 && angle < 336)
- {
- return TurnInstruction::TurnSharpLeft;
- }
- return TurnInstruction::UTurn;
- }
-
- static inline bool TurnIsNecessary(const TurnInstruction turn_instruction)
- {
- if (TurnInstruction::NoTurn == turn_instruction ||
- TurnInstruction::StayOnRoundAbout == turn_instruction)
- {
- return false;
- }
- return true;
- }
-};
-
-#endif /* TURN_INSTRUCTIONS_HPP */
diff --git a/data_structures/upper_bound.hpp b/data_structures/upper_bound.hpp
deleted file mode 100644
index 80695f2..0000000
--- a/data_structures/upper_bound.hpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef LOWER_BOUND_HPP
-#define LOWER_BOUND_HPP
-
-#include <functional>
-#include <limits>
-#include <queue>
-#include <type_traits>
-
-// max pq holds k elements
-// insert if key is smaller than max
-// if size > k then remove element
-// get() always yields a bound to the k smallest element in the stream
-
-template <typename key_type> class upper_bound
-{
- private:
- using parameter_type =
- typename std::conditional<std::is_fundamental<key_type>::value, key_type, key_type &>::type;
-
- public:
- upper_bound() = delete;
- upper_bound(std::size_t size) : size(size) {}
-
- key_type get() const
- {
- if (queue.size() < size)
- {
- return std::numeric_limits<key_type>::max();
- }
- return queue.top();
- }
-
- void insert(const parameter_type key)
- {
- if (key < get())
- {
- queue.emplace(key);
- while (queue.size() > size)
- {
- queue.pop();
- }
- }
- }
-
- private:
- std::priority_queue<key_type, std::vector<key_type>, std::less<key_type>> queue;
- const std::size_t size;
-};
-
-#endif // LOWER_BOUND_HPP
diff --git a/data_structures/xor_fast_hash.hpp b/data_structures/xor_fast_hash.hpp
deleted file mode 100644
index 3af5ab1..0000000
--- a/data_structures/xor_fast_hash.hpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef XOR_FAST_HASH_HPP
-#define XOR_FAST_HASH_HPP
-
-#include <algorithm>
-#include <vector>
-
-/*
- This is an implementation of Tabulation hashing, which has suprising properties like
- universality.
- The space requirement is 2*2^16 = 256 kb of memory, which fits into L2 cache.
- Evaluation boils down to 10 or less assembly instruction on any recent X86 CPU:
-
- 1: movq table2(%rip), %rdx
- 2: movl %edi, %eax
- 3: movzwl %di, %edi
- 4: shrl $16, %eax
- 5: movzwl %ax, %eax
- 6: movzbl (%rdx,%rax), %eax
- 7: movq table1(%rip), %rdx
- 8: xorb (%rdx,%rdi), %al
- 9: movzbl %al, %eax
- 10: ret
-
-*/
-class XORFastHash
-{ // 65k entries
- std::vector<unsigned short> table1;
- std::vector<unsigned short> table2;
-
- public:
- XORFastHash()
- {
- table1.resize(2 << 16);
- table2.resize(2 << 16);
- for (unsigned i = 0; i < (2 << 16); ++i)
- {
- table1[i] = static_cast<unsigned short>(i);
- table2[i] = static_cast<unsigned short>(i);
- }
- std::random_shuffle(table1.begin(), table1.end());
- std::random_shuffle(table2.begin(), table2.end());
- }
-
- inline unsigned short operator()(const unsigned originalValue) const
- {
- unsigned short lsb = ((originalValue)&0xffff);
- unsigned short msb = (((originalValue) >> 16) & 0xffff);
- return table1[lsb] ^ table2[msb];
- }
-};
-
-class XORMiniHash
-{ // 256 entries
- std::vector<unsigned char> table1;
- std::vector<unsigned char> table2;
- std::vector<unsigned char> table3;
- std::vector<unsigned char> table4;
-
- public:
- XORMiniHash()
- {
- table1.resize(1 << 8);
- table2.resize(1 << 8);
- table3.resize(1 << 8);
- table4.resize(1 << 8);
- for (unsigned i = 0; i < (1 << 8); ++i)
- {
- table1[i] = static_cast<unsigned char>(i);
- table2[i] = static_cast<unsigned char>(i);
- table3[i] = static_cast<unsigned char>(i);
- table4[i] = static_cast<unsigned char>(i);
- }
- std::random_shuffle(table1.begin(), table1.end());
- std::random_shuffle(table2.begin(), table2.end());
- std::random_shuffle(table3.begin(), table3.end());
- std::random_shuffle(table4.begin(), table4.end());
- }
- unsigned char operator()(const unsigned originalValue) const
- {
- unsigned char byte1 = ((originalValue)&0xff);
- unsigned char byte2 = ((originalValue >> 8) & 0xff);
- unsigned char byte3 = ((originalValue >> 16) & 0xff);
- unsigned char byte4 = ((originalValue >> 24) & 0xff);
- return table1[byte1] ^ table2[byte2] ^ table3[byte3] ^ table4[byte4];
- }
-};
-
-#endif // XOR_FAST_HASH_HPP
diff --git a/data_structures/xor_fast_hash_storage.hpp b/data_structures/xor_fast_hash_storage.hpp
deleted file mode 100644
index ff65717..0000000
--- a/data_structures/xor_fast_hash_storage.hpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef XOR_FAST_HASH_STORAGE_HPP
-#define XOR_FAST_HASH_STORAGE_HPP
-
-#include "xor_fast_hash.hpp"
-
-#include <limits>
-#include <vector>
-
-template <typename NodeID, typename Key> class XORFastHashStorage
-{
- public:
- struct HashCell
- {
- unsigned time;
- NodeID id;
- Key key;
- HashCell()
- : time(std::numeric_limits<unsigned>::max()), id(std::numeric_limits<unsigned>::max()),
- key(std::numeric_limits<unsigned>::max())
- {
- }
-
- HashCell(const HashCell &other) : time(other.key), id(other.id), key(other.time) {}
-
- operator Key() const { return key; }
-
- void operator=(const Key key_to_insert) { key = key_to_insert; }
- };
-
- XORFastHashStorage() = delete;
-
- explicit XORFastHashStorage(size_t) : positions(2 << 16), current_timestamp(0) {}
-
- HashCell &operator[](const NodeID node)
- {
- unsigned short position = fast_hasher(node);
- while ((positions[position].time == current_timestamp) && (positions[position].id != node))
- {
- ++position %= (2 << 16);
- }
-
- positions[position].time = current_timestamp;
- positions[position].id = node;
- return positions[position];
- }
-
- // peek into table, get key for node, think of it as a read-only operator[]
- Key peek_index(const NodeID node) const
- {
- unsigned short position = fast_hasher(node);
- while ((positions[position].time == current_timestamp) && (positions[position].id != node))
- {
- ++position %= (2 << 16);
- }
- return positions[position].key;
- }
-
- void Clear()
- {
- ++current_timestamp;
- if (std::numeric_limits<unsigned>::max() == current_timestamp)
- {
- positions.clear();
- positions.resize(2 << 16);
- }
- }
-
- private:
- std::vector<HashCell> positions;
- XORFastHash fast_hasher;
- unsigned current_timestamp;
-};
-
-#endif // XOR_FAST_HASH_STORAGE_HPP
diff --git a/descriptors/description_factory.cpp b/descriptors/description_factory.cpp
deleted file mode 100644
index 5086e0d..0000000
--- a/descriptors/description_factory.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "description_factory.hpp"
-
-#include "../algorithms/polyline_formatter.hpp"
-#include "../algorithms/coordinate_calculation.hpp"
-#include "../data_structures/internal_route_result.hpp"
-#include "../data_structures/turn_instructions.hpp"
-#include "../util/container.hpp"
-#include "../util/integer_range.hpp"
-#include "../typedefs.h"
-
-DescriptionFactory::DescriptionFactory() : entire_length(0) { via_indices.push_back(0); }
-
-std::vector<unsigned> const &DescriptionFactory::GetViaIndices() const { return via_indices; }
-
-void DescriptionFactory::SetStartSegment(const PhantomNode &source, const bool traversed_in_reverse)
-{
- start_phantom = source;
- const EdgeWeight segment_duration =
- (traversed_in_reverse ? source.reverse_weight : source.forward_weight);
- const TravelMode travel_mode =
- (traversed_in_reverse ? source.backward_travel_mode : source.forward_travel_mode);
- AppendSegment(source.location, PathData(0, source.name_id, TurnInstruction::HeadOn,
- segment_duration, travel_mode));
- BOOST_ASSERT(path_description.back().duration == segment_duration);
-}
-
-void DescriptionFactory::SetEndSegment(const PhantomNode &target,
- const bool traversed_in_reverse,
- const bool is_via_location)
-{
- target_phantom = target;
- const EdgeWeight segment_duration =
- (traversed_in_reverse ? target.reverse_weight : target.forward_weight);
- const TravelMode travel_mode =
- (traversed_in_reverse ? target.backward_travel_mode : target.forward_travel_mode);
- path_description.emplace_back(target.location, target.name_id, segment_duration, 0.f,
- is_via_location ? TurnInstruction::ReachViaLocation
- : TurnInstruction::NoTurn,
- true, true, travel_mode);
- BOOST_ASSERT(path_description.back().duration == segment_duration);
-}
-
-void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
- const PathData &path_point)
-{
- // if the start location is on top of a node, the first movement might be zero-length,
- // in which case we dont' add a new description, but instead update the existing one
- if ((1 == path_description.size()) && (path_description.front().location == coordinate))
- {
- if (path_point.segment_duration > 0)
- {
- path_description.front().name_id = path_point.name_id;
- path_description.front().travel_mode = path_point.travel_mode;
- }
- return;
- }
-
- // make sure mode changes are announced, even when there otherwise is no turn
- const TurnInstruction turn = [&]() -> TurnInstruction
- {
- if (TurnInstruction::NoTurn == path_point.turn_instruction &&
- path_description.front().travel_mode != path_point.travel_mode &&
- path_point.segment_duration > 0)
- {
- return TurnInstruction::GoStraight;
- }
- return path_point.turn_instruction;
- }();
-
- path_description.emplace_back(coordinate, path_point.name_id, path_point.segment_duration, 0.f,
- turn, path_point.travel_mode);
-}
-
-osrm::json::Value DescriptionFactory::AppendGeometryString(const bool return_encoded)
-{
- if (return_encoded)
- {
- return PolylineFormatter().printEncodedString(path_description);
- }
- return PolylineFormatter().printUnencodedString(path_description);
-}
-
-void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
-{
- summary.source_name_id = start_phantom.name_id;
- summary.target_name_id = target_phantom.name_id;
- summary.BuildDurationAndLengthStrings(distance, time);
-}
-
-void DescriptionFactory::Run(const unsigned zoom_level)
-{
- if (path_description.empty())
- {
- return;
- }
-
- /** starts at index 1 */
- path_description[0].length = 0.f;
- for (const auto i : osrm::irange<std::size_t>(1, path_description.size()))
- {
- // move down names by one, q&d hack
- path_description[i - 1].name_id = path_description[i].name_id;
- path_description[i].length = coordinate_calculation::great_circle_distance(
- path_description[i - 1].location, path_description[i].location);
- }
-
- /*Simplify turn instructions
- Input :
- 10. Turn left on B 36 for 20 km
- 11. Continue on B 35; B 36 for 2 km
- 12. Continue on B 36 for 13 km
-
- becomes:
- 10. Turn left on B 36 for 35 km
- */
- // TODO: rework to check only end and start of string.
- // stl string is way to expensive
-
- // unsigned lastTurn = 0;
- // for(unsigned i = 1; i < path_description.size(); ++i) {
- // string1 = sEngine.GetEscapedNameForNameID(path_description[i].name_id);
- // if(TurnInstruction::GoStraight == path_description[i].turn_instruction) {
- // if(std::string::npos != string0.find(string1+";")
- // || std::string::npos != string0.find(";"+string1)
- // || std::string::npos != string0.find(string1+" ;")
- // || std::string::npos != string0.find("; "+string1)
- // ){
- // SimpleLogger().Write() << "->next correct: " << string0 << " contains " <<
- // string1;
- // for(; lastTurn != i; ++lastTurn)
- // path_description[lastTurn].name_id = path_description[i].name_id;
- // path_description[i].turn_instruction = TurnInstruction::NoTurn;
- // } else if(std::string::npos != string1.find(string0+";")
- // || std::string::npos != string1.find(";"+string0)
- // || std::string::npos != string1.find(string0+" ;")
- // || std::string::npos != string1.find("; "+string0)
- // ){
- // SimpleLogger().Write() << "->prev correct: " << string1 << " contains " <<
- // string0;
- // path_description[i].name_id = path_description[i-1].name_id;
- // path_description[i].turn_instruction = TurnInstruction::NoTurn;
- // }
- // }
- // if (TurnInstruction::NoTurn != path_description[i].turn_instruction) {
- // lastTurn = i;
- // }
- // string0 = string1;
- // }
- //
-
- float segment_length = 0.;
- EdgeWeight segment_duration = 0;
- std::size_t segment_start_index = 0;
-
- for (const auto i : osrm::irange<std::size_t>(1, path_description.size()))
- {
- entire_length += path_description[i].length;
- segment_length += path_description[i].length;
- segment_duration += path_description[i].duration;
- path_description[segment_start_index].length = segment_length;
- path_description[segment_start_index].duration = segment_duration;
-
- if (TurnInstruction::NoTurn != path_description[i].turn_instruction)
- {
- BOOST_ASSERT(path_description[i].necessary);
- segment_length = 0;
- segment_duration = 0;
- segment_start_index = i;
- }
- }
-
- // Post-processing to remove empty or nearly empty path segments
- if (path_description.size() > 2 &&
- std::numeric_limits<float>::epsilon() > path_description.back().length &&
- !(path_description.end() - 2)->is_via_location)
- {
- path_description.pop_back();
- path_description.back().necessary = true;
- path_description.back().turn_instruction = TurnInstruction::NoTurn;
- target_phantom.name_id = (path_description.end() - 2)->name_id;
- }
-
- if (path_description.size() > 2 &&
- std::numeric_limits<float>::epsilon() > path_description.front().length &&
- !(path_description.begin() + 1)->is_via_location)
- {
- path_description.erase(path_description.begin());
- path_description.front().turn_instruction = TurnInstruction::HeadOn;
- path_description.front().necessary = true;
- start_phantom.name_id = path_description.front().name_id;
- }
-
- // Generalize poly line
- polyline_generalizer.Run(path_description.begin(), path_description.end(), zoom_level);
-
- // fix what needs to be fixed else
- unsigned necessary_segments = 0; // a running index that counts the necessary pieces
- osrm::for_each_pair(
- path_description, [&](SegmentInformation &first, const SegmentInformation &second)
- {
- if (!first.necessary)
- {
- return;
- }
-
- if (first.is_via_location)
- { // mark the end of a leg (of several segments)
- via_indices.push_back(necessary_segments);
- }
-
- const double post_turn_bearing = coordinate_calculation::bearing(first.location, second.location);
- const double pre_turn_bearing = coordinate_calculation::bearing(second.location, first.location);
- first.post_turn_bearing = static_cast<short>(post_turn_bearing * 10);
- first.pre_turn_bearing = static_cast<short>(pre_turn_bearing * 10);
-
- ++necessary_segments;
- });
-
- via_indices.push_back(necessary_segments);
- BOOST_ASSERT(via_indices.size() >= 2);
- return;
-}
diff --git a/descriptors/description_factory.hpp b/descriptors/description_factory.hpp
deleted file mode 100644
index 985f9c1..0000000
--- a/descriptors/description_factory.hpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef DESCRIPTION_FACTORY_HPP
-#define DESCRIPTION_FACTORY_HPP
-
-#include "../algorithms/douglas_peucker.hpp"
-#include "../data_structures/phantom_node.hpp"
-#include "../data_structures/segment_information.hpp"
-#include "../data_structures/turn_instructions.hpp"
-
-#include <boost/assert.hpp>
-
-#include <osrm/coordinate.hpp>
-#include <osrm/json_container.hpp>
-
-#include <cmath>
-
-#include <limits>
-#include <vector>
-
-struct PathData;
-/* This class is fed with all way segments in consecutive order
- * and produces the description plus the encoded polyline */
-
-class DescriptionFactory
-{
- DouglasPeucker polyline_generalizer;
- PhantomNode start_phantom, target_phantom;
-
- double DegreeToRadian(const double degree) const;
- double RadianToDegree(const double degree) const;
-
- std::vector<unsigned> via_indices;
-
- double entire_length;
-
- public:
- struct RouteSummary
- {
- unsigned distance;
- EdgeWeight duration;
- unsigned source_name_id;
- unsigned target_name_id;
- RouteSummary() : distance(0), duration(0), source_name_id(0), target_name_id(0) {}
-
- void BuildDurationAndLengthStrings(const double raw_distance, const unsigned raw_duration)
- {
- // compute distance/duration for route summary
- distance = static_cast<unsigned>(std::round(raw_distance));
- duration = static_cast<EdgeWeight>(std::round(raw_duration / 10.));
- }
- } summary;
-
- // I know, declaring this public is considered bad. I'm lazy
- std::vector<SegmentInformation> path_description;
- DescriptionFactory();
- void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data);
- void BuildRouteSummary(const double distance, const unsigned time);
- void SetStartSegment(const PhantomNode &start_phantom, const bool traversed_in_reverse);
- void SetEndSegment(const PhantomNode &start_phantom,
- const bool traversed_in_reverse,
- const bool is_via_location = false);
- osrm::json::Value AppendGeometryString(const bool return_encoded);
- std::vector<unsigned> const &GetViaIndices() const;
-
- double get_entire_length() const { return entire_length; }
-
- void Run(const unsigned zoom_level);
-};
-
-#endif /* DESCRIPTION_FACTORY_HPP */
diff --git a/descriptors/descriptor_base.hpp b/descriptors/descriptor_base.hpp
deleted file mode 100644
index e85ea90..0000000
--- a/descriptors/descriptor_base.hpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef DESCRIPTOR_BASE_HPP
-#define DESCRIPTOR_BASE_HPP
-
-#include "../algorithms/coordinate_calculation.hpp"
-#include "../data_structures/internal_route_result.hpp"
-#include "../data_structures/phantom_node.hpp"
-#include "../typedefs.h"
-
-#include <boost/assert.hpp>
-
-#include <osrm/json_container.hpp>
-
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-struct DescriptorTable : public std::unordered_map<std::string, unsigned>
-{
- unsigned get_id(const std::string &key)
- {
- auto iter = find(key);
- if (iter != end())
- {
- return iter->second;
- }
- return 0;
- }
-};
-
-struct DescriptorConfig
-{
- DescriptorConfig() : instructions(true), geometry(true), encode_geometry(true), zoom_level(18)
- {
- }
-
- template <class OtherT>
- DescriptorConfig(const OtherT &other)
- : instructions(other.print_instructions), geometry(other.geometry),
- encode_geometry(other.compression), zoom_level(other.zoom_level)
- {
- BOOST_ASSERT(zoom_level >= 0);
- }
-
- bool instructions;
- bool geometry;
- bool encode_geometry;
- short zoom_level;
-};
-
-template <class DataFacadeT> class BaseDescriptor
-{
- public:
- BaseDescriptor() {}
- // Maybe someone can explain the pure virtual destructor thing to me (dennis)
- virtual ~BaseDescriptor() {}
- virtual void Run(const InternalRouteResult &raw_route, osrm::json::Object &json_result) = 0;
- virtual void SetConfig(const DescriptorConfig &c) = 0;
-};
-
-#endif // DESCRIPTOR_BASE_HPP
diff --git a/descriptors/gpx_descriptor.hpp b/descriptors/gpx_descriptor.hpp
deleted file mode 100644
index fb4c5b9..0000000
--- a/descriptors/gpx_descriptor.hpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef GPX_DESCRIPTOR_HPP
-#define GPX_DESCRIPTOR_HPP
-
-#include "descriptor_base.hpp"
-#include "../util/xml_renderer.hpp"
-
-#include <osrm/json_container.hpp>
-
-#include <iostream>
-
-template <class DataFacadeT> class GPXDescriptor final : public BaseDescriptor<DataFacadeT>
-{
- private:
- DescriptorConfig config;
- DataFacadeT *facade;
-
- void AddRoutePoint(const FixedPointCoordinate &coordinate, osrm::json::Array &json_route)
- {
- osrm::json::Object json_lat;
- osrm::json::Object json_lon;
- osrm::json::Array json_row;
-
- std::string tmp;
-
- coordinate_calculation::lat_or_lon_to_string(coordinate.lat, tmp);
- json_lat.values["_lat"] = tmp;
-
- coordinate_calculation::lat_or_lon_to_string(coordinate.lon, tmp);
- json_lon.values["_lon"] = tmp;
-
- json_row.values.push_back(json_lat);
- json_row.values.push_back(json_lon);
- osrm::json::Object entry;
- entry.values["rtept"] = json_row;
- json_route.values.push_back(entry);
- }
-
- public:
- explicit GPXDescriptor(DataFacadeT *facade) : facade(facade) {}
-
- virtual void SetConfig(const DescriptorConfig &c) final { config = c; }
-
- virtual void Run(const InternalRouteResult &raw_route, osrm::json::Object &json_result) final
- {
- osrm::json::Array json_route;
- if (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT)
- {
- AddRoutePoint(raw_route.segment_end_coordinates.front().source_phantom.location,
- json_route);
-
- for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
- {
- for (const PathData &path_data : path_data_vector)
- {
- const FixedPointCoordinate current_coordinate =
- facade->GetCoordinateOfNode(path_data.node);
- AddRoutePoint(current_coordinate, json_route);
- }
- }
- AddRoutePoint(raw_route.segment_end_coordinates.back().target_phantom.location,
- json_route);
- }
- // osrm::json::gpx_render(reply.content, json_route);
- json_result.values["route"] = json_route;
- }
-};
-#endif // GPX_DESCRIPTOR_HPP
diff --git a/descriptors/json_descriptor.hpp b/descriptors/json_descriptor.hpp
deleted file mode 100644
index e476dd8..0000000
--- a/descriptors/json_descriptor.hpp
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef JSON_DESCRIPTOR_HPP
-#define JSON_DESCRIPTOR_HPP
-
-#include "descriptor_base.hpp"
-#include "description_factory.hpp"
-#include "../algorithms/object_encoder.hpp"
-#include "../algorithms/route_name_extraction.hpp"
-#include "../data_structures/segment_information.hpp"
-#include "../data_structures/turn_instructions.hpp"
-#include "../util/bearing.hpp"
-#include "../util/cast.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/json_renderer.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/string_util.hpp"
-#include "../util/timing_util.hpp"
-
-#include <osrm/json_container.hpp>
-
-#include <limits>
-#include <algorithm>
-#include <string>
-
-template <class DataFacadeT> class JSONDescriptor final : public BaseDescriptor<DataFacadeT>
-{
- private:
- DataFacadeT *facade;
- DescriptorConfig config;
- DescriptionFactory description_factory, alternate_description_factory;
- FixedPointCoordinate current;
-
- public:
- struct Segment
- {
- Segment() : name_id(INVALID_NAMEID), length(-1), position(0) {}
- Segment(unsigned n, int l, unsigned p) : name_id(n), length(l), position(p) {}
- unsigned name_id;
- int length;
- unsigned position;
- };
- private:
- std::vector<Segment> shortest_path_segments, alternative_path_segments;
- ExtractRouteNames<DataFacadeT, Segment> GenerateRouteNames;
-
- public:
- explicit JSONDescriptor(DataFacadeT *facade) : facade(facade)
- {
- }
-
- virtual void SetConfig(const DescriptorConfig &c) override final { config = c; }
-
- unsigned DescribeLeg(const std::vector<PathData> &route_leg,
- const PhantomNodes &leg_phantoms,
- const bool target_traversed_in_reverse,
- const bool is_via_leg)
- {
- unsigned added_element_count = 0;
- // Get all the coordinates for the computed route
- FixedPointCoordinate current_coordinate;
- for (const PathData &path_data : route_leg)
- {
- current_coordinate = facade->GetCoordinateOfNode(path_data.node);
- description_factory.AppendSegment(current_coordinate, path_data);
- ++added_element_count;
- }
- description_factory.SetEndSegment(leg_phantoms.target_phantom, target_traversed_in_reverse,
- is_via_leg);
- ++added_element_count;
- BOOST_ASSERT((route_leg.size() + 1) == added_element_count);
- return added_element_count;
- }
-
- virtual void Run(const InternalRouteResult &raw_route,
- osrm::json::Object &json_result) override final
- {
- if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
- {
- // We do not need to do much, if there is no route ;-)
- return;
- }
-
- // check if first segment is non-zero
- BOOST_ASSERT(raw_route.unpacked_path_segments.size() ==
- raw_route.segment_end_coordinates.size());
-
- description_factory.SetStartSegment(
- raw_route.segment_end_coordinates.front().source_phantom,
- raw_route.source_traversed_in_reverse.front());
-
- // for each unpacked segment add the leg to the description
- for (const auto i : osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size()))
- {
-#ifndef NDEBUG
- const int added_segments =
-#endif
- DescribeLeg(raw_route.unpacked_path_segments[i],
- raw_route.segment_end_coordinates[i],
- raw_route.target_traversed_in_reverse[i], raw_route.is_via_leg(i));
- BOOST_ASSERT(0 < added_segments);
- }
- description_factory.Run(config.zoom_level);
-
- if (config.geometry)
- {
- osrm::json::Value route_geometry =
- description_factory.AppendGeometryString(config.encode_geometry);
- json_result.values["route_geometry"] = route_geometry;
- }
- if (config.instructions)
- {
- osrm::json::Array json_route_instructions = BuildTextualDescription(description_factory, shortest_path_segments);
- json_result.values["route_instructions"] = json_route_instructions;
- }
- description_factory.BuildRouteSummary(description_factory.get_entire_length(),
- raw_route.shortest_path_length);
- osrm::json::Object json_route_summary;
- json_route_summary.values["total_distance"] = description_factory.summary.distance;
- json_route_summary.values["total_time"] = description_factory.summary.duration;
- json_route_summary.values["start_point"] =
- facade->get_name_for_id(description_factory.summary.source_name_id);
- json_route_summary.values["end_point"] =
- facade->get_name_for_id(description_factory.summary.target_name_id);
- json_result.values["route_summary"] = json_route_summary;
-
- BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
-
- osrm::json::Array json_via_points_array;
- osrm::json::Array json_first_coordinate;
- json_first_coordinate.values.push_back(
- raw_route.segment_end_coordinates.front().source_phantom.location.lat /
- COORDINATE_PRECISION);
- json_first_coordinate.values.push_back(
- raw_route.segment_end_coordinates.front().source_phantom.location.lon /
- COORDINATE_PRECISION);
- json_via_points_array.values.push_back(json_first_coordinate);
- for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
- {
- std::string tmp;
- osrm::json::Array json_coordinate;
- json_coordinate.values.push_back(nodes.target_phantom.location.lat /
- COORDINATE_PRECISION);
- json_coordinate.values.push_back(nodes.target_phantom.location.lon /
- COORDINATE_PRECISION);
- json_via_points_array.values.push_back(json_coordinate);
- }
- json_result.values["via_points"] = json_via_points_array;
-
- osrm::json::Array json_via_indices_array;
-
- std::vector<unsigned> const &shortest_leg_end_indices = description_factory.GetViaIndices();
- json_via_indices_array.values.insert(json_via_indices_array.values.end(),
- shortest_leg_end_indices.begin(),
- shortest_leg_end_indices.end());
- json_result.values["via_indices"] = json_via_indices_array;
-
- // only one alternative route is computed at this time, so this is hardcoded
- if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
- {
- json_result.values["found_alternative"] = osrm::json::True();
- BOOST_ASSERT(!raw_route.alt_source_traversed_in_reverse.empty());
- alternate_description_factory.SetStartSegment(
- raw_route.segment_end_coordinates.front().source_phantom,
- raw_route.alt_source_traversed_in_reverse.front());
- // Get all the coordinates for the computed route
- for (const PathData &path_data : raw_route.unpacked_alternative)
- {
- current = facade->GetCoordinateOfNode(path_data.node);
- alternate_description_factory.AppendSegment(current, path_data);
- }
- alternate_description_factory.SetEndSegment(
- raw_route.segment_end_coordinates.back().target_phantom,
- raw_route.alt_source_traversed_in_reverse.back());
- alternate_description_factory.Run(config.zoom_level);
-
- if (config.geometry)
- {
- osrm::json::Value alternate_geometry_string =
- alternate_description_factory.AppendGeometryString(config.encode_geometry);
- osrm::json::Array json_alternate_geometries_array;
- json_alternate_geometries_array.values.push_back(alternate_geometry_string);
- json_result.values["alternative_geometries"] = json_alternate_geometries_array;
- }
- // Generate instructions for each alternative (simulated here)
- osrm::json::Array json_alt_instructions;
- osrm::json::Array json_current_alt_instructions;
- if (config.instructions)
- {
- json_current_alt_instructions = BuildTextualDescription(alternate_description_factory, alternative_path_segments);
- json_alt_instructions.values.push_back(json_current_alt_instructions);
- json_result.values["alternative_instructions"] = json_alt_instructions;
- }
- alternate_description_factory.BuildRouteSummary(
- alternate_description_factory.get_entire_length(),
- raw_route.alternative_path_length);
-
- osrm::json::Object json_alternate_route_summary;
- osrm::json::Array json_alternate_route_summary_array;
- json_alternate_route_summary.values["total_distance"] =
- alternate_description_factory.summary.distance;
- json_alternate_route_summary.values["total_time"] =
- alternate_description_factory.summary.duration;
- json_alternate_route_summary.values["start_point"] =
- facade->get_name_for_id(alternate_description_factory.summary.source_name_id);
- json_alternate_route_summary.values["end_point"] =
- facade->get_name_for_id(alternate_description_factory.summary.target_name_id);
- json_alternate_route_summary_array.values.push_back(json_alternate_route_summary);
- json_result.values["alternative_summaries"] = json_alternate_route_summary_array;
-
- std::vector<unsigned> const &alternate_leg_end_indices =
- alternate_description_factory.GetViaIndices();
- osrm::json::Array json_altenative_indices_array;
- json_altenative_indices_array.values.insert(json_altenative_indices_array.values.end(),
- alternate_leg_end_indices.begin(),
- alternate_leg_end_indices.end());
- json_result.values["alternative_indices"] = json_altenative_indices_array;
- }
- else
- {
- json_result.values["found_alternative"] = osrm::json::False();
- }
-
- // Get Names for both routes
- RouteNames route_names =
- GenerateRouteNames(shortest_path_segments, alternative_path_segments, facade);
- osrm::json::Array json_route_names;
- json_route_names.values.push_back(route_names.shortest_path_name_1);
- json_route_names.values.push_back(route_names.shortest_path_name_2);
- json_result.values["route_name"] = json_route_names;
-
- if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
- {
- osrm::json::Array json_alternate_names_array;
- osrm::json::Array json_alternate_names;
- json_alternate_names.values.push_back(route_names.alternative_path_name_1);
- json_alternate_names.values.push_back(route_names.alternative_path_name_2);
- json_alternate_names_array.values.push_back(json_alternate_names);
- json_result.values["alternative_names"] = json_alternate_names_array;
- }
-
- json_result.values["hint_data"] = BuildHintData(raw_route);
- }
-
- inline osrm::json::Object BuildHintData(const InternalRouteResult& raw_route) const
- {
- osrm::json::Object json_hint_object;
- json_hint_object.values["checksum"] = facade->GetCheckSum();
- osrm::json::Array json_location_hint_array;
- std::string hint;
- for (const auto i : osrm::irange<std::size_t>(0, raw_route.segment_end_coordinates.size()))
- {
- ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates[i].source_phantom,
- hint);
- json_location_hint_array.values.push_back(hint);
- }
- ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates.back().target_phantom,
- hint);
- json_location_hint_array.values.push_back(hint);
- json_hint_object.values["locations"] = json_location_hint_array;
-
- return json_hint_object;
- }
-
- inline osrm::json::Array BuildTextualDescription(const DescriptionFactory &description_factory,
- std::vector<Segment> &route_segments_list) const
- {
- osrm::json::Array json_instruction_array;
- // Segment information has following format:
- //["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
- unsigned necessary_segments_running_index = 0;
-
- struct RoundAbout
- {
- RoundAbout() : start_index(std::numeric_limits<int>::max()), name_id(INVALID_NAMEID), leave_at_exit(std::numeric_limits<int>::max()) {}
- int start_index;
- unsigned name_id;
- int leave_at_exit;
- } round_about;
-
- round_about.leave_at_exit = 0;
- round_about.name_id = 0;
- std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
- TravelMode last_travel_mode = TRAVEL_MODE_DEFAULT;
-
- // Fetch data from Factory and generate a string from it.
- for (const SegmentInformation &segment : description_factory.path_description)
- {
- osrm::json::Array json_instruction_row;
- TurnInstruction current_instruction = segment.turn_instruction;
- if (TurnInstructionsClass::TurnIsNecessary(current_instruction))
- {
- if (TurnInstruction::EnterRoundAbout == current_instruction)
- {
- round_about.name_id = segment.name_id;
- round_about.start_index = necessary_segments_running_index;
- }
- else
- {
- std::string current_turn_instruction;
- if (TurnInstruction::LeaveRoundAbout == current_instruction)
- {
- temp_instruction = std::to_string(
- cast::enum_to_underlying(TurnInstruction::EnterRoundAbout));
- current_turn_instruction += temp_instruction;
- current_turn_instruction += "-";
- temp_instruction = std::to_string(round_about.leave_at_exit + 1);
- current_turn_instruction += temp_instruction;
- round_about.leave_at_exit = 0;
- }
- else
- {
- temp_instruction =
- std::to_string(cast::enum_to_underlying(current_instruction));
- current_turn_instruction += temp_instruction;
- }
- json_instruction_row.values.push_back(current_turn_instruction);
-
- json_instruction_row.values.push_back(facade->get_name_for_id(segment.name_id));
- json_instruction_row.values.push_back(std::round(segment.length));
- json_instruction_row.values.push_back(necessary_segments_running_index);
- json_instruction_row.values.push_back(std::round(segment.duration / 10.));
- json_instruction_row.values.push_back(
- std::to_string(static_cast<unsigned>(segment.length)) + "m");
-
- // post turn bearing
- const double post_turn_bearing_value = (segment.post_turn_bearing / 10.);
- json_instruction_row.values.push_back(bearing::get(post_turn_bearing_value));
- json_instruction_row.values.push_back(
- static_cast<unsigned>(round(post_turn_bearing_value)));
-
- json_instruction_row.values.push_back(segment.travel_mode);
- last_travel_mode = segment.travel_mode;
-
- // pre turn bearing
- const double pre_turn_bearing_value = (segment.pre_turn_bearing / 10.);
- json_instruction_row.values.push_back(bearing::get(pre_turn_bearing_value));
- json_instruction_row.values.push_back(
- static_cast<unsigned>(round(pre_turn_bearing_value)));
-
- json_instruction_array.values.push_back(json_instruction_row);
-
- route_segments_list.emplace_back(
- segment.name_id, static_cast<int>(segment.length),
- static_cast<unsigned>(route_segments_list.size()));
- }
- }
- else if (TurnInstruction::StayOnRoundAbout == current_instruction)
- {
- ++round_about.leave_at_exit;
- }
- if (segment.necessary)
- {
- ++necessary_segments_running_index;
- }
- }
-
- osrm::json::Array json_last_instruction_row;
- temp_instruction =
- std::to_string(cast::enum_to_underlying(TurnInstruction::ReachedYourDestination));
- json_last_instruction_row.values.push_back(temp_instruction);
- json_last_instruction_row.values.push_back("");
- json_last_instruction_row.values.push_back(0);
- json_last_instruction_row.values.push_back(necessary_segments_running_index - 1);
- json_last_instruction_row.values.push_back(0);
- json_last_instruction_row.values.push_back("0m");
- json_last_instruction_row.values.push_back(bearing::get(0.0));
- json_last_instruction_row.values.push_back(0.);
- json_last_instruction_row.values.push_back(last_travel_mode);
- json_last_instruction_row.values.push_back(bearing::get(0.0));
- json_last_instruction_row.values.push_back(0.);
- json_instruction_array.values.push_back(json_last_instruction_row);
-
- return json_instruction_array;
- }
-};
-
-#endif /* JSON_DESCRIPTOR_H_ */
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 4535949..aa37682 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -12,8 +12,6 @@ RUN pip install awscli
# luabind
RUN curl https://gist.githubusercontent.com/DennisOSRM/f2eb7b948e6fe1ae319e/raw/install-luabind.sh | sudo bash
-# osmosis
-RUN curl -s https://gist.githubusercontent.com/DennisOSRM/803a64a9178ec375069f/raw/ | sudo bash
RUN useradd -ms /bin/bash mapbox
USER mapbox
diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt
new file mode 100644
index 0000000..86a8a7f
--- /dev/null
+++ b/example/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 2.8.8)
+
+if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR AND NOT MSVC_IDE)
+ message(FATAL_ERROR "In-source builds are not allowed.
+Please create a directory and run cmake from there, passing the path to this source directory as the last argument.
+This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. Please delete them.")
+endif()
+
+project(osrm-example C CXX)
+
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ")
+
+set(bitness 32)
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(bitness 64)
+ message(STATUS "Building on a 64 bit system")
+else()
+ message(WARNING "Building on a 32 bit system is unsupported")
+endif()
+
+if(WIN32 AND MSVC_VERSION LESS 1800)
+ message(FATAL_ERROR "Building with Microsoft compiler needs Visual Studio 2013 or later (Express version works too)")
+endif()
+
+add_executable(osrm-example example.cpp)
+
+find_package(LibOSRM REQUIRED)
+find_package(Boost 1.49.0 COMPONENTS filesystem system thread REQUIRED)
+
+target_link_libraries(osrm-example ${LibOSRM_LIBRARIES} ${Boost_LIBRARIES})
+include_directories(SYSTEM ${LibOSRM_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
+
diff --git a/example/cmake/FindLibOSRM.cmake b/example/cmake/FindLibOSRM.cmake
new file mode 100644
index 0000000..8475c74
--- /dev/null
+++ b/example/cmake/FindLibOSRM.cmake
@@ -0,0 +1,65 @@
+# - Try to find LibOSRM
+# Once done this will define
+# LibOSRM_FOUND - System has LibOSRM
+# LibOSRM_INCLUDE_DIRS - The LibOSRM include directories
+# LibOSRM_LIBRARIES - The libraries needed to use LibOSRM
+# LibOSRM_DEFINITIONS - Compiler switches required for using LibOSRM
+
+find_package(PkgConfig)
+pkg_check_modules(PC_LibOSRM QUIET libosrm)
+set(LibOSRM_DEFINITIONS ${PC_LibOSRM_CFLAGS_OTHER})
+
+find_path(LibOSRM_INCLUDE_DIR osrm/osrm.hpp
+ PATH_SUFFIXES osrm include/osrm include
+ HINTS ${PC_LibOSRM_INCLUDEDIR} ${PC_LibOSRM_INCLUDE_DIRS}
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local
+ /usr
+ /opt/local
+ /opt)
+
+set(LibOSRM_INCLUDE_DIRS ${LibOSRM_INCLUDE_DIR} ${LibOSRM_INCLUDE_DIR}/osrm)
+
+find_library(TEST_LibOSRM_STATIC_LIBRARY Names osrm.lib libosrm.a
+ PATH_SUFFIXES osrm lib/osrm lib
+ HINTS ${PC_LibOSRM_LIBDIR} ${PC_LibOSRM_LIBRARY_DIRS}
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local
+ /usr
+ /opt/local
+ /opt)
+find_library(TEST_LibOSRM_DYNAMIC_LIBRARY Names osrm.dynlib libosrm.so
+ PATH_SUFFIXES osrm lib/osrm lib
+ HINTS ${PC_LibOSRM_LIBDIR} ${PC_LibOSRM_LIBRARY_DIRS}
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local
+ /usr
+ /opt/local
+ /opt)
+
+if (NOT ("${TEST_LibOSRM_STATIC_LIBRARY}" STREQUAL "TEST_LibOSRM_STATIC_LIBRARY-NOTFOUND"))
+ if ("${PC_LibOSRM_STATIC_LIBRARIES}" STREQUAL "")
+ set(LibOSRM_STATIC_LIBRARIES ${TEST_LibOSRM_STATIC_LIBRARY})
+ else()
+ set(LibOSRM_STATIC_LIBRARIES ${PC_LibOSRM_STATIC_LIBRARIES})
+ endif()
+ set(LibOSRM_LIBRARIES ${LibOSRM_STATIC_LIBRARIES})
+endif()
+
+if (NOT ("${TEST_LibOSRM_DYNAMIC_LIBRARY}" STREQUAL "TEST_LibOSRM_DYNAMIC_LIBRARY-NOTFOUND"))
+ if ("${PC_LibOSRM_LIBRARIES}" STREQUAL "")
+ set(LibOSRM_DYNAMIC_LIBRARIES ${TEST_LibOSRM_DYNAMIC_LIBRARY})
+ else()
+ set(LibOSRM_DYNAMIC_LIBRARIES ${PC_LibOSRM_LIBRARIES})
+ endif()
+ set(LibOSRM_LIBRARIES ${LibOSRM_DYNAMIC_LIBRARIES})
+endif()
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set LIBOSRM_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(LibOSRM DEFAULT_MSG
+ LibOSRM_LIBRARIES LibOSRM_INCLUDE_DIR)
diff --git a/example/cmake/FindTBB.cmake b/example/cmake/FindTBB.cmake
new file mode 100644
index 0000000..f9e3e0f
--- /dev/null
+++ b/example/cmake/FindTBB.cmake
@@ -0,0 +1,283 @@
+# Locate Intel Threading Building Blocks include paths and libraries
+# FindTBB.cmake can be found at https://code.google.com/p/findtbb/
+# Written by Hannes Hofmann <hannes.hofmann _at_ informatik.uni-erlangen.de>
+# Improvements by Gino van den Bergen <gino _at_ dtecta.com>,
+# Florian Uhlig <F.Uhlig _at_ gsi.de>,
+# Jiri Marsik <jiri.marsik89 _at_ gmail.com>
+
+# The MIT License
+#
+# Copyright (c) 2011 Hannes Hofmann
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# GvdB: This module uses the environment variable TBB_ARCH_PLATFORM which defines architecture and compiler.
+# e.g. "ia32/vc8" or "em64t/cc4.1.0_libc2.4_kernel2.6.16.21"
+# TBB_ARCH_PLATFORM is set by the build script tbbvars[.bat|.sh|.csh], which can be found
+# in the TBB installation directory (TBB_INSTALL_DIR).
+#
+# GvdB: Mac OS X distribution places libraries directly in lib directory.
+#
+# For backwards compatibility, you may explicitely set the CMake variables TBB_ARCHITECTURE and TBB_COMPILER.
+# TBB_ARCHITECTURE [ ia32 | em64t | itanium ]
+# which architecture to use
+# TBB_COMPILER e.g. vc9 or cc3.2.3_libc2.3.2_kernel2.4.21 or cc4.0.1_os10.4.9
+# which compiler to use (detected automatically on Windows)
+
+# This module respects
+# TBB_INSTALL_DIR or $ENV{TBB21_INSTALL_DIR} or $ENV{TBB_INSTALL_DIR}
+
+# This module defines
+# TBB_INCLUDE_DIRS, where to find task_scheduler_init.h, etc.
+# TBB_LIBRARY_DIRS, where to find libtbb, libtbbmalloc
+# TBB_DEBUG_LIBRARY_DIRS, where to find libtbb_debug, libtbbmalloc_debug
+# TBB_INSTALL_DIR, the base TBB install directory
+# TBB_LIBRARIES, the libraries to link against to use TBB.
+# TBB_DEBUG_LIBRARIES, the libraries to link against to use TBB with debug symbols.
+# TBB_FOUND, If false, don't try to use TBB.
+# TBB_INTERFACE_VERSION, as defined in tbb/tbb_stddef.h
+
+
+if (WIN32)
+ # has em64t/vc8 em64t/vc9
+ # has ia32/vc7.1 ia32/vc8 ia32/vc9
+ set(_TBB_DEFAULT_INSTALL_DIR "C:/Program Files/Intel/TBB" "C:/Program Files (x86)/Intel/TBB")
+ set(_TBB_LIB_NAME "tbb")
+ set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+ set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+ set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+ if (MSVC71)
+ set (_TBB_COMPILER "vc7.1")
+ endif(MSVC71)
+ if (MSVC80)
+ set(_TBB_COMPILER "vc8")
+ endif(MSVC80)
+ if (MSVC90)
+ set(_TBB_COMPILER "vc9")
+ endif(MSVC90)
+ if(MSVC10)
+ set(_TBB_COMPILER "vc10")
+ endif(MSVC10)
+ # Todo: add other Windows compilers such as ICL.
+ set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+endif (WIN32)
+
+if (UNIX)
+ if (APPLE)
+ # MAC
+ set(_TBB_DEFAULT_INSTALL_DIR "/Library/Frameworks/Intel_TBB.framework/Versions")
+ # libs: libtbb.dylib, libtbbmalloc.dylib, *_debug
+ set(_TBB_LIB_NAME "tbb")
+ set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+ set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+ set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+ # default flavor on apple: ia32/cc4.0.1_os10.4.9
+ # Jiri: There is no reason to presume there is only one flavor and
+ # that user's setting of variables should be ignored.
+ if(NOT TBB_COMPILER)
+ set(_TBB_COMPILER "cc4.0.1_os10.4.9")
+ elseif (NOT TBB_COMPILER)
+ set(_TBB_COMPILER ${TBB_COMPILER})
+ endif(NOT TBB_COMPILER)
+ if(NOT TBB_ARCHITECTURE)
+ set(_TBB_ARCHITECTURE "ia32")
+ elseif(NOT TBB_ARCHITECTURE)
+ set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+ endif(NOT TBB_ARCHITECTURE)
+ else (APPLE)
+ # LINUX
+ set(_TBB_DEFAULT_INSTALL_DIR "/opt/intel/tbb" "/usr/local/include" "/usr/include")
+ set(_TBB_LIB_NAME "tbb")
+ set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+ set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+ set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+ # has em64t/cc3.2.3_libc2.3.2_kernel2.4.21 em64t/cc3.3.3_libc2.3.3_kernel2.6.5 em64t/cc3.4.3_libc2.3.4_kernel2.6.9 em64t/cc4.1.0_libc2.4_kernel2.6.16.21
+ # has ia32/*
+ # has itanium/*
+ set(_TBB_COMPILER ${TBB_COMPILER})
+ set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+ endif (APPLE)
+endif (UNIX)
+
+if (CMAKE_SYSTEM MATCHES "SunOS.*")
+# SUN
+# not yet supported
+# has em64t/cc3.4.3_kernel5.10
+# has ia32/*
+endif (CMAKE_SYSTEM MATCHES "SunOS.*")
+
+
+#-- Clear the public variables
+set (TBB_FOUND "NO")
+
+
+#-- Find TBB install dir and set ${_TBB_INSTALL_DIR} and cached ${TBB_INSTALL_DIR}
+# first: use CMake variable TBB_INSTALL_DIR
+if (TBB_INSTALL_DIR)
+ set (_TBB_INSTALL_DIR ${TBB_INSTALL_DIR})
+endif (TBB_INSTALL_DIR)
+# second: use environment variable
+if (NOT _TBB_INSTALL_DIR)
+ if (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB_INSTALL_DIR})
+ endif (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "")
+ # Intel recommends setting TBB21_INSTALL_DIR
+ if (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB21_INSTALL_DIR})
+ endif (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "")
+ if (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB22_INSTALL_DIR})
+ endif (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "")
+ if (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB30_INSTALL_DIR})
+ endif (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "")
+endif (NOT _TBB_INSTALL_DIR)
+# third: try to find path automatically
+if (NOT _TBB_INSTALL_DIR)
+ if (_TBB_DEFAULT_INSTALL_DIR)
+ set (_TBB_INSTALL_DIR ${_TBB_DEFAULT_INSTALL_DIR})
+ endif (_TBB_DEFAULT_INSTALL_DIR)
+endif (NOT _TBB_INSTALL_DIR)
+# sanity check
+if (NOT _TBB_INSTALL_DIR)
+ message ("ERROR: Unable to find Intel TBB install directory. ${_TBB_INSTALL_DIR}")
+else (NOT _TBB_INSTALL_DIR)
+# finally: set the cached CMake variable TBB_INSTALL_DIR
+if (NOT TBB_INSTALL_DIR)
+ set (TBB_INSTALL_DIR ${_TBB_INSTALL_DIR} CACHE PATH "Intel TBB install directory")
+ mark_as_advanced(TBB_INSTALL_DIR)
+endif (NOT TBB_INSTALL_DIR)
+
+
+#-- A macro to rewrite the paths of the library. This is necessary, because
+# find_library() always found the em64t/vc9 version of the TBB libs
+macro(TBB_CORRECT_LIB_DIR var_name)
+# if (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t")
+ string(REPLACE em64t "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}})
+# endif (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t")
+ string(REPLACE ia32 "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}})
+ string(REPLACE vc7.1 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+ string(REPLACE vc8 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+ string(REPLACE vc9 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+ string(REPLACE vc10 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+endmacro(TBB_CORRECT_LIB_DIR var_content)
+
+
+#-- Look for include directory and set ${TBB_INCLUDE_DIR}
+set (TBB_INC_SEARCH_DIR ${_TBB_INSTALL_DIR}/include)
+# Jiri: tbbvars now sets the CPATH environment variable to the directory
+# containing the headers.
+find_path(TBB_INCLUDE_DIR
+ tbb/task_scheduler_init.h
+ PATHS ${TBB_INC_SEARCH_DIR} ENV CPATH
+)
+mark_as_advanced(TBB_INCLUDE_DIR)
+
+
+#-- Look for libraries
+# GvdB: $ENV{TBB_ARCH_PLATFORM} is set by the build script tbbvars[.bat|.sh|.csh]
+if (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "")
+ set (_TBB_LIBRARY_DIR
+ ${_TBB_INSTALL_DIR}/lib/$ENV{TBB_ARCH_PLATFORM}
+ ${_TBB_INSTALL_DIR}/$ENV{TBB_ARCH_PLATFORM}/lib
+ )
+endif (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "")
+# Jiri: This block isn't mutually exclusive with the previous one
+# (hence no else), instead I test if the user really specified
+# the variables in question.
+if ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL ""))
+ # HH: deprecated
+ message(STATUS "[Warning] FindTBB.cmake: The use of TBB_ARCHITECTURE and TBB_COMPILER is deprecated and may not be supported in future versions. Please set \$ENV{TBB_ARCH_PLATFORM} (using tbbvars.[bat|csh|sh]).")
+ # Jiri: It doesn't hurt to look in more places, so I store the hints from
+ # ENV{TBB_ARCH_PLATFORM} and the TBB_ARCHITECTURE and TBB_COMPILER
+ # variables and search them both.
+ set (_TBB_LIBRARY_DIR "${_TBB_INSTALL_DIR}/${_TBB_ARCHITECTURE}/${_TBB_COMPILER}/lib" ${_TBB_LIBRARY_DIR})
+endif ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL ""))
+
+# GvdB: Mac OS X distribution places libraries directly in lib directory.
+list(APPEND _TBB_LIBRARY_DIR ${_TBB_INSTALL_DIR}/lib)
+
+# Jiri: No reason not to check the default paths. From recent versions,
+# tbbvars has started exporting the LIBRARY_PATH and LD_LIBRARY_PATH
+# variables, which now point to the directories of the lib files.
+# It all makes more sense to use the ${_TBB_LIBRARY_DIR} as a HINTS
+# argument instead of the implicit PATHS as it isn't hard-coded
+# but computed by system introspection. Searching the LIBRARY_PATH
+# and LD_LIBRARY_PATH environment variables is now even more important
+# that tbbvars doesn't export TBB_ARCH_PLATFORM and it facilitates
+# the use of TBB built from sources.
+find_library(TBB_LIBRARY ${_TBB_LIB_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+find_library(TBB_MALLOC_LIBRARY ${_TBB_LIB_MALLOC_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+
+#Extract path from TBB_LIBRARY name
+get_filename_component(TBB_LIBRARY_DIR ${TBB_LIBRARY} PATH)
+
+#TBB_CORRECT_LIB_DIR(TBB_LIBRARY)
+#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY)
+mark_as_advanced(TBB_LIBRARY TBB_MALLOC_LIBRARY)
+
+#-- Look for debug libraries
+# Jiri: Changed the same way as for the release libraries.
+find_library(TBB_LIBRARY_DEBUG ${_TBB_LIB_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+find_library(TBB_MALLOC_LIBRARY_DEBUG ${_TBB_LIB_MALLOC_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+
+# Jiri: Self-built TBB stores the debug libraries in a separate directory.
+# Extract path from TBB_LIBRARY_DEBUG name
+get_filename_component(TBB_LIBRARY_DEBUG_DIR ${TBB_LIBRARY_DEBUG} PATH)
+
+#TBB_CORRECT_LIB_DIR(TBB_LIBRARY_DEBUG)
+#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY_DEBUG)
+mark_as_advanced(TBB_LIBRARY_DEBUG TBB_MALLOC_LIBRARY_DEBUG)
+
+
+if (TBB_INCLUDE_DIR)
+ if (TBB_LIBRARY)
+ set (TBB_FOUND "YES")
+ set (TBB_LIBRARIES ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY} ${TBB_LIBRARIES})
+ set (TBB_DEBUG_LIBRARIES ${TBB_LIBRARY_DEBUG} ${TBB_MALLOC_LIBRARY_DEBUG} ${TBB_DEBUG_LIBRARIES})
+ set (TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR} CACHE PATH "TBB include directory" FORCE)
+ set (TBB_LIBRARY_DIRS ${TBB_LIBRARY_DIR} CACHE PATH "TBB library directory" FORCE)
+ # Jiri: Self-built TBB stores the debug libraries in a separate directory.
+ set (TBB_DEBUG_LIBRARY_DIRS ${TBB_LIBRARY_DEBUG_DIR} CACHE PATH "TBB debug library directory" FORCE)
+ mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARY_DIRS TBB_DEBUG_LIBRARY_DIRS TBB_LIBRARIES TBB_DEBUG_LIBRARIES)
+ message(STATUS "Found Intel TBB")
+ endif (TBB_LIBRARY)
+endif (TBB_INCLUDE_DIR)
+
+if (NOT TBB_FOUND)
+ message("ERROR: Intel TBB NOT found!")
+ message(STATUS "Looked for Threading Building Blocks in ${_TBB_INSTALL_DIR}")
+ # do only throw fatal, if this pkg is REQUIRED
+ if (TBB_FIND_REQUIRED)
+ message(FATAL_ERROR "Could NOT find TBB library.")
+ endif (TBB_FIND_REQUIRED)
+endif (NOT TBB_FOUND)
+
+endif (NOT _TBB_INSTALL_DIR)
+
+if (TBB_FOUND)
+ set(TBB_INTERFACE_VERSION 0)
+ FILE(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _TBB_VERSION_CONTENTS)
+ STRING(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" TBB_INTERFACE_VERSION "${_TBB_VERSION_CONTENTS}")
+ set(TBB_INTERFACE_VERSION "${TBB_INTERFACE_VERSION}")
+endif (TBB_FOUND)
diff --git a/example/example.cpp b/example/example.cpp
new file mode 100644
index 0000000..fe1de36
--- /dev/null
+++ b/example/example.cpp
@@ -0,0 +1,85 @@
+#include "osrm/route_parameters.hpp"
+#include "osrm/table_parameters.hpp"
+#include "osrm/nearest_parameters.hpp"
+#include "osrm/trip_parameters.hpp"
+#include "osrm/match_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+#include <utility>
+#include <iostream>
+#include <exception>
+
+#include <cstdlib>
+
+int main(int argc, const char *argv[]) try
+{
+ if (argc < 2)
+ {
+ std::cerr << "Usage: " << argv[0] << " data.osrm\n";
+ return EXIT_FAILURE;
+ }
+
+ using namespace osrm;
+
+ // Configure based on a .osrm base path, and no datasets in shared mem from osrm-datastore
+ EngineConfig config;
+ config.storage_config = {argv[1]};
+ config.use_shared_memory = false;
+
+ // Routing machine with several services (such as Route, Table, Nearest, Trip, Match)
+ OSRM osrm{config};
+
+ // The following shows how to use the Route service; configure this service
+ RouteParameters params;
+
+ // Route in monaco
+ params.coordinates.push_back({util::FloatLongitude(7.419758), util::FloatLatitude(43.731142)});
+ params.coordinates.push_back({util::FloatLongitude(7.419505), util::FloatLatitude(43.736825)});
+
+ // Response is in JSON format
+ json::Object result;
+
+ // Execute routing request, this does the heavy lifting
+ const auto status = osrm.Route(params, result);
+
+ if (status == Status::Ok)
+ {
+ auto &routes = result.values["routes"].get<json::Array>();
+
+ // Let's just use the first route
+ auto &route = routes.values.at(0).get<json::Object>();
+ const auto distance = route.values["distance"].get<json::Number>().value;
+ const auto duration = route.values["duration"].get<json::Number>().value;
+
+ // Warn users if extract does not contain the default Berlin coordinates from above
+ if (distance == 0 or duration == 0)
+ {
+ std::cout << "Note: distance or duration is zero. ";
+ std::cout << "You are probably doing a query outside of the OSM extract.\n\n";
+ }
+
+ std::cout << "Distance: " << distance << " meter\n";
+ std::cout << "Duration: " << duration << " seconds\n";
+ }
+ else if (status == Status::Error)
+ {
+ const auto code = result.values["code"].get<json::String>().value;
+ const auto message = result.values["message"].get<json::String>().value;
+
+ std::cout << "Code: " << code << "\n";
+ std::cout << "Message: " << code << "\n";
+ return EXIT_FAILURE;
+ }
+}
+catch (const std::exception &e)
+{
+ std::cerr << "Error: " << e.what() << std::endl;
+ return EXIT_FAILURE;
+}
diff --git a/extract.cpp b/extract.cpp
deleted file mode 100644
index dabc19a..0000000
--- a/extract.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "extractor/extractor.hpp"
-#include "extractor/extractor_options.hpp"
-#include "util/simple_logger.hpp"
-
-#include <boost/filesystem.hpp>
-
-#include <cstdlib>
-#include <exception>
-#include <new>
-
-int main(int argc, char *argv[]) try
-{
- LogPolicy::GetInstance().Unmute();
- ExtractorConfig extractor_config;
-
- const return_code result = ExtractorOptions::ParseArguments(argc, argv, extractor_config);
-
- if (return_code::fail == result)
- {
- return EXIT_FAILURE;
- }
-
- if (return_code::exit == result)
- {
- return EXIT_SUCCESS;
- }
-
- ExtractorOptions::GenerateOutputFilesNames(extractor_config);
-
- if (1 > extractor_config.requested_num_threads)
- {
- SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
- return EXIT_FAILURE;
- }
-
- if (!boost::filesystem::is_regular_file(extractor_config.input_path))
- {
- SimpleLogger().Write(logWARNING) << "Input file " << extractor_config.input_path.string()
- << " not found!";
- return EXIT_FAILURE;
- }
-
- if (!boost::filesystem::is_regular_file(extractor_config.profile_path))
- {
- SimpleLogger().Write(logWARNING) << "Profile " << extractor_config.profile_path.string()
- << " not found!";
- return EXIT_FAILURE;
- }
- return extractor(extractor_config).run();
-}
-catch (const std::bad_alloc &e)
-{
- SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
- SimpleLogger().Write(logWARNING)
- << "Please provide more memory or consider using a larger swapfile";
- return EXIT_FAILURE;
-}
-catch (const std::exception &e)
-{
- SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
- return EXIT_FAILURE;
-}
diff --git a/extractor/edge_based_graph_factory.cpp b/extractor/edge_based_graph_factory.cpp
deleted file mode 100644
index 1ddeb6a..0000000
--- a/extractor/edge_based_graph_factory.cpp
+++ /dev/null
@@ -1,702 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "edge_based_graph_factory.hpp"
-#include "../algorithms/coordinate_calculation.hpp"
-#include "../data_structures/percent.hpp"
-#include "../util/compute_angle.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/lua_util.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/timing_util.hpp"
-#include "../util/osrm_exception.hpp"
-
-#include "../util/debug_geometry.hpp"
-
-#include <boost/assert.hpp>
-
-#include <fstream>
-#include <iomanip>
-#include <limits>
-
-EdgeBasedGraphFactory::EdgeBasedGraphFactory(
- std::shared_ptr<NodeBasedDynamicGraph> node_based_graph,
- const CompressedEdgeContainer &compressed_edge_container,
- const std::unordered_set<NodeID> &barrier_nodes,
- const std::unordered_set<NodeID> &traffic_lights,
- std::shared_ptr<const RestrictionMap> restriction_map,
- const std::vector<QueryNode> &node_info_list,
- SpeedProfileProperties speed_profile)
- : m_max_edge_id(0), m_node_info_list(node_info_list), m_node_based_graph(std::move(node_based_graph)),
- m_restriction_map(std::move(restriction_map)), m_barrier_nodes(barrier_nodes),
- m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container),
- speed_profile(std::move(speed_profile))
-{
-}
-
-void EdgeBasedGraphFactory::GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &output_edge_list)
-{
- BOOST_ASSERT_MSG(0 == output_edge_list.size(), "Vector is not empty");
- using std::swap; // Koenig swap
- swap(m_edge_based_edge_list, output_edge_list);
-}
-
-void EdgeBasedGraphFactory::GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes)
-{
-#ifndef NDEBUG
- for (const EdgeBasedNode &node : m_edge_based_node_list)
- {
- BOOST_ASSERT(m_node_info_list.at(node.u).lat != INT_MAX);
- BOOST_ASSERT(m_node_info_list.at(node.u).lon != INT_MAX);
- BOOST_ASSERT(m_node_info_list.at(node.v).lon != INT_MAX);
- BOOST_ASSERT(m_node_info_list.at(node.v).lat != INT_MAX);
- }
-#endif
- using std::swap; // Koenig swap
- swap(nodes, m_edge_based_node_list);
-}
-
-void EdgeBasedGraphFactory::GetStartPointMarkers(std::vector<bool> &node_is_startpoint)
-{
- using std::swap; // Koenig swap
- swap(m_edge_based_node_is_startpoint, node_is_startpoint);
-}
-
-unsigned EdgeBasedGraphFactory::GetHighestEdgeID()
-{
- return m_max_edge_id;
-}
-
-void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
- const NodeID node_v)
-{
- // merge edges together into one EdgeBasedNode
- BOOST_ASSERT(node_u != SPECIAL_NODEID);
- BOOST_ASSERT(node_v != SPECIAL_NODEID);
-
- // find forward edge id and
- const EdgeID edge_id_1 = m_node_based_graph->FindEdge(node_u, node_v);
- BOOST_ASSERT(edge_id_1 != SPECIAL_EDGEID);
-
- const EdgeData &forward_data = m_node_based_graph->GetEdgeData(edge_id_1);
-
- // find reverse edge id and
- const EdgeID edge_id_2 = m_node_based_graph->FindEdge(node_v, node_u);
- BOOST_ASSERT(edge_id_2 != SPECIAL_EDGEID);
-
- const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(edge_id_2);
-
- if (forward_data.edge_id == SPECIAL_NODEID &&
- reverse_data.edge_id == SPECIAL_NODEID)
- {
- return;
- }
-
- BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_1) ==
- m_compressed_edge_container.HasEntryForID(edge_id_2));
- if (m_compressed_edge_container.HasEntryForID(edge_id_1))
- {
- BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_2));
-
- // reconstruct geometry and put in each individual edge with its offset
- const auto& forward_geometry = m_compressed_edge_container.GetBucketReference(edge_id_1);
- const auto& reverse_geometry = m_compressed_edge_container.GetBucketReference(edge_id_2);
- BOOST_ASSERT(forward_geometry.size() == reverse_geometry.size());
- BOOST_ASSERT(0 != forward_geometry.size());
- const unsigned geometry_size = static_cast<unsigned>(forward_geometry.size());
- BOOST_ASSERT(geometry_size > 1);
-
- // reconstruct bidirectional edge with individual weights and put each into the NN index
-
- std::vector<int> forward_dist_prefix_sum(forward_geometry.size(), 0);
- std::vector<int> reverse_dist_prefix_sum(reverse_geometry.size(), 0);
-
- // quick'n'dirty prefix sum as std::partial_sum needs addtional casts
- // TODO: move to lambda function with C++11
- int temp_sum = 0;
-
- for (const auto i : osrm::irange(0u, geometry_size))
- {
- forward_dist_prefix_sum[i] = temp_sum;
- temp_sum += forward_geometry[i].second;
-
- BOOST_ASSERT(forward_data.distance >= temp_sum);
- }
-
- temp_sum = 0;
- for (const auto i : osrm::irange(0u, geometry_size))
- {
- temp_sum += reverse_geometry[reverse_geometry.size() - 1 - i].second;
- reverse_dist_prefix_sum[i] = reverse_data.distance - temp_sum;
- // BOOST_ASSERT(reverse_data.distance >= temp_sum);
- }
-
- NodeID current_edge_source_coordinate_id = node_u;
-
- // traverse arrays from start and end respectively
- for (const auto i : osrm::irange(0u, geometry_size))
- {
- BOOST_ASSERT(current_edge_source_coordinate_id ==
- reverse_geometry[geometry_size - 1 - i].first);
- const NodeID current_edge_target_coordinate_id = forward_geometry[i].first;
- BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
-
- // build edges
- m_edge_based_node_list.emplace_back(
- forward_data.edge_id, reverse_data.edge_id,
- current_edge_source_coordinate_id, current_edge_target_coordinate_id,
- forward_data.name_id, forward_geometry[i].second,
- reverse_geometry[geometry_size - 1 - i].second, forward_dist_prefix_sum[i],
- reverse_dist_prefix_sum[i], m_compressed_edge_container.GetPositionForID(edge_id_1),
- false, INVALID_COMPONENTID, i, forward_data.travel_mode, reverse_data.travel_mode);
- m_edge_based_node_is_startpoint.push_back(forward_data.startpoint || reverse_data.startpoint);
- current_edge_source_coordinate_id = current_edge_target_coordinate_id;
-
- BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
-
- BOOST_ASSERT(node_u != m_edge_based_node_list.back().u ||
- node_v != m_edge_based_node_list.back().v);
-
- BOOST_ASSERT(node_u != m_edge_based_node_list.back().v ||
- node_v != m_edge_based_node_list.back().u);
- }
-
- BOOST_ASSERT(current_edge_source_coordinate_id == node_v);
- BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
- }
- else
- {
- BOOST_ASSERT(!m_compressed_edge_container.HasEntryForID(edge_id_2));
-
- if (forward_data.edge_id != SPECIAL_NODEID)
- {
- BOOST_ASSERT(!forward_data.reversed);
- }
- else
- {
- BOOST_ASSERT(forward_data.reversed);
- }
-
- if (reverse_data.edge_id != SPECIAL_NODEID)
- {
- BOOST_ASSERT(!reverse_data.reversed);
- }
- else
- {
- BOOST_ASSERT(reverse_data.reversed);
- }
-
- BOOST_ASSERT(forward_data.edge_id != SPECIAL_NODEID ||
- reverse_data.edge_id != SPECIAL_NODEID);
-
- m_edge_based_node_list.emplace_back(
- forward_data.edge_id, reverse_data.edge_id, node_u, node_v,
- forward_data.name_id, forward_data.distance, reverse_data.distance, 0, 0, SPECIAL_EDGEID,
- false, INVALID_COMPONENTID, 0, forward_data.travel_mode, reverse_data.travel_mode);
- m_edge_based_node_is_startpoint.push_back(forward_data.startpoint || reverse_data.startpoint);
- BOOST_ASSERT(!m_edge_based_node_list.back().IsCompressed());
- }
-}
-
-void EdgeBasedGraphFactory::FlushVectorToStream(
- std::ofstream &edge_data_file, std::vector<OriginalEdgeData> &original_edge_data_vector) const
-{
- if (original_edge_data_vector.empty())
- {
- return;
- }
- edge_data_file.write((char *)&(original_edge_data_vector[0]),
- original_edge_data_vector.size() * sizeof(OriginalEdgeData));
- original_edge_data_vector.clear();
-}
-
-#ifdef DEBUG_GEOMETRY
-void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
- lua_State *lua_state,
- const std::string &edge_segment_lookup_filename,
- const std::string &edge_penalty_filename,
- const bool generate_edge_lookup,
- const std::string &debug_turns_path)
-#else
-void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
- lua_State *lua_state,
- const std::string &edge_segment_lookup_filename,
- const std::string &edge_penalty_filename,
- const bool generate_edge_lookup)
-#endif
-{
- TIMER_START(renumber);
- m_max_edge_id = RenumberEdges() - 1;
- TIMER_STOP(renumber);
-
- TIMER_START(generate_nodes);
- GenerateEdgeExpandedNodes();
- TIMER_STOP(generate_nodes);
-
- TIMER_START(generate_edges);
-#ifdef DEBUG_GEOMETRY
- GenerateEdgeExpandedEdges(original_edge_data_filename, lua_state,
- edge_segment_lookup_filename,edge_penalty_filename,
- generate_edge_lookup, debug_turns_path);
-#else
- GenerateEdgeExpandedEdges(original_edge_data_filename, lua_state,
- edge_segment_lookup_filename,edge_penalty_filename,
- generate_edge_lookup);
-#endif
-
- TIMER_STOP(generate_edges);
-
- SimpleLogger().Write() << "Timing statistics for edge-expanded graph:";
- SimpleLogger().Write() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
- SimpleLogger().Write() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
- SimpleLogger().Write() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
-}
-
-
-/// Renumbers all _forward_ edges and sets the edge_id.
-/// A specific numbering is not important. Any unique ID will do.
-/// Returns the number of edge based nodes.
-unsigned EdgeBasedGraphFactory::RenumberEdges()
-{
- // renumber edge based node of outgoing edges
- unsigned numbered_edges_count = 0;
- for (const auto current_node : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
- {
- for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
- {
- EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
-
- // only number incoming edges
- if (edge_data.reversed)
- {
- continue;
- }
-
- BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges());
- edge_data.edge_id = numbered_edges_count;
- ++numbered_edges_count;
-
- BOOST_ASSERT(SPECIAL_NODEID != edge_data.edge_id);
- }
- }
-
- return numbered_edges_count;
-}
-
-/// Creates the nodes in the edge expanded graph from edges in the node-based graph.
-void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
-{
- Percent progress(m_node_based_graph->GetNumberOfNodes());
-
- // loop over all edges and generate new set of nodes
- for (const auto node_u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
- {
- BOOST_ASSERT(node_u != SPECIAL_NODEID);
- BOOST_ASSERT(node_u < m_node_based_graph->GetNumberOfNodes());
- progress.printStatus(node_u);
- for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
- {
- const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
- BOOST_ASSERT(e1 != SPECIAL_EDGEID);
- const NodeID node_v = m_node_based_graph->GetTarget(e1);
-
- BOOST_ASSERT(SPECIAL_NODEID != node_v);
- // pick only every other edge, since we have every edge as an outgoing
- // and incoming egde
- if (node_u > node_v)
- {
- continue;
- }
-
- BOOST_ASSERT(node_u < node_v);
-
- // if we found a non-forward edge reverse and try again
- if (edge_data.edge_id == SPECIAL_NODEID)
- {
- InsertEdgeBasedNode(node_v, node_u);
- }
- else
- {
- InsertEdgeBasedNode(node_u, node_v);
- }
- }
- }
-
- BOOST_ASSERT(m_edge_based_node_list.size() == m_edge_based_node_is_startpoint.size());
-
- SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
- << " nodes in edge-expanded graph";
-}
-
-/// Actually it also generates OriginalEdgeData and serializes them...
-#ifdef DEBUG_GEOMETRY
-void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
- const std::string &original_edge_data_filename, lua_State *lua_state,
- const std::string &edge_segment_lookup_filename,
- const std::string &edge_fixed_penalties_filename,
- const bool generate_edge_lookup,
- const std::string &debug_turns_path)
-#else
-void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
- const std::string &original_edge_data_filename, lua_State *lua_state,
- const std::string &edge_segment_lookup_filename,
- const std::string &edge_fixed_penalties_filename,
- const bool generate_edge_lookup)
-#endif
-{
- SimpleLogger().Write() << "generating edge-expanded edges";
-
- unsigned node_based_edge_counter = 0;
- unsigned original_edges_counter = 0;
-
- std::ofstream edge_data_file(original_edge_data_filename.c_str(), std::ios::binary);
- std::ofstream edge_segment_file;
- std::ofstream edge_penalty_file;
-
- if (generate_edge_lookup)
- {
- edge_segment_file.open(edge_segment_lookup_filename.c_str(), std::ios::binary);
- edge_penalty_file.open(edge_fixed_penalties_filename.c_str(), std::ios::binary);
- }
-
- // writes a dummy value that is updated later
- edge_data_file.write((char *)&original_edges_counter, sizeof(unsigned));
-
- std::vector<OriginalEdgeData> original_edge_data_vector;
- original_edge_data_vector.reserve(1024 * 1024);
-
- // Loop over all turns and generate new set of edges.
- // Three nested loop look super-linear, but we are dealing with a (kind of)
- // linear number of turns only.
- unsigned restricted_turns_counter = 0;
- unsigned skipped_uturns_counter = 0;
- unsigned skipped_barrier_turns_counter = 0;
- unsigned compressed = 0;
-
- Percent progress(m_node_based_graph->GetNumberOfNodes());
-
-#ifdef DEBUG_GEOMETRY
- DEBUG_TURNS_START(debug_turns_path);
-#endif
-
- for (const auto node_u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
- {
- //progress.printStatus(node_u);
- for (const EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
- {
- if (m_node_based_graph->GetEdgeData(e1).reversed)
- {
- continue;
- }
-
- ++node_based_edge_counter;
- const NodeID node_v = m_node_based_graph->GetTarget(e1);
- const NodeID only_restriction_to_node =
- m_restriction_map->CheckForEmanatingIsOnlyTurn(node_u, node_v);
- const bool is_barrier_node = m_barrier_nodes.find(node_v) != m_barrier_nodes.end();
-
- for (const EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(node_v))
- {
- if (m_node_based_graph->GetEdgeData(e2).reversed)
- {
- continue;
- }
- const NodeID node_w = m_node_based_graph->GetTarget(e2);
-
- if ((only_restriction_to_node != SPECIAL_NODEID) &&
- (node_w != only_restriction_to_node))
- {
- // We are at an only_-restriction but not at the right turn.
- ++restricted_turns_counter;
- continue;
- }
-
- if (is_barrier_node)
- {
- if (node_u != node_w)
- {
- ++skipped_barrier_turns_counter;
- continue;
- }
- }
- else
- {
- if (node_u == node_w && m_node_based_graph->GetOutDegree(node_v) > 1)
- {
- auto number_of_emmiting_bidirectional_edges = 0;
- for (auto edge : m_node_based_graph->GetAdjacentEdgeRange(node_v))
- {
- auto target = m_node_based_graph->GetTarget(edge);
- auto reverse_edge = m_node_based_graph->FindEdge(target, node_v);
- if (!m_node_based_graph->GetEdgeData(reverse_edge).reversed)
- {
- ++number_of_emmiting_bidirectional_edges;
- }
- }
- if (number_of_emmiting_bidirectional_edges > 1)
- {
- ++skipped_uturns_counter;
- continue;
- }
- }
- }
-
- // only add an edge if turn is not a U-turn except when it is
- // at the end of a dead-end street
- if (m_restriction_map->CheckIfTurnIsRestricted(node_u, node_v, node_w) &&
- (only_restriction_to_node == SPECIAL_NODEID) &&
- (node_w != only_restriction_to_node))
- {
- // We are at an only_-restriction but not at the right turn.
- ++restricted_turns_counter;
- continue;
- }
-
- // only add an edge if turn is not prohibited
- const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(e1);
- const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(e2);
-
- BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
- BOOST_ASSERT(!edge_data1.reversed);
- BOOST_ASSERT(!edge_data2.reversed);
-
- // the following is the core of the loop.
- unsigned distance = edge_data1.distance;
- if (m_traffic_lights.find(node_v) != m_traffic_lights.end())
- {
- distance += speed_profile.traffic_signal_penalty;
-
- DEBUG_SIGNAL(node_v, m_node_info_list, speed_profile.traffic_signal_penalty);
- }
-
- // unpack last node of first segment if packed
- const auto first_coordinate =
- m_node_info_list[(m_compressed_edge_container.HasEntryForID(e1)
- ? m_compressed_edge_container.GetLastEdgeSourceID(e1)
- : node_u)];
-
- // unpack first node of second segment if packed
- const auto third_coordinate =
- m_node_info_list[(m_compressed_edge_container.HasEntryForID(e2)
- ? m_compressed_edge_container.GetFirstEdgeTargetID(e2)
- : node_w)];
-
- const double turn_angle = ComputeAngle::OfThreeFixedPointCoordinates(
- first_coordinate, m_node_info_list[node_v], third_coordinate);
-
- const int turn_penalty = GetTurnPenalty(turn_angle, lua_state);
- TurnInstruction turn_instruction = AnalyzeTurn(node_u, node_v, node_w, turn_angle);
- if (turn_instruction == TurnInstruction::UTurn)
- {
- distance += speed_profile.u_turn_penalty;
-
- DEBUG_UTURN(node_v, m_node_info_list, speed_profile.u_turn_penalty);
- }
-
- DEBUG_TURN(node_v, m_node_info_list, first_coordinate, turn_angle, turn_penalty);
-
- distance += turn_penalty;
-
- const bool edge_is_compressed = m_compressed_edge_container.HasEntryForID(e1);
-
- if (edge_is_compressed)
- {
- ++compressed;
- }
-
- original_edge_data_vector.emplace_back(
- (edge_is_compressed ? m_compressed_edge_container.GetPositionForID(e1) : node_v),
- edge_data1.name_id, turn_instruction, edge_is_compressed,
- edge_data2.travel_mode);
-
- ++original_edges_counter;
-
- if (original_edge_data_vector.size() > 1024 * 1024 * 10)
- {
- FlushVectorToStream(edge_data_file, original_edge_data_vector);
- }
-
- BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
- BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
-
-
- // NOTE: potential overflow here if we hit 2^32 routable edges
- BOOST_ASSERT(m_edge_based_edge_list.size() <= std::numeric_limits<NodeID>::max());
- m_edge_based_edge_list.emplace_back(edge_data1.edge_id, edge_data2.edge_id,
- m_edge_based_edge_list.size(), distance, true, false);
-
-
- // Here is where we write out the mapping between the edge-expanded edges, and
- // the node-based edges that are originally used to calculate the `distance`
- // for the edge-expanded edges. About 40 lines back, there is:
- //
- // unsigned distance = edge_data1.distance;
- //
- // This tells us that the weight for an edge-expanded-edge is based on the weight
- // of the *source* node-based edge. Therefore, we will look up the individual
- // segments of the source node-based edge, and write out a mapping between
- // those and the edge-based-edge ID.
- // External programs can then use this mapping to quickly perform
- // updates to the edge-expanded-edge based directly on its ID.
- if (generate_edge_lookup)
- {
- unsigned fixed_penalty = distance - edge_data1.distance;
- edge_penalty_file.write(reinterpret_cast<const char *>(&fixed_penalty), sizeof(fixed_penalty));
- if (edge_is_compressed)
- {
- const auto node_based_edges = m_compressed_edge_container.GetBucketReference(e1);
- NodeID previous = node_u;
-
- const unsigned node_count = node_based_edges.size()+1;
- edge_segment_file.write(reinterpret_cast<const char *>(&node_count), sizeof(node_count));
- const QueryNode &first_node = m_node_info_list[previous];
- edge_segment_file.write(reinterpret_cast<const char *>(&first_node.node_id), sizeof(first_node.node_id));
-
- for (auto target_node : node_based_edges)
- {
- const QueryNode &from = m_node_info_list[previous];
- const QueryNode &to = m_node_info_list[target_node.first];
- const double segment_length = coordinate_calculation::great_circle_distance(from.lat, from.lon, to.lat, to.lon);
-
- edge_segment_file.write(reinterpret_cast<const char *>(&to.node_id), sizeof(to.node_id));
- edge_segment_file.write(reinterpret_cast<const char *>(&segment_length), sizeof(segment_length));
- edge_segment_file.write(reinterpret_cast<const char *>(&target_node.second), sizeof(target_node.second));
- previous = target_node.first;
- }
- }
- else
- {
- static const unsigned node_count = 2;
- const QueryNode from = m_node_info_list[node_u];
- const QueryNode to = m_node_info_list[node_v];
- const double segment_length = coordinate_calculation::great_circle_distance(from.lat, from.lon, to.lat, to.lon);
- edge_segment_file.write(reinterpret_cast<const char *>(&node_count), sizeof(node_count));
- edge_segment_file.write(reinterpret_cast<const char *>(&from.node_id), sizeof(from.node_id));
- edge_segment_file.write(reinterpret_cast<const char *>(&to.node_id), sizeof(to.node_id));
- edge_segment_file.write(reinterpret_cast<const char *>(&segment_length), sizeof(segment_length));
- edge_segment_file.write(reinterpret_cast<const char *>(&edge_data1.distance), sizeof(edge_data1.distance));
- }
- }
- }
- }
- }
-
- DEBUG_TURNS_STOP();
-
- FlushVectorToStream(edge_data_file, original_edge_data_vector);
-
- edge_data_file.seekp(std::ios::beg);
- edge_data_file.write((char *)&original_edges_counter, sizeof(unsigned));
- edge_data_file.close();
-
- SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size() << " edge based nodes";
- SimpleLogger().Write() << "Node-based graph contains " << node_based_edge_counter << " edges";
- SimpleLogger().Write() << "Edge-expanded graph ...";
- SimpleLogger().Write() << " contains " << m_edge_based_edge_list.size() << " edges";
- SimpleLogger().Write() << " skips " << restricted_turns_counter << " turns, "
- "defined by "
- << m_restriction_map->size() << " restrictions";
- SimpleLogger().Write() << " skips " << skipped_uturns_counter << " U turns";
- SimpleLogger().Write() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
-}
-
-int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) const
-{
-
- if (speed_profile.has_turn_penalty_function)
- {
- try
- {
- // call lua profile to compute turn penalty
- double penalty = luabind::call_function<double>(lua_state, "turn_function", 180. - angle);
- return static_cast<int>(penalty);
- }
- catch (const luabind::error &er)
- {
- SimpleLogger().Write(logWARNING) << er.what();
- }
- }
- return 0;
-}
-
-TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID node_u,
- const NodeID node_v,
- const NodeID node_w,
- const double angle) const
-{
- if (node_u == node_w)
- {
- return TurnInstruction::UTurn;
- }
-
- const EdgeID edge1 = m_node_based_graph->FindEdge(node_u, node_v);
- const EdgeID edge2 = m_node_based_graph->FindEdge(node_v, node_w);
-
- const EdgeData &data1 = m_node_based_graph->GetEdgeData(edge1);
- const EdgeData &data2 = m_node_based_graph->GetEdgeData(edge2);
-
- // roundabouts need to be handled explicitely
- if (data1.roundabout && data2.roundabout)
- {
- // Is a turn possible? If yes, we stay on the roundabout!
- if (1 == m_node_based_graph->GetDirectedOutDegree(node_v))
- {
- // No turn possible.
- return TurnInstruction::NoTurn;
- }
- return TurnInstruction::StayOnRoundAbout;
- }
- // Does turn start or end on roundabout?
- if (data1.roundabout || data2.roundabout)
- {
- // We are entering the roundabout
- if ((!data1.roundabout) && data2.roundabout)
- {
- return TurnInstruction::EnterRoundAbout;
- }
- // We are leaving the roundabout
- if (data1.roundabout && (!data2.roundabout))
- {
- return TurnInstruction::LeaveRoundAbout;
- }
- }
-
- // If street names stay the same and if we are certain that it is not a
- // a segment of a roundabout, we skip it.
- if (data1.name_id == data2.name_id && data1.travel_mode == data2.travel_mode)
- {
- // TODO: Here we should also do a small graph exploration to check for
- // more complex situations
- if (0 != data1.name_id || m_node_based_graph->GetOutDegree(node_v) <= 2)
- {
- return TurnInstruction::NoTurn;
- }
- }
-
- return TurnInstructionsClass::GetTurnDirectionOfInstruction(angle);
-}
-
diff --git a/extractor/edge_based_graph_factory.hpp b/extractor/edge_based_graph_factory.hpp
deleted file mode 100644
index 997c7ea..0000000
--- a/extractor/edge_based_graph_factory.hpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-// This class constructs the edge-expanded routing graph
-
-#ifndef EDGE_BASED_GRAPH_FACTORY_HPP_
-#define EDGE_BASED_GRAPH_FACTORY_HPP_
-
-#include "speed_profile.hpp"
-#include "../typedefs.h"
-#include "../data_structures/compressed_edge_container.hpp"
-#include "../data_structures/deallocating_vector.hpp"
-#include "../data_structures/edge_based_node.hpp"
-#include "../data_structures/original_edge_data.hpp"
-#include "../data_structures/query_node.hpp"
-#include "../data_structures/turn_instructions.hpp"
-#include "../data_structures/node_based_graph.hpp"
-#include "../data_structures/restriction_map.hpp"
-
-#include <algorithm>
-#include <iosfwd>
-#include <memory>
-#include <queue>
-#include <string>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-#include <boost/filesystem/fstream.hpp>
-
-struct lua_State;
-
-class EdgeBasedGraphFactory
-{
- public:
- EdgeBasedGraphFactory() = delete;
- EdgeBasedGraphFactory(const EdgeBasedGraphFactory &) = delete;
-
- explicit EdgeBasedGraphFactory(std::shared_ptr<NodeBasedDynamicGraph> node_based_graph,
- const CompressedEdgeContainer &compressed_edge_container,
- const std::unordered_set<NodeID> &barrier_nodes,
- const std::unordered_set<NodeID> &traffic_lights,
- std::shared_ptr<const RestrictionMap> restriction_map,
- const std::vector<QueryNode> &node_info_list,
- SpeedProfileProperties speed_profile);
-
-#ifdef DEBUG_GEOMETRY
- void Run(const std::string &original_edge_data_filename,
- lua_State *lua_state,
- const std::string &edge_segment_lookup_filename,
- const std::string &edge_penalty_filename,
- const bool generate_edge_lookup,
- const std::string &debug_turns_path);
-#else
- void Run(const std::string &original_edge_data_filename,
- lua_State *lua_state,
- const std::string &edge_segment_lookup_filename,
- const std::string &edge_penalty_filename,
- const bool generate_edge_lookup);
-#endif
-
- void GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &edges);
-
- void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes);
- void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
-
- unsigned GetHighestEdgeID();
-
- TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, const double angle) const;
-
- int GetTurnPenalty(double angle, lua_State *lua_state) const;
-
- private:
- using EdgeData = NodeBasedDynamicGraph::EdgeData;
-
- //! maps index from m_edge_based_node_list to ture/false if the node is an entry point to the graph
- std::vector<bool> m_edge_based_node_is_startpoint;
- //! list of edge based nodes (compressed segments)
- std::vector<EdgeBasedNode> m_edge_based_node_list;
- DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
- unsigned m_max_edge_id;
-
- const std::vector<QueryNode>& m_node_info_list;
- std::shared_ptr<NodeBasedDynamicGraph> m_node_based_graph;
- std::shared_ptr<RestrictionMap const> m_restriction_map;
-
- const std::unordered_set<NodeID>& m_barrier_nodes;
- const std::unordered_set<NodeID>& m_traffic_lights;
- const CompressedEdgeContainer& m_compressed_edge_container;
-
- SpeedProfileProperties speed_profile;
-
- void CompressGeometry();
- unsigned RenumberEdges();
- void GenerateEdgeExpandedNodes();
-#ifdef DEBUG_GEOMETRY
- void GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
- lua_State *lua_state,
- const std::string &edge_segment_lookup_filename,
- const std::string &edge_fixed_penalties_filename,
- const bool generate_edge_lookup,
- const std::string &debug_turns_path);
-#else
- void GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
- lua_State *lua_state,
- const std::string &edge_segment_lookup_filename,
- const std::string &edge_fixed_penalties_filename,
- const bool generate_edge_lookup);
-#endif
-
- void InsertEdgeBasedNode(const NodeID u, const NodeID v);
-
- void FlushVectorToStream(std::ofstream &edge_data_file,
- std::vector<OriginalEdgeData> &original_edge_data_vector) const;
-
-};
-
-#endif /* EDGE_BASED_GRAPH_FACTORY_HPP_ */
diff --git a/extractor/extraction_node.hpp b/extractor/extraction_node.hpp
deleted file mode 100644
index e821d6f..0000000
--- a/extractor/extraction_node.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef EXTRACTION_NODE_HPP
-#define EXTRACTION_NODE_HPP
-
-struct ExtractionNode
-{
- ExtractionNode() : traffic_lights(false), barrier(false) {}
- void clear() { traffic_lights = barrier = false; }
- bool traffic_lights;
- bool barrier;
-};
-#endif // EXTRACTION_NODE_HPP
diff --git a/extractor/extraction_way.hpp b/extractor/extraction_way.hpp
deleted file mode 100644
index 094c10a..0000000
--- a/extractor/extraction_way.hpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef EXTRACTION_WAY_HPP
-#define EXTRACTION_WAY_HPP
-
-#include "../data_structures/travel_mode.hpp"
-#include "../typedefs.h"
-
-#include <string>
-#include <vector>
-
-/**
- * This struct is the direct result of the call to ```way_function```
- * in the lua based profile.
- *
- * It is split into multiple edge segments in the ExtractorCallback.
- */
-struct ExtractionWay
-{
- ExtractionWay() { clear(); }
-
- void clear()
- {
- forward_speed = -1;
- backward_speed = -1;
- duration = -1;
- roundabout = false;
- is_startpoint = true;
- is_access_restricted = false;
- name.clear();
- forward_travel_mode = TRAVEL_MODE_DEFAULT;
- backward_travel_mode = TRAVEL_MODE_DEFAULT;
- }
-
- enum Directions
- {
- notSure = 0,
- oneway,
- bidirectional,
- opposite
- };
-
- // These accessor methods exists to support the depreciated "way.direction" access
- // in LUA. Since the direction attribute was removed from ExtractionWay, the
- // accessors translate to/from the mode attributes.
- void set_direction(const Directions m)
- {
- if (Directions::oneway == m)
- {
- forward_travel_mode = TRAVEL_MODE_DEFAULT;
- backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
- }
- else if (Directions::opposite == m)
- {
- forward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
- backward_travel_mode = TRAVEL_MODE_DEFAULT;
- }
- else if (Directions::bidirectional == m)
- {
- forward_travel_mode = TRAVEL_MODE_DEFAULT;
- backward_travel_mode = TRAVEL_MODE_DEFAULT;
- }
- }
-
- Directions get_direction() const
- {
- if (TRAVEL_MODE_INACCESSIBLE != forward_travel_mode &&
- TRAVEL_MODE_INACCESSIBLE != backward_travel_mode)
- {
- return Directions::bidirectional;
- }
- else if (TRAVEL_MODE_INACCESSIBLE != forward_travel_mode)
- {
- return Directions::oneway;
- }
- else if (TRAVEL_MODE_INACCESSIBLE != backward_travel_mode)
- {
- return Directions::opposite;
- }
- else
- {
- return Directions::notSure;
- }
- }
-
- // These accessors exists because it's not possible to take the address of a bitfield,
- // and LUA therefore cannot read/write the mode attributes directly.
- void set_forward_mode(const TravelMode m) { forward_travel_mode = m; }
- TravelMode get_forward_mode() const { return forward_travel_mode; }
- void set_backward_mode(const TravelMode m) { backward_travel_mode = m; }
- TravelMode get_backward_mode() const { return backward_travel_mode; }
-
- double forward_speed;
- double backward_speed;
- double duration;
- std::string name;
- bool roundabout;
- bool is_access_restricted;
- bool is_startpoint;
- TravelMode forward_travel_mode : 4;
- TravelMode backward_travel_mode : 4;
-};
-
-#endif // EXTRACTION_WAY_HPP
diff --git a/extractor/extractor_options.cpp b/extractor/extractor_options.cpp
deleted file mode 100644
index b607dca..0000000
--- a/extractor/extractor_options.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "extractor_options.hpp"
-
-#include "util/version.hpp"
-#include "../util/ini_file.hpp"
-#include "../util/simple_logger.hpp"
-
-#include <boost/filesystem.hpp>
-#include <boost/program_options.hpp>
-
-#include <tbb/task_scheduler_init.h>
-
-return_code
-ExtractorOptions::ParseArguments(int argc, char *argv[], ExtractorConfig &extractor_config)
-{
- // declare a group of options that will be allowed only on command line
- boost::program_options::options_description generic_options("Options");
- generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
- /*
- * TODO: re-enable this
- "restrictions,r",
- boost::program_options::value<boost::filesystem::path>(&extractor_config.restrictions_path),
- "Restrictions file in .osrm.restrictions format")(
- */
- "config,c", boost::program_options::value<boost::filesystem::path>(
- &extractor_config.config_file_path)->default_value("extractor.ini"),
- "Path to a configuration file.");
-
- // declare a group of options that will be allowed both on command line and in config file
- boost::program_options::options_description config_options("Configuration");
- config_options.add_options()("profile,p",
- boost::program_options::value<boost::filesystem::path>(
- &extractor_config.profile_path)->default_value("profile.lua"),
- "Path to LUA routing profile")(
- "threads,t",
- boost::program_options::value<unsigned int>(&extractor_config.requested_num_threads)
- ->default_value(tbb::task_scheduler_init::default_num_threads()),
- "Number of threads to use")(
- "generate-edge-lookup",boost::program_options::value<bool>(
- &extractor_config.generate_edge_lookup)->implicit_value(true)->default_value(false),
- "Generate a lookup table for internal edge-expanded-edge IDs to OSM node pairs")(
- "small-component-size",
- boost::program_options::value<unsigned int>(&extractor_config.small_component_size)
- ->default_value(1000),
- "Number of nodes required before a strongly-connected-componennt is considered big (affects nearest neighbor snapping)");
-
-#ifdef DEBUG_GEOMETRY
- config_options.add_options()("debug-turns",
- boost::program_options::value<std::string>(&extractor_config.debug_turns_path),
- "Write out GeoJSON with turn penalty data");
-#endif // DEBUG_GEOMETRY
-
- // hidden options, will be allowed both on command line and in config file, but will not be
- // shown to the user
- boost::program_options::options_description hidden_options("Hidden options");
- hidden_options.add_options()("input,i", boost::program_options::value<boost::filesystem::path>(
- &extractor_config.input_path),
- "Input file in .osm, .osm.bz2 or .osm.pbf format");
-
-
- // positional option
- boost::program_options::positional_options_description positional_options;
- positional_options.add("input", 1);
-
- // combine above options for parsing
- boost::program_options::options_description cmdline_options;
- cmdline_options.add(generic_options).add(config_options).add(hidden_options);
-
- boost::program_options::options_description config_file_options;
- config_file_options.add(config_options).add(hidden_options);
-
- boost::program_options::options_description visible_options(
- boost::filesystem::basename(argv[0]) + " <input.osm/.osm.bz2/.osm.pbf> [options]");
- visible_options.add(generic_options).add(config_options);
-
- // parse command line options
- try
- {
- boost::program_options::variables_map option_variables;
- boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
- .options(cmdline_options)
- .positional(positional_options)
- .run(),
- option_variables);
- if (option_variables.count("version"))
- {
- SimpleLogger().Write() << OSRM_VERSION;
- return return_code::exit;
- }
-
- if (option_variables.count("help"))
- {
- SimpleLogger().Write() << visible_options;
- return return_code::exit;
- }
-
- boost::program_options::notify(option_variables);
-
- // parse config file
- if (boost::filesystem::is_regular_file(extractor_config.config_file_path))
- {
- SimpleLogger().Write()
- << "Reading options from: " << extractor_config.config_file_path.string();
- std::string ini_file_contents =
- read_file_lower_content(extractor_config.config_file_path);
- std::stringstream config_stream(ini_file_contents);
- boost::program_options::store(parse_config_file(config_stream, config_file_options),
- option_variables);
- boost::program_options::notify(option_variables);
- }
-
- if (!option_variables.count("input"))
- {
- SimpleLogger().Write() << visible_options;
- return return_code::exit;
- }
- }
- catch (std::exception &e)
- {
- SimpleLogger().Write(logWARNING) << e.what();
- return return_code::fail;
- }
-
- return return_code::ok;
-}
-
-void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_config)
-{
- boost::filesystem::path &input_path = extractor_config.input_path;
- extractor_config.output_file_name = input_path.string();
- extractor_config.restriction_file_name = input_path.string();
- extractor_config.names_file_name = input_path.string();
- extractor_config.timestamp_file_name = input_path.string();
- extractor_config.geometry_output_path = input_path.string();
- extractor_config.edge_output_path = input_path.string();
- extractor_config.edge_graph_output_path = input_path.string();
- extractor_config.node_output_path = input_path.string();
- extractor_config.rtree_nodes_output_path = input_path.string();
- extractor_config.rtree_leafs_output_path = input_path.string();
- extractor_config.edge_segment_lookup_path = input_path.string();
- extractor_config.edge_penalty_path = input_path.string();
- std::string::size_type pos = extractor_config.output_file_name.find(".osm.bz2");
- if (pos == std::string::npos)
- {
- pos = extractor_config.output_file_name.find(".osm.pbf");
- if (pos == std::string::npos)
- {
- pos = extractor_config.output_file_name.find(".osm.xml");
- }
- }
- if (pos == std::string::npos)
- {
- pos = extractor_config.output_file_name.find(".pbf");
- }
- if (pos == std::string::npos)
- {
- pos = extractor_config.output_file_name.find(".osm");
- if (pos == std::string::npos)
- {
- extractor_config.output_file_name.append(".osrm");
- extractor_config.restriction_file_name.append(".osrm.restrictions");
- extractor_config.names_file_name.append(".osrm.names");
- extractor_config.timestamp_file_name.append(".osrm.timestamp");
- extractor_config.geometry_output_path.append(".osrm.geometry");
- extractor_config.node_output_path.append(".osrm.nodes");
- extractor_config.edge_output_path.append(".osrm.edges");
- extractor_config.edge_graph_output_path.append(".osrm.ebg");
- extractor_config.rtree_nodes_output_path.append(".osrm.ramIndex");
- extractor_config.rtree_leafs_output_path.append(".osrm.fileIndex");
- extractor_config.edge_segment_lookup_path.append(".osrm.edge_segment_lookup");
- extractor_config.edge_penalty_path.append(".osrm.edge_penalties");
- }
- else
- {
- extractor_config.output_file_name.replace(pos, 5, ".osrm");
- extractor_config.restriction_file_name.replace(pos, 5, ".osrm.restrictions");
- extractor_config.names_file_name.replace(pos, 5, ".osrm.names");
- extractor_config.timestamp_file_name.replace(pos, 5, ".osrm.timestamp");
- extractor_config.geometry_output_path.replace(pos, 5, ".osrm.geometry");
- extractor_config.node_output_path.replace(pos, 5, ".osrm.nodes");
- extractor_config.edge_output_path.replace(pos, 5, ".osrm.edges");
- extractor_config.edge_graph_output_path.replace(pos, 5, ".osrm.ebg");
- extractor_config.rtree_nodes_output_path.replace(pos, 5, ".osrm.ramIndex");
- extractor_config.rtree_leafs_output_path.replace(pos, 5, ".osrm.fileIndex");
- extractor_config.edge_segment_lookup_path.replace(pos,5, ".osrm.edge_segment_lookup");
- extractor_config.edge_penalty_path.replace(pos,5, ".osrm.edge_penalties");
- }
- }
- else
- {
- extractor_config.output_file_name.replace(pos, 8, ".osrm");
- extractor_config.restriction_file_name.replace(pos, 8, ".osrm.restrictions");
- extractor_config.names_file_name.replace(pos, 8, ".osrm.names");
- extractor_config.timestamp_file_name.replace(pos, 8, ".osrm.timestamp");
- extractor_config.geometry_output_path.replace(pos, 8, ".osrm.geometry");
- extractor_config.node_output_path.replace(pos, 8, ".osrm.nodes");
- extractor_config.edge_output_path.replace(pos, 8, ".osrm.edges");
- extractor_config.edge_graph_output_path.replace(pos, 8, ".osrm.ebg");
- extractor_config.rtree_nodes_output_path.replace(pos, 8, ".osrm.ramIndex");
- extractor_config.rtree_leafs_output_path.replace(pos, 8, ".osrm.fileIndex");
- extractor_config.edge_segment_lookup_path.replace(pos,8, ".osrm.edge_segment_lookup");
- extractor_config.edge_penalty_path.replace(pos,8, ".osrm.edge_penalties");
- }
-}
diff --git a/extractor/first_and_last_segment_of_way.hpp b/extractor/first_and_last_segment_of_way.hpp
deleted file mode 100644
index ead8b4c..0000000
--- a/extractor/first_and_last_segment_of_way.hpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
-#define FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
-
-#include "../data_structures/external_memory_node.hpp"
-#include "../typedefs.h"
-
-#include <limits>
-#include <string>
-
-struct FirstAndLastSegmentOfWay
-{
- OSMWayID way_id;
- OSMNodeID first_segment_source_id;
- OSMNodeID first_segment_target_id;
- OSMNodeID last_segment_source_id;
- OSMNodeID last_segment_target_id;
-
- FirstAndLastSegmentOfWay()
- : way_id(SPECIAL_OSM_WAYID),
- first_segment_source_id(SPECIAL_OSM_NODEID),
- first_segment_target_id(SPECIAL_OSM_NODEID),
- last_segment_source_id(SPECIAL_OSM_NODEID),
- last_segment_target_id(SPECIAL_OSM_NODEID)
- {
- }
-
- FirstAndLastSegmentOfWay(OSMWayID w, OSMNodeID fs, OSMNodeID ft, OSMNodeID ls, OSMNodeID lt)
- : way_id(w), first_segment_source_id(fs), first_segment_target_id(ft),
- last_segment_source_id(ls), last_segment_target_id(lt)
- {
- }
-
- static FirstAndLastSegmentOfWay min_value()
- {
- return {MIN_OSM_WAYID,
- MIN_OSM_NODEID,
- MIN_OSM_NODEID,
- MIN_OSM_NODEID,
- MIN_OSM_NODEID};
- }
- static FirstAndLastSegmentOfWay max_value()
- {
- return {MAX_OSM_WAYID,
- MAX_OSM_NODEID,
- MAX_OSM_NODEID,
- MAX_OSM_NODEID,
- MAX_OSM_NODEID};
- }
-};
-
-struct FirstAndLastSegmentOfWayStxxlCompare
-{
- using value_type = FirstAndLastSegmentOfWay;
- bool operator()(const FirstAndLastSegmentOfWay &a, const FirstAndLastSegmentOfWay &b) const
- {
- return a.way_id < b.way_id;
- }
- value_type max_value() { return FirstAndLastSegmentOfWay::max_value(); }
- value_type min_value() { return FirstAndLastSegmentOfWay::min_value(); }
-};
-
-#endif /* FIRST_AND_LAST_SEGMENT_OF_WAY_HPP */
diff --git a/extractor/restriction_parser.hpp b/extractor/restriction_parser.hpp
deleted file mode 100644
index 11f94ee..0000000
--- a/extractor/restriction_parser.hpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef RESTRICTION_PARSER_HPP
-#define RESTRICTION_PARSER_HPP
-
-#include "../data_structures/restriction.hpp"
-
-#include <boost/optional/optional.hpp>
-
-#include <string>
-#include <vector>
-
-struct lua_State;
-namespace osmium
-{
-class Relation;
-}
-
-/**
- * Parses the relations that represents turn restrictions.
- *
- * Currently only restrictions where the via objects is a node are supported.
- * from via to
- * ------->(x)-------->
- *
- * While this class does not directly invoke any lua code _per relation_ it does
- * load configuration values from the profile, that are saved in variables.
- * Namely ```use_turn_restrictions``` and ```get_exceptions```.
- *
- * The restriction is represented by the osm id of the from way, the osm id of the
- * to way and the osm id of the via node. This representation must be post-processed
- * in the extractor to work with the edge-based data-model of OSRM:
- * Since the from and to way share the via-node a turn will have the following form:
- * ...----(a)-----(via)------(b)----...
- * So it can be represented by the tripe (a, via, b).
- */
-class RestrictionParser
-{
- public:
- RestrictionParser(lua_State *lua_state);
- boost::optional<InputRestrictionContainer> TryParse(const osmium::Relation &relation) const;
-
- private:
- void ReadUseRestrictionsSetting(lua_State *lua_state);
- void ReadRestrictionExceptions(lua_State *lua_state);
- bool ShouldIgnoreRestriction(const std::string &except_tag_string) const;
-
- std::vector<std::string> restriction_exceptions;
- bool use_turn_restrictions;
-};
-
-#endif /* RESTRICTION_PARSER_HPP */
diff --git a/extractor/scripting_environment.cpp b/extractor/scripting_environment.cpp
deleted file mode 100644
index 7ccc08a..0000000
--- a/extractor/scripting_environment.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "scripting_environment.hpp"
-
-#include "extraction_helper_functions.hpp"
-#include "extraction_node.hpp"
-#include "extraction_way.hpp"
-#include "internal_extractor_edge.hpp"
-#include "../data_structures/external_memory_node.hpp"
-#include "../data_structures/raster_source.hpp"
-#include "../util/lua_util.hpp"
-#include "../util/osrm_exception.hpp"
-#include "../util/simple_logger.hpp"
-#include "../typedefs.h"
-
-#include <luabind/tag_function.hpp>
-#include <luabind/operator.hpp>
-
-#include <osmium/osm.hpp>
-
-#include <sstream>
-namespace
-{
-// wrapper method as luabind doesn't automatically overload funcs w/ default parameters
-template <class T>
-auto get_value_by_key(T const &object, const char *key) -> decltype(object.get_value_by_key(key))
-{
- return object.get_value_by_key(key, "");
-}
-
-int lua_error_callback(lua_State *L) // This is so I can use my own function as an
-// exception handler, pcall_log()
-{
- std::string error_msg = lua_tostring(L, -1);
- std::ostringstream error_stream;
- error_stream << error_msg;
- throw osrm::exception("ERROR occured in profile script:\n" + error_stream.str());
-}
-}
-
-ScriptingEnvironment::ScriptingEnvironment(const std::string &file_name) : file_name(file_name)
-{
- SimpleLogger().Write() << "Using script " << file_name;
-}
-
-void ScriptingEnvironment::init_lua_state(lua_State *lua_state)
-{
- typedef double (osmium::Location::*location_member_ptr_type)() const;
-
- luabind::open(lua_state);
- // open utility libraries string library;
- luaL_openlibs(lua_state);
-
- luaAddScriptFolderToLoadPath(lua_state, file_name.c_str());
-
- // Add our function to the state's global scope
- luabind::module(lua_state)[
- luabind::def("print", LUA_print<std::string>),
- luabind::def("durationIsValid", durationIsValid),
- luabind::def("parseDuration", parseDuration),
- luabind::class_<SourceContainer>("sources")
- .def(luabind::constructor<>())
- .def("load", &SourceContainer::loadRasterSource)
- .def("query", &SourceContainer::getRasterDataFromSource)
- .def("interpolate", &SourceContainer::getRasterInterpolateFromSource),
- luabind::class_<const float>("constants")
- .enum_("enums")[luabind::value("precision", COORDINATE_PRECISION)],
-
- luabind::class_<std::vector<std::string>>("vector")
- .def("Add", static_cast<void (std::vector<std::string>::*)(const std::string &)>(
- &std::vector<std::string>::push_back)),
-
- luabind::class_<osmium::Location>("Location")
- .def<location_member_ptr_type>("lat", &osmium::Location::lat)
- .def<location_member_ptr_type>("lon", &osmium::Location::lon),
-
- luabind::class_<osmium::Node>("Node")
- // .def<node_member_ptr_type>("tags", &osmium::Node::tags)
- .def("location", &osmium::Node::location)
- .def("get_value_by_key", &osmium::Node::get_value_by_key)
- .def("get_value_by_key", &get_value_by_key<osmium::Node>)
- .def("id", &osmium::Node::id),
-
- luabind::class_<ExtractionNode>("ResultNode")
- .def_readwrite("traffic_lights", &ExtractionNode::traffic_lights)
- .def_readwrite("barrier", &ExtractionNode::barrier),
-
- luabind::class_<ExtractionWay>("ResultWay")
- // .def(luabind::constructor<>())
- .def_readwrite("forward_speed", &ExtractionWay::forward_speed)
- .def_readwrite("backward_speed", &ExtractionWay::backward_speed)
- .def_readwrite("name", &ExtractionWay::name)
- .def_readwrite("roundabout", &ExtractionWay::roundabout)
- .def_readwrite("is_access_restricted", &ExtractionWay::is_access_restricted)
- .def_readwrite("is_startpoint", &ExtractionWay::is_startpoint)
- .def_readwrite("duration", &ExtractionWay::duration)
- .property("forward_mode", &ExtractionWay::get_forward_mode,
- &ExtractionWay::set_forward_mode)
- .property("backward_mode", &ExtractionWay::get_backward_mode,
- &ExtractionWay::set_backward_mode)
- .enum_("constants")[
- luabind::value("notSure", 0),
- luabind::value("oneway", 1),
- luabind::value("bidirectional", 2),
- luabind::value("opposite", 3)
- ],
- luabind::class_<osmium::Way>("Way")
- .def("get_value_by_key", &osmium::Way::get_value_by_key)
- .def("get_value_by_key", &get_value_by_key<osmium::Way>)
- .def("id", &osmium::Way::id),
- luabind::class_<InternalExtractorEdge>("EdgeSource")
- .property("source_coordinate", &InternalExtractorEdge::source_coordinate)
- .property("weight_data", &InternalExtractorEdge::weight_data),
- luabind::class_<InternalExtractorEdge::WeightData>("WeightData")
- .def_readwrite("speed", &InternalExtractorEdge::WeightData::speed),
- luabind::class_<ExternalMemoryNode>("EdgeTarget")
- .property("lat", &ExternalMemoryNode::lat)
- .property("lon", &ExternalMemoryNode::lon),
- luabind::class_<FixedPointCoordinate>("Coordinate")
- .property("lat", &FixedPointCoordinate::lat)
- .property("lon", &FixedPointCoordinate::lon),
- luabind::class_<RasterDatum>("RasterDatum")
- .property("datum", &RasterDatum::datum)
- .def("invalid_data", &RasterDatum::get_invalid)
- ];
-
- if (0 != luaL_dofile(lua_state, file_name.c_str()))
- {
- luabind::object error_msg(luabind::from_stack(lua_state, -1));
- std::ostringstream error_stream;
- error_stream << error_msg;
- throw osrm::exception("ERROR occured in profile script:\n" + error_stream.str());
- }
-}
-
-lua_State *ScriptingEnvironment::get_lua_state()
-{
- std::lock_guard<std::mutex> lock(init_mutex);
- bool initialized = false;
- auto &ref = script_contexts.local(initialized);
- if (!initialized)
- {
- std::shared_ptr<lua_State> state(luaL_newstate(), lua_close);
- ref = state;
- init_lua_state(ref.get());
- }
- luabind::set_pcall_callback(&lua_error_callback);
-
- return ref.get();
-}
diff --git a/extractor/scripting_environment.hpp b/extractor/scripting_environment.hpp
deleted file mode 100644
index 8722aee..0000000
--- a/extractor/scripting_environment.hpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef SCRIPTING_ENVIRONMENT_HPP
-#define SCRIPTING_ENVIRONMENT_HPP
-
-#include <string>
-#include <memory>
-#include <mutex>
-#include <tbb/enumerable_thread_specific.h>
-
-struct lua_State;
-
-/**
- * Creates a lua context and binds osmium way, node and relation objects and
- * ExtractionWay and ExtractionNode to lua objects.
- *
- * Each thread has its own lua state which is implemented with thread specific
- * storage from TBB.
- */
-class ScriptingEnvironment
-{
- public:
- ScriptingEnvironment() = delete;
- explicit ScriptingEnvironment(const std::string &file_name);
-
- lua_State *get_lua_state();
-
- private:
- void init_lua_state(lua_State *lua_state);
- std::mutex init_mutex;
- std::string file_name;
- tbb::enumerable_thread_specific<std::shared_ptr<lua_State>> script_contexts;
-};
-
-#endif /* SCRIPTING_ENVIRONMENT_HPP */
diff --git a/extractor/speed_profile.hpp b/extractor/speed_profile.hpp
deleted file mode 100644
index 534ccce..0000000
--- a/extractor/speed_profile.hpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef SPEED_PROFILE_PROPERTIES_HPP
-#define SPEED_PROFILE_PROPERTIES_HPP
-
-struct SpeedProfileProperties
-{
- SpeedProfileProperties()
- : traffic_signal_penalty(0), u_turn_penalty(0), has_turn_penalty_function(false)
- {
- }
-
- int traffic_signal_penalty;
- int u_turn_penalty;
- bool has_turn_penalty_function;
-};
-
-#endif
diff --git a/features/bicycle/area.feature b/features/bicycle/area.feature
index 062e86f..626b383 100644
--- a/features/bicycle/area.feature
+++ b/features/bicycle/area.feature
@@ -4,7 +4,7 @@ Feature: Bike - Squares and other areas
Background:
Given the profile "bicycle"
- @square
+ @square @mokob @2154
Scenario: Bike - Route along edge of a squares
Given the node map
| x | |
@@ -17,15 +17,15 @@ Feature: Bike - Squares and other areas
| abcda | yes | residential |
When I route I should get
- | from | to | route |
- | a | b | abcda |
- | a | d | abcda |
- | b | c | abcda |
- | c | b | abcda |
- | c | d | abcda |
- | d | c | abcda |
- | d | a | abcda |
- | a | d | abcda |
+ | from | to | route |
+ | a | b | abcda,abcda |
+ | a | d | abcda,abcda |
+ | b | c | abcda,abcda |
+ | c | b | abcda,abcda |
+ | c | d | abcda,abcda |
+ | d | c | abcda,abcda |
+ | d | a | abcda,abcda |
+ | a | d | abcda,abcda |
@building
Scenario: Bike - Don't route on buildings
@@ -41,16 +41,16 @@ Feature: Bike - Squares and other areas
When I route I should get
| from | to | route |
- | a | b | xa |
- | a | d | xa |
- | b | c | xa |
- | c | b | xa |
- | c | d | xa |
- | d | c | xa |
- | d | a | xa |
- | a | d | xa |
+ | a | b | xa,xa |
+ | a | d | xa,xa |
+ | b | c | xa,xa |
+ | c | b | xa,xa |
+ | c | d | xa,xa |
+ | d | c | xa,xa |
+ | d | a | xa,xa |
+ | a | d | xa,xa |
- @parking
+ @parking @mokob @2154
Scenario: Bike - parking areas
Given the node map
| e | | | f |
@@ -65,19 +65,20 @@ Feature: Bike - Squares and other areas
| abcda | (nil) | parking |
When I route I should get
- | from | to | route |
- | x | y | xa,abcda,by |
- | y | x | by,abcda,xa |
- | a | b | abcda |
- | a | d | abcda |
- | b | c | abcda |
- | c | b | abcda |
- | c | d | abcda |
- | d | c | abcda |
- | d | a | abcda |
- | a | d | abcda |
+ | from | to | route |
+ | x | y | xa,abcda,by,by |
+ | y | x | by,abcda,xa,xa |
+ | a | b | abcda,abcda |
+ | a | d | abcda,abcda |
+ | b | c | abcda,abcda |
+ | c | b | abcda,abcda |
+ | c | d | abcda,abcda |
+ | d | c | abcda,abcda |
+ | d | a | abcda,abcda |
+ | a | d | abcda,abcda |
- @train @platform
+
+ @train @platform @mokob @2154
Scenario: Bike - railway platforms
Given the node map
| x | a | b | y |
@@ -90,14 +91,14 @@ Feature: Bike - Squares and other areas
| abcda | (nil) | platform |
When I route I should get
- | from | to | route |
- | x | y | xa,abcda,by |
- | y | x | by,abcda,xa |
- | a | b | abcda |
- | a | d | abcda |
- | b | c | abcda |
- | c | b | abcda |
- | c | d | abcda |
- | d | c | abcda |
- | d | a | abcda |
- | a | d | abcda |
+ | from | to | route |
+ | x | y | xa,abcda,by,by |
+ | y | x | by,abcda,xa,xa |
+ | a | b | abcda,abcda |
+ | a | d | abcda,abcda |
+ | b | c | abcda,abcda |
+ | c | b | abcda,abcda |
+ | c | d | abcda,abcda |
+ | d | c | abcda,abcda |
+ | d | a | abcda,abcda |
+ | a | d | abcda,abcda |
diff --git a/features/bicycle/bridge.feature b/features/bicycle/bridge.feature
index 8c26ee9..e691ae1 100644
--- a/features/bicycle/bridge.feature
+++ b/features/bicycle/bridge.feature
@@ -4,7 +4,7 @@ Feature: Bicycle - Handle movable bridge
Background:
Given the profile "bicycle"
- Scenario: Car - Use a ferry route
+ Scenario: Bicycle - Use a ferry route
Given the node map
| a | b | c | | |
| | | d | | |
@@ -17,17 +17,17 @@ Feature: Bicycle - Handle movable bridge
| efg | primary | | |
When I route I should get
- | from | to | route | modes |
- | a | g | abc,cde,efg | 1,5,1 |
- | b | f | abc,cde,efg | 1,5,1 |
- | e | c | cde | 5 |
- | e | b | cde,abc | 5,1 |
- | e | a | cde,abc | 5,1 |
- | c | e | cde | 5 |
- | c | f | cde,efg | 5,1 |
- | c | g | cde,efg | 5,1 |
+ | from | to | route | modes |
+ | a | g | abc,cde,efg,efg | cycling,movable bridge,cycling,cycling |
+ | b | f | abc,cde,efg,efg | cycling,movable bridge,cycling,cycling |
+ | e | c | cde,cde | movable bridge,movable bridge |
+ | e | b | cde,abc,abc | movable bridge,cycling,cycling |
+ | e | a | cde,abc,abc | movable bridge,cycling,cycling |
+ | c | e | cde,cde | movable bridge,movable bridge |
+ | c | f | cde,efg,efg | movable bridge,cycling,cycling |
+ | c | g | cde,efg,efg | movable bridge,cycling,cycling |
- Scenario: Car - Properly handle durations
+ Scenario: Bicycle - Properly handle durations
Given the node map
| a | b | c | | |
| | | d | | |
@@ -40,8 +40,8 @@ Feature: Bicycle - Handle movable bridge
| efg | primary | | |
When I route I should get
- | from | to | route | modes | speed |
- | a | g | abc,cde,efg | 1,5,1 | 5 km/h |
- | b | f | abc,cde,efg | 1,5,1 | 4 km/h |
- | c | e | cde | 5 | 2 km/h |
- | e | c | cde | 5 | 2 km/h |
+ | from | to | route | modes | speed |
+ | a | g | abc,cde,efg,efg | cycling,movable bridge,cycling,cycling | 5 km/h |
+ | b | f | abc,cde,efg,efg | cycling,movable bridge,cycling,cycling | 4 km/h |
+ | c | e | cde,cde | movable bridge,movable bridge | 2 km/h |
+ | e | c | cde,cde | movable bridge,movable bridge | 2 km/h |
diff --git a/features/bicycle/ferry.feature b/features/bicycle/ferry.feature
index 85c925f..aaec0ef 100644
--- a/features/bicycle/ferry.feature
+++ b/features/bicycle/ferry.feature
@@ -17,15 +17,15 @@ Feature: Bike - Handle ferry routes
| efg | primary | | |
When I route I should get
- | from | to | route |
- | a | g | abc,cde,efg |
- | b | f | abc,cde,efg |
- | e | c | cde |
- | e | b | cde,abc |
- | e | a | cde,abc |
- | c | e | cde |
- | c | f | cde,efg |
- | c | g | cde,efg |
+ | from | to | route |
+ | a | g | abc,cde,efg,efg |
+ | b | f | abc,cde,efg,efg |
+ | e | c | cde,cde |
+ | e | b | cde,abc,abc |
+ | e | a | cde,abc,abc |
+ | c | e | cde,cde |
+ | c | f | cde,efg,efg |
+ | c | g | cde,efg,efg |
Scenario: Bike - Ferry duration, single node
Given the node map
@@ -59,5 +59,5 @@ Feature: Bike - Handle ferry routes
When I route I should get
| from | to | route | time |
- | a | d | abcd | 3600s +-10 |
- | d | a | abcd | 3600s +-10 |
+ | a | d | abcd,abcd | 3600s +-10 |
+ | d | a | abcd,abcd | 3600s +-10 |
diff --git a/features/bicycle/maxspeed.feature b/features/bicycle/maxspeed.feature
index ba5bfba..ad2c2bf 100644
--- a/features/bicycle/maxspeed.feature
+++ b/features/bicycle/maxspeed.feature
@@ -48,9 +48,9 @@ Feature: Bike - Max speed restrictions
| bc | residential | 80 |
When I route I should get
- | from | to | route | speed |
- | a | b | ab | 15 km/h |
- | b | c | bc | 15 km/h |
+ | from | to | route | speed |
+ | a | b | ab,ab | 15 km/h |
+ | b | c | bc,bc | 15 km/h |
Scenario: Bike - Forward/backward maxspeed
Given the shortcuts
diff --git a/features/bicycle/mode.feature b/features/bicycle/mode.feature
index 2bfa4de..3587f6c 100644
--- a/features/bicycle/mode.feature
+++ b/features/bicycle/mode.feature
@@ -1,15 +1,9 @@
@routing @bicycle @mode
Feature: Bike - Mode flag
-# bicycle modes:
-# 1 bike
-# 2 pushing
-# 3 ferry
-# 4 train
-
Background:
Given the profile "bicycle"
-
+
Scenario: Bike - Mode when using a ferry
Given the node map
| a | b | |
@@ -22,13 +16,13 @@ Feature: Bike - Mode flag
| cd | primary | | |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd | head,right,left,destination | 1,3,1 |
- | d | a | cd,bc,ab | head,right,left,destination | 1,3,1 |
- | c | a | bc,ab | head,left,destination | 3,1 |
- | d | b | cd,bc | head,right,destination | 1,3 |
- | a | c | ab,bc | head,right,destination | 1,3 |
- | b | d | bc,cd | head,left,destination | 3,1 |
+ | from | to | route | turns | modes |
+ | a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,ferry,cycling,cycling |
+ | d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,ferry,cycling,cycling |
+ | c | a | bc,ab,ab | depart,left,arrive | ferry,cycling,cycling |
+ | d | b | cd,bc,bc | depart,right,arrive | cycling,ferry,ferry |
+ | a | c | ab,bc,bc | depart,right,arrive | cycling,ferry,ferry |
+ | b | d | bc,cd,cd | depart,left,arrive | ferry,cycling,cycling |
Scenario: Bike - Mode when using a train
Given the node map
@@ -42,13 +36,13 @@ Feature: Bike - Mode flag
| cd | primary | | |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd | head,right,left,destination | 1,4,1 |
- | d | a | cd,bc,ab | head,right,left,destination | 1,4,1 |
- | c | a | bc,ab | head,left,destination | 4,1 |
- | d | b | cd,bc | head,right,destination | 1,4 |
- | a | c | ab,bc | head,right,destination | 1,4 |
- | b | d | bc,cd | head,left,destination | 4,1 |
+ | from | to | route | turns | modes |
+ | a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,train,cycling,cycling |
+ | d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,train,cycling,cycling |
+ | c | a | bc,ab,ab | depart,left,arrive | train,cycling,cycling |
+ | d | b | cd,bc,bc | depart,right,arrive | cycling,train,train |
+ | a | c | ab,bc,bc | depart,right,arrive | cycling,train,train |
+ | b | d | bc,cd,cd | depart,left,arrive | train,cycling,cycling |
Scenario: Bike - Mode when pushing bike against oneways
Given the node map
@@ -62,13 +56,13 @@ Feature: Bike - Mode flag
| cd | primary | |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd | head,right,left,destination | 1,1,1 |
- | d | a | cd,bc,ab | head,right,left,destination | 1,2,1 |
- | c | a | bc,ab | head,left,destination | 2,1 |
- | d | b | cd,bc | head,right,destination | 1,2 |
- | a | c | ab,bc | head,right,destination | 1,1 |
- | b | d | bc,cd | head,left,destination | 1,1 |
+ | from | to | route | turns | modes |
+ | a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,cycling,cycling,cycling |
+ | d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
+ | c | a | bc,ab,ab | depart,left,arrive | pushing bike,cycling,cycling |
+ | d | b | cd,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike |
+ | a | c | ab,bc,bc | depart,right,arrive | cycling,cycling,cycling |
+ | b | d | bc,cd,cd | depart,left,arrive | cycling,cycling,cycling |
Scenario: Bike - Mode when pushing on pedestrain streets
Given the node map
@@ -82,13 +76,13 @@ Feature: Bike - Mode flag
| cd | primary |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd | head,right,left,destination | 1,2,1 |
- | d | a | cd,bc,ab | head,right,left,destination | 1,2,1 |
- | c | a | bc,ab | head,left,destination | 2,1 |
- | d | b | cd,bc | head,right,destination | 1,2 |
- | a | c | ab,bc | head,right,destination | 1,2 |
- | b | d | bc,cd | head,left,destination | 2,1 |
+ | from | to | route | turns | modes |
+ | a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
+ | d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
+ | c | a | bc,ab,ab | depart,left,arrive | pushing bike,cycling,cycling |
+ | d | b | cd,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike |
+ | a | c | ab,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike |
+ | b | d | bc,cd,cd | depart,left,arrive | pushing bike,cycling,cycling |
Scenario: Bike - Mode when pushing on pedestrain areas
Given the node map
@@ -102,13 +96,13 @@ Feature: Bike - Mode flag
| df | primary | |
When I route I should get
- | from | to | route | modes |
- | a | f | ab,bcd,df | 1,2,1 |
- | f | a | df,bcd,ab | 1,2,1 |
- | d | a | bcd,ab | 2,1 |
- | f | b | df,bcd | 1,2 |
- | a | d | ab,bcd | 1,2 |
- | b | f | bcd,df | 2,1 |
+ | from | to | route | modes |
+ | a | f | ab,bcd,df,df | cycling,pushing bike,cycling,cycling |
+ | f | a | df,bcd,ab,ab | cycling,pushing bike,cycling,cycling |
+ | d | a | bcd,ab,ab | pushing bike,cycling,cycling |
+ | f | b | df,bcd,bcd | cycling,pushing bike,pushing bike |
+ | a | d | ab,bcd,bcd | cycling,pushing bike,pushing bike |
+ | b | f | bcd,df,df | pushing bike,cycling,cycling |
Scenario: Bike - Mode when pushing on steps
Given the node map
@@ -122,13 +116,13 @@ Feature: Bike - Mode flag
| cd | primary |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd | head,right,left,destination | 1,2,1 |
- | d | a | cd,bc,ab | head,right,left,destination | 1,2,1 |
- | c | a | bc,ab | head,left,destination | 2,1 |
- | d | b | cd,bc | head,right,destination | 1,2 |
- | a | c | ab,bc | head,right,destination | 1,2 |
- | b | d | bc,cd | head,left,destination | 2,1 |
+ | from | to | route | turns | modes |
+ | a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
+ | d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
+ | c | a | bc,ab,ab | depart,left,arrive | pushing bike,cycling,cycling |
+ | d | b | cd,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike |
+ | a | c | ab,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike |
+ | b | d | bc,cd,cd | depart,left,arrive | pushing bike,cycling,cycling |
Scenario: Bike - Mode when bicycle=dismount
Given the node map
@@ -142,13 +136,13 @@ Feature: Bike - Mode flag
| cd | primary | |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd | head,right,left,destination | 1,2,1 |
- | d | a | cd,bc,ab | head,right,left,destination | 1,2,1 |
- | c | a | bc,ab | head,left,destination | 2,1 |
- | d | b | cd,bc | head,right,destination | 1,2 |
- | a | c | ab,bc | head,right,destination | 1,2 |
- | b | d | bc,cd | head,left,destination | 2,1 |
+ | from | to | route | turns | modes |
+ | a | d | ab,bc,cd,cd | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
+ | d | a | cd,bc,ab,ab | depart,right,left,arrive | cycling,pushing bike,cycling,cycling |
+ | c | a | bc,ab,ab | depart,left,arrive | pushing bike,cycling,cycling |
+ | d | b | cd,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike |
+ | a | c | ab,bc,bc | depart,right,arrive | cycling,pushing bike,pushing bike |
+ | b | d | bc,cd,cd | depart,left,arrive | pushing bike,cycling,cycling |
Scenario: Bicycle - Modes when starting on forward oneway
Given the node map
@@ -159,9 +153,9 @@ Feature: Bike - Mode flag
| ab | yes |
When I route I should get
- | from | to | route | modes |
- | a | b | ab | 1 |
- | b | a | ab | 2 |
+ | from | to | route | modes |
+ | a | b | ab,ab | cycling,cycling |
+ | b | a | ab,ab | pushing bike,pushing bike |
Scenario: Bicycle - Modes when starting on reverse oneway
Given the node map
@@ -172,6 +166,6 @@ Feature: Bike - Mode flag
| ab | -1 |
When I route I should get
- | from | to | route | modes |
- | a | b | ab | 2 |
- | b | a | ab | 1 |
+ | from | to | route | modes |
+ | a | b | ab,ab | pushing bike,pushing bike |
+ | b | a | ab,ab | cycling,cycling |
diff --git a/features/bicycle/names.feature b/features/bicycle/names.feature
index b0e2ec0..f67f6b1 100644
--- a/features/bicycle/names.feature
+++ b/features/bicycle/names.feature
@@ -15,8 +15,8 @@ Feature: Bike - Street names in instructions
| bc | Your Way |
When I route I should get
- | from | to | route |
- | a | c | My Way,Your Way |
+ | from | to | route |
+ | a | c | My Way,Your Way,Your Way |
@unnamed
Scenario: Bike - Use way type to describe unnamed ways
@@ -29,5 +29,5 @@ Feature: Bike - Street names in instructions
| bcd | track | |
When I route I should get
- | from | to | route |
- | a | d | {highway:cycleway},{highway:track} |
+ | from | to | route |
+ | a | d | {highway:cycleway},{highway:track},{highway:track} |
diff --git a/features/bicycle/oneway.feature b/features/bicycle/oneway.feature
index 4dd9e1f..0cb774c 100644
--- a/features/bicycle/oneway.feature
+++ b/features/bicycle/oneway.feature
@@ -29,9 +29,9 @@ Feature: Bike - Oneway streets
| da | | no |
When I route I should get
- | from | to | route |
- | a | b | ab |
- | b | a | bc,cd,da |
+ | from | to | route |
+ | a | b | ab,ab |
+ | b | a | bc,cd,da,da |
Scenario: Bike - Handle various oneway tag values
Then routability should be
@@ -124,5 +124,5 @@ Feature: Bike - Oneway streets
When I route I should get
- | from | to | route |
- | a | c | ab,bc |
+ | from | to | route |
+ | a | c | ab,bc,bc |
diff --git a/features/bicycle/pushing.feature b/features/bicycle/pushing.feature
index 5741fb1..3d00b53 100644
--- a/features/bicycle/pushing.feature
+++ b/features/bicycle/pushing.feature
@@ -32,7 +32,7 @@ Feature: Bike - Accessability of different way types
| primary | -1 | foot | bike |
| pedestrian | -1 | foot | foot |
- @square
+ @square
Scenario: Bike - Push bikes on pedestrian areas
Given the node map
| x | |
@@ -46,14 +46,14 @@ Feature: Bike - Accessability of different way types
When I route I should get
| from | to | route |
- | a | b | abcda |
- | a | d | abcda |
- | b | c | abcda |
- | c | b | abcda |
- | c | d | abcda |
- | d | c | abcda |
- | d | a | abcda |
- | a | d | abcda |
+ | a | b | abcda,abcda |
+ | a | d | abcda,abcda |
+ | b | c | abcda,abcda |
+ | c | b | abcda,abcda |
+ | c | d | abcda,abcda |
+ | d | c | abcda,abcda |
+ | d | a | abcda,abcda |
+ | a | d | abcda,abcda |
Scenario: Bike - Pushing bikes on ways with foot=yes
Then routability should be
@@ -62,7 +62,7 @@ Feature: Bike - Accessability of different way types
| motorway | yes | foot | |
| runway | | | |
| runway | yes | foot | foot |
-
+
@todo
Scenario: Bike - Pushing bikes on ways with foot=yes in one direction
Then routability should be
@@ -72,20 +72,20 @@ Feature: Bike - Accessability of different way types
| motorway | | yes | | foot |
@construction
- Scenario: Bike - Don't allow routing on ways still under construction
+ Scenario: Bike - Don't allow routing on ways still under construction
Then routability should be
| highway | foot | bicycle | bothw |
| primary | | | x |
| construction | | | |
| construction | yes | | |
| construction | | yes | |
-
+
@roundabout
Scenario: Bike - Don't push bikes against oneway flow on roundabouts
Then routability should be
| junction | forw | backw |
| roundabout | x | |
-
+
Scenario: Bike - Instructions when pushing bike on oneways
Given the node map
| a | b | |
@@ -98,11 +98,11 @@ Feature: Bike - Accessability of different way types
| cd | primary | |
When I route I should get
- | from | to | route | turns |
- | a | d | ab,bc,cd | head,right,left,destination |
- | d | a | cd,bc,ab | head,right,left,destination |
- | c | a | bc,ab | head,left,destination |
- | d | b | cd,bc | head,right,destination |
+ | from | to | route | turns |
+ | a | d | ab,bc,cd,cd | depart,right,left,arrive |
+ | d | a | cd,bc,ab,ab | depart,right,left,arrive |
+ | c | a | bc,ab,ab | depart,left,arrive |
+ | d | b | cd,bc,bc | depart,right,arrive |
@todo
Scenario: Bike - Instructions when pushing bike on footway/pedestrian, etc.
@@ -117,8 +117,8 @@ Feature: Bike - Accessability of different way types
| cd | primary |
When I route I should get
- | from | to | route | turns |
- | a | d | ab,bc,cd | head,right,left,destination |
- | d | a | cd,bc,ab | head,right,left,destination |
- | c | a | bc,ab | head,left,destination |
- | d | b | cd,bc | head,right,destination |
+ | from | to | route | turns |
+ | a | d | ab,bc,cd,cd | depart,right,left,arrive |
+ | d | a | cd,bc,ab,ab | depart,right,left,arrive |
+ | c | a | bc,ab,ab | depart,left,arrive |
+ | d | b | cd,bc,bc | depart,right,arrive |
diff --git a/features/bicycle/ref.feature b/features/bicycle/ref.feature
index 3afde77..195089e 100644
--- a/features/bicycle/ref.feature
+++ b/features/bicycle/ref.feature
@@ -13,8 +13,8 @@ Feature: Bike - Way ref
| ab | Utopia Drive | E7 |
When I route I should get
- | from | to | route |
- | a | b | Utopia Drive / E7 |
+ | from | to | route |
+ | a | b | Utopia Drive / E7,Utopia Drive / E7 |
Scenario: Bike - Way with only ref
Given the node map
@@ -26,7 +26,7 @@ Feature: Bike - Way ref
When I route I should get
| from | to | route |
- | a | b | E7 |
+ | a | b | E7,E7 |
Scenario: Bike - Way with only name
Given the node map
@@ -37,5 +37,5 @@ Feature: Bike - Way ref
| ab | Utopia Drive |
When I route I should get
- | from | to | route |
- | a | b | Utopia Drive |
+ | from | to | route |
+ | a | b | Utopia Drive,Utopia Drive |
diff --git a/features/bicycle/restrictions.feature b/features/bicycle/restrictions.feature
index 6218d81..1f60471 100644
--- a/features/bicycle/restrictions.feature
+++ b/features/bicycle/restrictions.feature
@@ -25,10 +25,10 @@ Feature: Bike - Turn restrictions
| restriction | sj | wj | j | no_left_turn |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@no_turning
Scenario: Bike - No right turn
@@ -49,10 +49,10 @@ Feature: Bike - Turn restrictions
| restriction | sj | ej | j | no_right_turn |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@no_turning
Scenario: Bike - No u-turn
@@ -73,10 +73,10 @@ Feature: Bike - Turn restrictions
| restriction | sj | wj | j | no_u_turn |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@no_turning
Scenario: Bike - Handle any no_* relation
@@ -97,10 +97,10 @@ Feature: Bike - Turn restrictions
| restriction | sj | wj | j | no_weird_zigzags |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@only_turning
Scenario: Bike - Only left turn
@@ -121,10 +121,10 @@ Feature: Bike - Turn restrictions
| restriction | sj | wj | j | only_left_turn |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@only_turning
Scenario: Bike - Only right turn
@@ -145,10 +145,10 @@ Feature: Bike - Turn restrictions
| restriction | sj | ej | j | only_right_turn |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@only_turning
Scenario: Bike - Only straight on
@@ -169,10 +169,10 @@ Feature: Bike - Turn restrictions
| restriction | sj | nj | j | only_straight_on |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@no_turning
Scenario: Bike - Handle any only_* restriction
@@ -193,10 +193,10 @@ Feature: Bike - Turn restrictions
| restriction | sj | nj | j | only_weird_zigzags |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@except
Scenario: Bike - Except tag and on no_ restrictions
@@ -222,11 +222,11 @@ Feature: Bike - Turn restrictions
| restriction | sj | dj | j | no_right_turn | bicycle |
When I route I should get
- | from | to | route |
- | s | a | sj,aj |
- | s | b | sj,bj |
- | s | c | sj,cj |
- | s | d | sj,dj |
+ | from | to | route |
+ | s | a | sj,aj,aj |
+ | s | b | sj,bj,bj |
+ | s | c | sj,cj,cj |
+ | s | d | sj,dj,dj |
@except
Scenario: Bike - Except tag and on only_ restrictions
@@ -246,9 +246,9 @@ Feature: Bike - Turn restrictions
| restriction | sj | aj | j | only_straight_on | bicycle |
When I route I should get
- | from | to | route |
- | s | a | sj,aj |
- | s | b | sj,bj |
+ | from | to | route |
+ | s | a | sj,aj,aj |
+ | s | b | sj,bj,bj |
@except
Scenario: Bike - Multiple except tag values
@@ -280,10 +280,10 @@ Feature: Bike - Turn restrictions
| restriction | sj | jf | j | no_straight_on | bicycle, bus |
When I route I should get
- | from | to | route |
- | s | a | sj,ja |
- | s | b | sj,jb |
- | s | c | sj,jc |
- | s | d | sj,jd |
- | s | e | sj,je |
- | s | f | sj,jf |
+ | from | to | route |
+ | s | a | sj,ja,ja |
+ | s | b | sj,jb,jb |
+ | s | c | sj,jc,jc |
+ | s | d | sj,jd,jd |
+ | s | e | sj,je,je |
+ | s | f | sj,jf,jf |
diff --git a/features/bicycle/roundabout.feature b/features/bicycle/roundabout.feature
index 6123280..2e0d099 100644
--- a/features/bicycle/roundabout.feature
+++ b/features/bicycle/roundabout.feature
@@ -21,10 +21,10 @@ Feature: Roundabout Instructions
| abcda | roundabout |
When I route I should get
- | from | to | route | turns |
- | s | t | sa,tb | head,enter_roundabout-1,destination |
- | s | u | sa,uc | head,enter_roundabout-2,destination |
- | s | v | sa,vd | head,enter_roundabout-3,destination |
- | u | v | uc,vd | head,enter_roundabout-1,destination |
- | u | s | uc,sa | head,enter_roundabout-2,destination |
- | u | t | uc,tb | head,enter_roundabout-3,destination |
+ | from | to | route | turns |
+ | s | t | sa,tb,tb | depart,roundabout-exit-1,arrive |
+ | s | u | sa,uc,uc | depart,roundabout-exit-2,arrive |
+ | s | v | sa,vd,vd | depart,roundabout-exit-3,arrive |
+ | u | v | uc,vd,vd | depart,roundabout-exit-1,arrive |
+ | u | s | uc,sa,sa | depart,roundabout-exit-2,arrive |
+ | u | t | uc,tb,tb | depart,roundabout-exit-3,arrive |
diff --git a/features/bicycle/stop_area.feature b/features/bicycle/stop_area.feature
index 5f6c3bc..9d02c13 100644
--- a/features/bicycle/stop_area.feature
+++ b/features/bicycle/stop_area.feature
@@ -31,7 +31,7 @@ Feature: Bike - Stop areas for public transport
| public_transport | stop_area | c | st |
When I route I should get
- | from | to | route |
- | a | d | abcd |
- | s | t | st |
- | s | d | /st,.+,abcd/ |
+ | from | to | route |
+ | a | d | abcd,abcd |
+ | s | t | st,st |
+ | s | d | /st,.+,abcd/,abcd/ |
diff --git a/features/bicycle/turn_penalty.feature b/features/bicycle/turn_penalty.feature
index d8c46b8..4d66cc3 100644
--- a/features/bicycle/turn_penalty.feature
+++ b/features/bicycle/turn_penalty.feature
@@ -23,11 +23,11 @@ Feature: Turn Penalties
| jg |
When I route I should get
- | from | to | route | time | distance |
- | s | a | sj,ja | 39s +-1 | 242m +-1 |
- | s | b | sj,jb | 30s +-1 | 200m +-1 |
- | s | c | sj,jc | 29s +-1 | 242m +-1 |
- | s | d | sj,jd | 20s +-1 | 200m +-1 |
- | s | e | sj,je | 29s +-1 | 242m +-1 |
- | s | f | sj,jf | 30s +-1 | 200m +-1 |
- | s | g | sj,jg | 39s +-1 | 242m +-1 |
\ No newline at end of file
+ | from | to | route | time | distance |
+ | s | a | sj,ja,ja | 39s +-1 | 242m +-1 |
+ | s | b | sj,jb,jb | 30s +-1 | 200m +-1 |
+ | s | c | sj,jc,jc | 29s +-1 | 242m +-1 |
+ | s | d | sj,jd,jd | 20s +-1 | 200m +-1 |
+ | s | e | sj,je,je | 29s +-1 | 242m +-1 |
+ | s | f | sj,jf,jf | 30s +-1 | 200m +-1 |
+ | s | g | sj,jg,jg | 39s +-1 | 242m +-1 |
diff --git a/features/car/advisory.feature b/features/car/advisory.feature
index db5e66d..b84ff05 100644
--- a/features/car/advisory.feature
+++ b/features/car/advisory.feature
@@ -17,8 +17,8 @@ OSRM will use 4/5 of the projected free-flow speed.
When I route I should get
| from | to | route | speed |
- | a | b | ab | 47 km/h +- 1 |
- | b | c | bc | 47 km/h +- 1 |
+ | a | b | ab,ab | 47 km/h +- 1 |
+ | b | c | bc,bc | 47 km/h +- 1 |
Scenario: Car - Advisory speed overwrites forward maxspeed
Given the node map
@@ -31,9 +31,10 @@ OSRM will use 4/5 of the projected free-flow speed.
When I route I should get
| from | to | route | speed |
- | a | b | ab | 47 km/h +- 1 |
- | b | c | bc | 47 km/h +- 1 |
+ | a | b | ab,ab | 47 km/h +- 1 |
+ | b | c | bc,bc | 47 km/h +- 1 |
+ @mokob @2162
Scenario: Car - Advisory speed overwrites backwards maxspeed
Given the node map
| a | b | c |
@@ -45,9 +46,26 @@ OSRM will use 4/5 of the projected free-flow speed.
When I route I should get
| from | to | route | speed |
- | b | a | ab | 47 km/h +- 1 |
- | c | b | bc | 47 km/h +- 1 |
+ | b | a | ab,ab | 47 km/h +- 1 |
+ | c | b | bc,bc | 47 km/h +- 1 |
+ @mokob @2162 @deleteme
+ Scenario: Car - Advisory speed overwrites backwards maxspeed
+ Given the node map
+ | a | b | c | d |
+
+ And the ways
+ | nodes | highway | maxspeed:backward | maxspeed:advisory:backward |
+ | ab | residential | | 45 |
+ | bc | residential | 90 | 45 |
+ | cd | residential | | 45 |
+
+ When I route I should get
+ | from | to | route | speed |
+ | c | b | bc,bc | 47 km/h +- 1 |
+ | d | c | cd,cd | 47 km/h +- 1 |
+
+ @mokob @2162
Scenario: Car - Directional advisory speeds play nice with eachother
Given the node map
| a | b | c |
@@ -59,9 +77,9 @@ OSRM will use 4/5 of the projected free-flow speed.
When I route I should get
| from | to | route | speed |
- | a | b | ab | 47 km/h +- 1 |
- | b | a | ab | 59 km/h +- 1 |
- | b | c | bc | 59 km/h +- 1 |
- | c | b | bc | 47 km/h +- 1 |
+ | a | b | ab,ab | 47 km/h +- 1 |
+ | b | a | ab,ab | 59 km/h +- 1 |
+ | b | c | bc,bc | 59 km/h +- 1 |
+ | c | b | bc,bc | 47 km/h +- 1 |
diff --git a/features/car/bridge.feature b/features/car/bridge.feature
index d3e470e..931f1d9 100644
--- a/features/car/bridge.feature
+++ b/features/car/bridge.feature
@@ -17,15 +17,15 @@ Feature: Car - Handle movable bridge
| efg | primary | | |
When I route I should get
- | from | to | route | modes |
- | a | g | abc,cde,efg | 1,3,1 |
- | b | f | abc,cde,efg | 1,3,1 |
- | e | c | cde | 3 |
- | e | b | cde,abc | 3,1 |
- | e | a | cde,abc | 3,1 |
- | c | e | cde | 3 |
- | c | f | cde,efg | 3,1 |
- | c | g | cde,efg | 3,1 |
+ | from | to | route | modes |
+ | a | g | abc,cde,efg,efg | driving,movable bridge,driving,driving |
+ | b | f | abc,cde,efg,efg | driving,movable bridge,driving,driving |
+ | e | c | cde,cde | movable bridge,movable bridge |
+ | e | b | cde,abc,abc | movable bridge,driving,driving |
+ | e | a | cde,abc,abc | movable bridge,driving,driving |
+ | c | e | cde,cde | movable bridge,movable bridge |
+ | c | f | cde,efg,efg | movable bridge,driving,driving |
+ | c | g | cde,efg,efg | movable bridge,driving,driving |
Scenario: Car - Properly handle durations
Given the node map
@@ -40,8 +40,8 @@ Feature: Car - Handle movable bridge
| efg | primary | | |
When I route I should get
- | from | to | route | modes | speed |
- | a | g | abc,cde,efg | 1,3,1 | 7 km/h |
- | b | f | abc,cde,efg | 1,3,1 | 5 km/h |
- | c | e | cde | 3 | 2 km/h |
- | e | c | cde | 3 | 2 km/h |
+ | from | to | route | modes | speed |
+ | a | g | abc,cde,efg,efg | driving,movable bridge,driving,driving | 7 km/h |
+ | b | f | abc,cde,efg,efg | driving,movable bridge,driving,driving | 5 km/h |
+ | c | e | cde,cde | movable bridge,movable bridge | 2 km/h |
+ | e | c | cde,cde | movable bridge,movable bridge | 2 km/h |
diff --git a/features/car/ferry.feature b/features/car/ferry.feature
index 37f520e..c6adc9f 100644
--- a/features/car/ferry.feature
+++ b/features/car/ferry.feature
@@ -17,15 +17,15 @@ Feature: Car - Handle ferry routes
| efg | primary | | |
When I route I should get
- | from | to | route | modes |
- | a | g | abc,cde,efg | 1,2,1 |
- | b | f | abc,cde,efg | 1,2,1 |
- | e | c | cde | 2 |
- | e | b | cde,abc | 2,1 |
- | e | a | cde,abc | 2,1 |
- | c | e | cde | 2 |
- | c | f | cde,efg | 2,1 |
- | c | g | cde,efg | 2,1 |
+ | from | to | route | modes |
+ | a | g | abc,cde,efg,efg | driving,ferry,driving,driving |
+ | b | f | abc,cde,efg,efg | driving,ferry,driving,driving |
+ | e | c | cde,cde | ferry,ferry |
+ | e | b | cde,abc,abc | ferry,driving,driving |
+ | e | a | cde,abc,abc | ferry,driving,driving |
+ | c | e | cde,cde | ferry,ferry |
+ | c | f | cde,efg,efg | ferry,driving,driving |
+ | c | g | cde,efg,efg | ferry,driving,driving |
Scenario: Car - Properly handle simple durations
Given the node map
@@ -40,11 +40,11 @@ Feature: Car - Handle ferry routes
| efg | primary | | |
When I route I should get
- | from | to | route | modes | speed |
- | a | g | abc,cde,efg | 1,2,1 | 25 km/h |
- | b | f | abc,cde,efg | 1,2,1 | 20 km/h |
- | c | e | cde | 2 | 12 km/h |
- | e | c | cde | 2 | 12 km/h |
+ | from | to | route | modes | speed |
+ | a | g | abc,cde,efg,efg | driving,ferry,driving,driving | 25 km/h |
+ | b | f | abc,cde,efg,efg | driving,ferry,driving,driving | 20 km/h |
+ | c | e | cde,cde | ferry,ferry | 12 km/h |
+ | e | c | cde,cde | ferry,ferry | 12 km/h |
Scenario: Car - Properly handle ISO 8601 durations
Given the node map
@@ -59,8 +59,8 @@ Feature: Car - Handle ferry routes
| efg | primary | | |
When I route I should get
- | from | to | route | modes | speed |
- | a | g | abc,cde,efg | 1,2,1 | 25 km/h |
- | b | f | abc,cde,efg | 1,2,1 | 20 km/h |
- | c | e | cde | 2 | 12 km/h |
- | e | c | cde | 2 | 12 km/h |
+ | from | to | route | modes | speed |
+ | a | g | abc,cde,efg,efg | driving,ferry,driving,driving | 25 km/h |
+ | b | f | abc,cde,efg,efg | driving,ferry,driving,driving | 20 km/h |
+ | c | e | cde,cde | ferry,ferry | 12 km/h |
+ | e | c | cde,cde | ferry,ferry | 12 km/h |
diff --git a/features/car/link.feature b/features/car/link.feature
index f4628e4..26f32d1 100644
--- a/features/car/link.feature
+++ b/features/car/link.feature
@@ -24,9 +24,9 @@ Feature: Car - Speed on links
| dy | unclassified |
When I route I should get
- | from | to | route |
- | x | y | xa,ae,ef,fd,dy |
- | b | c | bc |
+ | from | to | route |
+ | x | y | xa,ae,ef,fd,dy,dy |
+ | b | c | bc,bc |
Scenario: Car - Use trunk_link when reasonable
Given the node map
@@ -44,9 +44,9 @@ Feature: Car - Speed on links
| fd | trunk |
| dy | unclassified |
When I route I should get
- | from | to | route |
- | x | y | xa,ae,ef,fd,dy |
- | b | c | bc |
+ | from | to | route |
+ | x | y | xa,ae,ef,fd,dy,dy |
+ | b | c | bc,bc |
Scenario: Car - Use primary_link when reasonable
Given the node map
@@ -64,9 +64,9 @@ Feature: Car - Speed on links
| fd | primary |
| dy | unclassified |
When I route I should get
- | from | to | route |
- | x | y | xa,ae,ef,fd,dy |
- | b | c | bc |
+ | from | to | route |
+ | x | y | xa,ae,ef,fd,dy,dy |
+ | b | c | bc,bc |
Scenario: Car - Use secondary_link when reasonable
Given the node map
@@ -85,9 +85,9 @@ Feature: Car - Speed on links
| dy | unclassified |
When I route I should get
- | from | to | route |
- | x | y | xa,ae,ef,fd,dy |
- | b | c | bc |
+ | from | to | route |
+ | x | y | xa,ae,ef,fd,dy,dy |
+ | b | c | bc,bc |
Scenario: Car - Use tertiary_link when reasonable
Given the node map
@@ -106,6 +106,6 @@ Feature: Car - Speed on links
| dy | unclassified |
When I route I should get
- | from | to | route |
- | x | y | xa,ae,ef,fd,dy |
- | b | c | bc |
+ | from | to | route |
+ | x | y | xa,ae,ef,fd,dy,dy |
+ | b | c | bc,bc |
diff --git a/features/car/maxspeed.feature b/features/car/maxspeed.feature
index e2d26e0..3b94ac7 100644
--- a/features/car/maxspeed.feature
+++ b/features/car/maxspeed.feature
@@ -21,12 +21,12 @@ OSRM will use 4/5 of the projected free-flow speed.
When I route I should get
| from | to | route | speed |
- | a | b | ab | 78 km/h |
- | b | c | bc | 59 km/h +- 1 |
- | c | d | cd | 51 km/h |
- | d | e | de | 75 km/h |
- | e | f | ef | 90 km/h |
- | f | g | fg | 106 km/h |
+ | a | b | ab,ab | 79 km/h |
+ | b | c | bc,bc | 59 km/h +- 1 |
+ | c | d | cd,cd | 51 km/h |
+ | d | e | de,de | 75 km/h |
+ | e | f | ef,ef | 91 km/h |
+ | f | g | fg,fg | 107 km/h |
Scenario: Car - Do not ignore maxspeed when higher than way speed
Given the node map
@@ -40,9 +40,9 @@ OSRM will use 4/5 of the projected free-flow speed.
When I route I should get
| from | to | route | speed |
- | a | b | ab | 31 km/h |
- | b | c | bc | 83 km/h +- 1 |
- | c | d | cd | 51 km/h |
+ | a | b | ab,ab | 31 km/h |
+ | b | c | bc,bc | 83 km/h +- 1 |
+ | c | d | cd,cd | 51 km/h |
Scenario: Car - Forward/backward maxspeed
Given a grid size of 100 meters
diff --git a/features/car/mode.feature b/features/car/mode.feature
index ff156a0..f390982 100644
--- a/features/car/mode.feature
+++ b/features/car/mode.feature
@@ -15,13 +15,13 @@ Feature: Car - Mode flag
| cd | primary | | |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd | head,right,left,destination | 1,2,1 |
- | d | a | cd,bc,ab | head,right,left,destination | 1,2,1 |
- | c | a | bc,ab | head,left,destination | 2,1 |
- | d | b | cd,bc | head,right,destination | 1,2 |
- | a | c | ab,bc | head,right,destination | 1,2 |
- | b | d | bc,cd | head,left,destination | 2,1 |
+ | from | to | route | turns | modes |
+ | a | d | ab,bc,cd,cd | depart,right,left,arrive | driving,ferry,driving,driving |
+ | d | a | cd,bc,ab,ab | depart,right,left,arrive | driving,ferry,driving,driving |
+ | c | a | bc,ab,ab | depart,left,arrive | ferry,driving,driving |
+ | d | b | cd,bc,bc | depart,right,arrive | driving,ferry,ferry |
+ | a | c | ab,bc,bc | depart,right,arrive | driving,ferry,ferry |
+ | b | d | bc,cd,cd | depart,left,arrive | ferry,driving,driving |
Scenario: Car - Snapping when using a ferry
Given the node map
@@ -34,7 +34,7 @@ Feature: Car - Mode flag
| ef | primary | | |
When I route I should get
- | from | to | route | turns | modes | time |
- | c | d | bcde | head,destination | 2 | 600s |
+ | from | to | route | turns | modes | time |
+ | c | d | bcde,bcde | depart,arrive | ferry,ferry | 600s |
diff --git a/features/car/names.feature b/features/car/names.feature
index b6a95ae..7a47253 100644
--- a/features/car/names.feature
+++ b/features/car/names.feature
@@ -15,8 +15,8 @@ Feature: Car - Street names in instructions
| bc | Your Way | A1 |
When I route I should get
- | from | to | route |
- | a | c | My Way,Your Way (A1) |
+ | from | to | route |
+ | a | c | My Way,Your Way (A1),Your Way (A1) |
@todo
Scenario: Car - Use way type to describe unnamed ways
@@ -29,5 +29,5 @@ Feature: Car - Street names in instructions
| bcd | residential | |
When I route I should get
- | from | to | route |
- | a | c | tertiary,residential |
+ | from | to | route |
+ | a | c | tertiary,residential,residential |
diff --git a/features/car/oneway.feature b/features/car/oneway.feature
index b47c3c6..b1b08bf 100644
--- a/features/car/oneway.feature
+++ b/features/car/oneway.feature
@@ -44,9 +44,9 @@ Feature: Car - Oneway streets
| da | |
When I route I should get
- | from | to | route |
- | a | b | ab |
- | b | a | bc,cd,da |
+ | from | to | route |
+ | a | b | ab,ab |
+ | b | a | bc,cd,da,da |
Scenario: Car - Cars should not be affected by bicycle tags
Then routability should be
@@ -75,5 +75,5 @@ Feature: Car - Oneway streets
When I route I should get
- | from | to | route |
- | a | c | ab,bc |
+ | from | to | route |
+ | a | c | ab,bc,bc |
diff --git a/features/car/restrictions.feature b/features/car/restrictions.feature
index 89fffff..d311fb0 100644
--- a/features/car/restrictions.feature
+++ b/features/car/restrictions.feature
@@ -25,10 +25,10 @@ Feature: Car - Turn restrictions
| restriction | sj | wj | j | no_left_turn |
When I route I should get
- | from | to | route |
- | s | w | |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@no_turning
Scenario: Car - No straight on
@@ -55,8 +55,8 @@ Feature: Car - Turn restrictions
| restriction | bj | jd | j | no_straight_on |
When I route I should get
- | from | to | route |
- | a | e | av,vw,wx,xy,yz,ze |
+ | from | to | route |
+ | a | e | av,vw,wx,xy,yz,ze,ze |
@no_turning
Scenario: Car - No right turn
@@ -77,10 +77,10 @@ Feature: Car - Turn restrictions
| restriction | sj | ej | j | no_right_turn |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | |
@no_turning
Scenario: Car - No u-turn
@@ -101,10 +101,10 @@ Feature: Car - Turn restrictions
| restriction | sj | wj | j | no_u_turn |
When I route I should get
- | from | to | route |
- | s | w | |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@no_turning
Scenario: Car - Handle any no_* relation
@@ -125,10 +125,10 @@ Feature: Car - Turn restrictions
| restriction | sj | wj | j | no_weird_zigzags |
When I route I should get
- | from | to | route |
- | s | w | |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@only_turning
Scenario: Car - Only left turn
@@ -149,10 +149,10 @@ Feature: Car - Turn restrictions
| restriction | sj | wj | j | only_left_turn |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | |
- | s | e | |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | |
+ | s | e | |
@only_turning
Scenario: Car - Only right turn
@@ -173,10 +173,10 @@ Feature: Car - Turn restrictions
| restriction | sj | ej | j | only_right_turn |
When I route I should get
- | from | to | route |
- | s | w | |
- | s | n | |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | |
+ | s | n | |
+ | s | e | sj,ej,ej |
@only_turning
Scenario: Car - Only straight on
@@ -197,10 +197,10 @@ Feature: Car - Turn restrictions
| restriction | sj | nj | j | only_straight_on |
When I route I should get
- | from | to | route |
- | s | w | |
- | s | n | sj,nj |
- | s | e | |
+ | from | to | route |
+ | s | w | |
+ | s | n | sj,nj,nj |
+ | s | e | |
@no_turning
Scenario: Car - Handle any only_* restriction
@@ -221,10 +221,10 @@ Feature: Car - Turn restrictions
| restriction | sj | nj | j | only_weird_zigzags |
When I route I should get
- | from | to | route |
- | s | w | |
- | s | n | sj,nj |
- | s | e | |
+ | from | to | route |
+ | s | w | |
+ | s | n | sj,nj,nj |
+ | s | e | |
@specific
Scenario: Car - :hgv-qualified on a standard turn restriction
@@ -245,10 +245,10 @@ Feature: Car - Turn restrictions
| restriction | sj | nj | j | no_straight_on |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@specific
Scenario: Car - :motorcar-qualified on a standard turn restriction
@@ -269,10 +269,10 @@ Feature: Car - Turn restrictions
| restriction | sj | nj | j | no_straight_on |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | |
+ | s | e | sj,ej,ej |
@except
Scenario: Car - Except tag and on no_ restrictions
@@ -298,11 +298,11 @@ Feature: Car - Turn restrictions
| restriction | sj | dj | j | no_right_turn | motorcar |
When I route I should get
- | from | to | route |
- | s | a | sj,aj |
- | s | b | |
- | s | c | |
- | s | d | sj,dj |
+ | from | to | route |
+ | s | a | sj,aj,aj |
+ | s | b | |
+ | s | c | |
+ | s | d | sj,dj,dj |
@except
Scenario: Car - Except tag and on only_ restrictions
@@ -322,9 +322,9 @@ Feature: Car - Turn restrictions
| restriction | sj | aj | j | only_straight_on | motorcar |
When I route I should get
- | from | to | route |
- | s | a | sj,aj |
- | s | b | sj,bj |
+ | from | to | route |
+ | s | a | sj,aj,aj |
+ | s | b | sj,bj,bj |
@except
Scenario: Car - Several only_ restrictions at the same segment
@@ -356,10 +356,10 @@ Feature: Car - Turn restrictions
| restriction | da | ae | a | only_right_turn |
When I route I should get
- | from | to | route |
- | e | f | ae,xa,bx,fb |
- | c | f | dc,da,ae,ge,hg,hg,ge,ae,xa,bx,fb |
- | d | f | da,ae,ge,hg,hg,ge,ae,xa,bx,fb |
+ | from | to | route |
+ | e | f | ae,xa,bx,fb,fb |
+ | c | f | dc,da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb |
+ | d | f | da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb |
@except
Scenario: Car - two only_ restrictions share same to-way
@@ -391,9 +391,9 @@ Feature: Car - Turn restrictions
| restriction | by | xy | y | only_straight_on |
When I route I should get
- | from | to | route |
- | a | b | ax,xy,yb |
- | b | a | yb,xy,ax |
+ | from | to | route |
+ | a | b | ax,xy,yb,yb |
+ | b | a | yb,xy,ax,ax |
@except
Scenario: Car - two only_ restrictions share same from-way
@@ -425,7 +425,7 @@ Feature: Car - Turn restrictions
| restriction | xy | yb | y | only_straight_on |
When I route I should get
- | from | to | route |
- | a | b | ax,xy,yb |
- | b | a | yb,xy,ax |
+ | from | to | route |
+ | a | b | ax,xy,yb,yb |
+ | b | a | yb,xy,ax,ax |
diff --git a/features/car/roundabout.feature b/features/car/roundabout.feature
index 2965479..beb5d4e 100644
--- a/features/car/roundabout.feature
+++ b/features/car/roundabout.feature
@@ -21,10 +21,10 @@ Feature: Roundabout Instructions
| abcda | roundabout |
When I route I should get
- | from | to | route | turns |
- | s | t | sa,tb | head,enter_roundabout-1,destination |
- | s | u | sa,uc | head,enter_roundabout-2,destination |
- | s | v | sa,vd | head,enter_roundabout-3,destination |
- | u | v | uc,vd | head,enter_roundabout-1,destination |
- | u | s | uc,sa | head,enter_roundabout-2,destination |
- | u | t | uc,tb | head,enter_roundabout-3,destination |
+ | from | to | route | turns |
+ | s | t | sa,tb,tb | depart,roundabout-exit-1,arrive |
+ | s | u | sa,uc,uc | depart,roundabout-exit-2,arrive |
+ | s | v | sa,vd,vd | depart,roundabout-exit-3,arrive |
+ | u | v | uc,vd,vd | depart,roundabout-exit-1,arrive |
+ | u | s | uc,sa,sa | depart,roundabout-exit-2,arrive |
+ | u | t | uc,tb,tb | depart,roundabout-exit-3,arrive |
diff --git a/features/car/shuttle_train.feature b/features/car/shuttle_train.feature
index 97f32e5..f6e8b84 100644
--- a/features/car/shuttle_train.feature
+++ b/features/car/shuttle_train.feature
@@ -19,13 +19,13 @@ Feature: Car - Handle ferryshuttle train routes
| gh | primary | | no |
When I route I should get
- | from | to | route |
- | a | f | abc,cde,ef |
- | b | f | abc,cde,ef |
- | e | c | cde |
- | e | b | cde,abc |
- | e | a | cde,abc |
- | c | e | cde |
- | c | f | cde,ef |
- | f | g | |
- | g | h | gh |
+ | from | to | route |
+ | a | f | abc,cde,ef,ef |
+ | b | f | abc,cde,ef,ef |
+ | e | c | cde,cde |
+ | e | b | cde,abc,abc |
+ | e | a | cde,abc,abc |
+ | c | e | cde,cde |
+ | c | f | cde,ef,ef |
+ | f | g | |
+ | g | h | gh,gh |
diff --git a/features/car/traffic.feature b/features/car/traffic.feature
new file mode 100644
index 0000000..6d0c62d
--- /dev/null
+++ b/features/car/traffic.feature
@@ -0,0 +1,47 @@
+ at routing @speed @traffic
+Feature: Traffic - speeds
+
+ Background: Use specific speeds
+ Given the node locations
+ | node | lat | lon |
+ | a | 0.1 | 0.1 |
+ | b | .05 | 0.1 |
+ | c | 0.0 | 0.1 |
+ | d | .05 | .03 |
+ | e | .05 | .066 |
+ | f | .075 | .066 |
+ | g | .075 | 0.1 |
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | ad | primary |
+ | bc | primary |
+ | dc | primary |
+ | de | primary |
+ | eb | primary |
+ | df | primary |
+ | fb | primary |
+ And the speed file
+ """
+ 1,2,27
+ 2,1,27
+ 2,3,27
+ 3,2,27
+ 1,4,27
+ 4,1,27
+ """
+
+ Scenario: Weighting not based on raster sources
+ Given the profile "testbot"
+ Given the extract extra arguments "--generate-edge-lookup"
+ Given the contract extra arguments "--segment-speed-file speeds.csv"
+ And I route I should get
+ | from | to | route | speed |
+ | a | b | ab,ab | 27 km/h |
+ | a | c | ab,bc,bc | 27 km/h |
+ | b | c | bc,bc | 27 km/h |
+ | a | d | ad,ad | 27 km/h |
+ | d | c | dc,dc | 36 km/h |
+ | g | b | ab,ab | 27 km/h |
+ | a | g | ab,ab | 27 km/h |
+
diff --git a/features/foot/area.feature b/features/foot/area.feature
index 6edd585..8cfc0a8 100644
--- a/features/foot/area.feature
+++ b/features/foot/area.feature
@@ -17,15 +17,15 @@ Feature: Foot - Squares and other areas
| abcda | yes | residential |
When I route I should get
- | from | to | route |
- | a | b | abcda |
- | a | d | abcda |
- | b | c | abcda |
- | c | b | abcda |
- | c | d | abcda |
- | d | c | abcda |
- | d | a | abcda |
- | a | d | abcda |
+ | from | to | route |
+ | a | b | abcda,abcda |
+ | a | d | abcda,abcda |
+ | b | c | abcda,abcda |
+ | c | b | abcda,abcda |
+ | c | d | abcda,abcda |
+ | d | c | abcda,abcda |
+ | d | a | abcda,abcda |
+ | a | d | abcda,abcda |
@building
Scenario: Foot - Don't route on buildings
@@ -41,14 +41,14 @@ Feature: Foot - Squares and other areas
When I route I should get
| from | to | route |
- | a | b | xa |
- | a | d | xa |
- | b | c | xa |
- | c | b | xa |
- | c | d | xa |
- | d | c | xa |
- | d | a | xa |
- | a | d | xa |
+ | a | b | xa,xa |
+ | a | d | xa,xa |
+ | b | c | xa,xa |
+ | c | b | xa,xa |
+ | c | d | xa,xa |
+ | d | c | xa,xa |
+ | d | a | xa,xa |
+ | a | d | xa,xa |
@parking
Scenario: Foot - parking areas
@@ -65,17 +65,17 @@ Feature: Foot - Squares and other areas
| abcda | (nil) | parking |
When I route I should get
- | from | to | route |
- | x | y | xa,abcda,by |
- | y | x | by,abcda,xa |
- | a | b | abcda |
- | a | d | abcda |
- | b | c | abcda |
- | c | b | abcda |
- | c | d | abcda |
- | d | c | abcda |
- | d | a | abcda |
- | a | d | abcda |
+ | from | to | route |
+ | x | y | xa,abcda,by,by |
+ | y | x | by,abcda,xa,xa |
+ | a | b | abcda,abcda |
+ | a | d | abcda,abcda |
+ | b | c | abcda,abcda |
+ | c | b | abcda,abcda |
+ | c | d | abcda,abcda |
+ | d | c | abcda,abcda |
+ | d | a | abcda,abcda |
+ | a | d | abcda,abcda |
@train @platform
Scenario: Foot - railway platforms
@@ -90,14 +90,14 @@ Feature: Foot - Squares and other areas
| abcda | (nil) | platform |
When I route I should get
- | from | to | route |
- | x | y | xa,abcda,by |
- | y | x | by,abcda,xa |
- | a | b | abcda |
- | a | d | abcda |
- | b | c | abcda |
- | c | b | abcda |
- | c | d | abcda |
- | d | c | abcda |
- | d | a | abcda |
- | a | d | abcda |
+ | from | to | route |
+ | x | y | xa,abcda,by,by |
+ | y | x | by,abcda,xa,xa |
+ | a | b | abcda,abcda |
+ | a | d | abcda,abcda |
+ | b | c | abcda,abcda |
+ | c | b | abcda,abcda |
+ | c | d | abcda,abcda |
+ | d | c | abcda,abcda |
+ | d | a | abcda,abcda |
+ | a | d | abcda,abcda |
diff --git a/features/foot/ferry.feature b/features/foot/ferry.feature
index 866644d..9ad1c9d 100644
--- a/features/foot/ferry.feature
+++ b/features/foot/ferry.feature
@@ -17,15 +17,15 @@ Feature: Foot - Handle ferry routes
| efg | primary | | |
When I route I should get
- | from | to | route | modes |
- | a | g | abc,cde,efg | 1,2,1 |
- | b | f | abc,cde,efg | 1,2,1 |
- | e | c | cde | 2 |
- | e | b | cde,abc | 2,1 |
- | e | a | cde,abc | 2,1 |
- | c | e | cde | 2 |
- | c | f | cde,efg | 2,1 |
- | c | g | cde,efg | 2,1 |
+ | from | to | route | modes |
+ | a | g | abc,cde,efg,efg | walking,ferry,walking,walking |
+ | b | f | abc,cde,efg,efg | walking,ferry,walking,walking |
+ | e | c | cde,cde | ferry,ferry |
+ | e | b | cde,abc,abc | ferry,walking,walking |
+ | e | a | cde,abc,abc | ferry,walking,walking |
+ | c | e | cde,cde | ferry,ferry |
+ | c | f | cde,efg,efg | ferry,walking,walking |
+ | c | g | cde,efg,efg | ferry,walking,walking |
Scenario: Foot - Ferry duration, single node
Given the node map
@@ -58,6 +58,6 @@ Feature: Foot - Handle ferry routes
| abcd | | ferry | yes | 1:00 |
When I route I should get
- | from | to | route | time |
- | a | d | abcd | 3600s +-10 |
- | d | a | abcd | 3600s +-10 |
+ | from | to | route | time |
+ | a | d | abcd,abcd | 3600s +-10 |
+ | d | a | abcd,abcd | 3600s +-10 |
diff --git a/features/foot/names.feature b/features/foot/names.feature
index d5fdcc7..a765de6 100644
--- a/features/foot/names.feature
+++ b/features/foot/names.feature
@@ -15,8 +15,8 @@ Feature: Foot - Street names in instructions
| bc | Your Way |
When I route I should get
- | from | to | route |
- | a | c | My Way,Your Way |
+ | from | to | route |
+ | a | c | My Way,Your Way,Your Way |
@unnamed
Scenario: Foot - Use way type to describe unnamed ways
@@ -29,5 +29,5 @@ Feature: Foot - Street names in instructions
| bcd | track | |
When I route I should get
- | from | to | route |
- | a | d | {highway:footway},{highway:track} |
+ | from | to | route |
+ | a | d | {highway:footway},{highway:track},{highway:track} |
diff --git a/features/foot/ref.feature b/features/foot/ref.feature
index bc0c77e..8fed586 100644
--- a/features/foot/ref.feature
+++ b/features/foot/ref.feature
@@ -13,8 +13,8 @@ Feature: Foot - Way ref
| ab | Utopia Drive | E7 |
When I route I should get
- | from | to | route |
- | a | b | Utopia Drive / E7 |
+ | from | to | route |
+ | a | b | Utopia Drive / E7,Utopia Drive / E7 |
Scenario: Foot - Way with only ref
Given the node map
@@ -26,7 +26,7 @@ Feature: Foot - Way ref
When I route I should get
| from | to | route |
- | a | b | E7 |
+ | a | b | E7,E7 |
Scenario: Foot - Way with only name
Given the node map
@@ -37,5 +37,5 @@ Feature: Foot - Way ref
| ab | Utopia Drive |
When I route I should get
- | from | to | route |
- | a | b | Utopia Drive |
+ | from | to | route |
+ | a | b | Utopia Drive,Utopia Drive |
diff --git a/features/foot/restrictions.feature b/features/foot/restrictions.feature
index 8d6a029..ae66658 100644
--- a/features/foot/restrictions.feature
+++ b/features/foot/restrictions.feature
@@ -24,10 +24,10 @@ Feature: Foot - Turn restrictions
| restriction | sj | wj | j | no_left_turn |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@no_turning
Scenario: Foot - No right turn
@@ -48,10 +48,10 @@ Feature: Foot - Turn restrictions
| restriction | sj | ej | j | no_right_turn |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@no_turning
Scenario: Foot - No u-turn
@@ -72,10 +72,10 @@ Feature: Foot - Turn restrictions
| restriction | sj | wj | j | no_u_turn |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@no_turning
Scenario: Foot - Handle any no_* relation
@@ -96,10 +96,10 @@ Feature: Foot - Turn restrictions
| restriction | sj | wj | j | no_weird_zigzags |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@only_turning
Scenario: Foot - Only left turn
@@ -120,10 +120,10 @@ Feature: Foot - Turn restrictions
| restriction | sj | wj | j | only_left_turn |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@only_turning
Scenario: Foot - Only right turn
@@ -144,10 +144,10 @@ Feature: Foot - Turn restrictions
| restriction | sj | ej | j | only_right_turn |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@only_turning
Scenario: Foot - Only straight on
@@ -168,10 +168,10 @@ Feature: Foot - Turn restrictions
| restriction | sj | nj | j | only_straight_on |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@no_turning
Scenario: Foot - Handle any only_* restriction
@@ -192,10 +192,10 @@ Feature: Foot - Turn restrictions
| restriction | sj | nj | j | only_weird_zigzags |
When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
+ | from | to | route |
+ | s | w | sj,wj,wj |
+ | s | n | sj,nj,nj |
+ | s | e | sj,ej,ej |
@except
Scenario: Foot - Except tag and on no_ restrictions
@@ -221,11 +221,11 @@ Feature: Foot - Turn restrictions
| restriction | sj | dj | j | no_right_turn | foot |
When I route I should get
- | from | to | route |
- | s | a | sj,aj |
- | s | b | sj,bj |
- | s | c | sj,cj |
- | s | d | sj,dj |
+ | from | to | route |
+ | s | a | sj,aj,aj |
+ | s | b | sj,bj,bj |
+ | s | c | sj,cj,cj |
+ | s | d | sj,dj,dj |
@except
Scenario: Foot - Except tag and on only_ restrictions
@@ -245,9 +245,9 @@ Feature: Foot - Turn restrictions
| restriction | sj | aj | j | only_straight_on | foot |
When I route I should get
- | from | to | route |
- | s | a | sj,aj |
- | s | b | sj,bj |
+ | from | to | route |
+ | s | a | sj,aj,aj |
+ | s | b | sj,bj,bj |
@except
Scenario: Foot - Multiple except tag values
@@ -279,10 +279,10 @@ Feature: Foot - Turn restrictions
| restriction | sj | jf | j | no_straight_on | foot, bus |
When I route I should get
- | from | to | route |
- | s | a | sj,ja |
- | s | b | sj,jb |
- | s | c | sj,jc |
- | s | d | sj,jd |
- | s | e | sj,je |
- | s | f | sj,jf |
+ | from | to | route |
+ | s | a | sj,ja,ja |
+ | s | b | sj,jb,jb |
+ | s | c | sj,jc,jc |
+ | s | d | sj,jd,jd |
+ | s | e | sj,je,je |
+ | s | f | sj,jf,jf |
diff --git a/features/foot/roundabout.feature b/features/foot/roundabout.feature
index 5aa9860..181f240 100644
--- a/features/foot/roundabout.feature
+++ b/features/foot/roundabout.feature
@@ -3,12 +3,12 @@ Feature: Roundabout Instructions
Background:
Given the profile "foot"
-
+
@todo
Scenario: Foot - Roundabout instructions
# You can walk in both directions on a roundabout, bu the normal roundabout instructions don't
# make sense when you're going the opposite way around the roundabout.
-
+
Given the node map
| | | v | | |
| | | d | | |
@@ -25,10 +25,10 @@ Feature: Roundabout Instructions
| abcda | roundabout |
When I route I should get
- | from | to | route | turns |
- | s | t | sa,tb | head,enter_roundabout-1,destination |
- | s | u | sa,uc | head,enter_roundabout-2,destination |
- | s | v | sa,vd | head,enter_roundabout-3,destination |
- | u | v | uc,vd | head,enter_roundabout-1,destination |
- | u | s | uc,sa | head,enter_roundabout-2,destination |
- | u | t | uc,tb | head,enter_roundabout-3,destination |
+ | from | to | route | turns |
+ | s | t | sa,tb | depart,roundabout-exit-1,arrive |
+ | s | u | sa,uc | depart,roundabout-exit-2,arrive |
+ | s | v | sa,vd | depart,roundabout-exit-3,arrive |
+ | u | v | uc,vd | depart,roundabout-exit-1,arrive |
+ | u | s | uc,sa | depart,roundabout-exit-2,arrive |
+ | u | t | uc,tb | depart,roundabout-exit-3,arrive |
diff --git a/features/guidance/motorway.feature b/features/guidance/motorway.feature
new file mode 100644
index 0000000..bcde322
--- /dev/null
+++ b/features/guidance/motorway.feature
@@ -0,0 +1,202 @@
+ at routing @guidance
+Feature: Basic Roundabout
+
+ Background:
+ Given the profile "testbot"
+ Given a grid size of 10 meters
+
+ Scenario: Ramp Exit Right
+ Given the node map
+ | a | b | c | d | e |
+ | | | | f | g |
+
+ And the ways
+ | nodes | highway |
+ | abcde | motorway |
+ | bfg | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | abcde, abcde | depart, arrive |
+ | a,g | abcde, bfg, bfg | depart, ramp-slight-right, arrive |
+
+ Scenario: Ramp Exit Right Curved Right
+ Given the node map
+ | a | b | c | | |
+ | | | f | d | |
+ | | | | g | e |
+
+ And the ways
+ | nodes | highway |
+ | abcde | motorway |
+ | bfg | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | abcde, abcde | depart, arrive |
+ | a,g | abcde, bfg, bfg | depart, ramp-slight-right, arrive |
+
+ Scenario: Ramp Exit Right Curved Left
+ Given the node map
+ | | | | | e |
+ | | | | d | g |
+ | a | b | c | f | |
+
+
+ And the ways
+ | nodes | highway |
+ | abcde | motorway |
+ | cfg | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | abcde, abcde | depart, arrive |
+ | a,g | abcde, cfg, cfg | depart, ramp-slight-right, arrive |
+
+
+ Scenario: Ramp Exit Left
+ Given the node map
+ | | | | f | g |
+ | a | b | c | d | e |
+
+ And the ways
+ | nodes | highway |
+ | abcde | motorway |
+ | bfg | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | abcde, abcde | depart, arrive |
+ | a,g | abcde, bfg, bfg | depart, ramp-slight-left, arrive |
+
+ Scenario: Ramp Exit Left Curved Left
+ Given the node map
+ | | | | g | e |
+ | | | f | d | |
+ | a | b | c | | |
+
+ And the ways
+ | nodes | highway |
+ | abcde | motorway |
+ | bfg | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | abcde, abcde | depart, arrive |
+ | a,g | abcde, bfg, bfg | depart, ramp-slight-left, arrive |
+
+ Scenario: Ramp Exit Left Curved Right
+ Given the node map
+ | a | b | c | f | |
+ | | | | d | g |
+ | | | | | e |
+
+ And the ways
+ | nodes | highway |
+ | abcde | motorway |
+ | cfg | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | abcde, abcde | depart, arrive |
+ | a,g | abcde, cfg, cfg | depart, ramp-slight-left, arrive |
+
+ Scenario: On Ramp Right
+ Given the node map
+ | a | b | c | d | e |
+ | f | g | | | |
+
+ And the ways
+ | nodes | highway |
+ | abcde | motorway |
+ | fgd | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | abcde, abcde | depart, arrive |
+ | f,e | abcde, fgd, fgd | depart, merge-slight-left, arrive |
+
+ Scenario: On Ramp Left
+ Given the node map
+ | f | g | | | |
+ | a | b | c | d | e |
+
+ And the ways
+ | nodes | highway |
+ | abcde | motorway |
+ | fgd | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | abcde, abcde | depart, arrive |
+ | f,e | abcde, fgd, fgd | depart, merge-slight-right, arrive |
+
+ Scenario: Highway Fork
+ Given the node map
+ | | | | | d | e |
+ | a | b | c | | | |
+ | | | | | f | g |
+
+ And the ways
+ | nodes | highway |
+ | abcde | motorway |
+ | cfg | motorway |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | abcde, abcde, abcde | depart, fork-left, arrive |
+ | a,g | abcde, cfg, cfg | depart, fork-right, arrive |
+
+ Scenario: Fork After Ramp
+ Given the node map
+ | | | | | d | e |
+ | a | b | c | | | |
+ | | | | | f | g |
+
+ And the ways
+ | nodes | highway |
+ | abc | motorway_link |
+ | cde | motorway |
+ | cfg | motorway |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | abc, cde, cde | depart, fork-left, arrive |
+ | a,g | abc, cfg, cfg | depart, fork-right, arrive |
+
+ Scenario: On And Off Ramp Right
+ Given the node map
+ | a | b | | c | | d | e |
+ | f | g | | | | h | i |
+
+ And the ways
+ | nodes | highway |
+ | abcde | motorway |
+ | fgc | motorway_link |
+ | chi | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | abcde, abcde | depart, arrive |
+ | f,e | fgc, abcde, abcde | depart, merge-slight-left, arrive |
+ | a,i | abcde, chi, chi | depart, ramp-slight-right, arrive |
+ | f,i | fgc, chi, chi | depart, turn-slight-right, arrive |
+
+ Scenario: On And Off Ramp Left
+ Given the node map
+ | f | g | | | | h | i |
+ | a | b | | c | | d | e |
+
+ And the ways
+ | nodes | highway |
+ | abcde | motorway |
+ | fgc | motorway_link |
+ | chi | motorway_link |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e | abcde, abcde | depart, arrive |
+ | f,e | fgc, abcde, abcde | depart, merge-slight-right, arrive |
+ | a,i | abcde, chi, chi | depart, ramp-slight-left, arrive |
+ | f,i | fgc, chi, chi | depart, turn-slight-left, arrive |
+
diff --git a/features/guidance/roundabout.feature b/features/guidance/roundabout.feature
new file mode 100644
index 0000000..21d6530
--- /dev/null
+++ b/features/guidance/roundabout.feature
@@ -0,0 +1,173 @@
+ at routing @guidance
+Feature: Basic Roundabout
+
+ Background:
+ Given the profile "testbot"
+ Given a grid size of 10 meters
+
+ Scenario: Enter and Exit
+ Given the node map
+ | | | a | | |
+ | | | b | | |
+ | h | g | | c | d |
+ | | | e | | |
+ | | | f | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | cd | |
+ | ef | |
+ | gh | |
+ | bcegb | roundabout |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,d | ab,cd,cd | depart,roundabout-exit-1,arrive |
+ | a,f | ab,ef,ef | depart,roundabout-exit-2,arrive |
+ | a,h | ab,gh,gh | depart,roundabout-exit-3,arrive |
+ | d,f | cd,ef,ef | depart,roundabout-exit-1,arrive |
+ | d,h | cd,gh,gh | depart,roundabout-exit-2,arrive |
+ | d,a | cd,ab,ab | depart,roundabout-exit-3,arrive |
+ | f,h | ef,gh,gh | depart,roundabout-exit-1,arrive |
+ | f,a | ef,ab,ab | depart,roundabout-exit-2,arrive |
+ | f,d | ef,cd,cd | depart,roundabout-exit-3,arrive |
+ | h,a | gh,ab,ab | depart,roundabout-exit-1,arrive |
+ | h,d | gh,cd,cd | depart,roundabout-exit-2,arrive |
+ | h,f | gh,ef,ef | depart,roundabout-exit-3,arrive |
+
+ Scenario: Only Enter
+ Given the node map
+ | | | a | | |
+ | | | b | | |
+ | h | g | | c | d |
+ | | | e | | |
+ | | | f | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | cd | |
+ | ef | |
+ | gh | |
+ | bcegb | roundabout |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,b | ab,ab | depart,arrive |
+ | a,c | ab,bcegb | depart,roundabout-enter,arrive |
+ | a,e | ab,bcegb | depart,roundabout-enter,arrive |
+ | a,g | ab,bcegb | depart,roundabout-enter,arrive |
+ | d,c | cd,cd | depart,arrive |
+ | d,e | cd,bcegb | depart,roundabout-enter,arrive |
+ | d,g | cd,bcegb | depart,roundabout-enter,arrive |
+ | d,b | cd,bcegb | depart,roundabout-enter,arrive |
+ | f,e | ef,ef | depart,arrive |
+ | f,g | ef,bcegb | depart,roundabout-enter,arrive |
+ | f,b | ef,bcegb | depart,roundabout-enter,arrive |
+ | f,c | ef,bcegb | depart,roundabout-enter,arrive |
+ | h,g | gh,gh | depart,arrive |
+ | h,b | gh,bcegb | depart,roundabout-enter,arrive |
+ | h,c | gh,bcegb | depart,roundabout-enter,arrive |
+ | h,e | gh,bcegb | depart,roundabout-enter,arrive |
+
+ Scenario: Only Exit
+ Given the node map
+ | | | a | | |
+ | | | b | | |
+ | h | g | | c | d |
+ | | | e | | |
+ | | | f | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | cd | |
+ | ef | |
+ | gh | |
+ | bcegb | roundabout |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | b,a | ab,ab | depart,arrive |
+ | b,d | bcegb,cd,cd | depart,roundabout-exit-1,arrive |
+ | b,f | bcegb,ef,ef | depart,roundabout-exit-2,arrive |
+ | b,h | bcegb,gh,gh | depart,roundabout-exit-3,arrive |
+ | c,d | cd,cd | depart,arrive |
+ | c,f | bcegb,ef,ef | depart,roundabout-exit-1,arrive |
+ | c,h | bcegb,gh,gh | depart,roundabout-exit-2,arrive |
+ | c,a | bcegb,ab,ab | depart,roundabout-exit-3,arrive |
+ | e,f | ef,ef | depart,arrive |
+ | e,h | bcegb,gh,gh | depart,roundabout-exit-1,arrive |
+ | e,a | bcegb,ab,ab | depart,roundabout-exit-2,arrive |
+ | e,d | bcegb,cd,cd | depart,roundabout-exit-3,arrive |
+ | g,h | gh,gh | depart,arrive |
+ | g,a | bcegb,ab,ab | depart,roundabout-exit-1,arrive |
+ | g,d | bcegb,cd,cd | depart,roundabout-exit-2,arrive |
+ | g,f | bcegb,ef,ef | depart,roundabout-exit-3,arrive |
+
+ Scenario: Drive Around
+ Given the node map
+ | | | a | | |
+ | | | b | | |
+ | h | g | | c | d |
+ | | | e | | |
+ | | | f | | |
+
+ And the ways
+ | nodes | junction |
+ | ab | |
+ | cd | |
+ | ef | |
+ | gh | |
+ | bcegb | roundabout |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | b,c | bcegb,bcegb | depart,arrive |
+ | b,e | bcegb,bcegb | depart,arrive |
+ | b,g | bcegb,bcegb | depart,arrive |
+ | c,e | bcegb,bcegb | depart,arrive |
+ | c,g | bcegb,bcegb | depart,arrive |
+ | c,b | bcegb,bcegb | depart,arrive |
+ | e,g | bcegb,bcegb | depart,arrive |
+ | e,b | bcegb,bcegb | depart,arrive |
+ | e,c | bcegb,bcegb | depart,arrive |
+ | g,b | bcegb,bcegb | depart,arrive |
+ | g,c | bcegb,bcegb | depart,arrive |
+ | g,e | bcegb,bcegb | depart,arrive |
+
+ Scenario: Mixed Entry and Exit
+ Given the node map
+ | | a | | c | |
+ | l | | b | | d |
+ | | k | | e | |
+ | j | | h | | f |
+ | | i | | g | |
+
+ And the ways
+ | nodes | junction | oneway |
+ | abc | | yes |
+ | def | | yes |
+ | ghi | | yes |
+ | jkl | | yes |
+ | behkb | roundabout | yes |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,c | abc,abc,abc | depart,roundabout-exit-1,arrive |
+ | a,f | abc,def,def | depart,roundabout-exit-2,arrive |
+ | a,i | abc,ghi,ghi | depart,roundabout-exit-3,arrive |
+ | a,l | abc,jkl,jkl | depart,roundabout-exit-4,arrive |
+ | d,f | def,def,def | depart,roundabout-exit-1,arrive |
+ | d,i | def,ghi,ghi | depart,roundabout-exit-2,arrive |
+ | d,l | def,jkl,jkl | depart,roundabout-exit-3,arrive |
+ | d,c | def,abc,abc | depart,roundabout-exit-4,arrive |
+ | g,i | ghi,ghi,ghi | depart,roundabout-exit-1,arrive |
+ | g,l | ghi,jkl,jkl | depart,roundabout-exit-2,arrive |
+ | g,c | ghi,abc,abc | depart,roundabout-exit-3,arrive |
+ | g,f | ghi,edf,edf | depart,roundabout-exit-4,arrive |
+ | j,l | jkl,jkl,jkl | depart,roundabout-exit-1,arrive |
+ | j,c | jkl,abc,abc | depart,roundabout-exit-2,arrive |
+ | j,f | jkl,def,def | depart,roundabout-exit-3,arrive |
+ | j,i | jkl,ghi,ghi | depart,roundabout-exit-4,arrive |
diff --git a/features/options/prepare/files.feature b/features/options/contract/files.feature
similarity index 52%
rename from features/options/prepare/files.feature
rename to features/options/contract/files.feature
index 6e82a6b..5e50e14 100644
--- a/features/options/prepare/files.feature
+++ b/features/options/contract/files.feature
@@ -1,5 +1,5 @@
@prepare @options @files
-Feature: osrm-prepare command line options: files
+Feature: osrm-contract command line options: files
# expansions:
# {extracted_base} => path to current extracted input file
# {profile} => path to current profile script
@@ -13,18 +13,13 @@ Feature: osrm-prepare command line options: files
| ab |
And the data has been extracted
- Scenario: osrm-prepare - Passing base file
- When I run "osrm-prepare {extracted_base}.osrm --profile {profile}"
+ Scenario: osrm-contract - Passing base file
+ When I run "osrm-contract {extracted_base}.osrm"
Then stderr should be empty
And it should exit with code 0
- Scenario: osrm-prepare - Order of options should not matter
- When I run "osrm-prepare --profile {profile} {extracted_base}.osrm"
- Then stderr should be empty
- And it should exit with code 0
-
- Scenario: osrm-prepare - Missing input file
- When I run "osrm-prepare over-the-rainbow.osrm --profile {profile}"
+ Scenario: osrm-contract - Missing input file
+ When I run "osrm-contract over-the-rainbow.osrm"
And stderr should contain "over-the-rainbow.osrm"
And stderr should contain "not found"
And it should exit with code 1
diff --git a/features/options/prepare/help.feature b/features/options/contract/help.feature
similarity index 58%
rename from features/options/prepare/help.feature
rename to features/options/contract/help.feature
index 34ec3d5..411bc55 100644
--- a/features/options/prepare/help.feature
+++ b/features/options/contract/help.feature
@@ -1,56 +1,44 @@
@prepare @options @help
-Feature: osrm-prepare command line options: help
+Feature: osrm-contract command line options: help
- Background:
- Given the profile "testbot"
-
- Scenario: osrm-prepare - Help should be shown when no options are passed
- When I run "osrm-prepare"
+ Scenario: osrm-contract - Help should be shown when no options are passed
+ When I run "osrm-contract"
Then stderr should be empty
- And stdout should contain "osrm-prepare <input.osrm> [options]:"
+ And stdout should contain "osrm-contract <input.osrm> [options]:"
And stdout should contain "Options:"
And stdout should contain "--version"
And stdout should contain "--help"
- And stdout should contain "--config"
And stdout should contain "Configuration:"
- And stdout should contain "--profile"
And stdout should contain "--threads"
And stdout should contain "--core"
And stdout should contain "--level-cache"
And stdout should contain "--segment-speed-file"
- And stdout should contain 21 lines
And it should exit with code 1
- Scenario: osrm-prepare - Help, short
- When I run "osrm-prepare -h"
+ Scenario: osrm-contract - Help, short
+ When I run "osrm-contract -h"
Then stderr should be empty
- And stdout should contain "osrm-prepare <input.osrm> [options]:"
+ And stdout should contain "osrm-contract <input.osrm> [options]:"
And stdout should contain "Options:"
And stdout should contain "--version"
And stdout should contain "--help"
- And stdout should contain "--config"
And stdout should contain "Configuration:"
- And stdout should contain "--profile"
And stdout should contain "--threads"
And stdout should contain "--core"
And stdout should contain "--level-cache"
And stdout should contain "--segment-speed-file"
- And stdout should contain 21 lines
And it should exit with code 0
- Scenario: osrm-prepare - Help, long
- When I run "osrm-prepare --help"
+ Scenario: osrm-contract - Help, long
+ When I run "osrm-contract --help"
Then stderr should be empty
- And stdout should contain "osrm-prepare <input.osrm> [options]:"
+ And stdout should contain "osrm-contract <input.osrm> [options]:"
And stdout should contain "Options:"
And stdout should contain "--version"
And stdout should contain "--help"
- And stdout should contain "--config"
And stdout should contain "Configuration:"
- And stdout should contain "--profile"
And stdout should contain "--threads"
And stdout should contain "--core"
And stdout should contain "--level-cache"
And stdout should contain "--segment-speed-file"
- And stdout should contain 21 lines
And it should exit with code 0
diff --git a/features/options/prepare/invalid.feature b/features/options/contract/invalid.feature
similarity index 60%
rename from features/options/prepare/invalid.feature
rename to features/options/contract/invalid.feature
index 7450390..38ee3ac 100644
--- a/features/options/prepare/invalid.feature
+++ b/features/options/contract/invalid.feature
@@ -1,11 +1,11 @@
@prepare @options @invalid
-Feature: osrm-prepare command line options: invalid options
+Feature: osrm-contract command line options: invalid options
Background:
Given the profile "testbot"
- Scenario: osrm-prepare - Non-existing option
- When I run "osrm-prepare --fly-me-to-the-moon"
+ Scenario: osrm-contract - Non-existing option
+ When I run "osrm-contract --fly-me-to-the-moon"
Then stdout should be empty
And stderr should contain "option"
And stderr should contain "fly-me-to-the-moon"
diff --git a/features/options/prepare/version.feature b/features/options/contract/version.feature
similarity index 74%
rename from features/options/prepare/version.feature
rename to features/options/contract/version.feature
index 7a821c6..be99bbe 100644
--- a/features/options/prepare/version.feature
+++ b/features/options/contract/version.feature
@@ -1,5 +1,5 @@
@prepare @options @version
-Feature: osrm-prepare command line options: version
+Feature: osrm-contract command line options: version
# the regex will match these two formats:
# v0.3.7.0 # this is the normal format when you build from a git clone
# -128-NOTFOUND # if you build from a shallow clone (used on Travis)
@@ -7,15 +7,15 @@ Feature: osrm-prepare command line options: version
Background:
Given the profile "testbot"
- Scenario: osrm-prepare - Version, short
- When I run "osrm-prepare --v"
+ Scenario: osrm-contract - Version, short
+ When I run "osrm-contract --v"
Then stderr should be empty
And stdout should contain 1 line
And stdout should contain /(v\d{1,2}\.\d{1,2}\.\d{1,2}|\w*-\d+-\w+)/
And it should exit with code 0
- Scenario: osrm-prepare - Version, long
- When I run "osrm-prepare --version"
+ Scenario: osrm-contract - Version, long
+ When I run "osrm-contract --version"
Then stderr should be empty
And stdout should contain 1 line
And stdout should contain /(v\d{1,2}\.\d{1,2}\.\d{1,2}|\w*-\d+-\w+)/
diff --git a/features/options/extract/help.feature b/features/options/extract/help.feature
index 722c4dc..cdf1eb9 100644
--- a/features/options/extract/help.feature
+++ b/features/options/extract/help.feature
@@ -11,13 +11,11 @@ Feature: osrm-extract command line options: help
And stdout should contain "Options:"
And stdout should contain "--version"
And stdout should contain "--help"
- And stdout should contain "--config"
And stdout should contain "Configuration:"
And stdout should contain "--profile"
And stdout should contain "--threads"
And stdout should contain "--generate-edge-lookup"
And stdout should contain "--small-component-size"
- And stdout should contain 20 lines
And it should exit with code 0
Scenario: osrm-extract - Help, short
@@ -27,13 +25,11 @@ Feature: osrm-extract command line options: help
And stdout should contain "Options:"
And stdout should contain "--version"
And stdout should contain "--help"
- And stdout should contain "--config"
And stdout should contain "Configuration:"
And stdout should contain "--profile"
And stdout should contain "--threads"
And stdout should contain "--generate-edge-lookup"
And stdout should contain "--small-component-size"
- And stdout should contain 20 lines
And it should exit with code 0
Scenario: osrm-extract - Help, long
@@ -43,11 +39,9 @@ Feature: osrm-extract command line options: help
And stdout should contain "Options:"
And stdout should contain "--version"
And stdout should contain "--help"
- And stdout should contain "--config"
And stdout should contain "Configuration:"
And stdout should contain "--profile"
And stdout should contain "--threads"
And stdout should contain "--generate-edge-lookup"
And stdout should contain "--small-component-size"
- And stdout should contain 20 lines
And it should exit with code 0
diff --git a/features/options/routed/files.feature b/features/options/routed/files.feature
index 15ce679..59ce7c2 100644
--- a/features/options/routed/files.feature
+++ b/features/options/routed/files.feature
@@ -4,8 +4,8 @@ Feature: osrm-routed command line options: files
# For testing program options, the --trial option is used, which causes osrm-routed to quit
# immediately after initialization. This makes testing easier and faster.
#
-# The {prepared_base} part of the options to osrm-routed will be expanded to the actual base path of
-# the prepared input file.
+# The {contracted_base} part of the options to osrm-routed will be expanded to the actual base path of
+# the contracted input file.
# TODO
# Since we're not using osmr-datastore for all testing, osrm-routed is kept running.
@@ -19,14 +19,14 @@ Feature: osrm-routed command line options: files
And the ways
| nodes |
| ab |
- And the data has been prepared
+ And the data has been contracted
Scenario: osrm-routed - Passing base file
- When I run "osrm-routed {prepared_base}.osrm --trial"
+ When I run "osrm-routed {contracted_base}.osrm --trial"
Then stdout should contain /^\[info\] starting up engines/
And stdout should contain /\d{1,2}\.\d{1,2}\.\d{1,2}/
And stdout should contain /compiled at/
And stdout should contain /^\[info\] loaded plugin: viaroute/
And stdout should contain /^\[info\] trial run/
And stdout should contain /^\[info\] shutdown completed/
- And it should exit with code 0
\ No newline at end of file
+ And it should exit with code 0
diff --git a/features/options/routed/help.feature b/features/options/routed/help.feature
index 34c6ee2..8f64bd9 100644
--- a/features/options/routed/help.feature
+++ b/features/options/routed/help.feature
@@ -11,16 +11,8 @@ Feature: osrm-routed command line options: help
And stdout should contain "Options:"
And stdout should contain "--version"
And stdout should contain "--help"
- And stdout should contain "--config"
And stdout should contain "--trial"
And stdout should contain "Configuration:"
- And stdout should contain "--hsgrdata arg"
- And stdout should contain "--nodesdata arg"
- And stdout should contain "--edgesdata arg"
- And stdout should contain "--ramindex arg"
- And stdout should contain "--fileindex arg"
- And stdout should contain "--namesdata arg"
- And stdout should contain "--timestamp arg"
And stdout should contain "--ip"
And stdout should contain "--port"
And stdout should contain "--threads"
@@ -29,7 +21,6 @@ Feature: osrm-routed command line options: help
And stdout should contain "--max-trip-size"
And stdout should contain "--max-table-size"
And stdout should contain "--max-matching-size"
- And stdout should contain 30 lines
And it should exit with code 0
Scenario: osrm-routed - Help, short
@@ -39,16 +30,8 @@ Feature: osrm-routed command line options: help
And stdout should contain "Options:"
And stdout should contain "--version"
And stdout should contain "--help"
- And stdout should contain "--config"
And stdout should contain "--trial"
And stdout should contain "Configuration:"
- And stdout should contain "--hsgrdata arg"
- And stdout should contain "--nodesdata arg"
- And stdout should contain "--edgesdata arg"
- And stdout should contain "--ramindex arg"
- And stdout should contain "--fileindex arg"
- And stdout should contain "--namesdata arg"
- And stdout should contain "--timestamp arg"
And stdout should contain "--ip"
And stdout should contain "--port"
And stdout should contain "--threads"
@@ -57,7 +40,6 @@ Feature: osrm-routed command line options: help
And stdout should contain "--max-trip-size"
And stdout should contain "--max-table-size"
And stdout should contain "--max-matching-size"
- And stdout should contain 30 lines
And it should exit with code 0
Scenario: osrm-routed - Help, long
@@ -67,16 +49,8 @@ Feature: osrm-routed command line options: help
And stdout should contain "Options:"
And stdout should contain "--version"
And stdout should contain "--help"
- And stdout should contain "--config"
And stdout should contain "--trial"
And stdout should contain "Configuration:"
- And stdout should contain "--hsgrdata arg"
- And stdout should contain "--nodesdata arg"
- And stdout should contain "--edgesdata arg"
- And stdout should contain "--ramindex arg"
- And stdout should contain "--fileindex arg"
- And stdout should contain "--namesdata arg"
- And stdout should contain "--timestamp arg"
And stdout should contain "--ip"
And stdout should contain "--port"
And stdout should contain "--threads"
@@ -85,5 +59,4 @@ Feature: osrm-routed command line options: help
And stdout should contain "--max-table-size"
And stdout should contain "--max-table-size"
And stdout should contain "--max-matching-size"
- And stdout should contain 30 lines
And it should exit with code 0
diff --git a/features/options/routed/invalid.feature b/features/options/routed/invalid.feature
index a6d62d7..f3d90ea 100644
--- a/features/options/routed/invalid.feature
+++ b/features/options/routed/invalid.feature
@@ -13,7 +13,6 @@ Feature: osrm-routed command line options: invalid options
Scenario: osrm-routed - Missing file
When I run "osrm-routed over-the-rainbow.osrm"
- Then stdout should contain "over-the-rainbow.osrm"
- And stderr should contain "exception"
+ Then stderr should contain "over-the-rainbow.osrm"
And stderr should contain "not found"
And it should exit with code 1
diff --git a/features/raster/weights.feature b/features/raster/weights.feature
index 1d521d0..ae782a7 100644
--- a/features/raster/weights.feature
+++ b/features/raster/weights.feature
@@ -28,51 +28,52 @@ Feature: Raster - weights
0 0 0 250
0 0 0 0
"""
+ And the data has been saved to disk
Scenario: Weighting not based on raster sources
Given the profile "testbot"
When I run "osrm-extract {osm_base}.osm -p {profile}"
- And I run "osrm-prepare {osm_base}.osm"
+ And I run "osrm-contract {osm_base}.osm"
And I route I should get
- | from | to | route | speed |
- | a | b | ab | 36 km/h |
- | a | c | ab,bc | 36 km/h |
- | b | c | bc | 36 km/h |
- | a | d | ad | 36 km/h |
- | d | c | dc | 36 km/h |
+ | from | to | route | speed |
+ | a | b | ab,ab | 36 km/h |
+ | a | c | ab,bc,bc | 36 km/h |
+ | b | c | bc,bc | 36 km/h |
+ | a | d | ad,ad | 36 km/h |
+ | d | c | dc,dc | 36 km/h |
Scenario: Weighting based on raster sources
Given the profile "rasterbot"
When I run "osrm-extract {osm_base}.osm -p {profile}"
Then stdout should contain "evaluating segment"
- And I run "osrm-prepare {osm_base}.osm"
+ And I run "osrm-contract {osm_base}.osm"
And I route I should get
- | from | to | route | speed |
- | a | b | ab | 8 km/h |
- | a | c | ad,dc | 15 km/h |
- | b | c | bc | 8 km/h |
- | a | d | ad | 15 km/h |
- | d | c | dc | 15 km/h |
- | d | e | de | 10 km/h |
- | e | b | eb | 10 km/h |
- | d | f | df | 15 km/h |
- | f | b | fb | 7 km/h |
- | d | b | de,eb | 10 km/h |
+ | from | to | route | speed |
+ | a | b | ab,ab | 8 km/h |
+ | a | c | ad,dc,dc | 15 km/h |
+ | b | c | bc,bc | 8 km/h |
+ | a | d | ad,ad | 15 km/h |
+ | d | c | dc,dc | 15 km/h |
+ | d | e | de,de | 10 km/h |
+ | e | b | eb,eb | 10 km/h |
+ | d | f | df,df | 15 km/h |
+ | f | b | fb,fb | 7 km/h |
+ | d | b | de,eb,eb | 10 km/h |
Scenario: Weighting based on raster sources
- Given the profile "rasterbot-interp"
+ Given the profile "rasterbotinterp"
When I run "osrm-extract {osm_base}.osm -p {profile}"
Then stdout should contain "evaluating segment"
- And I run "osrm-prepare {osm_base}.osm"
+ And I run "osrm-contract {osm_base}.osm"
And I route I should get
- | from | to | route | speed |
- | a | b | ab | 8 km/h |
- | a | c | ad,dc | 15 km/h |
- | b | c | bc | 8 km/h |
- | a | d | ad | 15 km/h |
- | d | c | dc | 15 km/h |
- | d | e | de | 10 km/h |
- | e | b | eb | 10 km/h |
- | d | f | df | 15 km/h |
- | f | b | fb | 7 km/h |
- | d | b | de,eb | 10 km/h |
+ | from | to | route | speed |
+ | a | b | ab,ab | 8 km/h |
+ | a | c | ad,dc,dc | 15 km/h |
+ | b | c | bc,bc | 8 km/h |
+ | a | d | ad,ad | 15 km/h |
+ | d | c | dc,dc | 15 km/h |
+ | d | e | de,de | 10 km/h |
+ | e | b | eb,eb | 10 km/h |
+ | d | f | df,df | 15 km/h |
+ | f | b | fb,fb | 7 km/h |
+ | d | b | de,eb,eb | 10 km/h |
diff --git a/features/step_definitions/data.js b/features/step_definitions/data.js
new file mode 100644
index 0000000..db0071c
--- /dev/null
+++ b/features/step_definitions/data.js
@@ -0,0 +1,273 @@
+var util = require('util');
+var path = require('path');
+var fs = require('fs');
+var d3 = require('d3-queue');
+var OSM = require('../support/build_osm');
+
+module.exports = function () {
+ this.Given(/^the profile "([^"]*)"$/, (profile, callback) => {
+ this.setProfile(profile, callback);
+ });
+
+ this.Given(/^the extract extra arguments "(.*?)"$/, (args, callback) => {
+ this.setExtractArgs(args);
+ callback();
+ });
+
+ this.Given(/^the contract extra arguments "(.*?)"$/, (args, callback) => {
+ this.setContractArgs(args);
+ callback();
+ });
+
+ this.Given(/^a grid size of (\d+) meters$/, (meters, callback) => {
+ this.setGridSize(meters);
+ callback();
+ });
+
+ this.Given(/^the origin ([-+]?[0-9]*\.?[0-9]+),([-+]?[0-9]*\.?[0-9]+)$/, (lat, lon, callback) => {
+ this.setOrigin([parseFloat(lon), parseFloat(lat)]);
+ callback();
+ });
+
+ this.Given(/^the shortcuts$/, (table, callback) => {
+ var q = d3.queue();
+
+ var addShortcut = (row, cb) => {
+ this.shortcutsHash[row.key] = row.value;
+ cb();
+ };
+
+ table.hashes().forEach((row) => {
+ q.defer(addShortcut, row);
+ });
+
+ q.awaitAll(callback);
+ });
+
+ this.Given(/^the node map$/, (table, callback) => {
+ var q = d3.queue();
+
+ var addNode = (name, ri, ci, cb) => {
+ if (name) {
+ if (name.length !== 1) throw new Error(util.format('*** node invalid name %s, must be single characters', name));
+ if (!name.match(/[a-z0-9]/)) throw new Error(util.format('*** invalid node name %s, must me alphanumeric', name));
+
+ var lonLat;
+ if (name.match(/[a-z]/)) {
+ if (this.nameNodeHash[name]) throw new Error(util.format('*** duplicate node %s', name));
+ lonLat = this.tableCoordToLonLat(ci, ri);
+ this.addOSMNode(name, lonLat[0], lonLat[1], null);
+ } else {
+ if (this.locationHash[name]) throw new Error(util.format('*** duplicate node %s'), name);
+ lonLat = this.tableCoordToLonLat(ci, ri);
+ this.addLocation(name, lonLat[0], lonLat[1], null);
+ }
+
+ cb();
+ }
+ else cb();
+ };
+
+ table.raw().forEach((row, ri) => {
+ row.forEach((name, ci) => {
+ q.defer(addNode, name, ri, ci);
+ });
+ });
+
+ q.awaitAll(callback);
+ });
+
+ this.Given(/^the node locations$/, (table, callback) => {
+ var q = d3.queue();
+
+ var addNodeLocations = (row, cb) => {
+ var name = row.node;
+ if (this.findNodeByName(name)) throw new Error(util.format('*** duplicate node %s'), name);
+
+ if (name.match(/[a-z]/)) {
+ var id = row.id && parseInt(row.id);
+ this.addOSMNode(name, row.lon, row.lat, id);
+ } else {
+ this.addLocation(name, row.lon, row.lat);
+ }
+
+ cb();
+ };
+
+ table.hashes().forEach((row) => q.defer(addNodeLocations, row));
+
+ q.awaitAll(callback);
+ });
+
+ this.Given(/^the nodes$/, (table, callback) => {
+ var q = d3.queue();
+
+ var addNode = (row, cb) => {
+ var name = row.node,
+ node = this.findNodeByName(name);
+ delete row.node;
+ if (!node) throw new Error(util.format('*** unknown node %s'), name);
+ for (var key in row) {
+ node.addTag(key, row[key]);
+ }
+ cb();
+ };
+
+ table.hashes().forEach((row) => q.defer(addNode, row));
+
+ q.awaitAll(callback);
+ });
+
+ this.Given(/^the ways$/, (table, callback) => {
+ if (this.osm_str) throw new Error('*** Map data already defined - did you pass an input file in this scenario?');
+
+ var q = d3.queue();
+
+ var addWay = (row, cb) => {
+ var way = new OSM.Way(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID);
+
+ var nodes = row.nodes;
+ if (this.nameWayHash.nodes) throw new Error(util.format('*** duplicate way %s', nodes));
+
+ for (var i=0; i<nodes.length; i++) {
+ var c = nodes[i];
+ if (!c.match(/[a-z]/)) throw new Error(util.format('*** ways can only use names a-z (%s)', c));
+ var node = this.findNodeByName(c);
+ if (!node) throw new Error(util.format('*** unknown node %s', c));
+ way.addNode(node);
+ }
+
+ var tags = {
+ highway: 'primary'
+ };
+
+ for (var key in row) {
+ tags[key] = row[key];
+ }
+
+ delete tags.nodes;
+
+ if (row.highway === '(nil)') delete tags.highway;
+
+ if (row.name === undefined)
+ tags.name = nodes;
+ else if (row.name === '""' || row.name === "''") // eslint-disable-line quotes
+ tags.name = '';
+ else if (row.name === '' || row.name === '(nil)')
+ delete tags.name;
+ else
+ tags.name = row.name;
+
+ way.setTags(tags);
+ this.OSMDB.addWay(way);
+ this.nameWayHash[nodes] = way;
+ cb();
+ };
+
+ table.hashes().forEach((row) => q.defer(addWay, row));
+
+ q.awaitAll(callback);
+ });
+
+ this.Given(/^the relations$/, (table, callback) => {
+ if (this.osm_str) throw new Error('*** Map data already defined - did you pass an input file in this scenario?');
+
+ var q = d3.queue();
+
+ var addRelation = (row, cb) => {
+ var relation = new OSM.Relation(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID);
+
+ for (var key in row) {
+ var isNode = key.match(/^node:(.*)/),
+ isWay = key.match(/^way:(.*)/),
+ isColonSeparated = key.match(/^(.*):(.*)/);
+ if (isNode) {
+ row[key].split(',').map(function(v) { return v.trim(); }).forEach((nodeName) => {
+ if (nodeName.length !== 1) throw new Error(util.format('*** invalid relation node member "%s"'), nodeName);
+ var node = this.findNodeByName(nodeName);
+ if (!node) throw new Error(util.format('*** unknown relation node member "%s"'), nodeName);
+ relation.addMember('node', node.id, isNode[1]);
+ });
+ } else if (isWay) {
+ row[key].split(',').map(function(v) { return v.trim(); }).forEach((wayName) => {
+ var way = this.findWayByName(wayName);
+ if (!way) throw new Error(util.format('*** unknown relation way member "%s"'), wayName);
+ relation.addMember('way', way.id, isWay[1]);
+ });
+ } else if (isColonSeparated && isColonSeparated[1] !== 'restriction') {
+ throw new Error(util.format('*** unknown relation member type "%s:%s", must be either "node" or "way"'), isColonSeparated[1], isColonSeparated[2]);
+ } else {
+ relation.addTag(key, row[key]);
+ }
+ }
+ relation.uid = this.OSM_UID;
+
+ this.OSMDB.addRelation(relation);
+
+ cb();
+ };
+
+ table.hashes().forEach((row) => q.defer(addRelation, row));
+
+ q.awaitAll(callback);
+ });
+
+ this.Given(/^the input file ([^"]*)$/, (file, callback) => {
+ if (path.extname(file) !== '.osm') throw new Error('*** Input file must be in .osm format');
+ fs.readFile(file, 'utf8', (err, data) => {
+ if (!err) this.osm_str = data.toString();
+ callback(err);
+ });
+ });
+
+ this.Given(/^the raster source$/, (data, callback) => {
+ fs.writeFile(path.resolve(this.TEST_FOLDER, 'rastersource.asc'), data, callback);
+ });
+
+ this.Given(/^the speed file$/, (data, callback) => {
+ fs.writeFile(path.resolve(this.TEST_FOLDER, 'speeds.csv'), data, callback);
+ });
+
+ this.Given(/^the data has been saved to disk$/, (callback) => {
+ try {
+ this.reprocess(callback);
+ } catch(e) {
+ this.processError = e;
+ callback(e);
+ }
+ });
+
+ this.Given(/^the data has been extracted$/, (callback) => {
+ this.writeAndExtract((err) => {
+ if (err) this.processError = err;
+ callback();
+ });
+ });
+
+ this.Given(/^the data has been contracted$/, (callback) => {
+ this.reprocess((err) => {
+ if (err) this.processError = err;
+ callback();
+ });
+ });
+
+ this.Given(/^osrm\-routed is stopped$/, (callback) => {
+ this.OSRMLoader.shutdown((err) => {
+ if (err) this.processError = err;
+ callback();
+ });
+ });
+
+ this.Given(/^data is loaded directly/, () => {
+ this.loadMethod = 'directly';
+ });
+
+ this.Given(/^data is loaded with datastore$/, () => {
+ this.loadMethod = 'datastore';
+ });
+
+ this.Given(/^the HTTP method "([^"]*)"$/, (method, callback) => {
+ this.httpMethod = method;
+ callback();
+ });
+};
diff --git a/features/step_definitions/data.rb b/features/step_definitions/data.rb
deleted file mode 100644
index 3e4ccc9..0000000
--- a/features/step_definitions/data.rb
+++ /dev/null
@@ -1,192 +0,0 @@
-Given /^the profile "([^"]*)"$/ do |profile|
- set_profile profile
-end
-
-Given(/^the import format "(.*?)"$/) do |format|
- set_input_format format
-end
-
-Given /^the extract extra arguments "(.*?)"$/ do |args|
- set_extract_args args
-end
-
-Given /^a grid size of (\d+) meters$/ do |meters|
- set_grid_size meters
-end
-
-Given /^the origin ([-+]?[0-9]*\.?[0-9]+),([-+]?[0-9]*\.?[0-9]+)$/ do |lat,lon|
- set_origin [lon.to_f,lat.to_f]
-end
-
-Given /^the shortcuts$/ do |table|
- table.hashes.each do |row|
- shortcuts_hash[ row['key'] ] = row['value']
- end
-end
-
-Given /^the node map$/ do |table|
- table.raw.each_with_index do |row,ri|
- row.each_with_index do |name,ci|
- unless name.empty?
- raise "*** node invalid name '#{name}', must be single characters" unless name.size == 1
- raise "*** invalid node name '#{name}', must me alphanumeric" unless name.match /[a-z0-9]/
- if name.match /[a-z]/
- raise "*** duplicate node '#{name}'" if name_node_hash[name]
- add_osm_node name, *table_coord_to_lonlat(ci,ri), nil
- else
- raise "*** duplicate node '#{name}'" if location_hash[name]
- add_location name, *table_coord_to_lonlat(ci,ri)
- end
- end
- end
- end
-end
-
-Given /^the node locations$/ do |table|
- table.hashes.each do |row|
- name = row['node']
- raise "*** duplicate node '#{name}'" if find_node_by_name name
- if name.match /[a-z]/
- id = row['id']
- id = id.to_i if id
- add_osm_node name, row['lon'].to_f, row['lat'].to_f, id
- else
- add_location name, row['lon'].to_f, row['lat'].to_f
- end
- end
-end
-
-Given /^the nodes$/ do |table|
- table.hashes.each do |row|
- name = row.delete 'node'
- node = find_node_by_name(name)
- raise "*** unknown node '#{c}'" unless node
- node << row
- end
-end
-
-Given /^the ways$/ do |table|
- raise "*** Map data already defined - did you pass an input file in this scenaria?" if @osm_str
- table.hashes.each do |row|
- way = OSM::Way.new make_osm_id, OSM_USER, OSM_TIMESTAMP
- way.uid = OSM_UID
-
- nodes = row.delete 'nodes'
- raise "*** duplicate way '#{nodes}'" if name_way_hash[nodes]
- nodes.each_char do |c|
- raise "*** ways can only use names a-z, '#{name}'" unless c.match /[a-z]/
- node = find_node_by_name(c)
- raise "*** unknown node '#{c}'" unless node
- way << node
- end
-
- defaults = { 'highway' => 'primary' }
- tags = defaults.merge(row)
-
- if row['highway'] == '(nil)'
- tags.delete 'highway'
- end
-
- if row['name'] == nil
- tags['name'] = nodes
- elsif (row['name'] == '""') || (row['name'] == "''")
- tags['name'] = ''
- elsif row['name'] == '' || row['name'] == '(nil)'
- tags.delete 'name'
- else
- tags['name'] = row['name']
- end
-
- way << tags
- osm_db << way
- name_way_hash[nodes] = way
- end
-end
-
-Given /^the relations$/ do |table|
- raise "*** Map data already defined - did you pass an input file in this scenaria?" if @osm_str
- table.hashes.each do |row|
- relation = OSM::Relation.new make_osm_id, OSM_USER, OSM_TIMESTAMP
- row.each_pair do |key,value|
- if key =~ /^node:(.*)/
- value.split(',').map { |v| v.strip }.each do |node_name|
- raise "***invalid relation node member '#{node_name}', must be single character" unless node_name.size == 1
- node = find_node_by_name(node_name)
- raise "*** unknown relation node member '#{node_name}'" unless node
- relation << OSM::Member.new( 'node', node.id, $1 )
- end
- elsif key =~ /^way:(.*)/
- value.split(',').map { |v| v.strip }.each do |way_name|
- way = find_way_by_name(way_name)
- raise "*** unknown relation way member '#{way_name}'" unless way
- relation << OSM::Member.new( 'way', way.id, $1 )
- end
- elsif key =~ /^(.*):(.*)/ && "#{$1}" != 'restriction'
- raise "*** unknown relation member type '#{$1}:#{$2}', must be either 'node' or 'way'"
- else
- relation << { key => value }
- end
- end
- relation.uid = OSM_UID
- osm_db << relation
- end
-end
-
-Given /^the defaults$/ do
-end
-
-Given /^the input file ([^"]*)$/ do |file|
- raise "*** Input file must in .osm format" unless File.extname(file)=='.osm'
- @osm_str = File.read file
-end
-
-Given /^the raster source$/ do |data|
- Dir.chdir TEST_FOLDER do
- File.open("rastersource.asc", "w") {|f| f.write(data)}
- end
-end
-
-Given /^the data has been saved to disk$/ do
- begin
- write_input_data
- rescue OSRMError => e
- @process_error = e
- end
-end
-
-Given /^the data has been extracted$/ do
- begin
- write_input_data
- extract_data unless extracted?
- rescue OSRMError => e
- @process_error = e
- end
-end
-
-Given /^the data has been prepared$/ do
- begin
- reprocess
- rescue OSRMError => e
- @process_error = e
- end
-end
-
-Given /^osrm\-routed is stopped$/ do
- begin
- OSRMLoader.shutdown
- rescue OSRMError => e
- @process_error = e
- end
-end
-
-Given /^data is loaded directly/ do
- @load_method = 'directly'
-end
-
-Given /^data is loaded with datastore$/ do
- @load_method = 'datastore'
-end
-
-Given /^the HTTP method "([^"]*)"$/ do |method|
- @http_method = method
-end
diff --git a/features/step_definitions/distance_matrix.js b/features/step_definitions/distance_matrix.js
new file mode 100644
index 0000000..735847d
--- /dev/null
+++ b/features/step_definitions/distance_matrix.js
@@ -0,0 +1,81 @@
+var util = require('util');
+
+module.exports = function () {
+ this.When(/^I request a travel time matrix I should get$/, (table, callback) => {
+ var NO_ROUTE = 2147483647; // MAX_INT
+
+ var tableRows = table.raw();
+
+ if (tableRows[0][0] !== '') throw new Error('*** Top-left cell of matrix table must be empty');
+
+ var waypoints = [],
+ columnHeaders = tableRows[0].slice(1),
+ rowHeaders = tableRows.map((h) => h[0]).slice(1),
+ symmetric = columnHeaders.every((ele, i) => ele === rowHeaders[i]);
+
+ if (symmetric) {
+ columnHeaders.forEach((nodeName) => {
+ var node = this.findNodeByName(nodeName);
+ if (!node) throw new Error(util.format('*** unknown node "%s"'), nodeName);
+ waypoints.push({ coord: node, type: 'loc' });
+ });
+ } else {
+ columnHeaders.forEach((nodeName) => {
+ var node = this.findNodeByName(nodeName);
+ if (!node) throw new Error(util.format('*** unknown node "%s"'), nodeName);
+ waypoints.push({ coord: node, type: 'dst' });
+ });
+ rowHeaders.forEach((nodeName) => {
+ var node = this.findNodeByName(nodeName);
+ if (!node) throw new Error(util.format('*** unknown node "%s"'), nodeName);
+ waypoints.push({ coord: node, type: 'src' });
+ });
+ }
+
+ var actual = [];
+ actual.push(table.headers);
+
+ this.reprocessAndLoadData(() => {
+ // compute matrix
+ var params = this.queryParams;
+
+ this.requestTable(waypoints, params, (err, response) => {
+ if (err) return callback(err);
+ if (!response.body.length) return callback(new Error('Invalid response body'));
+
+ var json = JSON.parse(response.body);
+
+ var result = json['durations'].map(row => {
+ var hashes = {};
+ row.forEach((v, i) => { hashes[tableRows[0][i+1]] = isNaN(parseInt(v)) ? '' : v; });
+ return hashes;
+ });
+
+ var testRow = (row, ri, cb) => {
+ var ok = true;
+
+ for (var k in result[ri]) {
+ if (this.FuzzyMatch.match(result[ri][k], row[k])) {
+ result[ri][k] = row[k];
+ } else if (row[k] === '' && result[ri][k] === NO_ROUTE) {
+ result[ri][k] = '';
+ } else {
+ result[ri][k] = result[ri][k].toString();
+ ok = false;
+ }
+ }
+
+ if (!ok) {
+ var failed = { attempt: 'distance_matrix', query: this.query, response: response };
+ this.logFail(row, result[ri], [failed]);
+ }
+
+ result[ri][''] = row[''];
+ cb(null, result[ri]);
+ };
+
+ this.processRowsAndDiff(table, testRow, callback);
+ });
+ });
+ });
+};
diff --git a/features/step_definitions/distance_matrix.rb b/features/step_definitions/distance_matrix.rb
deleted file mode 100644
index 2143d37..0000000
--- a/features/step_definitions/distance_matrix.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-When /^I request a travel time matrix I should get$/ do |table|
- no_route = 2147483647 # MAX_INT
-
- raise "*** Top-left cell of matrix table must be empty" unless table.headers[0]==""
-
- waypoints = []
- column_headers = table.headers[1..-1]
- row_headers = table.rows.map { |h| h.first }
- symmetric = Set.new(column_headers) == Set.new(row_headers)
- if symmetric then
- column_headers.each do |node_name|
- node = find_node_by_name(node_name)
- raise "*** unknown node '#{node_name}" unless node
- waypoints << {:coord => node, :type => "loc"}
- end
- else
- column_headers.each do |node_name|
- node = find_node_by_name(node_name)
- raise "*** unknown node '#{node_name}" unless node
- waypoints << {:coord => node, :type => "dst"}
- end
- row_headers.each do |node_name|
- node = find_node_by_name(node_name)
- raise "*** unknown node '#{node_name}" unless node
- waypoints << {:coord => node, :type => "src"}
- end
- end
-
- reprocess
- actual = []
- actual << table.headers
- OSRMLoader.load(self,"#{prepared_file}.osrm") do
-
- # compute matrix
- params = @query_params
- response = request_table waypoints, params
- if response.body.empty? == false
- json_result = JSON.parse response.body
- result = json_result["distance_table"]
- end
-
-
- # compare actual and expected result, one row at a time
- table.rows.each_with_index do |row,ri|
- # fuzzy match
- ok = true
- 0.upto(result[ri].size-1) do |i|
- if FuzzyMatch.match result[ri][i], row[i+1]
- result[ri][i] = row[i+1]
- elsif row[i+1]=="" and result[ri][i]==no_route
- result[ri][i] = ""
- else
- result[ri][i] = result[ri][i].to_s
- ok = false
- end
- end
-
- # add row header
- r = [row[0],result[ri]].flatten
-
- # store row for comparison
- actual << r
- end
- end
- table.diff! actual
-end
diff --git a/features/step_definitions/hooks.js b/features/step_definitions/hooks.js
new file mode 100644
index 0000000..07b4719
--- /dev/null
+++ b/features/step_definitions/hooks.js
@@ -0,0 +1,30 @@
+var util = require('util');
+
+module.exports = function () {
+ this.Before((scenario, callback) => {
+ this.scenarioTitle = scenario.getName();
+
+ this.loadMethod = this.DEFAULT_LOAD_METHOD;
+ this.queryParams = {};
+ var d = new Date();
+ this.scenarioTime = util.format('%d-%d-%dT%s:%s:%sZ', d.getFullYear(), d.getMonth()+1, d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds());
+ this.resetData();
+ this.hasLoggedPreprocessInfo = false;
+ this.hasLoggedScenarioInfo = false;
+ this.setGridSize(this.DEFAULT_GRID_SIZE);
+ this.setOrigin(this.DEFAULT_ORIGIN);
+ callback();
+ });
+
+ this.Before('@ignore-platform-windows', () => {
+ this.skipThisScenario();
+ });
+
+ this.Before('@ignore-platform-unix', () => {
+ this.skipThisScenario();
+ });
+
+ this.Before('@ignore-platform-mac', () => {
+ this.skipThisScenario();
+ });
+};
diff --git a/features/step_definitions/matching.js b/features/step_definitions/matching.js
new file mode 100644
index 0000000..1b770d7
--- /dev/null
+++ b/features/step_definitions/matching.js
@@ -0,0 +1,174 @@
+var util = require('util');
+var d3 = require('d3-queue');
+
+module.exports = function () {
+ this.When(/^I match I should get$/, (table, callback) => {
+ var got;
+
+ this.reprocessAndLoadData(() => {
+ var testRow = (row, ri, cb) => {
+ var afterRequest = (err, res) => {
+ if (err) return cb(err);
+ var json;
+
+ var headers = new Set(table.raw()[0]);
+
+ if (res.body.length) {
+ json = JSON.parse(res.body);
+ }
+
+ if (headers.has('status')) {
+ got.status = json.status.toString();
+ }
+
+ if (headers.has('message')) {
+ got.message = json.status_message;
+ }
+
+ if (headers.has('#')) {
+ // comment column
+ got['#'] = row['#'];
+ }
+
+ var subMatchings = [],
+ turns = '',
+ route = '',
+ duration = '';
+
+ if (res.statusCode === 200) {
+ if (headers.has('matchings')) {
+ subMatchings = json.matchings.filter(m => !!m).map(sub => sub.matched_points);
+ }
+
+ if (headers.has('turns')) {
+ if (json.matchings.length != 1) throw new Error('*** Checking turns only supported for matchings with one subtrace');
+ turns = this.turnList(json.matchings[0].instructions);
+ }
+
+ if (headers.has('route')) {
+ if (json.matchings.length != 1) throw new Error('*** Checking route only supported for matchings with one subtrace');
+ route = this.wayList(json.matchings[0]);
+ }
+
+ if (headers.has('duration')) {
+ if (json.matchings.length != 1) throw new Error('*** Checking duration only supported for matchings with one subtrace');
+ duration = json.matchings[0].duration;
+ }
+ }
+
+ if (headers.has('turns')) {
+ got.turns = turns;
+ }
+
+ if (headers.has('route')) {
+ got.route = route;
+ }
+
+ if (headers.has('duration')) {
+ got.duration = duration.toString();
+ }
+
+ var ok = true;
+ var encodedResult = '',
+ extendedTarget = '';
+
+ var q = d3.queue();
+
+ var testSubMatching = (sub, si, scb) => {
+ if (si >= subMatchings.length) {
+ ok = false;
+ q.abort();
+ scb();
+ } else {
+ var sq = d3.queue();
+
+ var testSubNode = (ni, ncb) => {
+ var node = this.findNodeByName(sub[ni]),
+ outNode = subMatchings[si][ni];
+
+ if (this.FuzzyMatch.matchLocation(outNode, node)) {
+ encodedResult += sub[ni];
+ extendedTarget += sub[ni];
+ } else {
+ encodedResult += util.format('? [%s,%s]', outNode[0], outNode[1]);
+ extendedTarget += util.format('%s [%d,%d]', node.lat, node.lon);
+ ok = false;
+ }
+ ncb();
+ };
+
+ for (var i=0; i<sub.length; i++) {
+ sq.defer(testSubNode, i);
+ }
+
+ sq.awaitAll(scb);
+ }
+ };
+
+ row.matchings.split(',').forEach((sub, si) => {
+ q.defer(testSubMatching, sub, si);
+ });
+
+ q.awaitAll(() => {
+ if (ok) {
+ if (headers.has('matchings')) {
+ got.matchings = row.matchings;
+ }
+
+ if (headers.has('timestamps')) {
+ got.timestamps = row.timestamps;
+ }
+ } else {
+ got.matchings = encodedResult;
+ row.matchings = extendedTarget;
+ this.logFail(row, got, { matching: { query: this.query, response: res } });
+ }
+
+ cb(null, got);
+ });
+ };
+
+ if (row.request) {
+ got = {};
+ got.request = row.request;
+ this.requestUrl(row.request, afterRequest);
+ } else {
+ var params = this.queryParams;
+ got = {};
+ for (var k in row) {
+ var match = k.match(/param:(.*)/);
+ if (match) {
+ if (row[k] === '(nil)') {
+ params[match[1]] = null;
+ } else if (row[k]) {
+ params[match[1]] = [row[k]];
+ }
+ got[k] = row[k];
+ }
+ }
+
+ var trace = [],
+ timestamps = [];
+
+ if (row.trace) {
+ for (var i=0; i<row.trace.length; i++) {
+ var n = row.trace[i],
+ node = this.findNodeByName(n);
+ if (!node) throw new Error(util.format('*** unknown waypoint node "%s"'), n);
+ trace.push(node);
+ }
+ if (row.timestamps) {
+ timestamps = row.timestamps.split(' ').filter(s => !!s).map(t => parseInt(t, 10));
+ }
+ got.trace = row.trace;
+ this.requestMatching(trace, timestamps, params, afterRequest);
+ } else {
+ throw new Error('*** no trace');
+ }
+ }
+ };
+
+ this.processRowsAndDiff(table, testRow, callback);
+ });
+ });
+};
diff --git a/features/step_definitions/matching.rb b/features/step_definitions/matching.rb
deleted file mode 100644
index c490b46..0000000
--- a/features/step_definitions/matching.rb
+++ /dev/null
@@ -1,124 +0,0 @@
-When /^I match I should get$/ do |table|
- reprocess
- actual = []
- OSRMLoader.load(self,"#{prepared_file}.osrm") do
- table.hashes.each_with_index do |row,ri|
- if row['request']
- got = {'request' => row['request'] }
- response = request_url row['request']
- else
- params = @query_params
- got = {}
- row.each_pair do |k,v|
- if k =~ /param:(.*)/
- if v=='(nil)'
- params[$1]=nil
- elsif v!=nil
- params[$1]=[v]
- end
- got[k]=v
- end
- end
- trace = []
- timestamps = []
- if row['trace']
- row['trace'].each_char do |n|
- node = find_node_by_name(n.strip)
- raise "*** unknown waypoint node '#{n.strip}" unless node
- trace << node
- end
- if row['timestamps']
- timestamps = row['timestamps'].split(" ").compact.map { |t| t.to_i}
- end
- got = got.merge({'trace' => row['trace'] })
- response = request_matching trace, timestamps, params
- else
- raise "*** no trace"
- end
- end
-
- if response.body.empty? == false
- json = JSON.parse response.body
- end
-
- if table.headers.include? 'status'
- got['status'] = json['status'].to_s
- end
- if table.headers.include? 'message'
- got['message'] = json['status_message']
- end
- if table.headers.include? '#' # comment column
- got['#'] = row['#'] # copy value so it always match
- end
-
- sub_matchings = []
- turns = ''
- route = ''
- duration = ''
- if response.code == "200"
- if table.headers.include? 'matchings'
- sub_matchings = json['matchings'].compact.map { |sub| sub['matched_points']}
- end
- if table.headers.include? 'turns'
- raise "*** Checking turns only support for matchings with one subtrace" unless json['matchings'].size == 1
- turns = turn_list json['matchings'][0]['instructions']
- end
- if table.headers.include? 'route'
- raise "*** Checking route only support for matchings with one subtrace" unless json['matchings'].size == 1
- route = way_list json['matchings'][0]['instructions']
- if table.headers.include? 'duration'
- raise "*** Checking duration only support for matchings with one subtrace" unless json['matchings'].size == 1
- duration = json['matchings'][0]['route_summary']['total_time']
- end
- end
- end
-
- if table.headers.include? 'turns'
- got['turns'] = turns
- end
- if table.headers.include? 'route'
- got['route'] = route
- end
- if table.headers.include? 'duration'
- got['duration'] = duration.to_s
- end
-
- ok = true
- encoded_result = ""
- extended_target = ""
- row['matchings'].split(',').each_with_index do |sub, sub_idx|
- if sub_idx >= sub_matchings.length
- ok = false
- break
- end
- sub.length.times do |node_idx|
- node = find_node_by_name(sub[node_idx])
- out_node = sub_matchings[sub_idx][node_idx]
- if FuzzyMatch.match_location out_node, node
- encoded_result += sub[node_idx]
- extended_target += sub[node_idx]
- else
- encoded_result += "? [#{out_node[0]},#{out_node[1]}]"
- extended_target += "#{sub[node_idx]} [#{node.lat},#{node.lon}]"
- ok = false
- end
- end
- end
- if ok
- if table.headers.include? 'matchings'
- got['matchings'] = row['matchings']
- end
- if table.headers.include? 'timestamps'
- got['timestamps'] = row['timestamps']
- end
- else
- got['matchings'] = encoded_result
- row['matchings'] = extended_target
- log_fail row,got, { 'matching' => {:query => @query, :response => response} }
- end
-
- actual << got
- end
- end
- table.diff! actual
-end
diff --git a/features/step_definitions/nearest.js b/features/step_definitions/nearest.js
new file mode 100644
index 0000000..300eefe
--- /dev/null
+++ b/features/step_definitions/nearest.js
@@ -0,0 +1,53 @@
+var util = require('util');
+
+module.exports = function () {
+ this.When(/^I request nearest I should get$/, (table, callback) => {
+ this.reprocessAndLoadData(() => {
+ var testRow = (row, ri, cb) => {
+ var inNode = this.findNodeByName(row.in);
+ if (!inNode) throw new Error(util.format('*** unknown in-node "%s"'), row.in);
+
+ var outNode = this.findNodeByName(row.out);
+ if (!outNode) throw new Error(util.format('*** unknown out-node "%s"'), row.out);
+
+ this.requestNearest(inNode, this.queryParams, (err, response) => {
+ if (err) return cb(err);
+ var coord;
+
+ if (response.statusCode === 200 && response.body.length) {
+ var json = JSON.parse(response.body);
+
+ coord = json.waypoints[0].location;
+
+ var got = { in: row.in, out: row.out };
+
+ var ok = true;
+
+ Object.keys(row).forEach((key) => {
+ if (key === 'out') {
+ if (this.FuzzyMatch.matchLocation(coord, outNode)) {
+ got[key] = row[key];
+ } else {
+ row[key] = util.format('%s [%d,%d]', row[key], outNode.lat, outNode.lon);
+ ok = false;
+ }
+ }
+ });
+
+ if (!ok) {
+ var failed = { attempt: 'nearest', query: this.query, response: response };
+ this.logFail(row, got, [failed]);
+ }
+
+ cb(null, got);
+ }
+ else {
+ cb();
+ }
+ });
+ };
+
+ this.processRowsAndDiff(table, testRow, callback);
+ });
+ });
+};
diff --git a/features/step_definitions/nearest.rb b/features/step_definitions/nearest.rb
deleted file mode 100644
index b0b5f94..0000000
--- a/features/step_definitions/nearest.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-When /^I request nearest I should get$/ do |table|
- reprocess
- actual = []
- OSRMLoader.load(self,"#{prepared_file}.osrm") do
- table.hashes.each_with_index do |row,ri|
- in_node = find_node_by_name row['in']
- raise "*** unknown in-node '#{row['in']}" unless in_node
-
- out_node = find_node_by_name row['out']
- raise "*** unknown out-node '#{row['out']}" unless out_node
-
- response = request_nearest in_node, @query_params
- if response.code == "200" && response.body.empty? == false
- json = JSON.parse response.body
- if json['status'] == 200
- coord = json['mapped_coordinate']
- end
- end
-
- got = {'in' => row['in'], 'out' => coord }
-
- ok = true
- row.keys.each do |key|
- if key=='out'
- if FuzzyMatch.match_location coord, out_node
- got[key] = row[key]
- else
- row[key] = "#{row[key]} [#{out_node.lat},#{out_node.lon}]"
- ok = false
- end
- end
- end
-
- unless ok
- failed = { :attempt => 'nearest', :query => @query, :response => response }
- log_fail row,got,[failed]
- end
-
- actual << got
- end
- end
- table.diff! actual
-end
-
-When /^I request nearest (\d+) times I should get$/ do |n,table|
- ok = true
- n.to_i.times do
- ok = false unless step "I request nearest I should get", table
- end
- ok
-end
diff --git a/features/step_definitions/options.js b/features/step_definitions/options.js
new file mode 100644
index 0000000..27d6fd3
--- /dev/null
+++ b/features/step_definitions/options.js
@@ -0,0 +1,69 @@
+var assert = require('assert');
+
+module.exports = function () {
+ this.When(/^I run "osrm\-routed\s?(.*?)"$/, { timeout: this.SHUTDOWN_TIMEOUT }, (options, callback) => {
+ this.runBin('osrm-routed', options, () => {
+ callback();
+ });
+ });
+
+ this.When(/^I run "osrm\-extract\s?(.*?)"$/, (options, callback) => {
+ this.runBin('osrm-extract', options, () => {
+ callback();
+ });
+ });
+
+ this.When(/^I run "osrm\-contract\s?(.*?)"$/, (options, callback) => {
+ this.runBin('osrm-contract', options, () => {
+ callback();
+ });
+ });
+
+ this.When(/^I run "osrm\-datastore\s?(.*?)"$/, (options, callback) => {
+ this.runBin('osrm-datastore', options, () => {
+ callback();
+ });
+ });
+
+ this.Then(/^it should exit with code (\d+)$/, (code) => {
+ assert.equal(this.exitCode, parseInt(code));
+ });
+
+ this.Then(/^stdout should contain "(.*?)"$/, (str) => {
+ assert.ok(this.stdout.indexOf(str) > -1);
+ });
+
+ this.Then(/^stderr should contain "(.*?)"$/, (str) => {
+ assert.ok(this.stderr.indexOf(str) > -1);
+ });
+
+ this.Then(/^stdout should contain \/(.*)\/$/, (regexStr) => {
+ var re = new RegExp(regexStr);
+ assert.ok(this.stdout.match(re));
+ });
+
+ this.Then(/^stderr should contain \/(.*)\/$/, (regexStr) => {
+ var re = new RegExp(regexStr);
+ assert.ok(this.stdout.match(re));
+ });
+
+ this.Then(/^stdout should be empty$/, () => {
+ assert.equal(this.stdout.trim(), '');
+ });
+
+ this.Then(/^stderr should be empty$/, () => {
+ assert.equal(this.stderr.trim(), '');
+ });
+
+ this.Then(/^stdout should contain (\d+) lines?$/, (lines) => {
+ assert.equal(this.stdout.split('\n').length - 1, parseInt(lines));
+ });
+
+ this.Given(/^the query options$/, (table, callback) => {
+ table.raw().forEach(tuple => {
+ this.queryParams[tuple[0]] = tuple[1];
+ });
+
+ callback();
+ });
+};
diff --git a/features/step_definitions/options.rb b/features/step_definitions/options.rb
deleted file mode 100644
index 62329d5..0000000
--- a/features/step_definitions/options.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-When(/^I run "osrm\-routed\s?(.*?)"$/) do |options|
- begin
- Timeout.timeout(SHUTDOWN_TIMEOUT) { run_bin 'osrm-routed', options }
- rescue Timeout::Error
- raise "*** osrm-routed didn't quit. Maybe the --trial option wasn't used?"
- end
-end
-
-When(/^I run "osrm\-extract\s?(.*?)"$/) do |options|
- run_bin 'osrm-extract', options
-end
-
-When(/^I run "osrm\-prepare\s?(.*?)"$/) do |options|
- run_bin 'osrm-prepare', options
-end
-
-When(/^I run "osrm\-datastore\s?(.*?)"$/) do |options|
- run_bin 'osrm-datastore', options
-end
-
-Then /^it should exit with code (\d+)$/ do |code|
- expect(@exit_code).to eq( code.to_i )
-end
-
-Then /^stdout should contain "(.*?)"$/ do |str|
- expect(@stdout).to include(str)
-end
-
-Then /^stderr should contain "(.*?)"$/ do |str|
- expect(@stderr).to include(str)
-end
-
-Then(/^stdout should contain \/(.*)\/$/) do |regex_str|
- regex = Regexp.new regex_str
- expect(@stdout).to match( regex )
-end
-
-Then(/^stderr should contain \/(.*)\/$/) do |regex_str|
- regex = Regexp.new regex_str
- expect(@stderr).to match( regex )
-end
-
-Then /^stdout should be empty$/ do
- expect(@stdout).to eq("")
-end
-
-Then /^stderr should be empty$/ do
- expect(@stderr).to eq("")
-end
-
-Then /^stdout should contain (\d+) lines?$/ do |lines|
- expect(@stdout.lines.count).to eq( lines.to_i )
-end
-
-Given (/^the query options$/) do |table|
- table.rows_hash.each { |k,v| @query_params << [k, v] }
-end
diff --git a/features/step_definitions/requests.js b/features/step_definitions/requests.js
new file mode 100644
index 0000000..dcaf5cc
--- /dev/null
+++ b/features/step_definitions/requests.js
@@ -0,0 +1,60 @@
+var assert = require('assert');
+
+module.exports = function () {
+ this.When(/^I request \/(.*)$/, (path, callback) => {
+ this.reprocessAndLoadData(() => {
+ this.requestPath(path, {}, (err, res, body) => {
+ this.response = res;
+ callback(err, res, body);
+ });
+ });
+ });
+
+ this.Then(/^I should get a response/, () => {
+ this.ShouldGetAResponse();
+ });
+
+ this.Then(/^response should be valid JSON$/, (callback) => {
+ this.ShouldBeValidJSON(callback);
+ });
+
+ this.Then(/^response should be well-formed$/, () => {
+ this.ShouldBeWellFormed();
+ });
+
+ this.Then(/^status code should be (\d+)$/, (code, callback) => {
+ try {
+ this.json = JSON.parse(this.response.body);
+ } catch(e) {
+ return callback(e);
+ }
+ assert.equal(this.json.status, parseInt(code));
+ callback();
+ });
+
+ this.Then(/^status message should be "(.*?)"$/, (message, callback) => {
+ try {
+ this.json = JSON.parse(this.response.body);
+ } catch(e) {
+ return callback(e);
+ }
+ assert(this.json.status_message, message);
+ callback();
+ });
+
+ this.Then(/^response should be a well-formed route$/, () => {
+ this.ShouldBeWellFormed();
+ assert.equal(typeof this.json.status_message, 'string');
+ assert.equal(typeof this.json.route_summary, 'object');
+ assert.equal(typeof this.json.route_geometry, 'string');
+ assert.ok(Array.isArray(this.json.route_instructions));
+ assert.ok(Array.isArray(this.json.via_points));
+ assert.ok(Array.isArray(this.json.via_indices));
+ });
+
+ this.Then(/^"([^"]*)" should return code (\d+)$/, (binary, code) => {
+ assert.ok(this.processError instanceof this.OSRMError);
+ assert.equal(this.processError.process, binary);
+ assert.equal(parseInt(this.processError.code), parseInt(code));
+ });
+};
diff --git a/features/step_definitions/requests.rb b/features/step_definitions/requests.rb
deleted file mode 100644
index 1c012d7..0000000
--- a/features/step_definitions/requests.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-When /^I request \/(.*)$/ do |path|
- reprocess
- OSRMLoader.load(self,"#{prepared_file}.osrm") do
- @response = request_path path, []
- end
-end
-
-Then /^I should get a response/ do
- expect(@response.code).to eq("200")
- expect(@response.body).not_to eq(nil)
- expect(@response.body).not_to eq('')
-end
-
-Then /^response should be valid JSON$/ do
- @json = JSON.parse @response.body
-end
-
-Then /^response should be well-formed$/ do
- expect(@json['status'].class).to eq(Fixnum)
-end
-
-Then /^status code should be (\d+)$/ do |code|
- @json = JSON.parse @response.body
- expect(@json['status']).to eq(code.to_i)
-end
-
-Then /^status message should be "(.*?)"$/ do |message|
- @json = JSON.parse @response.body
- expect(@json['status_message']).to eq(message)
-end
-
-Then /^response should be a well-formed route$/ do
- step "response should be well-formed"
- expect(@json['status_message'].class).to eq(String)
- expect(@json['route_summary'].class).to eq(Hash)
- expect(@json['route_geometry'].class).to eq(String)
- expect(@json['route_instructions'].class).to eq(Array)
- expect(@json['via_points'].class).to eq(Array)
- expect(@json['via_indices'].class).to eq(Array)
-end
-
-Then /^"([^"]*)" should return code (\d+)$/ do |binary, code|
- expect(@process_error.is_a?(OSRMError)).to eq(true)
- expect(@process_error.process).to eq(binary)
- expect(@process_error.code.to_i).to eq(code.to_i)
-end
diff --git a/features/step_definitions/routability.js b/features/step_definitions/routability.js
new file mode 100644
index 0000000..1ef8643
--- /dev/null
+++ b/features/step_definitions/routability.js
@@ -0,0 +1,120 @@
+var util = require('util');
+var d3 = require('d3-queue');
+var classes = require('../support/data_classes');
+
+module.exports = function () {
+ this.Then(/^routability should be$/, (table, callback) => {
+ this.buildWaysFromTable(table, () => {
+ var directions = ['forw','backw','bothw'],
+ headers = new Set(Object.keys(table.hashes()[0]));
+
+ if (!directions.some(k => !!headers.has(k))) {
+ throw new Error('*** routability table must contain either "forw", "backw" or "bothw" column');
+ }
+
+ this.reprocessAndLoadData(() => {
+ var testRow = (row, i, cb) => {
+ var outputRow = row;
+
+ testRoutabilityRow(i, (err, result) => {
+ if (err) return cb(err);
+ directions.filter(d => headers.has(d)).forEach((direction) => {
+ var want = this.shortcutsHash[row[direction]] || row[direction];
+
+ switch (true) {
+ case '' === want:
+ case 'x' === want:
+ outputRow[direction] = result[direction].status ?
+ result[direction].status.toString() : '';
+ break;
+ case /^\d+s/.test(want):
+ break;
+ case /^\d+ km\/h/.test(want):
+ break;
+ default:
+ throw new Error(util.format('*** Unknown expectation format: %s', want));
+ }
+
+ if (this.FuzzyMatch.match(outputRow[direction], want)) {
+ outputRow[direction] = row[direction];
+ }
+ });
+
+ if (outputRow != row) {
+ this.logFail(row, outputRow, result);
+ }
+
+ cb(null, outputRow);
+ });
+ };
+
+ this.processRowsAndDiff(table, testRow, callback);
+ });
+ });
+ });
+
+ var testRoutabilityRow = (i, cb) => {
+ var result = {};
+
+ var testDirection = (dir, callback) => {
+ var a = new classes.Location(this.origin[0] + (1+this.WAY_SPACING*i) * this.zoom, this.origin[1]),
+ b = new classes.Location(this.origin[0] + (3+this.WAY_SPACING*i) * this.zoom, this.origin[1]),
+ r = {};
+
+ r.which = dir;
+
+ this.requestRoute((dir === 'forw' ? [a, b] : [b, a]), [], this.queryParams, (err, res, body) => {
+ if (err) return callback(err);
+
+ r.query = this.query;
+ r.json = JSON.parse(body);
+ r.status = res.statusCode === 200 ? 'x' : null;
+ if (r.status) {
+ r.route = this.wayList(r.json.routes[0]);
+
+ if (r.route.split(',')[0] === util.format('w%d', i)) {
+ r.time = r.json.routes[0].duration;
+ r.distance = r.json.routes[0].distance;
+ r.speed = r.time > 0 ? parseInt(3.6 * r.distance / r.time) : null;
+ } else {
+ r.status = null;
+ }
+ }
+
+ callback(null, r);
+ });
+ };
+
+ d3.queue(1)
+ .defer(testDirection, 'forw')
+ .defer(testDirection, 'backw')
+ .awaitAll((err, res) => {
+ if (err) return cb(err);
+ // check if forw and backw returned the same values
+ res.forEach((dirRes) => {
+ var which = dirRes.which;
+ delete dirRes.which;
+ result[which] = dirRes;
+ });
+
+ result.bothw = {};
+
+ var sq = d3.queue();
+
+ var parseRes = (key, scb) => {
+ if (result.forw[key] === result.backw[key]) {
+ result.bothw[key] = result.forw[key];
+ } else {
+ result.bothw[key] = 'diff';
+ }
+ scb();
+ };
+
+ ['status', 'time', 'distance', 'speed'].forEach((key) => {
+ sq.defer(parseRes, key);
+ });
+
+ sq.awaitAll(() => { cb(null, result); });
+ });
+ };
+};
diff --git a/features/step_definitions/routability.rb b/features/step_definitions/routability.rb
deleted file mode 100644
index 6b5134c..0000000
--- a/features/step_definitions/routability.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-def test_routability_row i
- result = {}
- ['forw','backw'].each do |direction|
- a = Location.new @origin[0]+(1+WAY_SPACING*i)*@zoom, @origin[1]
- b = Location.new @origin[0]+(3+WAY_SPACING*i)*@zoom, @origin[1]
- r = {}
- r[:response] = request_route (direction=='forw' ? [a,b] : [b,a]), [], @query_params
- r[:query] = @query
- r[:json] = JSON.parse(r[:response].body)
-
- r[:status] = (route_status r[:response]) == 200 ? 'x' : nil
- if r[:status] then
- r[:route] = way_list r[:json]['route_instructions']
-
- if r[:route]=="w#{i}"
- r[:time] = r[:json]['route_summary']['total_time']
- r[:distance] = r[:json]['route_summary']['total_distance']
- r[:speed] = r[:time]>0 ? (3.6*r[:distance]/r[:time]).to_i : nil
- else
- # if we hit the wrong way segment, we assume it's
- # because the one we tested was not unroutable
- r[:status] = nil
- end
- end
- result[direction] = r
- end
-
- # check if forw and backw returned the same values
- result['bothw'] = {}
- [:status,:time,:distance,:speed].each do |key|
- if result['forw'][key] == result['backw'][key]
- result['bothw'][key] = result['forw'][key]
- else
- result['bothw'][key] = 'diff'
- end
- end
- result
-end
-
-Then /^routability should be$/ do |table|
- build_ways_from_table table
- reprocess
- actual = []
- if table.headers&["forw","backw","bothw"] == []
- raise "*** routability tabel must contain either 'forw', 'backw' or 'bothw' column"
- end
- OSRMLoader.load(self,"#{prepared_file}.osrm") do
- table.hashes.each_with_index do |row,i|
- output_row = row.dup
- attempts = []
- result = test_routability_row i
- directions = ['forw','backw','bothw']
- (directions & table.headers).each do |direction|
- want = shortcuts_hash[row[direction]] || row[direction] #expand shortcuts
- case want
- when '', 'x'
- output_row[direction] = result[direction][:status] ? result[direction][:status].to_s : ''
- when /^\d+s/
- output_row[direction] = result[direction][:time] ? "#{result[direction][:time]}s" : ''
- when /^\d+ km\/h/
- output_row[direction] = result[direction][:speed] ? "#{result[direction][:speed]} km/h" : ''
- else
- raise "*** Unknown expectation format: #{want}"
- end
-
- if FuzzyMatch.match output_row[direction], want
- output_row[direction] = row[direction]
- end
- end
-
- if output_row != row
- log_fail row,output_row,result
- end
- actual << output_row
- end
- end
- table.diff! actual
-end
diff --git a/features/step_definitions/routing.js b/features/step_definitions/routing.js
new file mode 100644
index 0000000..d48573e
--- /dev/null
+++ b/features/step_definitions/routing.js
@@ -0,0 +1,16 @@
+var d3 = require('d3-queue');
+
+module.exports = function () {
+ this.When(/^I route I should get$/, this.WhenIRouteIShouldGet);
+
+ // This is used to route 100 times; timeout for entire step is therefore set to 100 * STRESS_TIMEOUT
+ this.When(/^I route (\d+) times I should get$/, { timeout: 30000 }, (n, table, callback) => {
+ var q = d3.queue(1);
+
+ for (var i=0; i<n; i++) {
+ q.defer(this.WhenIRouteIShouldGet, table);
+ }
+
+ q.awaitAll(callback);
+ });
+};
diff --git a/features/step_definitions/routing.rb b/features/step_definitions/routing.rb
deleted file mode 100644
index f1e9590..0000000
--- a/features/step_definitions/routing.rb
+++ /dev/null
@@ -1,165 +0,0 @@
-When /^I route I should get$/ do |table|
- reprocess
- actual = []
- OSRMLoader.load(self,"#{prepared_file}.osrm") do
- table.hashes.each_with_index do |row,ri|
- if row['request']
- got = {'request' => row['request'] }
- response = request_url row['request']
- else
- default_params = @query_params
- user_params = []
- got = {}
- row.each_pair do |k,v|
- if k =~ /param:(.*)/
- if v=='(nil)'
- user_params << [$1, nil]
- elsif v!=nil
- user_params << [$1, v]
- end
- got[k]=v
- end
- end
- params = overwrite_params default_params, user_params
- waypoints = []
- bearings = []
- if row['bearings']
- got['bearings'] = row['bearings']
- bearings = row['bearings'].split(' ').compact
- end
- if row['from'] and row['to']
- node = find_node_by_name(row['from'])
- raise "*** unknown from-node '#{row['from']}" unless node
- waypoints << node
-
- node = find_node_by_name(row['to'])
- raise "*** unknown to-node '#{row['to']}" unless node
- waypoints << node
-
- got = got.merge({'from' => row['from'], 'to' => row['to'] })
- response = request_route waypoints, bearings, params
- elsif row['waypoints']
- row['waypoints'].split(',').each do |n|
- node = find_node_by_name(n.strip)
- raise "*** unknown waypoint node '#{n.strip}" unless node
- waypoints << node
- end
- got = got.merge({'waypoints' => row['waypoints'] })
- response = request_route waypoints, bearings, params
- else
- raise "*** no waypoints"
- end
- end
-
- if response.body.empty? == false
- json = JSON.parse response.body
- end
-
- if response.body.empty? == false
- if json['status'] == 200
- instructions = way_list json['route_instructions']
- bearings = bearing_list json['route_instructions']
- compasses = compass_list json['route_instructions']
- turns = turn_list json['route_instructions']
- modes = mode_list json['route_instructions']
- times = time_list json['route_instructions']
- distances = distance_list json['route_instructions']
- end
- end
-
- if table.headers.include? 'status'
- got['status'] = json['status'].to_s
- end
- if table.headers.include? 'message'
- got['message'] = json['status_message']
- end
- if table.headers.include? '#' # comment column
- got['#'] = row['#'] # copy value so it always match
- end
-
- if table.headers.include? 'start'
- got['start'] = instructions ? json['route_summary']['start_point'] : nil
- end
- if table.headers.include? 'end'
- got['end'] = instructions ? json['route_summary']['end_point'] : nil
- end
- if table.headers.include? 'geometry'
- got['geometry'] = json['route_geometry']
- end
- if table.headers.include? 'route'
- got['route'] = (instructions || '').strip
- if table.headers.include?('alternative')
- got['alternative'] =
- if json['found_alternative']
- way_list json['alternative_instructions'].first
- else
- ""
- end
- end
- if table.headers.include?('distance')
- if row['distance']!=''
- raise "*** Distance must be specied in meters. (ex: 250m)" unless row['distance'] =~ /\d+m/
- end
- got['distance'] = instructions ? "#{json['route_summary']['total_distance'].to_s}m" : ''
- end
- if table.headers.include?('time')
- raise "*** Time must be specied in seconds. (ex: 60s)" unless row['time'] =~ /\d+s/
- got['time'] = instructions ? "#{json['route_summary']['total_time'].to_s}s" : ''
- end
- if table.headers.include?('speed')
- if row['speed'] != '' && instructions
- raise "*** Speed must be specied in km/h. (ex: 50 km/h)" unless row['speed'] =~ /\d+ km\/h/
- time = json['route_summary']['total_time']
- distance = json['route_summary']['total_distance']
- speed = time>0 ? (3.6*distance/time).round : nil
- got['speed'] = "#{speed} km/h"
- else
- got['speed'] = ''
- end
- end
- if table.headers.include? 'bearing'
- got['bearing'] = instructions ? bearings : ''
- end
- if table.headers.include? 'compass'
- got['compass'] = instructions ? compasses : ''
- end
- if table.headers.include? 'turns'
- got['turns'] = instructions ? turns : ''
- end
- if table.headers.include? 'modes'
- got['modes'] = instructions ? modes : ''
- end
- if table.headers.include? 'times'
- got['times'] = instructions ? times : ''
- end
- if table.headers.include? 'distances'
- got['distances'] = instructions ? distances : ''
- end
- end
-
- ok = true
- row.keys.each do |key|
- if FuzzyMatch.match got[key], row[key]
- got[key] = row[key]
- else
- ok = false
- end
- end
-
- unless ok
- log_fail row,got, { 'route' => {:query => @query, :response => response} }
- end
-
- actual << got
- end
- end
- table.diff! actual
-end
-
-When /^I route (\d+) times I should get$/ do |n,table|
- ok = true
- n.to_i.times do
- ok = false unless step "I route I should get", table
- end
- ok
-end
diff --git a/features/step_definitions/timestamp.js b/features/step_definitions/timestamp.js
new file mode 100644
index 0000000..55af74b
--- /dev/null
+++ b/features/step_definitions/timestamp.js
@@ -0,0 +1,13 @@
+var assert = require('assert');
+
+module.exports = function () {
+ this.Then(/^I should get a valid timestamp/, (callback) => {
+ this.ShouldGetAResponse();
+ this.ShouldBeValidJSON((err) => {
+ this.ShouldBeWellFormed();
+ assert.equal(typeof this.json.timestamp, 'string');
+ assert.equal(this.json.timestamp, '2000-01-01T00:00:00Z');
+ callback(err);
+ });
+ });
+};
diff --git a/features/step_definitions/timestamp.rb b/features/step_definitions/timestamp.rb
deleted file mode 100644
index df45615..0000000
--- a/features/step_definitions/timestamp.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-Then /^I should get a valid timestamp/ do
- step "I should get a response"
- step "response should be valid JSON"
- step "response should be well-formed"
- expect(@json['timestamp'].class).to eq(String)
- expect(@json['timestamp']).to eq("2000-01-01T00:00:00Z")
-end
diff --git a/features/step_definitions/trip.js b/features/step_definitions/trip.js
new file mode 100644
index 0000000..b1727da
--- /dev/null
+++ b/features/step_definitions/trip.js
@@ -0,0 +1,141 @@
+var util = require('util');
+
+module.exports = function () {
+ this.When(/^I plan a trip I should get$/, (table, callback) => {
+ var got;
+
+ this.reprocessAndLoadData(() => {
+ var testRow = (row, ri, cb) => {
+ var afterRequest = (err, res) => {
+ if (err) return cb(err);
+ var headers = new Set(table.raw()[0]);
+
+ for (var k in row) {
+ var match = k.match(/param:(.*)/);
+ if (match) {
+ if (row[k] === '(nil)') {
+ params[match[1]] = null;
+ } else if (row[k]) {
+ params[match[1]] = [row[k]];
+ }
+
+ got[k] = row[k];
+ }
+ }
+
+ var json;
+ if (res.body.length) {
+ json = JSON.parse(res.body);
+ }
+
+ if (headers.has('status')) {
+ got.status = json.status.toString();
+ }
+
+ if (headers.has('message')) {
+ got.message = json.status_message;
+ }
+
+ if (headers.has('#')) {
+ // comment column
+ got['#'] = row['#'];
+ }
+
+ var subTrips;
+ if (res.statusCode === 200) {
+ if (headers.has('trips')) {
+ subTrips = json.trips.filter(t => !!t).map(t => t.legs).map(tl => Array.prototype.concat.apply([], tl.map((sl, i) => {
+ var toAdd = [];
+ if (i === 0) toAdd.push(sl.steps[0].maneuver.location);
+ toAdd.push(sl.steps[sl.steps.length-1].maneuver.location);
+ return toAdd;
+ })));
+ }
+ }
+
+ var ok = true,
+ encodedResult = '',
+ extendedTarget = '';
+
+ row.trips.split(',').forEach((sub, si) => {
+ if (si >= subTrips.length) {
+ ok = false;
+ } else {
+ ok = false;
+ // TODO: Check all rotations of the round trip
+ for (var ni=0; ni<sub.length; ni++) {
+ var node = this.findNodeByName(sub[ni]),
+ outNode = subTrips[si][ni];
+ if (this.FuzzyMatch.matchLocation(outNode, node)) {
+ encodedResult += sub[ni];
+ extendedTarget += sub[ni];
+ ok = true;
+ } else {
+ encodedResult += util.format('? [%s,%s]', outNode[0], outNode[1]);
+ extendedTarget += util.format('%s [%d,%d]', sub[ni], node.lat, node.lon);
+ }
+ }
+ }
+ });
+
+ if (ok) {
+ got.trips = row.trips;
+ got.via_points = row.via_points;
+ } else {
+ got.trips = encodedResult;
+ got.trips = extendedTarget;
+ this.logFail(row, got, { trip: { query: this.query, response: res }});
+ }
+
+ ok = true;
+
+ for (var key in row) {
+ if (this.FuzzyMatch.match(got[key], row[key])) {
+ got[key] = row[key];
+ } else {
+ ok = false;
+ }
+ }
+
+ if (!ok) {
+ this.logFail(row, got, { trip: { query: this.query, response: res }});
+ }
+
+ cb(null, got);
+ };
+
+ if (row.request) {
+ got.request = row.request;
+ this.requestUrl(row.request, afterRequest);
+ } else {
+ var params = this.queryParams,
+ waypoints = [];
+ if (row.from && row.to) {
+ var fromNode = this.findNodeByName(row.from);
+ if (!fromNode) throw new Error(util.format('*** unknown from-node "%s"', row.from));
+ waypoints.push(fromNode);
+
+ var toNode = this.findNodeByName(row.to);
+ if (!toNode) throw new Error(util.format('*** unknown to-node "%s"', row.to));
+ waypoints.push(toNode);
+
+ got = { from: row.from, to: row.to };
+ this.requestTrip(waypoints, params, afterRequest);
+ } else if (row.waypoints) {
+ row.waypoints.split(',').forEach((n) => {
+ var node = this.findNodeByName(n);
+ if (!node) throw new Error(util.format('*** unknown waypoint node "%s"', n.trim()));
+ waypoints.push(node);
+ });
+ got = { waypoints: row.waypoints };
+ this.requestTrip(waypoints, params, afterRequest);
+ } else {
+ throw new Error('*** no waypoints');
+ }
+ }
+ };
+
+ this.processRowsAndDiff(table, testRow, callback);
+ });
+ });
+};
diff --git a/features/step_definitions/trip.rb b/features/step_definitions/trip.rb
deleted file mode 100644
index ecb4c77..0000000
--- a/features/step_definitions/trip.rb
+++ /dev/null
@@ -1,121 +0,0 @@
-When /^I plan a trip I should get$/ do |table|
- reprocess
- actual = []
- OSRMLoader.load(self,"#{prepared_file}.osrm") do
- table.hashes.each_with_index do |row,ri|
- if row['request']
- got = {'request' => row['request'] }
- response = request_url row['request']
- else
- params = @query_params
- waypoints = []
- if row['from'] and row['to']
- node = find_node_by_name(row['from'])
- raise "*** unknown from-node '#{row['from']}" unless node
- waypoints << node
-
- node = find_node_by_name(row['to'])
- raise "*** unknown to-node '#{row['to']}" unless node
- waypoints << node
-
- got = {'from' => row['from'], 'to' => row['to'] }
- response = request_trip waypoints, params
- elsif row['waypoints']
- row['waypoints'].split(',').each do |n|
- node = find_node_by_name(n.strip)
- raise "*** unknown waypoint node '#{n.strip}" unless node
- waypoints << node
- end
- got = {'waypoints' => row['waypoints'] }
- response = request_trip waypoints, params
- else
- raise "*** no waypoints"
- end
- end
-
- row.each_pair do |k,v|
- if k =~ /param:(.*)/
- if v=='(nil)'
- params[$1]=nil
- elsif v!=nil
- params[$1]=[v]
- end
- got[k]=v
- end
- end
-
- if response.body.empty? == false
- json = JSON.parse response.body
- end
-
- if table.headers.include? 'status'
- got['status'] = json['status'].to_s
- end
- if table.headers.include? 'message'
- got['message'] = json['status_message']
- end
- if table.headers.include? '#' # comment column
- got['#'] = row['#'] # copy value so it always match
- end
-
- if response.code == "200"
- if table.headers.include? 'trips'
- sub_trips = json['trips'].compact.map { |sub| sub['via_points']}
- end
- end
-
- ######################
- ok = true
- encoded_result = ""
- extended_target = ""
- row['trips'].split(',').each_with_index do |sub, sub_idx|
- if sub_idx >= sub_trips.length
- ok = false
- break
- end
-
- ok = false;
- #TODO: Check all rotations of the round trip
- sub.length.times do |node_idx|
- node = find_node_by_name(sub[node_idx])
- out_node = sub_trips[sub_idx][node_idx]
- if FuzzyMatch.match_location out_node, node
- encoded_result += sub[node_idx]
- extended_target += sub[node_idx]
- ok = true
- else
- encoded_result += "? [#{out_node[0]},#{out_node[1]}]"
- extended_target += "#{sub[node_idx]} [#{node.lat},#{node.lon}]"
- end
- end
- end
-
- if ok
- got['trips'] = row['trips']
- got['via_points'] = row['via_points']
- else
- got['trips'] = encoded_result
- row['trips'] = extended_target
- log_fail row,got, { 'trip' => {:query => @query, :response => response} }
- end
-
-
- ok = true
- row.keys.each do |key|
- if FuzzyMatch.match got[key], row[key]
- got[key] = row[key]
- else
- ok = false
- end
- end
-
- unless ok
- log_fail row,got, { 'trip' => {:query => @query, :response => response} }
- end
-
- actual << got
- end
- end
- table.diff! actual
-end
-
diff --git a/features/support/build_osm.js b/features/support/build_osm.js
new file mode 100644
index 0000000..7fe6874
--- /dev/null
+++ b/features/support/build_osm.js
@@ -0,0 +1,165 @@
+'use strict';
+
+var builder = require('xmlbuilder');
+
+var ensureDecimal = (i) => {
+ if (parseInt(i) === i) return i.toFixed(1);
+ else return i;
+};
+
+class DB {
+ constructor () {
+ this.nodes = new Array();
+ this.ways = new Array();
+ this.relations = new Array();
+ }
+
+ addNode (node) {
+ this.nodes.push(node);
+ }
+
+ addWay (way) {
+ this.ways.push(way);
+ }
+
+ addRelation (relation) {
+ this.relations.push(relation);
+ }
+
+ clear () {
+ this.nodes = [];
+ this.ways = [];
+ this.relations = [];
+ }
+
+ toXML (callback) {
+ var xml = builder.create('osm', {'encoding':'UTF-8'});
+ xml.att('generator', 'osrm-test')
+ .att('version', '0.6');
+
+ this.nodes.forEach((n) => {
+ var node = xml.ele('node', {
+ id: n.id,
+ version: 1,
+ uid: n.OSM_UID,
+ user: n.OSM_USER,
+ timestamp: n.OSM_TIMESTAMP,
+ lon: ensureDecimal(n.lon),
+ lat: ensureDecimal(n.lat)
+ });
+
+ for (var k in n.tags) {
+ node.ele('tag')
+ .att('k', k)
+ .att('v', n.tags[k]);
+ }
+ });
+
+ this.ways.forEach((w) => {
+ var way = xml.ele('way', {
+ id: w.id,
+ version: 1,
+ uid: w.OSM_UID,
+ user: w.OSM_USER,
+ timestamp: w.OSM_TIMESTAMP
+ });
+
+ w.nodes.forEach((k) => {
+ way.ele('nd')
+ .att('ref', k.id);
+ });
+
+ for (var k in w.tags) {
+ way.ele('tag')
+ .att('k', k)
+ .att('v', w.tags[k]);
+ }
+ });
+
+ this.relations.forEach((r) => {
+ var relation = xml.ele('relation', {
+ id: r.id,
+ user: r.OSM_USER,
+ timestamp: r.OSM_TIMESTAMP,
+ uid: r.OSM_UID
+ });
+
+ r.members.forEach((m) => {
+ relation.ele('member', {
+ type: m.type,
+ ref: m.id,
+ role: m.role
+ });
+ });
+
+ for (var k in r.tags) {
+ relation.ele('tag')
+ .att('k', k)
+ .att('v', r.tags[k]);
+ }
+ });
+
+ callback(xml.end({ pretty: true, indent: ' ' }));
+ }
+}
+
+class Node {
+ constructor (id, OSM_USER, OSM_TIMESTAMP, OSM_UID, lon, lat, tags) {
+ this.id = id;
+ this.OSM_USER = OSM_USER;
+ this.OSM_TIMESTAMP = OSM_TIMESTAMP;
+ this.OSM_UID = OSM_UID;
+ this.lon = lon;
+ this.lat = lat;
+ this.tags = tags;
+ }
+
+ addTag (k, v) {
+ this.tags[k] = v;
+ }
+}
+
+class Way {
+ constructor (id, OSM_USER, OSM_TIMESTAMP, OSM_UID) {
+ this.id = id;
+ this.OSM_USER = OSM_USER;
+ this.OSM_TIMESTAMP = OSM_TIMESTAMP;
+ this.OSM_UID = OSM_UID;
+ this.tags = {};
+ this.nodes = [];
+ }
+
+ addNode (node) {
+ this.nodes.push(node);
+ }
+
+ setTags (tags) {
+ this.tags = tags;
+ }
+}
+
+class Relation {
+ constructor (id, OSM_USER, OSM_TIMESTAMP, OSM_UID) {
+ this.id = id;
+ this.OSM_USER = OSM_USER;
+ this.OSM_TIMESTAMP = OSM_TIMESTAMP;
+ this.OSM_UID = OSM_UID;
+ this.members = [];
+ this.tags = {};
+ }
+
+ addMember (memberType, id, role) {
+ this.members.push({type: memberType, id: id, role: role});
+ }
+
+ addTag (k, v) {
+ this.tags[k] = v;
+ }
+}
+
+module.exports = {
+ DB: DB,
+ Node: Node,
+ Way: Way,
+ Relation: Relation
+};
diff --git a/features/support/config.js b/features/support/config.js
new file mode 100644
index 0000000..cae7398
--- /dev/null
+++ b/features/support/config.js
@@ -0,0 +1,115 @@
+var fs = require('fs');
+var path = require('path');
+var util = require('util');
+var d3 = require('d3-queue');
+var OSM = require('./build_osm');
+var classes = require('./data_classes');
+
+module.exports = function () {
+ this.initializeOptions = (callback) => {
+ this.profile = this.profile || this.DEFAULT_SPEEDPROFILE;
+
+ this.OSMDB = this.OSMDB || new OSM.DB();
+
+ this.nameNodeHash = this.nameNodeHash || {};
+
+ this.locationHash = this.locationHash || {};
+
+ this.nameWayHash = this.nameWayHash || {};
+
+ this.osmData = new classes.osmData(this);
+
+ this.STRESS_TIMEOUT = 300;
+
+ this.OSRMLoader = this._OSRMLoader();
+
+ this.PREPROCESS_LOG_FILE = path.resolve(this.TEST_FOLDER, 'preprocessing.log');
+
+ this.LOG_FILE = path.resolve(this.TEST_FOLDER, 'fail.log');
+
+ this.HOST = 'http://127.0.0.1:' + this.OSRM_PORT;
+
+ this.DESTINATION_REACHED = 15; // OSRM instruction code
+
+ this.shortcutsHash = this.shortcutsHash || {};
+
+ var hashLuaLib = (cb) => {
+ fs.readdir(path.normalize(this.PROFILES_PATH + '/lib/'), (err, files) => {
+ if (err) cb(err);
+ var luaFiles = files.filter(f => !!f.match(/\.lua$/)).map(f => path.normalize(this.PROFILES_PATH + '/lib/' + f));
+ this.hashOfFiles(luaFiles, hash => {
+ this.luaLibHash = hash;
+ cb();
+ });
+ });
+ };
+
+ var hashProfile = (cb) => {
+ this.hashProfile((hash) => {
+ this.profileHash = hash;
+ cb();
+ });
+ };
+
+ var hashExtract = (cb) => {
+ this.hashOfFiles(util.format('%s/osrm-extract%s', this.BIN_PATH, this.EXE), (hash) => {
+ this.binExtractHash = hash;
+ cb();
+ });
+ };
+
+ var hashContract = (cb) => {
+ this.hashOfFiles(util.format('%s/osrm-contract%s', this.BIN_PATH, this.EXE), (hash) => {
+ this.binContractHash = hash;
+ this.fingerprintContract = this.hashString(this.binContractHash);
+ cb();
+ });
+ };
+
+ var hashRouted = (cb) => {
+ this.hashOfFiles(util.format('%s/osrm-routed%s', this.BIN_PATH, this.EXE), (hash) => {
+ this.binRoutedHash = hash;
+ this.fingerprintRoute = this.hashString(this.binRoutedHash);
+ cb();
+ });
+ };
+
+ d3.queue()
+ .defer(hashLuaLib)
+ .defer(hashProfile)
+ .defer(hashExtract)
+ .defer(hashContract)
+ .defer(hashRouted)
+ .awaitAll(() => {
+ this.fingerprintExtract = this.hashString([this.profileHash, this.luaLibHash, this.binExtractHash].join('-'));
+ this.AfterConfiguration(() => {
+ callback();
+ });
+ });
+ };
+
+ this.setProfileBasedHashes = () => {
+ this.fingerprintExtract = this.hashString([this.profileHash, this.luaLibHash, this.binExtractHash].join('-'));
+ this.fingerprintContract = this.hashString(this.binContractHash);
+ };
+
+ this.setProfile = (profile, cb) => {
+ var lastProfile = this.profile;
+ if (profile !== lastProfile) {
+ this.profile = profile;
+ this.hashProfile((hash) => {
+ this.profileHash = hash;
+ this.setProfileBasedHashes();
+ cb();
+ });
+ } else cb();
+ };
+
+ this.setExtractArgs = (args) => {
+ this.extractArgs = args;
+ };
+
+ this.setContractArgs = (args) => {
+ this.contractArgs = args;
+ };
+};
diff --git a/features/support/config.rb b/features/support/config.rb
deleted file mode 100644
index 434b4ec..0000000
--- a/features/support/config.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-def profile
- @profile ||= reset_profile
-end
-
-def reset_profile
- @profile = nil
- set_profile DEFAULT_SPEEDPROFILE
-end
-
-def set_profile profile
- @profile = profile
-end
-
-def set_extract_args args
- @extract_args = args
-end
diff --git a/features/support/data.js b/features/support/data.js
new file mode 100644
index 0000000..29e5170
--- /dev/null
+++ b/features/support/data.js
@@ -0,0 +1,340 @@
+var fs = require('fs');
+var path = require('path');
+var util = require('util');
+var exec = require('child_process').exec;
+var d3 = require('d3-queue');
+
+var OSM = require('./build_osm');
+var classes = require('./data_classes');
+
+module.exports = function () {
+ this.setGridSize = (meters) => {
+ // the constant is calculated (with BigDecimal as: 1.0/(DEG_TO_RAD*EARTH_RADIUS_IN_METERS
+ // see ApproximateDistance() in ExtractorStructs.h
+ // it's only accurate when measuring along the equator, or going exactly north-south
+ this.zoom = parseFloat(meters) * 0.8990679362704610899694577444566908445396483347536032203503E-5;
+ };
+
+ this.setOrigin = (origin) => {
+ this.origin = origin;
+ };
+
+ this.buildWaysFromTable = (table, callback) => {
+ // add one unconnected way for each row
+ var buildRow = (row, ri, cb) => {
+ // comments ported directly from ruby suite:
+ // NOTE: currently osrm crashes when processing an isolated oneway with just 2 nodes, so we use 4 edges
+ // this is related to the fact that a oneway dead-end street doesn't make a lot of sense
+
+ // if we stack ways on different x coordinates, routability tests get messed up, because osrm might pick a neighboring way if the one test can't be used.
+ // instead we place all lines as a string on the same y coordinate. this prevents using neighboring ways.
+
+ // add some nodes
+
+ var makeFakeNode = (namePrefix, offset) => {
+ return new OSM.Node(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP,
+ this.OSM_UID, this.origin[0]+(offset + this.WAY_SPACING * ri) * this.zoom,
+ this.origin[1], {name: util.format('%s%d', namePrefix, ri)});
+ };
+
+ var nodes = ['a','b','c','d','e'].map((l, i) => makeFakeNode(l, i));
+
+ nodes.forEach(node => { this.OSMDB.addNode(node); });
+
+ // ...with a way between them
+ var way = new OSM.Way(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID);
+
+ nodes.forEach(node => { way.addNode(node); });
+
+ // remove tags that describe expected test result, reject empty tags
+ var tags = {};
+ for (var rkey in row) {
+ if (!rkey.match(/^forw\b/) &&
+ !rkey.match(/^backw\b/) &&
+ !rkey.match(/^bothw\b/) &&
+ row[rkey].length)
+ tags[rkey] = row[rkey];
+ }
+
+ var wayTags = { highway: 'primary' },
+ nodeTags = {};
+
+ for (var key in tags) {
+ var nodeMatch = key.match(/node\/(.*)/);
+ if (nodeMatch) {
+ if (tags[key] === '(nil)') {
+ delete nodeTags[key];
+ } else {
+ nodeTags[nodeMatch[1]] = tags[key];
+ }
+ } else {
+ if (tags[key] === '(nil)') {
+ delete wayTags[key];
+ } else {
+ wayTags[key] = tags[key];
+ }
+ }
+ }
+
+ wayTags.name = util.format('w%d', ri);
+ way.setTags(wayTags);
+ this.OSMDB.addWay(way);
+
+ for (var k in nodeTags) {
+ nodes[2].addTag(k, nodeTags[k]);
+ }
+ cb();
+ };
+
+ var q = d3.queue();
+ table.hashes().forEach((row, ri) => {
+ q.defer(buildRow, row, ri);
+ });
+
+ q.awaitAll(callback);
+ };
+
+ this.ensureDecimal = (i) => {
+ if (parseInt(i) === i) return i.toFixed(1);
+ else return i;
+ };
+
+ this.tableCoordToLonLat = (ci, ri) => {
+ return [this.origin[0] + ci * this.zoom, this.origin[1] - ri * this.zoom].map(this.ensureDecimal);
+ };
+
+ this.addOSMNode = (name, lon, lat, id) => {
+ id = id || this.makeOSMId();
+ var node = new OSM.Node(id, this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID, lon, lat, {name: name});
+ this.OSMDB.addNode(node);
+ this.nameNodeHash[name] = node;
+ };
+
+ this.addLocation = (name, lon, lat) => {
+ this.locationHash[name] = new classes.Location(lon, lat);
+ };
+
+ this.findNodeByName = (s) => {
+ if (s.length !== 1) throw new Error(util.format('*** invalid node name "%s", must be single characters', s));
+ if (!s.match(/[a-z0-9]/)) throw new Error(util.format('*** invalid node name "%s", must be alphanumeric', s));
+
+ var fromNode;
+ if (s.match(/[a-z]/)) {
+ fromNode = this.nameNodeHash[s.toString()];
+ } else {
+ fromNode = this.locationHash[s.toString()];
+ }
+
+ return fromNode;
+ };
+
+ this.findWayByName = (s) => {
+ return this.nameWayHash[s.toString()] || this.nameWayHash[s.toString().split('').reverse().join('')];
+ };
+
+ this.resetData = () => {
+ this.resetOSM();
+ };
+
+ this.makeOSMId = () => {
+ this.osmID = this.osmID + 1;
+ return this.osmID;
+ };
+
+ this.resetOSM = () => {
+ this.OSMDB.clear();
+ this.osmData.reset();
+ this.nameNodeHash = {};
+ this.locationHash = {};
+ this.nameWayHash = {};
+ this.osmID = 0;
+ };
+
+ this.writeOSM = (callback) => {
+ fs.exists(this.DATA_FOLDER, (exists) => {
+ var mkDirFn = exists ? (cb) => { cb(); } : fs.mkdir.bind(fs.mkdir, this.DATA_FOLDER);
+ mkDirFn((err) => {
+ if (err) return callback(err);
+ var osmPath = path.resolve(this.DATA_FOLDER, util.format('%s.osm', this.osmData.osmFile));
+ fs.exists(osmPath, (exists) => {
+ if (!exists) fs.writeFile(osmPath, this.osmData.str, callback);
+ else callback();
+ });
+ });
+ });
+ };
+
+ this.isExtracted = (callback) => {
+ fs.exists(util.format('%s.osrm', this.osmData.extractedFile), (core) => {
+ if (!core) return callback(false);
+ fs.exists(util.format('%s.osrm.names', this.osmData.extractedFile), (names) => {
+ if (!names) return callback(false);
+ fs.exists(util.format('%s.osrm.restrictions', this.osmData.extractedFile), (restrictions) => {
+ return callback(restrictions);
+ });
+ });
+ });
+ };
+
+ this.isContracted = (callback) => {
+ fs.exists(util.format('%s.osrm.hsgr', this.osmData.contractedFile), callback);
+ };
+
+ this.writeTimestamp = (callback) => {
+ fs.writeFile(util.format('%s.osrm.timestamp', this.osmData.contractedFile), this.OSM_TIMESTAMP, callback);
+ };
+
+ this.writeInputData = (callback) => {
+ this.writeOSM((err) => {
+ if (err) return callback(err);
+ this.writeTimestamp(callback);
+ });
+ };
+
+ this.extractData = (callback) => {
+ this.logPreprocessInfo();
+ this.log(util.format('== Extracting %s.osm...', this.osmData.osmFile), 'preprocess');
+ var cmd = util.format('%s%s/osrm-extract %s.osm %s --profile %s/%s.lua >>%s 2>&1',
+ this.LOAD_LIBRARIES, this.BIN_PATH, this.osmData.osmFile, this.extractArgs || '', this.PROFILES_PATH, this.profile, this.PREPROCESS_LOG_FILE);
+ this.log(cmd);
+ process.chdir(this.TEST_FOLDER);
+ exec(cmd, (err) => {
+ if (err) {
+ this.log(util.format('*** Exited with code %d', err.code), 'preprocess');
+ process.chdir('../');
+ return callback(this.ExtractError(err.code, util.format('osrm-extract exited with code %d', err.code)));
+ }
+
+ var q = d3.queue();
+
+ var rename = (file, cb) => {
+ this.log(util.format('Renaming %s.%s to %s.%s', this.osmData.osmFile, file, this.osmData.extractedFile, file), 'preprocess');
+ fs.rename([this.osmData.osmFile, file].join('.'), [this.osmData.extractedFile, file].join('.'), (err) => {
+ if (err) return cb(this.FileError(null, 'failed to rename data file after extracting'));
+ cb();
+ });
+ };
+
+ var renameIfExists = (file, cb) => {
+ fs.stat([this.osmData.osmFile, file].join('.'), (doesNotExistErr, exists) => {
+ if (exists) rename(file, cb);
+ else cb();
+ });
+ };
+
+ ['osrm','osrm.names','osrm.restrictions','osrm.ebg','osrm.enw','osrm.edges','osrm.fileIndex','osrm.geometry','osrm.nodes','osrm.ramIndex','osrm.properties'].forEach(file => {
+ q.defer(rename, file);
+ });
+
+ ['osrm.edge_segment_lookup','osrm.edge_penalties'].forEach(file => {
+ q.defer(renameIfExists, file);
+ });
+
+ q.awaitAll((err) => {
+ this.log('Finished extracting ' + this.osmData.extractedFile, 'preprocess');
+ process.chdir('../');
+ callback(err);
+ });
+ });
+ };
+
+ this.contractData = (callback) => {
+ this.logPreprocessInfo();
+ this.log(util.format('== Contracting %s.osm...', this.osmData.extractedFile), 'preprocess');
+ var cmd = util.format('%s%s/osrm-contract %s %s.osrm >>%s 2>&1',
+ this.LOAD_LIBRARIES, this.BIN_PATH, this.contractArgs || '', this.osmData.extractedFile, this.PREPROCESS_LOG_FILE);
+ this.log(cmd);
+ process.chdir(this.TEST_FOLDER);
+ exec(cmd, (err) => {
+ if (err) {
+ this.log(util.format('*** Exited with code %d', err.code), 'preprocess');
+ process.chdir('../');
+ return callback(this.ContractError(err.code, util.format('osrm-contract exited with code %d', err.code)));
+ }
+
+ var rename = (file, cb) => {
+ this.log(util.format('Renaming %s.%s to %s.%s', this.osmData.extractedFile, file, this.osmData.contractedFile, file), 'preprocess');
+ fs.rename([this.osmData.extractedFile, file].join('.'), [this.osmData.contractedFile, file].join('.'), (err) => {
+ if (err) return cb(this.FileError(null, 'failed to rename data file after contracting.'));
+ cb();
+ });
+ };
+
+ var copy = (file, cb) => {
+ this.log(util.format('Copying %s.%s to %s.%s', this.osmData.extractedFile, file, this.osmData.contractedFile, file), 'preprocess');
+ fs.createReadStream([this.osmData.extractedFile, file].join('.'))
+ .pipe(fs.createWriteStream([this.osmData.contractedFile, file].join('.'))
+ .on('finish', cb)
+ )
+ .on('error', () => {
+ return cb(this.FileError(null, 'failed to copy data after contracting.'));
+ });
+ };
+
+ var q = d3.queue();
+
+ ['osrm.hsgr','osrm.fileIndex','osrm.geometry','osrm.nodes','osrm.ramIndex','osrm.core','osrm.edges','osrm.datasource_indexes','osrm.datasource_names','osrm.level'].forEach((file) => {
+ q.defer(rename, file);
+ });
+
+ ['osrm.names','osrm.restrictions','osrm.properties','osrm'].forEach((file) => {
+ q.defer(copy, file);
+ });
+
+ q.awaitAll((err) => {
+ this.log('Finished contracting ' + this.osmData.contractedFile, 'preprocess');
+ process.chdir('../');
+ callback(err);
+ });
+ });
+ };
+
+ var noop = (cb) => cb();
+
+ this.reprocess = (callback) => {
+ this.writeAndExtract((e) => {
+ if (e) return callback(e);
+ this.isContracted((isContracted) => {
+ var contractFn = isContracted ? noop : this.contractData;
+ if (isContracted) this.log('Already contracted ' + this.osmData.contractedFile, 'preprocess');
+ contractFn((e) => {
+ if (e) return callback(e);
+ this.logPreprocessDone();
+ callback();
+ });
+ });
+ });
+ };
+
+ this.writeAndExtract = (callback) => {
+ this.osmData.populate(() => {
+ this.writeInputData((e) => {
+ if (e) return callback(e);
+ this.isExtracted((isExtracted) => {
+ var extractFn = isExtracted ? noop : this.extractData;
+ if (isExtracted) this.log('Already extracted ' + this.osmData.extractedFile, 'preprocess');
+ extractFn((e) => {
+ callback(e);
+ });
+ });
+ });
+ });
+ };
+
+ this.reprocessAndLoadData = (callback) => {
+ this.reprocess(() => {
+ this.OSRMLoader.load(util.format('%s.osrm', this.osmData.contractedFile), callback);
+ });
+ };
+
+ this.processRowsAndDiff = (table, fn, callback) => {
+ var q = d3.queue(1);
+
+ table.hashes().forEach((row, i) => { q.defer(fn, row, i); });
+
+ q.awaitAll((err, actual) => {
+ if (err) return callback(err);
+ this.diffTables(table, actual, {}, callback);
+ });
+ };
+};
diff --git a/features/support/data.rb b/features/support/data.rb
deleted file mode 100644
index 62ed7d3..0000000
--- a/features/support/data.rb
+++ /dev/null
@@ -1,325 +0,0 @@
-require 'OSM/objects' #osmlib gem
-require 'OSM/Database'
-require 'builder'
-require 'fileutils'
-
-class Location
- attr_accessor :lon,:lat
-
- def initialize lon,lat
- @lat = lat
- @lon = lon
- end
-end
-
-
-def set_input_format format
- raise '*** Input format must be eiter "osm" or "pbf"' unless ['pbf','osm'].include? format.to_s
- @input_format = format.to_s
-end
-
-def input_format
- @input_format || DEFAULT_INPUT_FORMAT
-end
-
-def sanitized_scenario_title
- @sanitized_scenario_title ||= @scenario_title.to_s.gsub /[^0-9A-Za-z.\-]/, '_'
-end
-
-def set_grid_size meters
- #the constant is calculated (with BigDecimal as: 1.0/(DEG_TO_RAD*EARTH_RADIUS_IN_METERS
- #see ApproximateDistance() in ExtractorStructs.h
- #it's only accurate when measuring along the equator, or going exactly north-south
- @zoom = meters.to_f*0.8990679362704610899694577444566908445396483347536032203503E-5
-end
-
-def set_origin origin
- @origin = origin
-end
-
-def build_ways_from_table table
- #add one unconnected way for each row
- table.hashes.each_with_index do |row,ri|
- #NOTE:
- #currently osrm crashes when processing an isolated oneway with just 2 nodes, so we use 4 edges
- #this is relatated to the fact that a oneway dead-end street doesn't make a lot of sense
-
- #if we stack ways on different x coordinates, routability tests get messed up, because osrm might pick a neighboring way if the one test can't be used.
- #instead we place all lines as a string on the same y coordinate. this prevents using neightboring ways.
-
- #a few nodes...
- node1 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(0+WAY_SPACING*ri)*@zoom, @origin[1]
- node2 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(1+WAY_SPACING*ri)*@zoom, @origin[1]
- node3 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(2+WAY_SPACING*ri)*@zoom, @origin[1]
- node4 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(3+WAY_SPACING*ri)*@zoom, @origin[1]
- node5 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(4+WAY_SPACING*ri)*@zoom, @origin[1]
- node1.uid = OSM_UID
- node2.uid = OSM_UID
- node3.uid = OSM_UID
- node4.uid = OSM_UID
- node5.uid = OSM_UID
- node1 << { :name => "a#{ri}" }
- node2 << { :name => "b#{ri}" }
- node3 << { :name => "c#{ri}" }
- node4 << { :name => "d#{ri}" }
- node5 << { :name => "e#{ri}" }
-
- osm_db << node1
- osm_db << node2
- osm_db << node3
- osm_db << node4
- osm_db << node5
-
- #...with a way between them
- way = OSM::Way.new make_osm_id, OSM_USER, OSM_TIMESTAMP
- way.uid = OSM_UID
- way << node1
- way << node2
- way << node3
- way << node4
- way << node5
-
- tags = row.dup
-
- # remove tags that describe expected test result
- tags.reject! do |k,v|
- k =~ /^forw\b/ ||
- k =~ /^backw\b/ ||
- k =~ /^bothw\b/
- end
-
- ##remove empty tags
- tags.reject! { |k,v| v=='' }
-
- # sort tag keys in the form of 'node/....'
- way_tags = { 'highway' => 'primary' }
-
- node_tags = {}
- tags.each_pair do |k,v|
- if k =~ /node\/(.*)/
- if v=='(nil)'
- node_tags.delete k
- else
- node_tags[$1] = v
- end
- else
- if v=='(nil)'
- way_tags.delete k
- else
- way_tags[k] = v
- end
- end
- end
-
- way_tags['name'] = "w#{ri}"
- way << way_tags
- node3 << node_tags
-
- osm_db << way
- end
-end
-
-def table_coord_to_lonlat ci,ri
- [@origin[0]+ci*@zoom, @origin[1]-ri*@zoom]
-end
-
-def add_osm_node name,lon,lat,id
- id = make_osm_id if id == nil
- node = OSM::Node.new id, OSM_USER, OSM_TIMESTAMP, lon, lat
- node << { :name => name }
- node.uid = OSM_UID
- osm_db << node
- name_node_hash[name] = node
-end
-
-def add_location name,lon,lat
- location_hash[name] = Location.new(lon,lat)
-end
-
-def find_node_by_name s
- raise "***invalid node name '#{s}', must be single characters" unless s.size == 1
- raise "*** invalid node name '#{s}', must be alphanumeric" unless s.match /[a-z0-9]/
- if s.match /[a-z]/
- from_node = name_node_hash[ s.to_s ]
- else
- from_node = location_hash[ s.to_s ]
- end
-end
-
-def find_way_by_name s
- name_way_hash[s.to_s] || name_way_hash[s.to_s.reverse]
-end
-
-def reset_data
- Dir.chdir TEST_FOLDER do
- #clear_log
- #clear_data_files
- end
- reset_profile
- reset_osm
- @fingerprint_osm = nil
- @fingerprint_extract = nil
- @fingerprint_prepare = nil
- @fingerprint_route = nil
-end
-
-def make_osm_id
- @osm_id = @osm_id+1
-end
-
-def reset_osm
- osm_db.clear
- name_node_hash.clear
- location_hash.clear
- name_way_hash.clear
- @osm_str = nil
- @osm_hash = nil
- @osm_id = 0
-end
-
-def clear_data_files
- File.delete *Dir.glob("#{DATA_FOLDER}/test.*")
-end
-
-def clear_log
- File.delete *Dir.glob("*.log")
-end
-
-def osm_db
- @osm_db ||= OSM::Database.new
-end
-
-def name_node_hash
- @name_node_hash ||= {}
-end
-
-def location_hash
- @location_hash ||= {}
-end
-
-def name_way_hash
- @name_way_hash ||= {}
-end
-
-def osm_str
- return @osm_str if @osm_str
- @osm_str = ''
- doc = Builder::XmlMarkup.new :indent => 2, :target => @osm_str
- doc.instruct!
- osm_db.to_xml doc, OSM_GENERATOR
- @osm_str
-end
-
-def osm_file
- @osm_file ||= "#{DATA_FOLDER}/#{fingerprint_osm}"
-end
-
-def extracted_file
- @extracted_file ||= "#{osm_file}_#{fingerprint_extract}"
-end
-
-def prepared_file
- @prepared_file ||= "#{osm_file}_#{fingerprint_extract}_#{fingerprint_prepare}"
-end
-
-def write_osm
- Dir.mkdir DATA_FOLDER unless File.exist? DATA_FOLDER
- unless File.exist?("#{osm_file}.osm")
- File.open( "#{osm_file}.osm", 'w') {|f| f.write(osm_str) }
- end
-end
-
-def convert_osm_to_pbf
- unless File.exist?("#{osm_file}.osm.pbf")
- log_preprocess_info
- log "== Converting #{osm_file}.osm to protobuffer format...", :preprocess
- unless system "osmosis --read-xml #{osm_file}.osm --write-pbf #{osm_file}.osm.pbf omitmetadata=true >>#{PREPROCESS_LOG_FILE} 2>&1"
- raise OsmosisError.new $?, "osmosis exited with code #{$?.exitstatus}"
- end
- log '', :preprocess
- end
-end
-
-def extracted?
- Dir.chdir TEST_FOLDER do
- File.exist?("#{extracted_file}.osrm") &&
- File.exist?("#{extracted_file}.osrm.names") &&
- File.exist?("#{extracted_file}.osrm.restrictions")
- end
-end
-
-def prepared?
- Dir.chdir TEST_FOLDER do
- File.exist?("#{prepared_file}.osrm.hsgr")
- end
-end
-
-def write_timestamp
- File.open( "#{prepared_file}.osrm.timestamp", 'w') {|f| f.write(OSM_TIMESTAMP) }
-end
-
-def pbf?
- input_format=='pbf'
-end
-
-def write_input_data
- Dir.chdir TEST_FOLDER do
- write_osm
- write_timestamp
- convert_osm_to_pbf if pbf?
- end
-end
-
-def extract_data
- Dir.chdir TEST_FOLDER do
- log_preprocess_info
- log "== Extracting #{osm_file}.osm...", :preprocess
- unless system "#{BIN_PATH}/osrm-extract #{osm_file}.osm#{'.pbf' if pbf?} #{@extract_args} --profile #{PROFILES_PATH}/#{@profile}.lua >>#{PREPROCESS_LOG_FILE} 2>&1"
- log "*** Exited with code #{$?.exitstatus}.", :preprocess
- raise ExtractError.new $?.exitstatus, "osrm-extract exited with code #{$?.exitstatus}."
- end
- begin
- ["osrm","osrm.names","osrm.restrictions","osrm.ebg","osrm.edges","osrm.fileIndex","osrm.geometry","osrm.nodes","osrm.ramIndex"].each do |file|
- log "Renaming #{osm_file}.#{file} to #{extracted_file}.#{file}", :preprocess
- File.rename "#{osm_file}.#{file}", "#{extracted_file}.#{file}"
- end
- rescue Exception => e
- raise FileError.new nil, "failed to rename data file after extracting."
- end
- end
-end
-
-def prepare_data
- Dir.chdir TEST_FOLDER do
- log_preprocess_info
- log "== Preparing #{extracted_file}.osm...", :preprocess
- unless system "#{BIN_PATH}/osrm-prepare #{extracted_file}.osrm --profile #{PROFILES_PATH}/#{@profile}.lua >>#{PREPROCESS_LOG_FILE} 2>&1"
- log "*** Exited with code #{$?.exitstatus}.", :preprocess
- raise PrepareError.new $?.exitstatus, "osrm-prepare exited with code #{$?.exitstatus}."
- end
- begin
- ["osrm.hsgr","osrm.fileIndex","osrm.geometry","osrm.nodes","osrm.ramIndex","osrm.core","osrm.edges"].each do |file|
- log "Renaming #{extracted_file}.#{file} to #{prepared_file}.#{file}", :preprocess
- File.rename "#{extracted_file}.#{file}", "#{prepared_file}.#{file}"
- end
- rescue Exception => e
- raise FileError.new nil, "failed to rename data file after preparing."
- end
- begin
- ["osrm.names","osrm.restrictions","osrm"].each do |file|
- log "Copying #{extracted_file}.#{file} to #{prepared_file}.#{file}", :preprocess
- FileUtils.cp "#{extracted_file}.#{file}", "#{prepared_file}.#{file}"
- end
- rescue Exception => e
- raise FileError.new nil, "failed to copy data file after preparing."
- end
- log '', :preprocess
- end
-end
-
-def reprocess
- write_input_data
- extract_data unless extracted?
- prepare_data unless prepared?
- log_preprocess_done
-end
diff --git a/features/support/data_classes.js b/features/support/data_classes.js
new file mode 100644
index 0000000..8eeaab3
--- /dev/null
+++ b/features/support/data_classes.js
@@ -0,0 +1,85 @@
+'use strict';
+
+var util = require('util');
+var path = require('path');
+
+module.exports = {
+ Location: class {
+ constructor (lon, lat) {
+ this.lon = lon;
+ this.lat = lat;
+ }
+ },
+
+ osmData: class {
+ constructor (scope) {
+ this.scope = scope;
+ this.str = null;
+ this.hash = null;
+ this.fingerprintOSM = null;
+ this.osmFile = null;
+ this.extractedFile = null;
+ this.contractedFile = null;
+ }
+
+ populate (callback) {
+ this.scope.OSMDB.toXML((str) => {
+ this.str = str;
+
+ this.hash = this.scope.hashString(str);
+ this.fingerprintOSM = this.scope.hashString(this.hash);
+
+ this.osmFile = path.resolve(this.scope.DATA_FOLDER, this.fingerprintOSM);
+
+ this.extractedFile = path.resolve([this.osmFile, this.scope.fingerprintExtract].join('_'));
+ this.contractedFile = path.resolve([this.osmFile, this.scope.fingerprintExtract, this.scope.fingerprintContract].join('_'));
+
+ callback();
+ });
+ }
+
+ reset () {
+ this.str = null;
+ this.hash = null;
+ this.fingerprintOSM = null;
+ this.osmFile = null;
+ this.extractedFile = null;
+ this.contractedFile = null;
+ }
+ },
+
+ FuzzyMatch: class {
+ match (got, want) {
+ var matchPercent = want.match(/(.*)\s+~(.+)%$/),
+ matchAbs = want.match(/(.*)\s+\+\-(.+)$/),
+ matchRe = want.match(/^\/(.*)\/$/);
+
+ if (got === want) {
+ return true;
+ } else if (matchPercent) { // percentage range: 100 ~ 5%
+ var target = parseFloat(matchPercent[1]),
+ percentage = parseFloat(matchPercent[2]);
+ if (target === 0) {
+ return true;
+ } else {
+ var ratio = Math.abs(1 - parseFloat(got) / target);
+ return 100 * ratio < percentage;
+ }
+ } else if (matchAbs) { // absolute range: 100 +-5
+ var margin = parseFloat(matchAbs[2]),
+ fromR = parseFloat(matchAbs[1]) - margin,
+ toR = parseFloat(matchAbs[1]) + margin;
+ return parseFloat(got) >= fromR && parseFloat(got) <= toR;
+ } else if (matchRe) { // regex: /a,b,.*/
+ return got.match(matchRe[1]);
+ } else {
+ return false;
+ }
+ }
+
+ matchLocation (got, want) {
+ return this.match(got[0], util.format('%d ~0.0025%', want.lon)) &&
+ this.match(got[1], util.format('%d ~0.0025%', want.lat));
+ }
+ }
+};
diff --git a/features/support/env.js b/features/support/env.js
new file mode 100644
index 0000000..cae361c
--- /dev/null
+++ b/features/support/env.js
@@ -0,0 +1,125 @@
+var path = require('path');
+var util = require('util');
+var fs = require('fs');
+var exec = require('child_process').exec;
+var d3 = require('d3-queue');
+
+module.exports = function () {
+ this.initializeEnv = (callback) => {
+ this.DEFAULT_PORT = 5000;
+ this.DEFAULT_TIMEOUT = 2000;
+ this.setDefaultTimeout(this.DEFAULT_TIMEOUT);
+ this.ROOT_FOLDER = process.cwd();
+ this.OSM_USER = 'osrm';
+ this.OSM_GENERATOR = 'osrm-test';
+ this.OSM_UID = 1;
+ this.TEST_FOLDER = path.resolve(this.ROOT_FOLDER, 'test');
+ this.DATA_FOLDER = path.resolve(this.TEST_FOLDER, 'cache');
+ this.OSM_TIMESTAMP = '2000-01-01T00:00:00Z';
+ this.DEFAULT_SPEEDPROFILE = 'bicycle';
+ this.WAY_SPACING = 100;
+ this.DEFAULT_GRID_SIZE = 100; // meters
+ this.PROFILES_PATH = path.resolve(this.ROOT_FOLDER, 'profiles');
+ this.FIXTURES_PATH = path.resolve(this.ROOT_FOLDER, 'unit_tests/fixtures');
+ this.BIN_PATH = path.resolve(this.ROOT_FOLDER, 'build');
+ this.DEFAULT_INPUT_FORMAT = 'osm';
+ this.DEFAULT_ORIGIN = [1,1];
+ this.LAUNCH_TIMEOUT = 1000;
+ this.SHUTDOWN_TIMEOUT = 10000;
+ this.DEFAULT_LOAD_METHOD = 'datastore';
+ this.OSRM_ROUTED_LOG_FILE = path.resolve(this.TEST_FOLDER, 'osrm-routed.log');
+ this.ERROR_LOG_FILE = path.resolve(this.TEST_FOLDER, 'error.log');
+
+ // OS X shim to ensure shared libraries from custom locations can be loaded
+ // This is needed in OS X >= 10.11 because DYLD_LIBRARY_PATH is blocked
+ // https://forums.developer.apple.com/thread/9233
+ this.LOAD_LIBRARIES = process.env.OSRM_SHARED_LIBRARY_PATH ? util.format('DYLD_LIBRARY_PATH=%s ', process.env.OSRM_SHARED_LIBRARY_PATH) : '';
+
+ // TODO make sure this works on win
+ if (process.platform.match(/indows.*/)) {
+ this.TERMSIGNAL = 9;
+ this.EXE = '.exe';
+ this.QQ = '"';
+ } else {
+ this.TERMSIGNAL = 'SIGTERM';
+ this.EXE = '';
+ this.QQ = '';
+ }
+
+ // eslint-disable-next-line no-console
+ console.info(util.format('Node Version', process.version));
+ if (parseInt(process.version.match(/v(\d)/)[1]) < 4) throw new Error('*** PLease upgrade to Node 4.+ to run OSRM cucumber tests');
+
+ if (process.env.OSRM_PORT) {
+ this.OSRM_PORT = parseInt(process.env.OSRM_PORT);
+ // eslint-disable-next-line no-console
+ console.info(util.format('Port set to %d', this.OSRM_PORT));
+ } else {
+ this.OSRM_PORT = this.DEFAULT_PORT;
+ // eslint-disable-next-line no-console
+ console.info(util.format('Using default port %d', this.OSRM_PORT));
+ }
+
+ if (process.env.OSRM_TIMEOUT) {
+ this.OSRM_TIMEOUT = parseInt(process.env.OSRM_TIMEOUT);
+ // eslint-disable-next-line no-console
+ console.info(util.format('Timeout set to %d', this.OSRM_TIMEOUT));
+ } else {
+ this.OSRM_TIMEOUT = this.DEFAULT_TIMEOUT;
+ // eslint-disable-next-line no-console
+ console.info(util.format('Using default timeout %d', this.OSRM_TIMEOUT));
+ }
+
+ fs.exists(this.TEST_FOLDER, (exists) => {
+ if (!exists) throw new Error(util.format('*** Test folder %s doesn\'t exist.', this.TEST_FOLDER));
+ callback();
+ });
+ };
+
+ this.verifyOSRMIsNotRunning = () => {
+ if (this.OSRMLoader.up()) {
+ throw new Error('*** osrm-routed is already running.');
+ }
+ };
+
+ this.verifyExistenceOfBinaries = (callback) => {
+ var verify = (bin, cb) => {
+ var binPath = path.resolve(util.format('%s/%s%s', this.BIN_PATH, bin, this.EXE));
+ fs.exists(binPath, (exists) => {
+ if (!exists) throw new Error(util.format('%s is missing. Build failed?', binPath));
+ var helpPath = util.format('%s%s --help > /dev/null 2>&1', this.LOAD_LIBRARIES, binPath);
+ exec(helpPath, (err) => {
+ if (err) {
+ this.log(util.format('*** Exited with code %d', err.code), 'preprocess');
+ throw new Error(util.format('*** %s exited with code %d', helpPath, err.code));
+ }
+ cb();
+ });
+ });
+ };
+
+ var q = d3.queue();
+ ['osrm-extract', 'osrm-contract', 'osrm-routed'].forEach(bin => { q.defer(verify, bin); });
+ q.awaitAll(() => {
+ callback();
+ });
+ };
+
+ this.AfterConfiguration = (callback) => {
+ this.clearLogFiles(() => {
+ this.verifyOSRMIsNotRunning();
+ this.verifyExistenceOfBinaries(() => {
+ callback();
+ });
+ });
+ };
+
+ process.on('exit', () => {
+ if (this.OSRMLoader.loader) this.OSRMLoader.shutdown(() => {});
+ });
+
+ process.on('SIGINT', () => {
+ process.exit(2);
+ // TODO need to handle for windows??
+ });
+};
diff --git a/features/support/env.rb b/features/support/env.rb
deleted file mode 100644
index cb707f9..0000000
--- a/features/support/env.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-require 'rspec/expectations'
-
-
-DEFAULT_PORT = 5000
-DEFAULT_TIMEOUT = 2
-ROOT_FOLDER = Dir.pwd
-OSM_USER = 'osrm'
-OSM_GENERATOR = 'osrm-test'
-OSM_UID = 1
-TEST_FOLDER = File.join ROOT_FOLDER, 'test'
-DATA_FOLDER = 'cache'
-OSM_TIMESTAMP = '2000-01-01T00:00:00Z'
-DEFAULT_SPEEDPROFILE = 'bicycle'
-WAY_SPACING = 100
-DEFAULT_GRID_SIZE = 100 #meters
-PROFILES_PATH = File.join ROOT_FOLDER, 'profiles'
-FIXTURES_PATH = File.join ROOT_FOLDER, 'unit_tests/fixtures'
-BIN_PATH = File.join ROOT_FOLDER, 'build'
-DEFAULT_INPUT_FORMAT = 'osm'
-DEFAULT_ORIGIN = [1,1]
-LAUNCH_TIMEOUT = 1
-SHUTDOWN_TIMEOUT = 10
-DEFAULT_LOAD_METHOD = 'datastore'
-OSRM_ROUTED_LOG_FILE = 'osrm-routed.log'
-
-if ENV['OS']=~/Windows.*/ then
- TERMSIGNAL=9
-else
- TERMSIGNAL='TERM'
-end
-
-
-def log_time_and_run cmd
- log_time cmd
- `#{cmd}`
-end
-
-def log_time cmd
- puts "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S:%L')}] #{cmd}"
-end
-
-
-puts "Ruby version #{RUBY_VERSION}"
-unless RUBY_VERSION.to_f >= 1.9
- raise "*** Please upgrade to Ruby 1.9.x to run the OSRM cucumber tests"
-end
-
-if ENV["OSRM_PORT"]
- OSRM_PORT = ENV["OSRM_PORT"].to_i
- puts "Port set to #{OSRM_PORT}"
-else
- OSRM_PORT = DEFAULT_PORT
- puts "Using default port #{OSRM_PORT}"
-end
-
-if ENV["OSRM_TIMEOUT"]
- OSRM_TIMEOUT = ENV["OSRM_TIMEOUT"].to_i
- puts "Timeout set to #{OSRM_TIMEOUT}"
-else
- OSRM_TIMEOUT = DEFAULT_TIMEOUT
- puts "Using default timeout #{OSRM_TIMEOUT}"
-end
-
-unless File.exists? TEST_FOLDER
- raise "*** Test folder #{TEST_FOLDER} doesn't exist."
-end
-
-def verify_osrm_is_not_running
- if OSRMLoader::OSRMBaseLoader.new.osrm_up?
- raise "*** osrm-routed is already running."
- end
-end
-
-def verify_existance_of_binaries
- ["osrm-extract", "osrm-prepare", "osrm-routed"].each do |bin|
- unless File.exists? "#{BIN_PATH}/#{bin}#{EXE}"
- raise "*** #{BIN_PATH}/#{bin}#{EXE} is missing. Build failed?"
- end
- end
-end
-
-if ENV['OS']=~/Windows.*/ then
- EXE='.exe'
- QQ='"'
-else
- EXE=''
- QQ=''
-end
-
-AfterConfiguration do |config|
- clear_log_files
- verify_osrm_is_not_running
- verify_existance_of_binaries
-end
-
-at_exit do
- OSRMLoader::OSRMBaseLoader.new.shutdown
-end
diff --git a/features/support/exception_classes.js b/features/support/exception_classes.js
new file mode 100644
index 0000000..36bdffe
--- /dev/null
+++ b/features/support/exception_classes.js
@@ -0,0 +1,132 @@
+'use strict';
+
+var util = require('util');
+var path = require('path');
+var fs = require('fs');
+var chalk = require('chalk');
+
+var OSRMError = class extends Error {
+ constructor (process, code, msg, log, lines) {
+ super(msg);
+ this.process = process;
+ this.code = code;
+ this.msg = msg;
+ this.lines = lines;
+ this.log = log;
+ }
+
+ extract (callback) {
+ this.logTail(this.log, this.lines, callback);
+ }
+
+ // toString (callback) {
+ // this.extract((tail) => {
+ // callback(util.format('*** %s\nLast %s from %s:\n%s\n', this.msg, this.lines, this.log, tail));
+ // });
+ // }
+
+ logTail (logPath, n, callback) {
+ var expanded = path.resolve(this.TEST_FOLDER, logPath);
+ fs.exists(expanded, (exists) => {
+ if (exists) {
+ fs.readFile(expanded, (err, data) => {
+ var lines = data.toString().trim().split('\n');
+ callback(lines
+ .slice(lines.length - n)
+ .map(line => util.format(' %s', line))
+ .join('\n'));
+ });
+ } else {
+ callback(util.format('File %s does not exist!', expanded));
+ }
+ });
+ }
+};
+
+var unescapeStr = (str) => str.replace(/\\\|/g, '\|').replace(/\\\\/g, '\\');
+
+module.exports = {
+ OSRMError: OSRMError,
+
+ FileError: class extends OSRMError {
+ constructor (logFile, code, msg) {
+ super ('fileutil', code, msg, logFile, 5);
+ }
+ },
+
+ LaunchError: class extends OSRMError {
+ constructor (logFile, launchProcess, code, msg) {
+ super (launchProcess, code, msg, logFile, 5);
+ }
+ },
+
+ ExtractError: class extends OSRMError {
+ constructor (logFile, code, msg) {
+ super('osrm-extract', code, msg, logFile, 3);
+ }
+ },
+
+ ContractError: class extends OSRMError {
+ constructor (logFile, code, msg) {
+ super('osrm-contract', code, msg, logFile, 3);
+ }
+ },
+
+ RoutedError: class extends OSRMError {
+ constructor (logFile, msg) {
+ super('osrm-routed', null, msg, logFile, 3);
+ }
+ },
+
+ TableDiffError: class extends Error {
+ constructor (expected, actual) {
+ super();
+ this.headers = expected.raw()[0];
+ this.expected = expected.hashes();
+ this.actual = actual;
+ this.diff = [];
+ this.hasErrors = false;
+
+ var good = 0, bad = 0;
+
+ this.expected.forEach((row, i) => {
+ var rowError = false;
+
+ for (var j in row) {
+ if (unescapeStr(row[j]) != actual[i][j]) {
+ rowError = true;
+ this.hasErrors = true;
+ break;
+ }
+ }
+
+ if (rowError) {
+ bad++;
+ this.diff.push(Object.assign({}, row, {c_status: 'undefined'}));
+ this.diff.push(Object.assign({}, actual[i], {c_status: 'comment'}));
+ } else {
+ good++;
+ this.diff.push(row);
+ }
+ });
+ }
+
+ get string () {
+ if (!this.hasErrors) return null;
+
+ var s = ['Tables were not identical:'];
+ s.push(this.headers.map(key => ' ' + key).join(' | '));
+ this.diff.forEach((row) => {
+ var rowString = '| ';
+ this.headers.forEach((header) => {
+ if (!row.c_status) rowString += chalk.green(' ' + row[header] + ' | ');
+ else if (row.c_status === 'undefined') rowString += chalk.yellow('(-) ' + row[header] + ' | ');
+ else rowString += chalk.red('(+) ' + row[header] + ' | ');
+ });
+ s.push(rowString);
+ });
+
+ return s.join('\n') + '\nTODO this is a temp workaround waiting for https://github.com/cucumber/cucumber-js/issues/534';
+ }
+ }
+};
diff --git a/features/support/exceptions.js b/features/support/exceptions.js
new file mode 100644
index 0000000..6af1a93
--- /dev/null
+++ b/features/support/exceptions.js
@@ -0,0 +1,15 @@
+var exceptions = require('./exception_classes');
+
+module.exports = function () {
+ this.OSRMError = exceptions.OSRMError,
+
+ this.FileError = (code, msg) => new (exceptions.FileError.bind(exceptions.FileError, this.PREPROCESS_LOG_FILE))(code, msg);
+
+ this.LaunchError = (code, launchProcess, msg) => new (exceptions.LaunchError.bind(exceptions.LaunchError, this.ERROR_LOG_FILE))(code, launchProcess, msg);
+
+ this.ExtractError = (code, msg) => new (exceptions.ExtractError.bind(exceptions.ExtractError, this.PREPROCESS_LOG_FILE))(code, msg);
+
+ this.ContractError = (code, msg) => new (exceptions.ContractError.bind(exceptions.ContractError, this.PREPROCESS_LOG_FILE))(code, msg);
+
+ this.RoutedError = (msg) => new (exceptions.RoutedError.bind(exceptions.RoutedError, this.OSRM_ROUTED_LOG_FILE))(msg);
+};
diff --git a/features/support/exceptions.rb b/features/support/exceptions.rb
deleted file mode 100644
index 02f59d3..0000000
--- a/features/support/exceptions.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-
-class OSRMError < StandardError
- attr_accessor :msg, :code, :process
-
- def initialize process, code, msg, log, lines
- @process = process
- @code = code
- @msg = msg
- @lines = lines
- @log = log
- @extract = log_tail @log, @lines
- end
-
- def to_s
- "*** #{@msg}\nLast #{@lines} lines from #{@log}:\n#{@extract}\n"
- end
-
- private
-
- def log_tail path, n
- Dir.chdir TEST_FOLDER do
- expanded = File.expand_path path
- if File.exists? expanded
- File.open(expanded) do |f|
- return f.tail(n).map { |line| " #{line}" }.join "\n"
- end
- else
- return "File '#{expanded} does not exist!"
- end
- end
- end
-end
-
-class FileError < OSRMError
- def initialize code, msg
- super 'fileutil', code, msg, PREPROCESS_LOG_FILE, 5
- end
-end
-
-class OsmosisError < OSRMError
- def initialize code, msg
- super 'osmosis', code, msg, PREPROCESS_LOG_FILE, 40
- end
-end
-
-class ExtractError < OSRMError
- def initialize code, msg
- super 'osrm-extract', code, msg, PREPROCESS_LOG_FILE, 3
- end
-end
-
-class PrepareError < OSRMError
- def initialize code, msg
- super 'osrm-prepare', code, msg, PREPROCESS_LOG_FILE, 3
- end
-end
-
-class RoutedError < OSRMError
- def initialize msg
- super 'osrm-routed', nil, msg, OSRM_ROUTED_LOG_FILE, 3
- end
-end
diff --git a/features/support/file.rb b/features/support/file.rb
deleted file mode 100644
index dfaae0a..0000000
--- a/features/support/file.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-class File
-
- # read last n lines of a file (trailing newlines are ignored)
- def tail(n)
- return [] if size==0
- buffer = 1024
- str = nil
-
- if size>buffer
- chunks = []
- lines = 0
- idx = size
- begin
- idx -= buffer # rewind
- if idx<0
- buffer += idx # adjust last read to avoid negative index
- idx = 0
- end
- seek(idx)
- chunk = read(buffer)
- chunk.gsub!(/\n+\Z/,"") if chunks.empty? # strip newlines from end of file (first chunk)
- lines += chunk.count("\n") # update total lines found
- chunks.unshift chunk # prepend
- end while lines<(n) && idx>0 # stop when enough lines found or no more to read
- str = chunks.join('')
- else
- str = read(buffer)
- end
-
- # return last n lines of str
- lines = str.split("\n")
- lines.size>=n ? lines[-n,n] : lines
- end
-end
\ No newline at end of file
diff --git a/features/support/fuzzy.js b/features/support/fuzzy.js
new file mode 100644
index 0000000..6eebe0a
--- /dev/null
+++ b/features/support/fuzzy.js
@@ -0,0 +1,5 @@
+var classes = require('./data_classes');
+
+module.exports = function() {
+ this.FuzzyMatch = new classes.FuzzyMatch();
+};
diff --git a/features/support/fuzzy.rb b/features/support/fuzzy.rb
deleted file mode 100644
index 066d9c5..0000000
--- a/features/support/fuzzy.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-class FuzzyMatch
-
- def self.match got, want
- if got == want
- return true
- elsif want.match /(.*)\s+~(.+)%$/ #percentage range: 100 ~5%
- target = $1.to_f
- percentage = $2.to_f
- if target==0
- return true
- else
- ratio = (1-(got.to_f / target)).abs;
- return 100*ratio < percentage;
- end
- elsif want.match /(.*)\s+\+\-(.+)$/ #absolute range: 100 +-5
- margin = $2.to_f
- from = $1.to_f-margin
- to = $1.to_f+margin
- return got.to_f >= from && got.to_f <= to
- elsif want =~ /^\/(.*)\/$/ #regex: /a,b,.*/
- return got =~ /#{$1}/
- else
- return false
- end
- end
-
- def self.match_location got, want
- match( got[0], "#{want.lat} ~0.0025%" ) &&
- match( got[1], "#{want.lon} ~0.0025%" )
- end
-
-end
diff --git a/features/support/hash.js b/features/support/hash.js
new file mode 100644
index 0000000..6ab44ad
--- /dev/null
+++ b/features/support/hash.js
@@ -0,0 +1,37 @@
+var fs = require('fs');
+var path = require('path');
+var crypto = require('crypto');
+var d3 = require('d3-queue');
+
+module.exports = function () {
+ this.hashOfFiles = (paths, cb) => {
+ paths = Array.isArray(paths) ? paths : [paths];
+ var shasum = crypto.createHash('sha1');
+
+ var q = d3.queue(1);
+
+ var addFile = (path, cb) => {
+ fs.readFile(path, (err, data) => {
+ shasum.update(data);
+ cb(err);
+ });
+ };
+
+ paths.forEach(path => { q.defer(addFile, path); });
+
+ q.awaitAll(err => {
+ if (err) throw new Error('*** Error reading files:', err);
+ cb(shasum.digest('hex'));
+ });
+ };
+
+ this.hashProfile = (cb) => {
+ this.hashOfFiles(path.resolve(this.PROFILES_PATH, this.profile + '.lua'), cb);
+ };
+
+ this.hashString = (str) => {
+ return crypto.createHash('sha1').update(str).digest('hex');
+ };
+
+ return this;
+};
diff --git a/features/support/hash.rb b/features/support/hash.rb
deleted file mode 100644
index 6980b66..0000000
--- a/features/support/hash.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-require 'digest/sha1'
-
-bin_extract_hash = nil
-profile_hashes = nil
-
-def hash_of_files paths
- paths = [paths] unless paths.is_a? Array
- hash = Digest::SHA1.new
- for path in paths do
- open(path,'rb') do |io|
- while !io.eof
- buf = io.readpartial 1024
- hash.update buf
- end
- end
- end
- return hash.hexdigest
-end
-
-
-def profile_hash
- profile_hashes ||= {}
- profile_hashes[@profile] ||= hash_of_files "#{PROFILES_PATH}/#{@profile}.lua"
-end
-
-def osm_hash
- @osm_hash ||= Digest::SHA1.hexdigest osm_str
-end
-
-def lua_lib_hash
- @lua_lib_hash ||= hash_of_files Dir.glob("../profiles/lib/*.lua")
-end
-
-def bin_extract_hash
- @bin_extract_hash ||= hash_of_files "#{BIN_PATH}/osrm-extract#{EXE}"
- @bin_extract_hash
-end
-
-def bin_prepare_hash
- @bin_prepare_hash ||= hash_of_files "#{BIN_PATH}/osrm-prepare#{EXE}"
-end
-
-def bin_routed_hash
- @bin_routed_hash ||= hash_of_files "#{BIN_PATH}/osrm-routed#{EXE}"
-end
-
-# combine state of data, profile and binaries into a hashes that identifies
-# the exact test situation at different stages, so we can later skip steps when possible.
-def fingerprint_osm
- @fingerprint_osm ||= Digest::SHA1.hexdigest "#{osm_hash}"
-end
-
-def fingerprint_extract
- @fingerprint_extract ||= Digest::SHA1.hexdigest "#{profile_hash}-#{lua_lib_hash}-#{bin_extract_hash}"
-end
-
-def fingerprint_prepare
- @fingerprint_prepare ||= Digest::SHA1.hexdigest "#{bin_prepare_hash}"
-end
-
-def fingerprint_route
- @fingerprint_route ||= Digest::SHA1.hexdigest "#{bin_routed_hash}"
-end
\ No newline at end of file
diff --git a/features/support/hooks.js b/features/support/hooks.js
new file mode 100644
index 0000000..f8c7a2f
--- /dev/null
+++ b/features/support/hooks.js
@@ -0,0 +1,37 @@
+var util = require('util');
+
+module.exports = function () {
+ this.BeforeFeatures((features, callback) => {
+ this.pid = null;
+ this.initializeEnv(() => {
+ this.initializeOptions(callback);
+ });
+ });
+
+ this.Before((scenario, callback) => {
+ this.scenarioTitle = scenario.getName();
+
+ this.loadMethod = this.DEFAULT_LOAD_METHOD;
+ this.queryParams = {};
+ var d = new Date();
+ this.scenarioTime = util.format('%d-%d-%dT%s:%s:%sZ', d.getFullYear(), d.getMonth()+1, d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds());
+ this.resetData();
+ this.hasLoggedPreprocessInfo = false;
+ this.hasLoggedScenarioInfo = false;
+ this.setGridSize(this.DEFAULT_GRID_SIZE);
+ this.setOrigin(this.DEFAULT_ORIGIN);
+ callback();
+ });
+
+ this.After((scenario, callback) => {
+ this.setExtractArgs('');
+ this.setContractArgs('');
+ if (this.loadMethod === 'directly' && !!this.OSRMLoader.loader) this.OSRMLoader.shutdown(callback);
+ else callback();
+ });
+
+ this.Around('@stress', (scenario, callback) => {
+ // TODO implement stress timeout? Around support is being dropped in cucumber-js anyway
+ callback();
+ });
+};
diff --git a/features/support/hooks.rb b/features/support/hooks.rb
deleted file mode 100644
index 6af9a8f..0000000
--- a/features/support/hooks.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-
-STRESS_TIMEOUT = 300
-
-
-Before do |scenario|
-
- # fetch scenario and feature name, so we can use it in log files if needed
- case scenario
- when Cucumber::RunningTestCase::Scenario
- @feature_name = scenario.feature.name
- @scenario_title = scenario.name
- when Cucumber::RunningTestCase::ExampleRow
- @feature_name = scenario.scenario_outline.feature.name
- @scenario_title = scenario.scenario_outline.name
- end
-
- @load_method = DEFAULT_LOAD_METHOD
- @query_params = []
- @scenario_time = Time.now.strftime("%Y-%m-%dT%H:%m:%SZ")
- reset_data
- @has_logged_preprocess_info = false
- @has_logged_scenario_info = false
- set_grid_size DEFAULT_GRID_SIZE
- set_origin DEFAULT_ORIGIN
-
-end
-
-Around('@stress') do |scenario, block|
- Timeout.timeout(STRESS_TIMEOUT) do
- block.call
- end
-end
-
-After do
-end
diff --git a/features/support/http.js b/features/support/http.js
new file mode 100644
index 0000000..5da59c4
--- /dev/null
+++ b/features/support/http.js
@@ -0,0 +1,51 @@
+var Timeout = require('node-timeout');
+var request = require('request');
+
+module.exports = function () {
+ this.paramsToString = (params) => {
+ var paramString = '';
+ if (params.coordinates !== undefined) {
+ // FIXME this disables passing the output if its a default
+ // Remove after #2173 is fixed.
+ var outputString = (params.output && params.output !== 'json') ? ('.' + params.output) : '';
+ paramString = params.coordinates.join(';') + outputString;
+ delete params.coordinates;
+ delete params.output;
+ }
+ if (Object.keys(params).length) {
+ paramString += '?' + Object.keys(params).map(k => k + '=' + params[k]).join('&');
+ }
+
+ return paramString;
+ };
+
+ this.sendRequest = (baseUri, parameters, callback) => {
+ var limit = Timeout(this.OSRM_TIMEOUT, { err: { statusCode: 408 } });
+
+ var runRequest = (cb) => {
+ var params = this.paramsToString(parameters);
+ this.query = baseUri + (params.length ? '/' + params : '');
+
+ request(this.query, (err, res, body) => {
+ if (err && err.code === 'ECONNREFUSED') {
+ throw new Error('*** osrm-routed is not running.');
+ } else if (err && err.statusCode === 408) {
+ throw new Error();
+ }
+
+ return cb(err, res, body);
+ });
+ };
+
+ runRequest(limit((err, res, body) => {
+ if (err) {
+ if (err.statusCode === 408)
+ return callback(this.RoutedError('*** osrm-routed did not respond'));
+ else if (err.code === 'ECONNREFUSED')
+ return callback(this.RoutedError('*** osrm-routed is not running'));
+ }
+ //console.log(body+"\n");
+ return callback(err, res, body);
+ }));
+ };
+};
diff --git a/features/support/http.rb b/features/support/http.rb
deleted file mode 100644
index 0b9fb9a..0000000
--- a/features/support/http.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require 'net/http'
-
-# Converts an array [["param","val1"], ["param","val2"]] into ?param=val1¶m=val2
-def params_to_url params
- kv_pairs = params.map { |kv| kv[0].to_s + "=" + kv[1].to_s }
- url = kv_pairs.size > 0 ? ("?" + kv_pairs.join("&")) : ""
- return url
-end
-
-# Converts an array [["param","val1"], ["param","val2"]] into ["param"=>["val1", "val2"]]
-def params_to_map params
- result = {}
- params.each do |pair|
- if not result.has_key? pair[0]
- result[pair[0]] = []
- end
- result[pair[0]] << [pair[1]]
- end
-end
-
-def send_request base_uri, parameters
- Timeout.timeout(OSRM_TIMEOUT) do
- if @http_method.eql? "POST"
- uri = URI.parse base_uri
- @query = uri.to_s
- response = Net::HTTP.post_form uri, (params_to_map parameters)
- else
- uri = URI.parse base_uri+(params_to_url parameters)
- @query = uri.to_s
- response = Net::HTTP.get_response uri
- end
- end
-rescue Errno::ECONNREFUSED => e
- raise "*** osrm-routed is not running."
-rescue Timeout::Error
- raise "*** osrm-routed did not respond."
-end
diff --git a/features/support/launch.js b/features/support/launch.js
new file mode 100644
index 0000000..ee335e3
--- /dev/null
+++ b/features/support/launch.js
@@ -0,0 +1,5 @@
+var launchClasses = require('./launch_classes');
+
+module.exports = function () {
+ this._OSRMLoader = () => new (launchClasses._OSRMLoader.bind(launchClasses._OSRMLoader, this))();
+};
diff --git a/features/support/launch.rb b/features/support/launch.rb
deleted file mode 100644
index d8d23ae..0000000
--- a/features/support/launch.rb
+++ /dev/null
@@ -1,137 +0,0 @@
-require 'socket'
-require 'open3'
-require 'json'
-
-# Only one isntance of osrm-routed is ever launched, to avoid collisions.
-# The default is to keep osrm-routed running and load data with datastore.
-# however, osrm-routed it shut down and relaunched for each scenario thats
-# loads data directly.
-class OSRMLoader
-
- class OSRMBaseLoader
- @@pid = nil
-
- def launch
- Timeout.timeout(LAUNCH_TIMEOUT) do
- osrm_up
- wait_for_connection
- end
- rescue Timeout::Error
- raise RoutedError.new "Launching osrm-routed timed out."
- end
-
- def shutdown
- Timeout.timeout(SHUTDOWN_TIMEOUT) do
- osrm_down
- end
- rescue Timeout::Error
- kill
- raise RoutedError.new "Shutting down osrm-routed timed out."
- end
-
- def osrm_up?
- if @@pid
- begin
- if Process.waitpid(@@pid, Process::WNOHANG) then
- false
- else
- true
- end
- rescue Errno::ESRCH, Errno::ECHILD
- false
- end
- end
- end
-
- def osrm_down
- if @@pid
- Process.kill TERMSIGNAL, @@pid
- wait_for_shutdown
- @@pid = nil
- end
- end
-
- def kill
- if @@pid
- Process.kill 'KILL', @@pid
- end
- end
-
- def wait_for_connection
- while true
- begin
- socket = TCPSocket.new('127.0.0.1', OSRM_PORT)
- return
- rescue Errno::ECONNREFUSED
- sleep 0.1
- end
- end
- end
-
- def wait_for_shutdown
- while osrm_up?
- sleep 0.01
- end
- end
- end
-
- # looading data directly when lauching osrm-routed:
- # under this scheme, osmr-routed is launched and shutdown for each scenario,
- # and osrm-datastore is not used
- class OSRMDirectLoader < OSRMBaseLoader
- def load world, input_file, &block
- @world = world
- @input_file = input_file
- Dir.chdir TEST_FOLDER do
- shutdown
- launch
- yield
- shutdown
- end
- end
-
- def osrm_up
- return if @@pid
- @@pid = Process.spawn("#{BIN_PATH}/osrm-routed #{@input_file} --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
- Process.detach(@@pid) # avoid zombie processes
- end
-
- end
-
- # looading data with osrm-datastore:
- # under this scheme, osmr-routed is launched once and kept running for all scenarios,
- # and osrm-datastore is used to load data for each scenario
- class OSRMDatastoreLoader < OSRMBaseLoader
- def load world, input_file, &block
- @world = world
- @input_file = input_file
- Dir.chdir TEST_FOLDER do
- load_data
- launch unless @@pid
- yield
- end
- end
-
- def load_data
- run_bin "osrm-datastore", @input_file
- end
-
- def osrm_up
- return if osrm_up?
- @@pid = Process.spawn("#{BIN_PATH}/osrm-routed --shared-memory=1 --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
- Process.detach(@@pid) # avoid zombie processes
- end
- end
-
- def self.load world, input_file, &block
- method = world.instance_variable_get "@load_method"
- if method == 'datastore'
- OSRMDatastoreLoader.new.load world, input_file, &block
- elsif method == 'directly'
- OSRMDirectLoader.new.load world, input_file, &block
- else
- raise "*** Unknown load method '#{method}'"
- end
- end
-
-end
diff --git a/features/support/launch_classes.js b/features/support/launch_classes.js
new file mode 100644
index 0000000..38f3b31
--- /dev/null
+++ b/features/support/launch_classes.js
@@ -0,0 +1,163 @@
+'use strict';
+
+var fs = require('fs');
+var net = require('net');
+var spawn = require('child_process').spawn;
+var util = require('util');
+var Timeout = require('node-timeout');
+
+var OSRMBaseLoader = class {
+ constructor (scope) {
+ this.scope = scope;
+ }
+
+ launch (callback) {
+ var limit = Timeout(this.scope.LAUNCH_TIMEOUT, { err: this.scope.RoutedError('Launching osrm-routed timed out.') });
+
+ var runLaunch = (cb) => {
+ this.osrmUp(() => {
+ this.waitForConnection(cb);
+ });
+ };
+
+ runLaunch(limit((e) => { if (e) callback(e); else callback(); }));
+ }
+
+ shutdown (callback) {
+ var limit = Timeout(this.scope.SHUTDOWN_TIMEOUT, { err: this.scope.RoutedError('Shutting down osrm-routed timed out.')});
+
+ var runShutdown = (cb) => {
+ this.osrmDown(cb);
+ };
+
+ runShutdown(limit((e) => { if (e) callback(e); else callback(); }));
+ }
+
+ osrmIsRunning () {
+ return !!this.scope.pid && this.child && !this.child.killed;
+ }
+
+ osrmDown (callback) {
+ if (this.scope.pid) {
+ process.kill(this.scope.pid, this.scope.TERMSIGNAL);
+ this.waitForShutdown(callback);
+ this.scope.pid = null;
+ } else callback(true);
+ }
+
+ waitForConnection (callback) {
+ net.connect({
+ port: this.scope.OSRM_PORT,
+ host: '127.0.0.1'
+ })
+ .on('connect', () => {
+ callback();
+ })
+ .on('error', (e) => {
+ setTimeout(() => {
+ callback(e);
+ }, 100);
+ });
+ }
+
+ waitForShutdown (callback) {
+ var check = () => {
+ if (!this.osrmIsRunning()) return callback();
+ };
+ setTimeout(check, 100);
+ }
+};
+
+var OSRMDirectLoader = class extends OSRMBaseLoader {
+ constructor (scope) {
+ super(scope);
+ }
+
+ load (inputFile, callback) {
+ this.inputFile = inputFile;
+ this.shutdown(() => {
+ this.launch(callback);
+ });
+ }
+
+ osrmUp (callback) {
+ if (this.scope.pid) return callback();
+ var writeToLog = (data) => {
+ fs.appendFile(this.scope.OSRM_ROUTED_LOG_FILE, data, (err) => { if (err) throw err; });
+ };
+
+ var child = spawn(util.format('%s%s/osrm-routed', this.scope.LOAD_LIBRARIES, this.scope.BIN_PATH), [this.inputFile, util.format('-p%d', this.scope.OSRM_PORT)]);
+ this.scope.pid = child.pid;
+ child.stdout.on('data', writeToLog);
+ child.stderr.on('data', writeToLog);
+
+ callback();
+ }
+};
+
+var OSRMDatastoreLoader = class extends OSRMBaseLoader {
+ constructor (scope) {
+ super(scope);
+ }
+
+ load (inputFile, callback) {
+ this.inputFile = inputFile;
+ this.loadData((err) => {
+ if (err) return callback(err);
+ if (!this.scope.pid) return this.launch(callback);
+ else callback();
+ });
+ }
+
+ loadData (callback) {
+ this.scope.runBin('osrm-datastore', this.inputFile, (err) => {
+ if (err) return callback(this.scope.LaunchError(this.exitCode, 'datastore', err));
+ callback();
+ });
+ }
+
+ osrmUp (callback) {
+ if (this.scope.pid) return callback();
+ var writeToLog = (data) => {
+ fs.appendFile(this.scope.OSRM_ROUTED_LOG_FILE, data, (err) => { if (err) throw err; });
+ };
+
+ var child = spawn(util.format('%s%s/osrm-routed', this.scope.LOAD_LIBRARIES, this.scope.BIN_PATH), ['--shared-memory=1', util.format('-p%d', this.scope.OSRM_PORT)]);
+ this.child = child;
+ this.scope.pid = child.pid;
+ child.stdout.on('data', writeToLog);
+ child.stderr.on('data', writeToLog);
+
+ callback();
+ }
+};
+
+module.exports = {
+ _OSRMLoader: class {
+ constructor (scope) {
+ this.scope = scope;
+ this.loader = null;
+ }
+
+ load (inputFile, callback) {
+ var method = this.scope.loadMethod;
+ if (method === 'datastore') {
+ this.loader = new OSRMDatastoreLoader(this.scope);
+ this.loader.load(inputFile, callback);
+ } else if (method === 'directly') {
+ this.loader = new OSRMDirectLoader(this.scope);
+ this.loader.load(inputFile, callback);
+ } else {
+ throw new Error('*** Unknown load method ' + method);
+ }
+ }
+
+ shutdown (callback) {
+ this.loader.shutdown(callback);
+ }
+
+ up () {
+ return this.loader ? this.loader.osrmIsRunning() : false;
+ }
+ }
+};
diff --git a/features/support/log.js b/features/support/log.js
new file mode 100644
index 0000000..c428cb9
--- /dev/null
+++ b/features/support/log.js
@@ -0,0 +1,90 @@
+var fs = require('fs');
+
+module.exports = function () {
+ this.clearLogFiles = (callback) => {
+ // emptying existing files, rather than deleting and writing new ones makes it
+ // easier to use tail -f from the command line
+ fs.writeFile(this.OSRM_ROUTED_LOG_FILE, '', err => {
+ if (err) throw err;
+ fs.writeFile(this.PREPROCESS_LOG_FILE, '', err => {
+ if (err) throw err;
+ fs.writeFile(this.LOG_FILE, '', err => {
+ if (err) throw err;
+ callback();
+ });
+ });
+ });
+ };
+
+ var log = this.log = (s, type) => {
+ s = s || '';
+ type = type || null;
+ var file = type === 'preprocess' ? this.PREPROCESS_LOG_FILE : this.LOG_FILE;
+ fs.appendFile(file, s + '\n', err => {
+ if (err) throw err;
+ });
+ };
+
+ this.logScenarioFailInfo = () => {
+ if (this.hasLoggedScenarioInfo) return;
+
+ log('=========================================');
+ log('Failed scenario: ' + this.scenarioTitle);
+ log('Time: ' + this.scenarioTime);
+ log('Fingerprint osm stage: ' + this.osmData.fingerprintOSM);
+ log('Fingerprint extract stage: ' + this.fingerprintExtract);
+ log('Fingerprint contract stage: ' + this.fingerprintContract);
+ log('Fingerprint route stage: ' + this.fingerprintRoute);
+ log('Profile: ' + this.profile);
+ log();
+ log('```xml'); // so output can be posted directly to github comment fields
+ log(this.osmData.str.trim());
+ log('```');
+ log();
+ log();
+
+ this.hasLoggedScenarioInfo = true;
+ };
+
+ this.logFail = (expected, got, attempts) => {
+ this.logScenarioFailInfo();
+ log('== ');
+ log('Expected: ' + JSON.stringify(expected));
+ log('Got: ' + JSON.stringify(got));
+ log();
+ ['route','forw','backw'].forEach((direction) => {
+ if (attempts[direction]) {
+ log('Direction: ' + direction);
+ log('Query: ' + attempts[direction].query);
+ log('Response: ' + attempts[direction].response.body);
+ log();
+ }
+ });
+ };
+
+ this.logPreprocessInfo = () => {
+ if (this.hasLoggedPreprocessInfo) return;
+ log('=========================================', 'preprocess');
+ log('Preprocessing data for scenario: ' + this.scenarioTitle, 'preprocess');
+ log('Time: ' + this.scenarioTime, 'preprocess');
+ log('', 'preprocess');
+ log('== OSM data:', 'preprocess');
+ log('```xml', 'preprocess'); // so output can be posted directly to github comment fields
+ log(this.osmData.str, 'preprocess');
+ log('```', 'preprocess');
+ log('', 'preprocess');
+ log('== Profile:', 'preprocess');
+ log(this.profile, 'preprocess');
+ log('', 'preprocess');
+ this.hasLoggedPreprocessInfo = true;
+ };
+
+ this.logPreprocess = (str) => {
+ this.logPreprocessInfo();
+ log(str, 'preprocess');
+ };
+
+ this.logPreprocessDone = () => {
+ log('Done with preprocessing at ' + new Date(), 'preprocess');
+ };
+};
diff --git a/features/support/log.rb b/features/support/log.rb
deleted file mode 100644
index 8e6f9c1..0000000
--- a/features/support/log.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-# logging
-
-PREPROCESS_LOG_FILE = 'preprocessing.log'
-LOG_FILE = 'fail.log'
-
-
-def clear_log_files
- Dir.chdir TEST_FOLDER do
- # emptying existing files, rather than deleting and writing new ones makes it
- # easier to use tail -f from the command line
- `echo '' > #{OSRM_ROUTED_LOG_FILE}`
- `echo '' > #{PREPROCESS_LOG_FILE}`
- `echo '' > #{LOG_FILE}`
- end
-end
-
-def log s='', type=nil
- if type == :preprocess
- file = PREPROCESS_LOG_FILE
- else
- file = LOG_FILE
- end
- File.open(file, 'a') {|f| f.write("#{s}\n") }
-end
-
-
-def log_scenario_fail_info
- return if @has_logged_scenario_info
- log "========================================="
- log "Failed scenario: #{@scenario_title}"
- log "Time: #{@scenario_time}"
- log "Fingerprint osm stage: #{@fingerprint_osm}"
- log "Fingerprint extract stage: #{@fingerprint_extract}"
- log "Fingerprint prepare stage: #{@fingerprint_prepare}"
- log "Fingerprint route stage: #{@fingerprint_route}"
- log "Profile: #{@profile}"
- log
- log '```xml' #so output can be posted directly to github comment fields
- log osm_str.strip
- log '```'
- log
- log
- @has_logged_scenario_info = true
-end
-
-def log_fail expected,got,attempts
- return
- log_scenario_fail_info
- log "== "
- log "Expected: #{expected}"
- log "Got: #{got}"
- log
- ['route','forw','backw'].each do |direction|
- if attempts[direction]
- attempts[direction]
- log "Direction: #{direction}"
- log "Query: #{attempts[direction][:query]}"
- log "Response: #{attempts[direction][:response].body}"
- log
- end
- end
-end
-
-
-def log_preprocess_info
- return if @has_logged_preprocess_info
- log "=========================================", :preprocess
- log "Preprocessing data for scenario: #{@scenario_title}", :preprocess
- log "Time: #{@scenario_time}", :preprocess
- log '', :preprocess
- log "== OSM data:", :preprocess
- log '```xml', :preprocess #so output can be posted directly to github comment fields
- log osm_str, :preprocess
- log '```', :preprocess
- log '', :preprocess
- log "== Profile:", :preprocess
- log @profile, :preprocess
- log '', :preprocess
- @has_logged_preprocess_info = true
-end
-
-def log_preprocess str
- log_preprocess_info
- log str, :preprocess
-end
-
-def log_preprocess_done
-end
diff --git a/features/support/osm_parser.rb b/features/support/osm_parser.rb
deleted file mode 100644
index 1da7c73..0000000
--- a/features/support/osm_parser.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require 'OSM/StreamParser'
-
-locations = nil
-
-class OSMTestParserCallbacks < OSM::Callbacks
- locations = nil
-
- def self.locations
- if locations
- locations
- else
- #parse the test file, so we can later reference nodes and ways by name in tests
- locations = {}
- file = 'test/data/test.osm'
- callbacks = OSMTestParserCallbacks.new
- parser = OSM::StreamParser.new(:filename => file, :callbacks => callbacks)
- parser.parse
- puts locations
- end
- end
-
- def node(node)
- locations[node.name] = [node.lat,node.lon]
- end
-end
\ No newline at end of file
diff --git a/features/support/osmlib.rb b/features/support/osmlib.rb
deleted file mode 100644
index 6b03dfa..0000000
--- a/features/support/osmlib.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-#monkey-patch osmlib to fix a bug
-
-module OSM
- class Way
- def to_xml(xml)
- xml.way(attributes) do
- nodes.each do |node|
- xml.nd(:ref => node)
- end
- tags.to_xml(xml)
- end
- end
- end
-end
diff --git a/features/support/route.js b/features/support/route.js
new file mode 100644
index 0000000..7c208ff
--- /dev/null
+++ b/features/support/route.js
@@ -0,0 +1,166 @@
+var Timeout = require('node-timeout');
+var request = require('request');
+
+module.exports = function () {
+ this.requestPath = (service, params, callback) => {
+ var uri;
+ if (service == 'timestamp') {
+ uri = [this.HOST, service].join('/');
+ } else {
+ uri = [this.HOST, service, 'v1', this.profile].join('/');
+ }
+
+ return this.sendRequest(uri, params, callback);
+ };
+
+ this.requestUrl = (path, callback) => {
+ var uri = this.query = [this.HOST, path].join('/'),
+ limit = Timeout(this.OSRM_TIMEOUT, { err: { statusCode: 408 } });
+
+ function runRequest (cb) {
+ request(uri, cb);
+ }
+
+ runRequest(limit((err, res, body) => {
+ if (err) {
+ if (err.statusCode === 408) return callback(this.RoutedError('*** osrm-routed did not respond'));
+ else if (err.code === 'ECONNREFUSED')
+ return callback(this.RoutedError('*** osrm-routed is not running'));
+ } else
+ return callback(err, res, body);
+ }));
+ };
+
+ // Overwrites the default values in defaults
+ // e.g. [[a, 1], [b, 2]], [[a, 5], [d, 10]] => [[a, 5], [b, 2], [d, 10]]
+ this.overwriteParams = (defaults, other) => {
+ var otherMap = {};
+ for (var key in other) otherMap[key] = other[key];
+ return Object.assign({}, defaults, otherMap);
+ };
+
+ var encodeWaypoints = (waypoints) => {
+ return waypoints.map(w => [w.lon, w.lat].map(this.ensureDecimal).join(','));
+ };
+
+ this.requestRoute = (waypoints, bearings, userParams, callback) => {
+ if (bearings.length && bearings.length !== waypoints.length) throw new Error('*** number of bearings does not equal the number of waypoints');
+
+ var defaults = {
+ output: 'json',
+ steps: 'true',
+ alternatives: 'false'
+ },
+ params = this.overwriteParams(defaults, userParams),
+ encodedWaypoints = encodeWaypoints(waypoints);
+
+ params.coordinates = encodedWaypoints;
+
+ if (bearings.length) {
+ params.bearings = bearings.map(b => {
+ var bs = b.split(',');
+ if (bs.length === 2) return b;
+ else return b += ',10';
+ }).join(';');
+ }
+
+ return this.requestPath('route', params, callback);
+ };
+
+ this.requestNearest = (node, userParams, callback) => {
+ var defaults = {
+ output: 'json'
+ },
+ params = this.overwriteParams(defaults, userParams);
+ params.coordinates = [[node.lon, node.lat].join(',')];
+
+ return this.requestPath('nearest', params, callback);
+ };
+
+ this.requestTable = (waypoints, userParams, callback) => {
+ var defaults = {
+ output: 'json'
+ },
+ params = this.overwriteParams(defaults, userParams);
+
+ params.coordinates = waypoints.map(w => [w.coord.lon, w.coord.lat].join(','));
+ var srcs = waypoints.map((w, i) => [w.type, i]).filter(w => w[0] === 'src').map(w => w[1]),
+ dsts = waypoints.map((w, i) => [w.type, i]).filter(w => w[0] === 'dst').map(w => w[1]);
+ if (srcs.length) params.sources = srcs.join(';');
+ if (dsts.length) params.destinations = dsts.join(';');
+
+ return this.requestPath('table', params, callback);
+ };
+
+ this.requestTrip = (waypoints, userParams, callback) => {
+ var defaults = {
+ output: 'json'
+ },
+ params = this.overwriteParams(defaults, userParams);
+
+ params.coordinates = encodeWaypoints(waypoints);
+
+ return this.requestPath('trip', params, callback);
+ };
+
+ this.requestMatching = (waypoints, timestamps, userParams, callback) => {
+ var defaults = {
+ output: 'json'
+ },
+ params = this.overwriteParams(defaults, userParams);
+
+ params.coordinates = encodeWaypoints(waypoints);
+
+ if (timestamps.length) {
+ params.timestamps = timestamps.join(';');
+ }
+
+ return this.requestPath('match', params, callback);
+ };
+
+ this.extractInstructionList = (instructions, keyFinder, postfix) => {
+ postfix = postfix || null;
+ if (instructions) {
+ return instructions.legs.reduce((m, v) => m.concat(v.steps), [])
+ .map(keyFinder)
+ .join(',');
+ }
+ };
+
+ this.wayList = (instructions) => {
+ return this.extractInstructionList(instructions, s => s.name);
+ };
+
+ this.bearingList = (instructions) => {
+ return this.extractInstructionList(instructions, s => s.maneuver.bearing_after);
+ };
+
+ this.turnList = (instructions) => {
+ return instructions.legs.reduce((m, v) => m.concat(v.steps), [])
+ .map(v => {
+ switch (v.maneuver.type) {
+ case 'depart':
+ case 'arrive':
+ return v.maneuver.type;
+ case 'roundabout':
+ return 'roundabout-exit-' + v.maneuver.exit;
+ // FIXME this is a little bit over-simplistic for merge/fork instructions
+ default:
+ return v.maneuver.modifier;
+ }
+ })
+ .join(',');
+ };
+
+ this.modeList = (instructions) => {
+ return this.extractInstructionList(instructions, s => s.mode);
+ };
+
+ this.timeList = (instructions) => {
+ return this.extractInstructionList(instructions, s => s.duration + 's');
+ };
+
+ this.distanceList = (instructions) => {
+ return this.extractInstructionList(instructions, s => s.distance + 'm');
+ };
+};
diff --git a/features/support/route.rb b/features/support/route.rb
deleted file mode 100644
index 935c5be..0000000
--- a/features/support/route.rb
+++ /dev/null
@@ -1,181 +0,0 @@
-require 'net/http'
-
-HOST = "http://127.0.0.1:#{OSRM_PORT}"
-DESTINATION_REACHED = 15 #OSRM instruction code
-
-def request_path service, params
- uri = "#{HOST}/" + service
- response = send_request uri, params
- return response
-end
-
-def request_url path
- uri = URI.parse"#{HOST}/#{path}"
- @query = uri.to_s
- Timeout.timeout(OSRM_TIMEOUT) do
- Net::HTTP.get_response uri
- end
-rescue Errno::ECONNREFUSED => e
- raise "*** osrm-routed is not running."
-rescue Timeout::Error
- raise "*** osrm-routed did not respond."
-end
-
-# Overwriters the default values in defaults.
-# e.g. [[a, 1], [b, 2]], [[a, 5], [d, 10]] => [[a, 5], [b, 2], [d, 10]]
-def overwrite_params defaults, other
- merged = []
- defaults.each do |k,v|
- idx = other.index { |p| p[0] == k }
- if idx == nil then
- merged << [k, v]
- else
- merged << [k, other[idx][1]]
- end
- end
- other.each do |k,v|
- if merged.index { |pair| pair[0] == k} == nil then
- merged << [k, v]
- end
- end
-
- return merged
-end
-
-def request_route waypoints, bearings, user_params
- raise "*** number of bearings does not equal the number of waypoints" unless bearings.size == 0 || bearings.size == waypoints.size
-
- defaults = [['output','json'], ['instructions',true], ['alt',false]]
- params = overwrite_params defaults, user_params
- encoded_waypoint = waypoints.map{ |w| ["loc","#{w.lat},#{w.lon}"] }
- if bearings.size > 0
- encoded_bearings = bearings.map { |b| ["b", b.to_s]}
- parasm = params.concat encoded_waypoint.zip(encoded_bearings).flatten! 1
- else
- params = params.concat encoded_waypoint
- end
-
- return request_path "viaroute", params
-end
-
-def request_nearest node, user_params
- defaults = [['output', 'json']]
- params = overwrite_params defaults, user_params
- params << ["loc", "#{node.lat},#{node.lon}"]
-
- return request_path "nearest", params
-end
-
-def request_table waypoints, user_params
- defaults = [['output', 'json']]
- params = overwrite_params defaults, user_params
- params = params.concat waypoints.map{ |w| [w[:type],"#{w[:coord].lat},#{w[:coord].lon}"] }
-
- return request_path "table", params
-end
-
-def request_trip waypoints, user_params
- defaults = [['output', 'json']]
- params = overwrite_params defaults, user_params
- params = params.concat waypoints.map{ |w| ["loc","#{w.lat},#{w.lon}"] }
-
- return request_path "trip", params
-end
-
-def request_matching waypoints, timestamps, user_params
- defaults = [['output', 'json']]
- params = overwrite_params defaults, user_params
- encoded_waypoint = waypoints.map{ |w| ["loc","#{w.lat},#{w.lon}"] }
- if timestamps.size > 0
- encoded_timestamps = timestamps.map { |t| ["t", t.to_s]}
- parasm = params.concat encoded_waypoint.zip(encoded_timestamps).flatten! 1
- else
- params = params.concat encoded_waypoint
- end
-
- return request_path "match", params
-end
-
-def got_route? response
- if response.code == "200" && !response.body.empty?
- json = JSON.parse response.body
- if json['status'] == 200
- return way_list( json['route_instructions']).empty? == false
- end
- end
- return false
-end
-
-def route_status response
- if response.code == "200" && !response.body.empty?
- json = JSON.parse response.body
- return json['status']
- else
- "HTTP #{response.code}"
- end
-end
-
-def extract_instruction_list instructions, index, postfix=nil
- if instructions
- instructions.reject { |r| r[0].to_s=="#{DESTINATION_REACHED}" }.
- map { |r| r[index] }.
- map { |r| (r=="" || r==nil) ? '""' : "#{r}#{postfix}" }.
- join(',')
- end
-end
-
-def way_list instructions
- extract_instruction_list instructions, 1
-end
-
-def compass_list instructions
- extract_instruction_list instructions, 6
-end
-
-def bearing_list instructions
- extract_instruction_list instructions, 7
-end
-
-def turn_list instructions
- if instructions
- types = {
- 0 => :none,
- 1 => :straight,
- 2 => :slight_right,
- 3 => :right,
- 4 => :sharp_right,
- 5 => :u_turn,
- 6 => :sharp_left,
- 7 => :left,
- 8 => :slight_left,
- 9 => :via,
- 10 => :head,
- 11 => :enter_roundabout,
- 12 => :leave_roundabout,
- 13 => :stay_roundabout,
- 14 => :start_end_of_street,
- 15 => :destination,
- 16 => :enter_contraflow,
- 17 => :leave_contraflow
- }
- # replace instructions codes with strings
- # "11-3" (enter roundabout and leave a 3rd exit) gets converted to "enter_roundabout-3"
- instructions.map do |r|
- r[0].to_s.gsub(/^\d*/) do |match|
- types[match.to_i].to_s
- end
- end.join(',')
- end
-end
-
-def mode_list instructions
- extract_instruction_list instructions, 8
-end
-
-def time_list instructions
- extract_instruction_list instructions, 4, "s"
-end
-
-def distance_list instructions
- extract_instruction_list instructions, 2, "m"
-end
diff --git a/features/support/run.js b/features/support/run.js
new file mode 100644
index 0000000..cede245
--- /dev/null
+++ b/features/support/run.js
@@ -0,0 +1,40 @@
+var fs = require('fs');
+var util = require('util');
+var exec = require('child_process').exec;
+
+module.exports = function () {
+ this.runBin = (bin, options, callback) => {
+ var opts = options.slice();
+
+ if (opts.match('{osm_base}')) {
+ if (!this.osmData.osmFile) throw new Error('*** {osm_base} is missing');
+ opts = opts.replace('{osm_base}', this.osmData.osmFile);
+ }
+
+ if (opts.match('{extracted_base}')) {
+ if (!this.osmData.extractedFile) throw new Error('*** {extracted_base} is missing');
+ opts = opts.replace('{extracted_base}', this.osmData.extractedFile);
+ }
+
+ if (opts.match('{contracted_base}')) {
+ if (!this.osmData.contractedFile) throw new Error('*** {contracted_base} is missing');
+ opts = opts.replace('{contracted_base}', this.osmData.contractedFile);
+ }
+
+ if (opts.match('{profile}')) {
+ opts = opts.replace('{profile}', [this.PROFILES_PATH, this.profile + '.lua'].join('/'));
+ }
+
+ var cmd = util.format('%s%s%s/%s%s%s %s 2>%s', this.QQ, this.LOAD_LIBRARIES, this.BIN_PATH, bin, this.EXE, this.QQ, opts, this.ERROR_LOG_FILE);
+ process.chdir(this.TEST_FOLDER);
+ exec(cmd, (err, stdout, stderr) => {
+ this.stdout = stdout.toString();
+ fs.readFile(this.ERROR_LOG_FILE, (e, data) => {
+ this.stderr = data ? data.toString() : '';
+ this.exitCode = err && err.code || 0;
+ process.chdir('../');
+ callback(err, stdout, stderr);
+ });
+ });
+ };
+};
diff --git a/features/support/run.rb b/features/support/run.rb
deleted file mode 100644
index 42dc597..0000000
--- a/features/support/run.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-def run_bin bin, options
- Dir.chdir TEST_FOLDER do
- opt = options.dup
-
- if opt.include? '{osm_base}'
- raise "*** {osm_base} is missing" unless osm_file
- opt.gsub! "{osm_base}", "#{osm_file}"
- end
-
- if opt.include? '{extracted_base}'
- raise "*** {extracted_base} is missing" unless extracted_file
- opt.gsub! "{extracted_base}", "#{extracted_file}"
- end
-
- if opt.include? '{prepared_base}'
- raise "*** {prepared_base} is missing" unless prepared_file
- opt.gsub! "{prepared_base}", "#{prepared_file}"
- end
- if opt.include? '{profile}'
- opt.gsub! "{profile}", "#{PROFILES_PATH}/#{@profile}.lua"
- end
-
- cmd = "#{QQ}#{BIN_PATH}/#{bin}#{EXE}#{QQ} #{opt} 2>error.log"
- @stdout = `#{cmd}`
- @stderr = File.read 'error.log'
- @exit_code = $?.exitstatus
- end
-end
\ No newline at end of file
diff --git a/features/support/shared_steps.js b/features/support/shared_steps.js
new file mode 100644
index 0000000..5751492
--- /dev/null
+++ b/features/support/shared_steps.js
@@ -0,0 +1,202 @@
+var util = require('util');
+var assert = require('assert');
+
+module.exports = function () {
+ this.ShouldGetAResponse = () => {
+ assert.equal(this.response.statusCode, 200);
+ assert.ok(this.response.body);
+ assert.ok(this.response.body.length);
+ };
+
+ this.ShouldBeValidJSON = (callback) => {
+ try {
+ this.json = JSON.parse(this.response.body);
+ callback();
+ } catch (e) {
+ callback(e);
+ }
+ };
+
+ this.ShouldBeWellFormed = () => {
+ assert.equal(typeof this.json.status, 'number');
+ };
+
+ this.WhenIRouteIShouldGet = (table, callback) => {
+ this.reprocessAndLoadData(() => {
+ var headers = new Set(table.raw()[0]);
+
+ var requestRow = (row, ri, cb) => {
+ var got;
+
+ var afterRequest = (err, res, body) => {
+ if (err) return cb(err);
+ if (body && body.length) {
+ var instructions, bearings, turns, modes, times, distances;
+
+ var json = JSON.parse(body);
+
+ var hasRoute = json.code === 'ok';
+
+ if (hasRoute) {
+ instructions = this.wayList(json.routes[0]);
+ bearings = this.bearingList(json.routes[0]);
+ turns = this.turnList(json.routes[0]);
+ modes = this.modeList(json.routes[0]);
+ times = this.timeList(json.routes[0]);
+ distances = this.distanceList(json.routes[0]);
+ }
+
+ if (headers.has('status')) {
+ got.status = res.statusCode.toString();
+ }
+
+ if (headers.has('message')) {
+ got.message = json.message || '';
+ }
+
+ if (headers.has('#')) {
+ // comment column
+ got['#'] = row['#'];
+ }
+
+ if (headers.has('start')) {
+ got.start = instructions ? json.route_summary.start_point : null;
+ }
+
+ if (headers.has('end')) {
+ got.end = instructions ? json.route_summary.end_point : null;
+ }
+
+ if (headers.has('geometry')) {
+ got.geometry = json.routes[0].geometry;
+ }
+
+ if (headers.has('route')) {
+ got.route = (instructions || '').trim();
+
+ if (headers.has('alternative')) {
+ // TODO examine more than first alternative?
+ got.alternative ='';
+ if (json.routes && json.routes.length > 1)
+ got.alternative = this.wayList(json.routes[1]);
+ }
+
+ var distance = hasRoute && json.routes[0].distance,
+ time = hasRoute && json.routes[0].duration;
+
+ if (headers.has('distance')) {
+ if (row.distance.length) {
+ if (!row.distance.match(/\d+m/))
+ throw new Error('*** Distance must be specified in meters. (ex: 250m)');
+ got.distance = instructions ? util.format('%dm', distance) : '';
+ } else {
+ got.distance = '';
+ }
+ }
+
+ if (headers.has('time')) {
+ if (!row.time.match(/\d+s/))
+ throw new Error('*** Time must be specied in seconds. (ex: 60s)');
+ got.time = instructions ? util.format('%ds', time) : '';
+ }
+
+ if (headers.has('speed')) {
+ if (row.speed !== '' && instructions) {
+ if (!row.speed.match(/\d+ km\/h/))
+ throw new Error('*** Speed must be specied in km/h. (ex: 50 km/h)');
+ var speed = time > 0 ? Math.round(3.6*distance/time) : null;
+ got.speed = util.format('%d km/h', speed);
+ } else {
+ got.speed = '';
+ }
+ }
+
+ var putValue = (key, value) => {
+ if (headers.has(key)) got[key] = instructions ? value : '';
+ };
+
+ putValue('bearing', bearings);
+ putValue('turns', turns);
+ putValue('modes', modes);
+ putValue('times', times);
+ putValue('distances', distances);
+ }
+
+ var ok = true;
+
+ for (var key in row) {
+ if (this.FuzzyMatch.match(got[key], row[key])) {
+ got[key] = row[key];
+ } else {
+ ok = false;
+ }
+ }
+
+ if (!ok) {
+ this.logFail(row, got, { route: { query: this.query, response: res }});
+ }
+
+ cb(null, got);
+ } else {
+ cb(new Error('request failed to return valid body'));
+ }
+ };
+
+ if (headers.has('request')) {
+ got = { request: row.request };
+ this.requestUrl(row.request, afterRequest);
+ } else {
+ var defaultParams = this.queryParams;
+ var userParams = [];
+ got = {};
+ for (var k in row) {
+ var match = k.match(/param:(.*)/);
+ if (match) {
+ if (row[k] === '(nil)') {
+ userParams.push([match[1], null]);
+ } else if (row[k]) {
+ userParams.push([match[1], row[k]]);
+ }
+ got[k] = row[k];
+ }
+ }
+
+ var params = this.overwriteParams(defaultParams, userParams),
+ waypoints = [],
+ bearings = [];
+
+ if (row.bearings) {
+ got.bearings = row.bearings;
+ bearings = row.bearings.split(' ').filter(b => !!b);
+ }
+
+ if (row.from && row.to) {
+ var fromNode = this.findNodeByName(row.from);
+ if (!fromNode) throw new Error(util.format('*** unknown from-node "%s"'), row.from);
+ waypoints.push(fromNode);
+
+ var toNode = this.findNodeByName(row.to);
+ if (!toNode) throw new Error(util.format('*** unknown to-node "%s"'), row.to);
+ waypoints.push(toNode);
+
+ got.from = row.from;
+ got.to = row.to;
+ this.requestRoute(waypoints, bearings, params, afterRequest);
+ } else if (row.waypoints) {
+ row.waypoints.split(',').forEach((n) => {
+ var node = this.findNodeByName(n.trim());
+ if (!node) throw new Error('*** unknown waypoint node "%s"', n.trim());
+ waypoints.push(node);
+ });
+ got.waypoints = row.waypoints;
+ this.requestRoute(waypoints, bearings, params, afterRequest);
+ } else {
+ throw new Error('*** no waypoints');
+ }
+ }
+ };
+
+ this.processRowsAndDiff(table, requestRow, callback);
+ });
+ };
+};
diff --git a/features/support/shortcuts.rb b/features/support/shortcuts.rb
deleted file mode 100644
index 20bc3c0..0000000
--- a/features/support/shortcuts.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-def shortcuts_hash
- @shortcuts_hash ||= {}
-end
diff --git a/features/support/table_patch.js b/features/support/table_patch.js
new file mode 100644
index 0000000..16ffebb
--- /dev/null
+++ b/features/support/table_patch.js
@@ -0,0 +1,11 @@
+var DifferentError = require('./exception_classes').TableDiffError;
+
+module.exports = function () {
+ this.diffTables = (expected, actual, options, callback) => {
+ // this is a temp workaround while waiting for https://github.com/cucumber/cucumber-js/issues/534
+
+ var error = new DifferentError(expected, actual);
+
+ return callback(error.string);
+ };
+};
diff --git a/features/testbot/64bit.feature b/features/testbot/64bit.feature
index d2d0c8a..83ca884 100644
--- a/features/testbot/64bit.feature
+++ b/features/testbot/64bit.feature
@@ -19,5 +19,5 @@ Feature: Support 64bit node IDs
| cdec |
When I route I should get
- | from | to | route | turns |
- | x | y | abc | head,destination |
+ | from | to | route | turns |
+ | x | y | abc,abc | depart,arrive |
diff --git a/features/testbot/alternative.feature b/features/testbot/alternative.feature
index d6ca030..4031631 100644
--- a/features/testbot/alternative.feature
+++ b/features/testbot/alternative.feature
@@ -6,7 +6,7 @@ Feature: Alternative route
And the node map
| | b | c | d | | |
- | a | | | | | z |
+ | a | | k | | | z |
| | g | h | i | j | |
And the ways
@@ -20,19 +20,21 @@ Feature: Alternative route
| hi |
| ij |
| jz |
+ | ck |
+ | kh |
Scenario: Enabled alternative
Given the query options
- | alt | true |
+ | alternatives | true |
When I route I should get
- | from | to | route | alternative |
- | a | z | ab,bc,cd,dz | ag,gh,hi,ij,jz |
+ | from | to | route | alternative |
+ | a | z | ab,bc,cd,dz,dz | ag,gh,hi,ij,jz,jz |
Scenario: Disabled alternative
Given the query options
- | alt | false |
+ | alternatives | false |
When I route I should get
- | from | to | route | alternative |
- | a | z | ab,bc,cd,dz | |
+ | from | to | route | alternative |
+ | a | z | ab,bc,cd,dz,dz | |
diff --git a/features/testbot/alternative_loop.feature b/features/testbot/alternative_loop.feature
new file mode 100644
index 0000000..159a399
--- /dev/null
+++ b/features/testbot/alternative_loop.feature
@@ -0,0 +1,29 @@
+ at routing @testbot @alternative
+Feature: Alternative route
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Alternative Loop Paths
+ Given the node map
+ | a | 2 | 1 | b |
+ | 7 | | | 4 |
+ | 8 | | | 3 |
+ | c | 5 | 6 | d |
+
+ And the ways
+ | nodes | oneway |
+ | ab | yes |
+ | bd | yes |
+ | dc | yes |
+ | ca | yes |
+
+ And the query options
+ | alternatives | true |
+
+ When I route I should get
+ | from | to | route | alternative |
+ | 1 | 2 | ab,bd,dc,ca,ab,ab | |
+ | 3 | 4 | bd,dc,ca,ab,bd,bd | |
+ | 5 | 6 | dc,ca,ab,bd,dc,dc | |
+ | 7 | 8 | ca,ab,bd,dc,ca,ca | |
diff --git a/features/testbot/bad.feature b/features/testbot/bad.feature
index d7e3c95..18ee5f8 100644
--- a/features/testbot/bad.feature
+++ b/features/testbot/bad.feature
@@ -11,7 +11,7 @@ Feature: Handle bad data in a graceful manner
Given the ways
| nodes |
- When the data has been prepared
+ When the data has been contracted
Then "osrm-extract" should return code 1
Scenario: Only dead-end oneways
@@ -23,8 +23,8 @@ Feature: Handle bad data in a graceful manner
| abcde | yes |
When I route I should get
- | from | to | route |
- | b | d | abcde |
+ | from | to | route |
+ | b | d | abcde,abcde |
@todo
Scenario: Start/end point at the same location
@@ -78,7 +78,7 @@ Feature: Handle bad data in a graceful manner
# | b | c | cd |
# | a | d | cd |
# | c | d | cd |
- | d | e | de |
+ | d | e | de,de |
# | k | l | kl |
# | l | m | lm |
# | o | l | lm |
diff --git a/features/testbot/basic.feature b/features/testbot/basic.feature
index 599b062..c2f969d 100644
--- a/features/testbot/basic.feature
+++ b/features/testbot/basic.feature
@@ -14,9 +14,9 @@ Feature: Basic Routing
| ab |
When I route I should get
- | from | to | route |
- | a | b | ab |
- | b | a | ab |
+ | from | to | route |
+ | a | b | ab,ab |
+ | b | a | ab,ab |
Scenario: Routing in between two nodes of way
Given the node map
@@ -27,9 +27,9 @@ Feature: Basic Routing
| abcd |
When I route I should get
- | from | to | route |
- | 1 | 2 | abcd |
- | 2 | 1 | abcd |
+ | from | to | route |
+ | 1 | 2 | abcd,abcd |
+ | 2 | 1 | abcd,abcd |
Scenario: Routing between the middle nodes of way
Given the node map
@@ -40,19 +40,19 @@ Feature: Basic Routing
| abcdef |
When I route I should get
- | from | to | route |
- | b | c | abcdef |
- | b | d | abcdef |
- | b | e | abcdef |
- | c | b | abcdef |
- | c | d | abcdef |
- | c | e | abcdef |
- | d | b | abcdef |
- | d | c | abcdef |
- | d | e | abcdef |
- | e | b | abcdef |
- | e | c | abcdef |
- | e | d | abcdef |
+ | from | to | route |
+ | b | c | abcdef,abcdef |
+ | b | d | abcdef,abcdef |
+ | b | e | abcdef,abcdef |
+ | c | b | abcdef,abcdef |
+ | c | d | abcdef,abcdef |
+ | c | e | abcdef,abcdef |
+ | d | b | abcdef,abcdef |
+ | d | c | abcdef,abcdef |
+ | d | e | abcdef,abcdef |
+ | e | b | abcdef,abcdef |
+ | e | c | abcdef,abcdef |
+ | e | d | abcdef,abcdef |
Scenario: Two ways connected in a straight line
Given the node map
@@ -64,13 +64,13 @@ Feature: Basic Routing
| bc |
When I route I should get
- | from | to | route |
- | a | c | ab,bc |
- | c | a | bc,ab |
- | a | b | ab |
- | b | a | ab |
- | b | c | bc |
- | c | b | bc |
+ | from | to | route |
+ | a | c | ab,bc,bc |
+ | c | a | bc,ab,ab |
+ | a | b | ab,ab |
+ | b | a | ab,ab |
+ | b | c | bc,bc |
+ | c | b | bc,bc |
Scenario: 2 unconnected parallel ways
Given the node map
@@ -83,33 +83,33 @@ Feature: Basic Routing
| def |
When I route I should get
- | from | to | route |
- | a | b | abc |
- | b | a | abc |
- | b | c | abc |
- | c | b | abc |
- | d | e | def |
- | e | d | def |
- | e | f | def |
- | f | e | def |
- | a | d | |
- | d | a | |
- | b | d | |
- | d | b | |
- | c | d | |
- | d | c | |
- | a | e | |
- | e | a | |
- | b | e | |
- | e | b | |
- | c | e | |
- | e | c | |
- | a | f | |
- | f | a | |
- | b | f | |
- | f | b | |
- | c | f | |
- | f | c | |
+ | from | to | route |
+ | a | b | abc,abc |
+ | b | a | abc,abc |
+ | b | c | abc,abc |
+ | c | b | abc,abc |
+ | d | e | def,def |
+ | e | d | def,def |
+ | e | f | def,def |
+ | f | e | def,def |
+ | a | d | |
+ | d | a | |
+ | b | d | |
+ | d | b | |
+ | c | d | |
+ | d | c | |
+ | a | e | |
+ | e | a | |
+ | b | e | |
+ | e | b | |
+ | c | e | |
+ | e | c | |
+ | a | f | |
+ | f | a | |
+ | b | f | |
+ | f | b | |
+ | c | f | |
+ | f | c | |
Scenario: 3 ways connected in a triangle
Given the node map
@@ -124,13 +124,13 @@ Feature: Basic Routing
| ca |
When I route I should get
- | from | to | route |
- | a | b | ab |
- | a | c | ca |
- | b | c | bc |
- | b | a | ab |
- | c | a | ca |
- | c | b | bc |
+ | from | to | route |
+ | a | b | ab,ab |
+ | a | c | ca,ca |
+ | b | c | bc,bc |
+ | b | a | ab,ab |
+ | c | a | ca,ca |
+ | c | b | bc,bc |
Scenario: 3 connected triangles
Given a grid size of 100 meters
@@ -157,12 +157,12 @@ Feature: Basic Routing
When I route I should get
| from | to | route |
- | a | b | ab |
- | a | c | ca |
- | b | c | bc |
- | b | a | ab |
- | c | a | ca |
- | c | b | bc |
+ | a | b | ab,ab |
+ | a | c | ca,ca |
+ | b | c | bc,bc |
+ | b | a | ab,ab |
+ | c | a | ca,ca |
+ | c | b | bc,bc |
Scenario: To ways connected at a 45 degree angle
Given the node map
@@ -176,13 +176,13 @@ Feature: Basic Routing
| cde |
When I route I should get
- | from | to | route |
- | b | d | abc,cde |
- | a | e | abc,cde |
- | a | c | abc |
- | c | a | abc |
- | c | e | cde |
- | e | c | cde |
+ | from | to | route |
+ | b | d | abc,cde,cde |
+ | a | e | abc,cde,cde |
+ | a | c | abc,abc |
+ | c | a | abc,abc |
+ | c | e | cde,cde |
+ | e | c | cde,cde |
Scenario: Grid city center
Given the node map
@@ -203,11 +203,11 @@ Feature: Basic Routing
| dhlp |
When I route I should get
- | from | to | route |
- | f | g | efgh |
- | g | f | efgh |
- | f | j | bfjn |
- | j | f | bfjn |
+ | from | to | route |
+ | f | g | efgh,efgh |
+ | g | f | efgh,efgh |
+ | f | j | bfjn,bfjn |
+ | j | f | bfjn,bfjn |
Scenario: Grid city periphery
Given the node map
@@ -228,11 +228,11 @@ Feature: Basic Routing
| dhlp |
When I route I should get
- | from | to | route |
- | a | d | abcd |
- | d | a | abcd |
- | a | m | aeim |
- | m | a | aeim |
+ | from | to | route |
+ | a | d | abcd,abcd |
+ | d | a | abcd,abcd |
+ | a | m | aeim,aeim |
+ | m | a | aeim,aeim |
Scenario: Testbot - Triangle challenge
Given the node map
@@ -249,5 +249,5 @@ Feature: Basic Routing
When I route I should get
| from | to | route |
- | d | c | de,ce |
- | e | d | de |
+ | d | c | de,ce,ce |
+ | e | d | de,de |
diff --git a/features/testbot/bearing.feature b/features/testbot/bearing.feature
index 9b3dc4e..76a2819 100644
--- a/features/testbot/bearing.feature
+++ b/features/testbot/bearing.feature
@@ -14,8 +14,8 @@ Feature: Compass bearing
| ab |
When I route I should get
- | from | to | route | compass | bearing |
- | a | b | ab | NW | 315 |
+ | from | to | route | bearing |
+ | a | b | ab,ab | 315,0 |
Scenario: Bearing when going west
Given the node map
@@ -26,8 +26,8 @@ Feature: Compass bearing
| ab |
When I route I should get
- | from | to | route | compass | bearing |
- | a | b | ab | W | 270 |
+ | from | to | route | bearing |
+ | a | b | ab,ab | 270,0 |
Scenario: Bearing af 45 degree intervals
Given the node map
@@ -47,15 +47,15 @@ Feature: Compass bearing
| xh |
When I route I should get
- | from | to | route | compass | bearing |
- | x | a | xa | N | 0 |
- | x | b | xb | NW | 315 |
- | x | c | xc | W | 270 |
- | x | d | xd | SW | 225 |
- | x | e | xe | S | 180 |
- | x | f | xf | SE | 135 |
- | x | g | xg | E | 90 |
- | x | h | xh | NE | 45 |
+ | from | to | route | bearing |
+ | x | a | xa,xa | 0,0 |
+ | x | b | xb,xb | 315,0 |
+ | x | c | xc,xc | 270,0 |
+ | x | d | xd,xd | 225,0 |
+ | x | e | xe,xe | 180,0 |
+ | x | f | xf,xf | 135,0 |
+ | x | g | xg,xg | 90,0 |
+ | x | h | xh,xh | 45,0 |
Scenario: Bearing in a roundabout
Given the node map
@@ -76,9 +76,9 @@ Feature: Compass bearing
| ha | yes |
When I route I should get
- | from | to | route | compass | bearing |
- | c | b | cd,de,ef,fg,gh,ha,ab | W,SW,S,SE,E,NE,N | 270,225,180,135,90,45,0 |
- | g | f | gh,ha,ab,bc,cd,de,ef | E,NE,N,NW,W,SW,S | 90,45,0,315,270,225,180 |
+ | from | to | route | bearing |
+ | c | b | cd,de,ef,fg,gh,ha,ab,ab | 270,225,180,135,90,45,0,0 |
+ | g | f | gh,ha,ab,bc,cd,de,ef,ef | 90,45,0,315,270,225,180,0 |
Scenario: Bearing should stay constant when zig-zagging
Given the node map
@@ -96,8 +96,8 @@ Feature: Compass bearing
| gh |
When I route I should get
- | from | to | route | compass | bearing |
- | a | h | ab,bc,cd,de,ef,fg,gh | N,SE,N,SE,N,SE,N | 0,135,0,135,0,135,0 |
+ | from | to | route | bearing |
+ | a | h | ab,bc,cd,de,ef,fg,gh,gh | 0,135,0,135,0,135,0,0 |
Scenario: Bearings on an east-west way.
Given the node map
@@ -108,37 +108,37 @@ Feature: Compass bearing
| abcdef |
When I route I should get
- | from | to | route | compass | bearing |
- | a | b | abcdef | E | 90 |
- | a | c | abcdef | E | 90 |
- | a | d | abcdef | E | 90 |
- | a | e | abcdef | E | 90 |
- | a | f | abcdef | E | 90 |
- | b | a | abcdef | W | 270 |
- | b | c | abcdef | E | 90 |
- | b | d | abcdef | E | 90 |
- | b | e | abcdef | E | 90 |
- | b | f | abcdef | E | 90 |
- | c | a | abcdef | W | 270 |
- | c | b | abcdef | W | 270 |
- | c | d | abcdef | E | 90 |
- | c | e | abcdef | E | 90 |
- | c | f | abcdef | E | 90 |
- | d | a | abcdef | W | 270 |
- | d | b | abcdef | W | 270 |
- | d | c | abcdef | W | 270 |
- | d | e | abcdef | E | 90 |
- | d | f | abcdef | E | 90 |
- | e | a | abcdef | W | 270 |
- | e | b | abcdef | W | 270 |
- | e | c | abcdef | W | 270 |
- | e | d | abcdef | W | 270 |
- | e | f | abcdef | E | 90 |
- | f | a | abcdef | W | 270 |
- | f | b | abcdef | W | 270 |
- | f | c | abcdef | W | 270 |
- | f | d | abcdef | W | 270 |
- | f | e | abcdef | W | 270 |
+ | from | to | route | bearing |
+ | a | b | abcdef,abcdef | 90,0 |
+ | a | c | abcdef,abcdef | 90,0 |
+ | a | d | abcdef,abcdef | 90,0 |
+ | a | e | abcdef,abcdef | 90,0 |
+ | a | f | abcdef,abcdef | 90,0 |
+ | b | a | abcdef,abcdef | 270,0 |
+ | b | c | abcdef,abcdef | 90,0 |
+ | b | d | abcdef,abcdef | 90,0 |
+ | b | e | abcdef,abcdef | 90,0 |
+ | b | f | abcdef,abcdef | 90,0 |
+ | c | a | abcdef,abcdef | 270,0 |
+ | c | b | abcdef,abcdef | 270,0 |
+ | c | d | abcdef,abcdef | 90,0 |
+ | c | e | abcdef,abcdef | 90,0 |
+ | c | f | abcdef,abcdef | 90,0 |
+ | d | a | abcdef,abcdef | 270,0 |
+ | d | b | abcdef,abcdef | 270,0 |
+ | d | c | abcdef,abcdef | 270,0 |
+ | d | e | abcdef,abcdef | 90,0 |
+ | d | f | abcdef,abcdef | 90,0 |
+ | e | a | abcdef,abcdef | 270,0 |
+ | e | b | abcdef,abcdef | 270,0 |
+ | e | c | abcdef,abcdef | 270,0 |
+ | e | d | abcdef,abcdef | 270,0 |
+ | e | f | abcdef,abcdef | 90,0 |
+ | f | a | abcdef,abcdef | 270,0 |
+ | f | b | abcdef,abcdef | 270,0 |
+ | f | c | abcdef,abcdef | 270,0 |
+ | f | d | abcdef,abcdef | 270,0 |
+ | f | e | abcdef,abcdef | 270,0 |
Scenario: Bearings at high latitudes
# The coordinas below was calculated using http://www.movable-type.co.uk/scripts/latlong.html,
@@ -161,19 +161,19 @@ Feature: Compass bearing
| bd |
When I route I should get
- | from | to | route | compass | bearing |
- | a | b | ab | N | 0 |
- | b | c | bc | E | 90 |
- | c | d | cd | S | 180 |
- | d | a | da | W | 270 |
- | b | a | ab | S | 180 |
- | c | b | bc | W | 270 |
- | d | c | cd | N | 0 |
- | a | d | da | E | 90 |
- | a | c | ac | NE | 45 |
- | c | a | ac | SW | 225 |
- | b | d | bd | SE | 135 |
- | d | b | bd | NW | 315 |
+ | from | to | route | bearing |
+ | a | b | ab,ab | 0,0 |
+ | b | c | bc,bc | 90,0 |
+ | c | d | cd,cd | 180,0 |
+ | d | a | da,da | 270,0 |
+ | b | a | ab,ab | 180,0 |
+ | c | b | bc,bc | 270,0 |
+ | d | c | cd,cd | 0,0 |
+ | a | d | da,da | 90,0 |
+ | a | c | ac,ac | 45,0 |
+ | c | a | ac,ac | 225,0 |
+ | b | d | bd,bd | 135,0 |
+ | d | b | bd,bd | 315,0 |
Scenario: Bearings at high negative latitudes
# The coordinas below was calculated using http://www.movable-type.co.uk/scripts/latlong.html,
@@ -196,16 +196,16 @@ Feature: Compass bearing
| bd |
When I route I should get
- | from | to | route | compass | bearing |
- | a | b | ab | S | 180 |
- | b | c | bc | E | 90 |
- | c | d | cd | N | 0 |
- | d | a | da | W | 270 |
- | b | a | ab | N | 0 |
- | c | b | bc | W | 270 |
- | d | c | cd | S | 180 |
- | a | d | da | E | 90 |
- | a | c | ac | SE | 135 |
- | c | a | ac | NW | 315 |
- | b | d | bd | NE | 45 |
- | d | b | bd | SW | 225 |
+ | from | to | route | bearing |
+ | a | b | ab,ab | 180,0 |
+ | b | c | bc,bc | 90,0 |
+ | c | d | cd,cd | 0,0 |
+ | d | a | da,da | 270,0 |
+ | b | a | ab,ab | 0,0 |
+ | c | b | bc,bc | 270,0 |
+ | d | c | cd,cd | 180,0 |
+ | a | d | da,da | 90,0 |
+ | a | c | ac,ac | 135,0 |
+ | c | a | ac,ac | 315,0 |
+ | b | d | bd,bd | 45,0 |
+ | d | b | bd,bd | 225,0 |
diff --git a/features/testbot/bearing_param.feature b/features/testbot/bearing_param.feature
index 1efa817..ea60856 100644
--- a/features/testbot/bearing_param.feature
+++ b/features/testbot/bearing_param.feature
@@ -15,11 +15,11 @@ Feature: Bearing parameter
When I route I should get
| from | to | bearings | route | bearing |
- | b | c | 90 90 | ad | 90 |
+ | b | c | 90 90 | ad,ad | 90,0 |
| b | c | 180 90 | | |
- | b | c | 80 100 | ad | 90 |
+ | b | c | 80 100 | ad,ad | 90,0 |
| b | c | 79 100 | | |
- | b | c | 79,11 100 | ad | 90 |
+ | b | c | 79,11 100 | ad,ad | 90,0 |
Scenario: Testbot - Intial bearing in simple case
Given the node map
@@ -35,10 +35,10 @@ Feature: Bearing parameter
When I route I should get
| from | to | bearings | route | bearing |
| 0 | c | 0 0 | | |
- | 0 | c | 45 45 | bc | 45 ~3% |
+ | 0 | c | 45 45 | bc,bc | 45 ~3% |
| 0 | c | 85 85 | | |
| 0 | c | 95 95 | | |
- | 0 | c | 135 135 | ac | 135 ~1% |
+ | 0 | c | 135 135 | ac,ac | 135 ~1% |
| 0 | c | 180 180 | | |
Scenario: Testbot - Initial bearing on split way
@@ -55,19 +55,19 @@ Feature: Bearing parameter
When I route I should get
| from | to | bearings | route | bearing |
- | 0 | b | 10 10 | bc | 0 |
- | 0 | b | 90 90 | ab | 90 |
+ | 0 | b | 10 10 | bc,bc | 0,0 |
+ | 0 | b | 90 90 | ab,ab | 90,0 |
# The returned bearing is wrong here, it's based on the snapped
# coordinates, not the acutal edge bearing. This should be
- # fixed one day, but it's only a problem when we snap too vias
+ # fixed one day, but it's only a problem when we snap two vias
# to the same point - DP
#| 0 | b | 170 170 | da | 180 |
#| 0 | b | 189 189 | da | 180 |
- | 0 | 1 | 90 270 | ab,bc,cd | 90,0,270 |
- | 1 | d | 10 10 | bc | 0 |
- | 1 | d | 90 90 | ab,bc,cd,da | 90,0,270,180 |
- | 1 | 0 | 189 189 | da | 180 |
- | 1 | d | 270 270 | cd | 270 |
+ | 0 | 1 | 90 270 | ab,bc,cd,cd | 90,0,270,0 |
+ | 1 | d | 10 10 | bc,bc | 0,0 |
+ | 1 | d | 90 90 | ab,bc,cd,da,da | 90,0,270,180,0 |
+ | 1 | 0 | 189 189 | da,da | 180,0 |
+ | 1 | d | 270 270 | cd,cd | 270,0 |
| 1 | d | 349 349 | | |
Scenario: Testbot - Initial bearing in all direction
@@ -100,12 +100,12 @@ Feature: Bearing parameter
| ha | yes |
When I route I should get
- | from | to | bearings | route | bearing |
- | 0 | q | 0 90 | ia,ab,bc,cd,de,ef,fg,gh,ha | 0,90,180,180,270,270,0,0,90 |
- | 0 | a | 45 90 | jb,bc,cd,de,ef,fg,gh,ha | 45,180,180,270,270,0,0,90 |
- | 0 | q | 90 90 | kc,cd,de,ef,fg,gh,ha | 90,180,270,270,0,0,90 |
- | 0 | a | 135 90 | ld,de,ef,fg,gh,ha | 135,270,270,0,0,90 |
- | 0 | a | 180 90 | me,ef,fg,gh,ha | 180,270,0,0,90 |
- | 0 | a | 225 90 | nf,fg,gh,ha | 225,0,0,90 |
- | 0 | a | 270 90 | og,gh,ha | 270,0,90 |
- | 0 | a | 315 90 | ph,ha | 315,90 |
+ | from | to | bearings | route | bearing |
+ | 0 | q | 0 90 | ia,ab,bc,cd,de,ef,fg,gh,ha,ha | 0,90,180,180,270,270,0,0,90,0 |
+ | 0 | a | 45 90 | jb,bc,cd,de,ef,fg,gh,ha,ha | 45,180,180,270,270,0,0,90,0 |
+ | 0 | q | 90 90 | kc,cd,de,ef,fg,gh,ha,ha | 90,180,270,270,0,0,90,0 |
+ | 0 | a | 135 90 | ld,de,ef,fg,gh,ha,ha | 135,270,270,0,0,90,0 |
+ | 0 | a | 180 90 | me,ef,fg,gh,ha,ha | 180,270,0,0,90,0 |
+ | 0 | a | 225 90 | nf,fg,gh,ha,ha | 225,0,0,90,0 |
+ | 0 | a | 270 90 | og,gh,ha,ha | 270,0,90,0 |
+ | 0 | a | 315 90 | ph,ha,ha | 315,90,0 |
diff --git a/features/testbot/compression.feature b/features/testbot/compression.feature
index 4c0121d..79823ce 100644
--- a/features/testbot/compression.feature
+++ b/features/testbot/compression.feature
@@ -17,6 +17,6 @@ Feature: Geometry Compression
| fg |
When I route I should get
- | from | to | route | distance | speed |
- | b | e | abcdef | 589m | 36 km/h |
- | e | b | abcdef | 589m | 36 km/h |
+ | from | to | route | distance | speed |
+ | b | e | abcdef,abcdef | 589m | 36 km/h |
+ | e | b | abcdef,abcdef | 589m | 36 km/h |
diff --git a/features/testbot/datastore.feature b/features/testbot/datastore.feature
index 568ae7a..70a754b 100644
--- a/features/testbot/datastore.feature
+++ b/features/testbot/datastore.feature
@@ -14,8 +14,8 @@ Feature: Temporary tests related to osrm-datastore
When I route I should get
| from | to | route |
- | a | b | ab |
- | b | a | ab |
+ | a | b | ab,ab |
+ | b | a | ab,ab |
Scenario: Scenaria xy
Given the node map
@@ -27,5 +27,5 @@ Feature: Temporary tests related to osrm-datastore
When I route I should get
| from | to | route |
- | x | y | xy |
- | y | x | xy |
+ | x | y | xy,xy |
+ | y | x | xy,xy |
diff --git a/features/testbot/distance.feature b/features/testbot/distance.feature
index 55b5f64..b8e571f 100644
--- a/features/testbot/distance.feature
+++ b/features/testbot/distance.feature
@@ -15,7 +15,7 @@ Feature: Distance calculation
When I route I should get
| from | to | route | distance |
- | a | b | ab | 100m +- 2 |
+ | a | b | ab,ab | 100m +- 2 |
Scenario: Distance should equal sum of segments, leftwinded
Given the node map
@@ -28,8 +28,8 @@ Feature: Distance calculation
| abcde |
When I route I should get
- | from | to | route | distance |
- | a | d | abcde | 300m +-2 |
+ | from | to | route | distance |
+ | a | d | abcde,abcde | 300m +-2 |
Scenario: Distance should equal sum of segments, rightwinded
Given the node map
@@ -42,8 +42,8 @@ Feature: Distance calculation
| abcde |
When I route I should get
- | from | to | route | distance |
- | a | d | abcde | 300m +-2 |
+ | from | to | route | distance |
+ | a | d | abcde,abcde | 300m +-2 |
Scenario: 10m distances
Given a grid size of 10 meters
@@ -56,13 +56,13 @@ Feature: Distance calculation
| abc |
When I route I should get
- | from | to | route | distance |
- | a | b | abc | 10m +-2 |
- | b | a | abc | 10m +-2 |
- | b | c | abc | 10m +-2 |
- | c | b | abc | 10m +-2 |
- | a | c | abc | 20m +-4 |
- | c | a | abc | 20m +-4 |
+ | from | to | route | distance |
+ | a | b | abc,abc | 10m +-2 |
+ | b | a | abc,abc | 10m +-2 |
+ | b | c | abc,abc | 10m +-2 |
+ | c | b | abc,abc | 10m +-2 |
+ | a | c | abc,abc | 20m +-4 |
+ | c | a | abc,abc | 20m +-4 |
Scenario: 100m distances
Given a grid size of 100 meters
@@ -75,13 +75,13 @@ Feature: Distance calculation
| abc |
When I route I should get
- | from | to | route | distance |
- | a | b | abc | 100m +-2 |
- | b | a | abc | 100m +-2 |
- | b | c | abc | 100m +-2 |
- | c | b | abc | 100m +-2 |
- | a | c | abc | 200m +-4 |
- | c | a | abc | 200m +-4 |
+ | from | to | route | distance |
+ | a | b | abc,abc | 100m +-2 |
+ | b | a | abc,abc | 100m +-2 |
+ | b | c | abc,abc | 100m +-2 |
+ | c | b | abc,abc | 100m +-2 |
+ | a | c | abc,abc | 200m +-4 |
+ | c | a | abc,abc | 200m +-4 |
Scenario: 1km distance
Given a grid size of 1000 meters
@@ -94,13 +94,13 @@ Feature: Distance calculation
| abc |
When I route I should get
- | from | to | route | distance |
- | a | b | abc | 1000m +-2 |
- | b | a | abc | 1000m +-2 |
- | b | c | abc | 1000m +-2 |
- | c | b | abc | 1000m +-2 |
- | a | c | abc | 2000m +-4 |
- | c | a | abc | 2000m +-4 |
+ | from | to | route | distance |
+ | a | b | abc,abc | 1000m +-2 |
+ | b | a | abc,abc | 1000m +-2 |
+ | b | c | abc,abc | 1000m +-2 |
+ | c | b | abc,abc | 1000m +-2 |
+ | a | c | abc,abc | 2000m +-4 |
+ | c | a | abc,abc | 2000m +-4 |
Scenario: Distance of a winding south-north path
Given a grid size of 10 meters
@@ -115,14 +115,14 @@ Feature: Distance calculation
| abcdefgh |
When I route I should get
- | from | to | route | distance |
- | a | b | abcdefgh | 10m +-2 |
- | a | c | abcdefgh | 20m +-4 |
- | a | d | abcdefgh | 30m +-6 |
- | a | e | abcdefgh | 40m +-8 |
- | a | f | abcdefgh | 50m +-10 |
- | a | g | abcdefgh | 60m +-12 |
- | a | h | abcdefgh | 70m +-14 |
+ | from | to | route | distance |
+ | a | b | abcdefgh,abcdefgh | 10m +-2 |
+ | a | c | abcdefgh,abcdefgh | 20m +-4 |
+ | a | d | abcdefgh,abcdefgh | 30m +-6 |
+ | a | e | abcdefgh,abcdefgh | 40m +-8 |
+ | a | f | abcdefgh,abcdefgh | 50m +-10 |
+ | a | g | abcdefgh,abcdefgh | 60m +-12 |
+ | a | h | abcdefgh,abcdefgh | 70m +-14 |
Scenario: Distance of a winding east-west path
Given a grid size of 10 meters
@@ -135,14 +135,14 @@ Feature: Distance calculation
| abcdefgh |
When I route I should get
- | from | to | route | distance |
- | a | b | abcdefgh | 10m +-2 |
- | a | c | abcdefgh | 20m +-4 |
- | a | d | abcdefgh | 30m +-6 |
- | a | e | abcdefgh | 40m +-8 |
- | a | f | abcdefgh | 50m +-10 |
- | a | g | abcdefgh | 60m +-12 |
- | a | h | abcdefgh | 70m +-14 |
+ | from | to | route | distance |
+ | a | b | abcdefgh,abcdefgh | 10m +-2 |
+ | a | c | abcdefgh,abcdefgh | 20m +-4 |
+ | a | d | abcdefgh,abcdefgh | 30m +-6 |
+ | a | e | abcdefgh,abcdefgh | 40m +-8 |
+ | a | f | abcdefgh,abcdefgh | 50m +-10 |
+ | a | g | abcdefgh,abcdefgh | 60m +-12 |
+ | a | h | abcdefgh,abcdefgh | 70m +-14 |
Scenario: Geometric distances
Given a grid size of 100 meters
@@ -184,30 +184,30 @@ Feature: Distance calculation
When I route I should get
| from | to | route | distance |
- | x | a | xa | 300m +-2 |
- | x | b | xb | 316m +-2 |
- | x | c | xc | 360m +-2 |
- | x | d | xd | 424m +-2 |
- | x | e | xe | 360m +-2 |
- | x | f | xf | 316m +-2 |
- | x | g | xg | 300m +-2 |
- | x | h | xh | 316m +-2 |
- | x | i | xi | 360m +-2 |
- | x | j | xj | 424m +-2 |
- | x | k | xk | 360m +-2 |
- | x | l | xl | 316m +-2 |
- | x | m | xm | 300m +-2 |
- | x | n | xn | 316m +-2 |
- | x | o | xo | 360m +-2 |
- | x | p | xp | 424m +-2 |
- | x | q | xq | 360m +-2 |
- | x | r | xr | 316m +-2 |
- | x | s | xs | 300m +-2 |
- | x | t | xt | 316m +-2 |
- | x | u | xu | 360m +-2 |
- | x | v | xv | 424m +-2 |
- | x | w | xw | 360m +-2 |
- | x | y | xy | 316m +-2 |
+ | x | a | xa,xa | 300m +-2 |
+ | x | b | xb,xb | 316m +-2 |
+ | x | c | xc,xc | 360m +-2 |
+ | x | d | xd,xd | 424m +-2 |
+ | x | e | xe,xe | 360m +-2 |
+ | x | f | xf,xf | 316m +-2 |
+ | x | g | xg,xg | 300m +-2 |
+ | x | h | xh,xh | 316m +-2 |
+ | x | i | xi,xi | 360m +-2 |
+ | x | j | xj,xj | 424m +-2 |
+ | x | k | xk,xk | 360m +-2 |
+ | x | l | xl,xl | 316m +-2 |
+ | x | m | xm,xm | 300m +-2 |
+ | x | n | xn,xn | 316m +-2 |
+ | x | o | xo,xo | 360m +-2 |
+ | x | p | xp,xp | 424m +-2 |
+ | x | q | xq,xq | 360m +-2 |
+ | x | r | xr,xr | 316m +-2 |
+ | x | s | xs,xs | 300m +-2 |
+ | x | t | xt,xt | 316m +-2 |
+ | x | u | xu,xu | 360m +-2 |
+ | x | v | xv,xv | 424m +-2 |
+ | x | w | xw,xw | 360m +-2 |
+ | x | y | xy,xy | 316m +-2 |
@maze
Scenario: Distance of a maze of short segments
@@ -224,5 +224,5 @@ Feature: Distance calculation
| abcdefghijklmnopqrst |
When I route I should get
- | from | to | route | distance |
- | a | t | abcdefghijklmnopqrst | 133m +-2 |
+ | from | to | route | distance |
+ | a | t | abcdefghijklmnopqrst,abcdefghijklmnopqrst | 133m +-2 |
diff --git a/features/testbot/distance_matrix.feature b/features/testbot/distance_matrix.feature
index 4910126..4afa307 100644
--- a/features/testbot/distance_matrix.feature
+++ b/features/testbot/distance_matrix.feature
@@ -16,9 +16,9 @@ Feature: Basic Distance Matrix
| ab |
When I request a travel time matrix I should get
- | | a | b |
- | a | 0 | 100 |
- | b | 100 | 0 |
+ | | a | b |
+ | a | 0 | 10 |
+ | b | 10 | 0 |
Scenario: Testbot - Travel time matrix with different way speeds
Given the node map
@@ -29,13 +29,13 @@ Feature: Basic Distance Matrix
| ab | primary |
| bc | secondary |
| cd | tertiary |
-
+
When I request a travel time matrix I should get
- | | a | b | c | d |
- | a | 0 | 100 | 300 | 600 |
- | b | 100 | 0 | 200 | 500 |
- | c | 300 | 200 | 0 | 300 |
- | d | 600 | 500 | 300 | 0 |
+ | | a | b | c | d |
+ | a | 0 | 10 | 30 | 60 |
+ | b | 10 | 0 | 20 | 50 |
+ | c | 30 | 20 | 0 | 30 |
+ | d | 60 | 50 | 30 | 0 |
Scenario: Testbot - Travel time matrix with fuzzy match
Given the node map
@@ -47,9 +47,9 @@ Feature: Basic Distance Matrix
When I request a travel time matrix I should get
| | a | b |
- | a | 0 | 95 +- 10 |
- | b | 95 ~10% | 0 |
-
+ | a | 0 | 9 +- 2 |
+ | b | 9 ~15% | 0 |
+
Scenario: Testbot - Travel time matrix of small grid
Given the node map
| a | b | c |
@@ -64,11 +64,11 @@ Feature: Basic Distance Matrix
| cf |
When I request a travel time matrix I should get
- | | a | b | e | f |
- | a | 0 | 100 | 200 | 300 |
- | b | 100 | 0 | 100 | 200 |
- | e | 200 | 100 | 0 | 100 |
- | f | 300 | 200 | 100 | 0 |
+ | | a | b | e | f |
+ | a | 0 | 10 | 20 | 30 |
+ | b | 10 | 0 | 10 | 20 |
+ | e | 20 | 10 | 0 | 10 |
+ | f | 30 | 20 | 10 | 0 |
Scenario: Testbot - Travel time matrix of network with unroutable parts
Given the node map
@@ -79,10 +79,10 @@ Feature: Basic Distance Matrix
| ab | yes |
When I request a travel time matrix I should get
- | | a | b |
- | a | 0 | 100 |
- | b | | 0 |
-
+ | | a | b |
+ | a | 0 | 10 |
+ | b | | 0 |
+
Scenario: Testbot - Travel time matrix of network with oneways
Given the node map
| x | a | b | y |
@@ -95,11 +95,11 @@ Feature: Basic Distance Matrix
| by | |
When I request a travel time matrix I should get
- | | x | y | d | e |
- | x | 0 | 300 | 400 | 300 |
- | y | 500 | 0 | 300 | 200 |
- | d | 200 | 300 | 0 | 300 |
- | e | 300 | 400 | 100 | 0 |
+ | | x | y | d | e |
+ | x | 0 | 30 | 40 | 30 |
+ | y | 50 | 0 | 30 | 20 |
+ | d | 20 | 30 | 0 | 30 |
+ | e | 30 | 40 | 10 | 0 |
Scenario: Testbot - Travel time matrix and with only one source
Given the node map
@@ -115,8 +115,8 @@ Feature: Basic Distance Matrix
| cf |
When I request a travel time matrix I should get
- | | a | b | e | f |
- | a | 0 | 100 | 200 | 300 |
+ | | a | b | e | f |
+ | a | 0 | 10 | 20 | 30 |
Scenario: Testbot - Travel time 3x2 matrix
Given the node map
@@ -132,11 +132,11 @@ Feature: Basic Distance Matrix
| cf |
When I request a travel time matrix I should get
- | | b | e | f |
- | a | 100 | 200 | 300 |
- | b | 0 | 100 | 200 |
+ | | b | e | f |
+ | a | 10 | 20 | 30 |
+ | b | 0 | 10 | 20 |
- Scenario: Testbog - All coordinates are from same small component
+ Scenario: Testbot - All coordinates are from same small component
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the node map
@@ -152,11 +152,11 @@ Feature: Basic Distance Matrix
| fg |
When I request a travel time matrix I should get
- | | f | g |
- | f | 0 | 300 |
- | g | 300 | 0 |
+ | | f | g |
+ | f | 0 | 30 |
+ | g | 30 | 0 |
- Scenario: Testbog - Coordinates are from different small component and snap to big CC
+ Scenario: Testbot - Coordinates are from different small component and snap to big CC
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the node map
@@ -173,9 +173,27 @@ Feature: Basic Distance Matrix
| hi |
When I request a travel time matrix I should get
- | | f | g | h | i |
- | f | 0 | 300 | 0 | 300 |
- | g | 300 | 0 | 300 | 0 |
- | h | 0 | 300 | 0 | 300 |
- | i | 300 | 0 | 300 | 0 |
+ | | f | g | h | i |
+ | f | 0 | 30 | 0 | 30 |
+ | g | 30 | 0 | 30 | 0 |
+ | h | 0 | 30 | 0 | 30 |
+ | i | 30 | 0 | 30 | 0 |
+
+ Scenario: Testbot - Travel time matrix with loops
+ Given the node map
+ | a | 1 | 2 | b |
+ | d | 4 | 3 | c |
+ And the ways
+ | nodes | oneway |
+ | ab | yes |
+ | bc | yes |
+ | cd | yes |
+ | da | yes |
+
+ When I request a travel time matrix I should get
+ | | 1 | 2 | 3 | 4 |
+ | 1 | 0 | 10 +-1 | 40 +-1 | 50 +-1 |
+ | 2 | 70 +-1 | 0 | 30 +-1 | 40 +-1 |
+ | 3 | 40 +-1 | 50 +-1 | 0 | 10 +-1 |
+ | 4 | 30 +-1 | 40 +-1 | 70 +-1 | 0 |
diff --git a/features/testbot/duration.feature b/features/testbot/duration.feature
index d5c6e46..bb158db 100644
--- a/features/testbot/duration.feature
+++ b/features/testbot/duration.feature
@@ -20,11 +20,11 @@ Feature: Durations
When I route I should get
| from | to | route | distance | time |
- | a | b | ab | 100m +-1 | 60s +-1 |
- | b | c | bc | 200m +-1 | 600s +-1 |
- | c | d | cd | 300m +-1 | 3600s +-1 |
- | d | e | de | 141m +-2 | 36000s +-1 |
- | e | f | ef | 224m +-2 | 3723s +-1 |
+ | a | b | ab,ab | 100m +-1 | 60s +-1 |
+ | b | c | bc,bc | 200m +-1 | 600s +-1 |
+ | c | d | cd,cd | 300m +-1 | 3600s +-1 |
+ | d | e | de,de | 141m +-2 | 36000s +-1 |
+ | e | f | ef,ef | 224m +-2 | 3723s +-1 |
@todo
Scenario: Partial duration of ways
@@ -36,7 +36,7 @@ Feature: Durations
| abc | primary | 0:01 |
When I route I should get
- | from | to | route | distance | time |
- | a | c | abc | 300m +-1 | 60s +-1 |
- | a | b | ab | 100m +-1 | 20s +-1 |
- | b | c | bc | 200m +-1 | 40s +-1 |
+ | from | to | route | distance | time |
+ | a | c | abc,abc | 300m +-1 | 60s +-1 |
+ | a | b | ab,ab | 100m +-1 | 20s +-1 |
+ | b | c | bc,bc | 200m +-1 | 40s +-1 |
diff --git a/features/testbot/example.feature b/features/testbot/example.feature
index c2aa1e9..075a22e 100644
--- a/features/testbot/example.feature
+++ b/features/testbot/example.feature
@@ -20,18 +20,18 @@ Feature: Testbot - Walkthrough
| de | primary | |
When I route I should get
- | from | to | route |
- | a | b | abc |
- | a | c | abc |
- | a | d | abc,cd |
- | a | e | abc,ce |
- | b | a | abc |
- | b | c | abc |
- | b | d | abc,cd |
- | b | e | abc,ce |
- | d | a | de,ce,abc |
- | d | b | de,ce,abc |
- | d | e | de |
- | e | a | ce,abc |
- | e | b | ce,abc |
- | e | c | ce |
+ | from | to | route |
+ | a | b | abc,abc |
+ | a | c | abc,abc |
+ | a | d | abc,cd,cd |
+ | a | e | abc,ce,ce |
+ | b | a | abc,abc |
+ | b | c | abc,abc |
+ | b | d | abc,cd,cd |
+ | b | e | abc,ce,ce |
+ | d | a | de,ce,abc,abc |
+ | d | b | de,ce,abc,abc |
+ | d | e | de,de |
+ | e | a | ce,abc,abc |
+ | e | b | ce,abc,abc |
+ | e | c | ce,ce |
diff --git a/features/testbot/fastest.feature b/features/testbot/fastest.feature
index 8c24a53..5576c73 100644
--- a/features/testbot/fastest.feature
+++ b/features/testbot/fastest.feature
@@ -18,9 +18,9 @@ Feature: Choosing fastest route
| asb | primary |
When I route I should get
- | from | to | route |
- | x | y | xa,atb,by |
- | y | x | by,atb,xa |
+ | from | to | route |
+ | x | y | xa,atb,by,by |
+ | y | x | by,atb,xa,xa |
Scenario: Pick the fastest route, even when it's longer
Given the node map
@@ -33,6 +33,6 @@ Feature: Choosing fastest route
| asb | secondary |
When I route I should get
- | from | to | route |
- | a | b | apb |
- | b | a | apb |
+ | from | to | route |
+ | a | b | apb,apb |
+ | b | a | apb,apb |
diff --git a/features/testbot/ferry.feature b/features/testbot/ferry.feature
index 21cefcb..6dd896b 100644
--- a/features/testbot/ferry.feature
+++ b/features/testbot/ferry.feature
@@ -32,11 +32,11 @@ Feature: Testbot - Handle ferry routes
When I route I should get
| from | to | route | time |
- | b | c | bc | 60s +-1 |
- | f | g | fg | 600s +-1 |
- | j | k | jk | 3600s +-1 |
- | n | o | no | 86400s +-1 |
- | r | s | rs | 345600s +-1 |
+ | b | c | bc,bc | 60s +-1 |
+ | f | g | fg,fg | 600s +-1 |
+ | j | k | jk,jk | 3600s +-1 |
+ | n | o | no,no | 86400s +-1 |
+ | r | s | rs,rs | 345600s +-1 |
@todo
Scenario: Testbot - Week long ferry routes
@@ -59,9 +59,9 @@ Feature: Testbot - Handle ferry routes
When I route I should get
| from | to | route | time |
- | b | c | bc | 86400s +-1 |
- | f | g | fg | 604800s +-1 |
- | j | k | jk | 259200s +-1 |
+ | b | c | bc,bc | 86400s +-1 |
+ | f | g | fg,fg | 604800s +-1 |
+ | j | k | jk,jk | 259200s +-1 |
Scenario: Testbot - Ferry duration, multiple nodes
Given the node map
@@ -76,8 +76,8 @@ Feature: Testbot - Handle ferry routes
When I route I should get
| from | to | route | time |
- | a | d | ad | 3600s +-1 |
- | d | a | ad | 3600s +-1 |
+ | a | d | ad,ad | 3600s +-1 |
+ | d | a | ad,ad | 3600s +-1 |
@todo
Scenario: Testbot - Ferry duration, individual parts, fast
@@ -95,11 +95,11 @@ Feature: Testbot - Handle ferry routes
| abcd | | ferry | 0:06 |
When I route I should get
- | from | to | route | time |
- | a | d | abcd | 360s +-1 |
- | a | b | abcd | 60s +-1 |
- | b | c | abcd | 120s +-1 |
- | c | d | abcd | 180s +-1 |
+ | from | to | route | time |
+ | a | d | abcd,abcd | 360s +-1 |
+ | a | b | abcd,abcd | 60s +-1 |
+ | b | c | abcd,abcd | 120s +-1 |
+ | c | d | abcd,abcd | 180s +-1 |
@todo
Scenario: Testbot - Ferry duration, individual parts, slow
@@ -116,11 +116,11 @@ Feature: Testbot - Handle ferry routes
| abcd | | ferry | 1:00 |
When I route I should get
- | from | to | route | time |
- | a | d | abcd | 3600s ~1% |
- | a | b | abcd | 600s ~1% |
- | b | c | abcd | 1200s ~1% |
- | c | d | abcd | 1800s ~1% |
+ | from | to | route | time |
+ | a | d | abcd,abcd | 3600s ~1% |
+ | a | b | abcd,abcd | 600s ~1% |
+ | b | c | abcd,abcd | 1200s ~1% |
+ | c | d | abcd,abcd | 1800s ~1% |
Scenario: Testbot - Ferry duration, connected routes
Given the node map
@@ -135,9 +135,9 @@ Feature: Testbot - Handle ferry routes
| defg | | ferry | 0:30 |
When I route I should get
- | from | to | route | time |
- | a | g | abcd,defg | 3600s +-1 |
- | g | a | defg,abcd | 3600s +-1 |
+ | from | to | route | time |
+ | a | g | abcd,defg,defg | 3600s +-1 |
+ | g | a | defg,abcd,abcd | 3600s +-1 |
Scenario: Testbot - Prefer road when faster than ferry
Given the node map
@@ -154,9 +154,9 @@ Feature: Testbot - Handle ferry routes
| defg | | ferry | 0:01 |
When I route I should get
- | from | to | route | time |
- | a | g | xa,xy,yg | 60s +-25% |
- | g | a | yg,xy,xa | 60s +-25% |
+ | from | to | route | time |
+ | a | g | xa,xy,yg,yg | 60s +-25% |
+ | g | a | yg,xy,xa,xa | 60s +-25% |
Scenario: Testbot - Long winding ferry route
Given the node map
@@ -170,9 +170,9 @@ Feature: Testbot - Handle ferry routes
| abcdefg | | ferry | 6:30 |
When I route I should get
- | from | to | route | time |
- | a | g | abcdefg | 23400s +-2 |
- | g | a | abcdefg | 23400s +-2 |
+ | from | to | route | time |
+ | a | g | abcdefg,abcdefg | 23400s +-2 |
+ | g | a | abcdefg,abcdefg | 23400s +-2 |
@todo
Scenario: Testbot - Ferry duration formats
@@ -194,12 +194,12 @@ Feature: Testbot - Handle ferry routes
When I route I should get
| from | to | route | time |
- | a | b | ab | 60s +-1 |
- | c | d | cd | 60s +-1 |
- | e | f | ef | 3600s +-1 |
- | g | h | gh | 3600s +-1 |
- | i | j | ij | 8400s +-1 |
- | k | l | kl | 36000s +-1 |
- | m | n | mn | 360000s +-1 |
- | o | p | mn | 3600000s +-1 |
- | q | r | mn | 36000000s +-1 |
+ | a | b | ab,ab | 60s +-1 |
+ | c | d | cd,cd | 60s +-1 |
+ | e | f | ef,ef | 3600s +-1 |
+ | g | h | gh,gh | 3600s +-1 |
+ | i | j | ij,ij | 8400s +-1 |
+ | k | l | kl,kl | 36000s +-1 |
+ | m | n | mn,mn | 360000s +-1 |
+ | o | p | mn,mn | 3600000s +-1 |
+ | q | r | mn,mn | 36000000s +-1 |
diff --git a/features/testbot/fixed.feature b/features/testbot/fixed.feature
index 0edf25c..dc09eaa 100644
--- a/features/testbot/fixed.feature
+++ b/features/testbot/fixed.feature
@@ -22,5 +22,5 @@ Feature: Fixed bugs, kept to check for regressions
| cdec |
When I route I should get
- | from | to | route | turns |
- | x | y | abc | head,destination |
+ | from | to | route |
+ | x | y | abc,abc |
diff --git a/features/testbot/geometry.feature b/features/testbot/geometry.feature
index 8b38c06..24f3d23 100644
--- a/features/testbot/geometry.feature
+++ b/features/testbot/geometry.feature
@@ -21,10 +21,8 @@ Feature: Retrieve geometry
| cd |
When I route I should get
- | from | to | route | geometry |
- | a | c | ab,bc | _c`\|@_upzA_c`\|@_c`\|@_c`\|@_c`\|@ |
- | b | d | bc,cd | _gayB_yqwC_c`\|@_c`\|@_c`\|@_c`\|@ |
+ | from | to | route | geometry |
+ | a | c | ab,bc,bc | _ibE_~cH_seK_seK |
+ | b | d | bc,cd,cd | _seK_hgN_seK_seK |
# Mind the \ before the pipes
-# polycodec.rb decode2 '_c`|@_upzA_c`|@_c`|@_c`|@_c`|@' [[1.0, 1.5], [2.0, 2.5], [3.0, 3.5]]
-# polycodec.rb decode2 '_gayB_yqwC_c`|@_c`|@_c`|@_c`|@' [[2.0, 2.5], [3.0, 3.5], [4.0, 4.5]]
diff --git a/features/testbot/graph.feature b/features/testbot/graph.feature
index adff998..f86b994 100644
--- a/features/testbot/graph.feature
+++ b/features/testbot/graph.feature
@@ -17,8 +17,8 @@ Feature: Basic Routing
| dce |
When I route I should get
- | from | to | route |
- | a | e | abc,dce |
+ | from | to | route |
+ | a | e | abc,dce,dce |
Scenario: Turn instructions on compressed road network geometry
Given the node map
@@ -36,5 +36,5 @@ Feature: Basic Routing
| fy | last |
When I route I should get
- | from | to | route | turns |
- | x | y | first,compr,last | head,right,left,destination |
+ | from | to | route | turns |
+ | x | y | first,compr,last,last | depart,right,left,arrive |
diff --git a/features/testbot/load.feature b/features/testbot/load.feature
index cf5e470..b29fdc7 100644
--- a/features/testbot/load.feature
+++ b/features/testbot/load.feature
@@ -17,8 +17,8 @@ Feature: Ways of loading data
When I route I should get
| from | to | route |
- | a | b | ab |
- | b | a | ab |
+ | a | b | ab,ab |
+ | b | a | ab,ab |
Scenario: Load data directly - st
Given data is loaded directly
@@ -31,10 +31,10 @@ Feature: Ways of loading data
When I route I should get
| from | to | route |
- | s | t | st |
- | t | s | st |
+ | s | t | st,st |
+ | t | s | st,st |
- Scenario: Load data datstore - xy
+ Scenario: Load data datastore - xy
Given data is loaded with datastore
Given the node map
| x | y |
@@ -45,8 +45,8 @@ Feature: Ways of loading data
When I route I should get
| from | to | route |
- | x | y | xy |
- | y | x | xy |
+ | x | y | xy,xy |
+ | y | x | xy,xy |
Scenario: Load data directly - cd
Given data is loaded directly
@@ -59,5 +59,5 @@ Feature: Ways of loading data
When I route I should get
| from | to | route |
- | c | d | cd |
- | d | c | cd |
+ | c | d | cd,cd |
+ | d | c | cd,cd |
diff --git a/features/testbot/loop.feature b/features/testbot/loop.feature
index c69e7a2..f035ab0 100644
--- a/features/testbot/loop.feature
+++ b/features/testbot/loop.feature
@@ -4,7 +4,7 @@ Feature: Avoid weird loops caused by rounding errors
Background:
Given the profile "testbot"
- Scenario: Weired sidestreet loops
+ Scenario: Weird sidestreet loops
Given the node map
| a | 1 | b | 2 | c | 3 | d |
| | | | | | | |
@@ -18,10 +18,10 @@ Feature: Avoid weird loops caused by rounding errors
| cg |
When I route I should get
- | waypoints | route | turns |
- | a,1,d | abcd,abcd | head,via,destination |
- | a,2,d | abcd,abcd | head,via,destination |
- | a,3,d | abcd,abcd | head,via,destination |
+ | waypoints | route |
+ | a,1,d | abcd,abcd,abcd,abcd |
+ | a,2,d | abcd,abcd,abcd,abcd |
+ | a,3,d | abcd,abcd,abcd,abcd |
Scenario: Avoid weird loops 1
Given the node locations
@@ -47,8 +47,8 @@ Feature: Avoid weird loops caused by rounding errors
| ie |
When I route I should get
- | from | to | route | turns |
- | x | y | hfgd | head,destination |
+ | from | to | route |
+ | x | y | hfgd,hfgd |
Scenario: Avoid weird loops 2
Given the node locations
@@ -67,8 +67,8 @@ Feature: Avoid weird loops caused by rounding errors
| cdec |
When I route I should get
- | from | to | route | turns |
- | x | y | abc | head,destination |
+ | from | to | route |
+ | x | y | abc,abc |
@412
Scenario: Avoid weird loops 3
@@ -92,6 +92,6 @@ Feature: Avoid weird loops caused by rounding errors
| cf | primary |
When I route I should get
- | waypoints | route | turns |
- | a,2,d | ab,be,ef,ef,cf,cd | head,left,right,via,right,left,destination |
- | a,1,d | ab,be,ef,ef,cf,cd | head,left,right,via,right,left,destination |
+ | waypoints | route |
+ | a,2,d | ab,be,ef,ef,ef,cf,cd,cd |
+ | a,1,d | ab,be,ef,ef,ef,cf,cd,cd |
diff --git a/features/testbot/matching.feature b/features/testbot/matching.feature
index 91bf928..bee3d9c 100644
--- a/features/testbot/matching.feature
+++ b/features/testbot/matching.feature
@@ -5,6 +5,23 @@ Feature: Basic Map Matching
Given the profile "testbot"
Given a grid size of 10 meters
+ Scenario: Testbot - Map matching with outlier that has no candidate
+ Given a grid size of 100 meters
+ Given the node map
+ | a | b | c | d |
+ | | | | |
+ | | | | |
+ | | | | |
+ | | | 1 | |
+
+ And the ways
+ | nodes | oneway |
+ | abcd | no |
+
+ When I match I should get
+ | trace | timestamps | matchings |
+ | ab1d | 0 1 2 3 | abcd |
+
Scenario: Testbot - Map matching with trace splitting
Given the node map
| a | b | c | d |
@@ -18,6 +35,20 @@ Feature: Basic Map Matching
| trace | timestamps | matchings |
| abcd | 0 1 62 63 | ab,cd |
+ Scenario: Testbot - Map matching with core factor
+ Given the contract extra arguments "--core 0.8"
+ Given the node map
+ | a | b | c | d |
+ | | | e | |
+
+ And the ways
+ | nodes | oneway |
+ | abcd | no |
+
+ When I match I should get
+ | trace | timestamps | matchings |
+ | abcd | 0 1 2 3 | abcd |
+
Scenario: Testbot - Map matching with small distortion
Given the node map
| a | b | c | d | e |
diff --git a/features/testbot/matching_turns.feature b/features/testbot/matching_turns.feature
deleted file mode 100644
index 8bca4a2..0000000
--- a/features/testbot/matching_turns.feature
+++ /dev/null
@@ -1,121 +0,0 @@
- at routing @turns @testbot
-Feature: Turn directions/codes
-
- Background:
- Given the profile "testbot"
-
- Scenario: Turn directions
- Given the query options
- | instructions | true |
- Given the node map
- | o | p | a | b | c |
- | n | | | | d |
- | m | | x | | e |
- | l | | | | f |
- | k | j | i | h | g |
-
- And the ways
- | nodes |
- | xa |
- | xb |
- | xc |
- | xd |
- | xe |
- | xf |
- | xg |
- | xh |
- | xi |
- | xj |
- | xk |
- | xl |
- | xm |
- | xn |
- | xo |
- | xp |
-
- When I match I should get
- | trace | route | turns | matchings |
- | im | xi,xm | head,left,destination | im |
- | io | xi,xo | head,slight_left,destination | io |
- | ia | xi,xa | head,straight,destination | ia |
- | ic | xi,xc | head,slight_right,destination | ic |
- | ie | xi,xe | head,right,destination | ie |
-
- | ko | xk,xo | head,left,destination | ko |
- | ka | xk,xa | head,slight_left,destination | ka |
- | kc | xk,xc | head,straight,destination | kc |
- | ke | xk,xe | head,slight_right,destination | ke |
- | kg | xk,xg | head,right,destination | kg |
-
- | ma | xm,xa | head,left,destination | ma |
- | mc | xm,xc | head,slight_left,destination | mc |
- | me | xm,xe | head,straight,destination | me |
- | mg | xm,xg | head,slight_right,destination | mg |
- | mi | xm,xi | head,right,destination | mi |
-
- | oc | xo,xc | head,left,destination | oc |
- | oe | xo,xe | head,slight_left,destination | oe |
- | og | xo,xg | head,straight,destination | og |
- | oi | xo,xi | head,slight_right,destination | oi |
- | ok | xo,xk | head,right,destination | ok |
-
- | ae | xa,xe | head,left,destination | ae |
- | ag | xa,xg | head,slight_left,destination | ag |
- | ai | xa,xi | head,straight,destination | ai |
- | ak | xa,xk | head,slight_right,destination | ak |
- | am | xa,xm | head,right,destination | am |
-
- | cg | xc,xg | head,left,destination | cg |
- | ci | xc,xi | head,slight_left,destination | ci |
- | ck | xc,xk | head,straight,destination | ck |
- | cm | xc,xm | head,slight_right,destination | cm |
- | co | xc,xo | head,right,destination | co |
-
- | ei | xe,xi | head,left,destination | ei |
- | ek | xe,xk | head,slight_left,destination | ek |
- | em | xe,xm | head,straight,destination | em |
- | eo | xe,xo | head,slight_right,destination | eo |
- | ea | xe,xa | head,right,destination | ea |
-
- | gk | xg,xk | head,left,destination | gk |
- | gm | xg,xm | head,slight_left,destination | gm |
- | go | xg,xo | head,straight,destination | go |
- | ga | xg,xa | head,slight_right,destination | ga |
- | gc | xg,xc | head,right,destination | gc |
-
- Scenario: Turn directions
- Given the query options
- | instructions | true |
- Given the node map
- | o | p | a | b | c |
- | n | | | | d |
- | m | | x | | e |
- | l | | | | f |
- | k | j | i | h | g |
-
- And the ways
- | nodes |
- | xa |
- | xb |
- | xc |
- | xd |
- | xe |
- | xf |
- | xg |
- | xh |
- | xi |
- | xj |
- | xk |
- | xl |
- | xm |
- | xn |
- | xo |
- | xp |
-
- When I match I should get
- | trace | route | turns | matchings | duration |
- | im | xi,xm | head,left,destination | im | 80 |
- | io | xi,xo | head,slight_left,destination | io | 88 |
- | ia | xi,xa | head,straight,destination | ia | 80 |
- | ic | xi,xc | head,slight_right,destination | ic | 88 |
- | ie | xi,xe | head,right,destination | ie | 60 |
diff --git a/features/testbot/mode.feature b/features/testbot/mode.feature
index ef8cd25..3f2463d 100644
--- a/features/testbot/mode.feature
+++ b/features/testbot/mode.feature
@@ -2,7 +2,7 @@
Feature: Testbot - Travel mode
# testbot modes:
-# 1 normal
+# 1 driving
# 2 route
# 3 river downstream
# 4 river upstream
@@ -12,6 +12,7 @@ Feature: Testbot - Travel mode
Background:
Given the profile "testbot"
+ @mokob @2166
Scenario: Testbot - Always announce mode change
Given the node map
| a | b | c | d |
@@ -23,9 +24,27 @@ Feature: Testbot - Travel mode
| cd | residential | foo |
When I route I should get
- | from | to | route | modes |
- | a | d | foo,foo,foo | 1,3,1 |
+ | from | to | route | modes |
+ | a | d | foo,foo,foo,foo | driving,river downstream,driving,driving |
+ | b | d | foo,foo,foo | river downstream,driving,driving |
+ @mokob @2166
+ Scenario: Testbot - Compressed Modes
+ Given the node map
+ | a | b | c | d | e | f | g |
+
+ And the ways
+ | nodes | highway | name |
+ | abc | residential | road |
+ | cde | river | liquid |
+ | efg | residential | solid |
+
+ When I route I should get
+ | from | to | route | modes |
+ | a | g | road,liquid,solid,solid | driving,river downstream,driving,driving |
+ | c | g | liquid,solid,solid | river downstream,driving,driving |
+
+ @mokob @2166
Scenario: Testbot - Modes in each direction, different forward/backward speeds
Given the node map
| | 0 | 1 | |
@@ -36,15 +55,15 @@ Feature: Testbot - Travel mode
| ab | river | |
When I route I should get
- | from | to | route | modes |
- | a | 0 | ab | 3 |
- | a | b | ab | 3 |
- | 0 | 1 | ab | 3 |
- | 0 | b | ab | 3 |
- | b | 1 | ab | 4 |
- | b | a | ab | 4 |
- | 1 | 0 | ab | 4 |
- | 1 | a | ab | 4 |
+ | from | to | route | modes |
+ | a | 0 | ab,ab | river downstream,river downstream |
+ | a | b | ab,ab | river downstream,river downstream |
+ | 0 | 1 | ab,ab | river downstream,river downstream |
+ | 0 | b | ab,ab | river downstream,river downstream |
+ | b | 1 | ab,ab | river upstream,river upstream |
+ | b | a | ab,ab | river upstream,river upstream |
+ | 1 | 0 | ab,ab | river upstream,river upstream |
+ | 1 | a | ab,ab | river upstream,river upstream |
Scenario: Testbot - Modes in each direction, same forward/backward speeds
Given the node map
@@ -56,11 +75,11 @@ Feature: Testbot - Travel mode
| ab | steps |
When I route I should get
- | from | to | route | modes | time |
- | 0 | 1 | ab | 5 | 60s +-1 |
- | 1 | 0 | ab | 6 | 60s +-1 |
+ | from | to | route | modes | time |
+ | 0 | 1 | ab,ab | steps down,steps down | 60s +-1 |
+ | 1 | 0 | ab,ab | steps up,steps up | 60s +-1 |
- @oneway
+ @oneway @mokob @2166
Scenario: Testbot - Modes for oneway, different forward/backward speeds
Given the node map
| a | b |
@@ -70,9 +89,9 @@ Feature: Testbot - Travel mode
| ab | river | yes |
When I route I should get
- | from | to | route | modes |
- | a | b | ab | 3 |
- | b | a | | |
+ | from | to | route | modes |
+ | a | b | ab,ab | river downstream,river downstream |
+ | b | a | | |
@oneway
Scenario: Testbot - Modes for oneway, same forward/backward speeds
@@ -84,11 +103,11 @@ Feature: Testbot - Travel mode
| ab | steps | yes |
When I route I should get
- | from | to | route | modes |
- | a | b | ab | 5 |
- | b | a | | |
+ | from | to | route | modes |
+ | a | b | ab,ab | steps down,steps down |
+ | b | a | | |
- @oneway
+ @oneway @mokob @2166
Scenario: Testbot - Modes for reverse oneway, different forward/backward speeds
Given the node map
| a | b |
@@ -98,9 +117,9 @@ Feature: Testbot - Travel mode
| ab | river | -1 |
When I route I should get
- | from | to | route | modes |
- | a | b | | |
- | b | a | ab | 4 |
+ | from | to | route | modes |
+ | a | b | | |
+ | b | a | ab,ab | river upstream,river upstream |
@oneway
Scenario: Testbot - Modes for reverse oneway, same forward/backward speeds
@@ -112,11 +131,11 @@ Feature: Testbot - Travel mode
| ab | steps | -1 |
When I route I should get
- | from | to | route | modes |
- | a | b | | |
- | b | a | ab | 6 |
+ | from | to | route | modes |
+ | a | b | | |
+ | b | a | ab,ab | steps up,steps up |
- @via
+ @via @mokob @2166
Scenario: Testbot - Mode should be set at via points
Given the node map
| a | 1 | b |
@@ -126,10 +145,11 @@ Feature: Testbot - Travel mode
| ab | river |
When I route I should get
- | waypoints | route | modes | turns |
- | a,1,b | ab,ab | 3,3 | head,via,destination |
- | b,1,a | ab,ab | 4,4 | head,via,destination |
+ | waypoints | route | modes |
+ | a,1,b | ab,ab,ab,ab | river downstream,river downstream,river downstream,river downstream |
+ | b,1,a | ab,ab,ab,ab | river upstream,river upstream,river upstream,river upstream |
+ @mokob @2166
Scenario: Testbot - Starting at a tricky node
Given the node map
| | a | | | |
@@ -141,9 +161,10 @@ Feature: Testbot - Travel mode
| bc | primary |
When I route I should get
- | from | to | route | modes |
- | b | a | ab | 4 |
+ | from | to | route | modes |
+ | b | a | ab,ab | river upstream,river upstream |
+ @mokob @2166
Scenario: Testbot - Mode changes on straight way without name change
Given the node map
| a | 1 | b | 2 | c |
@@ -154,11 +175,11 @@ Feature: Testbot - Travel mode
| bc | river | Avenue |
When I route I should get
- | from | to | route | modes | turns |
- | a | c | Avenue,Avenue | 1,3 | head,straight,destination |
- | c | a | Avenue,Avenue | 4,1 | head,straight,destination |
- | 1 | 2 | Avenue,Avenue | 1,3 | head,straight,destination |
- | 2 | 1 | Avenue,Avenue | 4,1 | head,straight,destination |
+ | from | to | route | modes |
+ | a | c | Avenue,Avenue,Avenue | driving,river downstream,river downstream |
+ | c | a | Avenue,Avenue,Avenue | river upstream,driving,driving |
+ | 1 | 2 | Avenue,Avenue,Avenue | driving,river downstream,river downstream |
+ | 2 | 1 | Avenue,Avenue,Avenue | river upstream,driving,driving |
Scenario: Testbot - Mode for routes
Given the node map
@@ -174,15 +195,16 @@ Feature: Testbot - Travel mode
| ef | primary | | |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd | head,right,left,destination | 1,2,1 |
- | d | a | cd,bc,ab | head,right,left,destination | 1,2,1 |
- | c | a | bc,ab | head,left,destination | 2,1 |
- | d | b | cd,bc | head,right,destination | 1,2 |
- | a | c | ab,bc | head,right,destination | 1,2 |
- | b | d | bc,cd | head,left,destination | 2,1 |
- | a | f | ab,bc,cd,de,ef | head,right,left,straight,straight,destination | 1,2,1,1,1 |
-
+ | from | to | route | modes |
+ | a | d | ab,bc,cd,cd | driving,route,driving,driving |
+ | d | a | cd,bc,ab,ab | driving,route,driving,driving |
+ | c | a | bc,ab,ab | route,driving,driving |
+ | d | b | cd,bc,bc | driving,route,route |
+ | a | c | ab,bc,bc | driving,route,route |
+ | b | d | bc,cd,cd | route,driving,driving |
+ | a | f | ab,bc,cd,de,ef,ef | driving,route,driving,driving,driving,driving |
+
+ @mokob @2166
Scenario: Testbot - Modes, triangle map
Given the node map
| | | | | | | d |
@@ -201,22 +223,23 @@ Feature: Testbot - Travel mode
| de | primary | |
When I route I should get
- | from | to | route | modes |
- | 0 | 1 | abc,ce,de | 1,3,1 |
- | 1 | 0 | de,ce,abc | 1,4,1 |
- | 0 | 2 | abc,cd | 1,1 |
- | 2 | 0 | cd,de,ce,abc | 1,1,4,1 |
- | 0 | 3 | abc,ce | 1,3 |
- | 3 | 0 | ce,abc | 4,1 |
- | 4 | 3 | ce | 3 |
- | 3 | 4 | ce | 4 |
- | 3 | 1 | ce,de | 3,1 |
- | 1 | 3 | de,ce | 1,4 |
- | a | e | abc,ce | 1,3 |
- | e | a | ce,abc | 4,1 |
- | a | d | abc,cd | 1,1 |
- | d | a | de,ce,abc | 1,4,1 |
-
+ | from | to | route | modes |
+ | 0 | 1 | abc,ce,de,de | driving,river downstream,driving,driving |
+ | 1 | 0 | de,ce,abc,abc | driving,river upstream,driving,driving |
+ | 0 | 2 | abc,cd,cd | driving,driving,driving |
+ | 2 | 0 | cd,de,ce,abc,abc | driving,driving,river upstream,driving,driving |
+ | 0 | 3 | abc,ce,ce | driving,river downstream,river downstream |
+ | 3 | 0 | ce,abc,abc | river upstream,driving,driving |
+ | 4 | 3 | ce,ce | river downstream,river downstream |
+ | 3 | 4 | ce,ce | river upstream,river upstream |
+ | 3 | 1 | ce,de,de | river downstream,driving,driving |
+ | 1 | 3 | de,ce,ce | driving,river upstream,river upstream |
+ | a | e | abc,ce,ce | driving,river downstream,river downstream |
+ | e | a | ce,abc,abc | river upstream,driving,driving |
+ | a | d | abc,cd,cd | driving,driving,driving |
+ | d | a | de,ce,abc,abc | driving,river upstream,driving,driving |
+
+ @mokob @2166
Scenario: Testbot - River in the middle
Given the node map
| a | b | c | | |
@@ -230,12 +253,12 @@ Feature: Testbot - Travel mode
| efg | primary |
When I route I should get
- | from | to | route | modes |
- | a | g | abc,cde,efg | 1,3,1 |
- | b | f | abc,cde,efg | 1,3,1 |
- | e | c | cde | 4 |
- | e | b | cde,abc | 4,1 |
- | e | a | cde,abc | 4,1 |
- | c | e | cde | 3 |
- | c | f | cde,efg | 3,1 |
- | c | g | cde,efg | 3,1 |
+ | from | to | route | modes |
+ | a | g | abc,cde,efg,efg | driving,river downstream,driving,driving |
+ | b | f | abc,cde,efg,efg | driving,river downstream,driving,driving |
+ | e | c | cde,cde | river upstream,river upstream |
+ | e | b | cde,abc,abc | river upstream,driving,driving |
+ | e | a | cde,abc,abc | river upstream,driving,driving |
+ | c | e | cde,cde | river downstream,river downstream |
+ | c | f | cde,efg,efg | river downstream,driving,driving |
+ | c | g | cde,efg,efg | river downstream,driving,driving |
diff --git a/features/testbot/oneway.feature b/features/testbot/oneway.feature
index 766bf8b..6e2326d 100644
--- a/features/testbot/oneway.feature
+++ b/features/testbot/oneway.feature
@@ -29,23 +29,23 @@ Feature: Testbot - oneways
| xe | yes |
When I route I should get
- | from | to | route |
- | a | b | ab |
- | b | c | bc |
- | c | d | cd |
- | d | e | de |
- | e | f | ef |
- | f | g | fg |
- | g | h | gh |
- | h | a | ha |
- | b | a | bc,cd,de,ef,fg,gh,ha |
- | c | b | cd,de,ef,fg,gh,ha,ab |
- | d | c | de,ef,fg,gh,ha,ab,bc |
- | e | d | ef,fg,gh,ha,ab,bc,cd |
- | f | e | fg,gh,ha,ab,bc,cd,de |
- | g | f | gh,ha,ab,bc,cd,de,ef |
- | h | g | ha,ab,bc,cd,de,ef,fg |
- | a | h | ab,bc,cd,de,ef,fg,gh |
+ | from | to | route |
+ | a | b | ab,ab |
+ | b | c | bc,bc |
+ | c | d | cd,cd |
+ | d | e | de,de |
+ | e | f | ef,ef |
+ | f | g | fg,fg |
+ | g | h | gh,gh |
+ | h | a | ha,ha |
+ | b | a | bc,cd,de,ef,fg,gh,ha,ha |
+ | c | b | cd,de,ef,fg,gh,ha,ab,ab |
+ | d | c | de,ef,fg,gh,ha,ab,bc,bc |
+ | e | d | ef,fg,gh,ha,ab,bc,cd,cd |
+ | f | e | fg,gh,ha,ab,bc,cd,de,de |
+ | g | f | gh,ha,ab,bc,cd,de,ef,ef |
+ | h | g | ha,ab,bc,cd,de,ef,fg,fg |
+ | a | h | ab,bc,cd,de,ef,fg,gh,gh |
Scenario: Testbot - Simple oneway
Then routability should be
@@ -70,9 +70,9 @@ Feature: Testbot - oneways
| da | | no |
When I route I should get
- | from | to | route |
- | a | b | ab |
- | b | a | bc,cd,da |
+ | from | to | route |
+ | a | b | ab,ab |
+ | b | a | bc,cd,da,da |
Scenario: Testbot - Handle various oneway tag values
Then routability should be
@@ -98,5 +98,5 @@ Feature: Testbot - oneways
When I route I should get
- | from | to | route |
- | a | c | ab,bc |
+ | from | to | route |
+ | a | c | ab,bc,bc |
diff --git a/features/testbot/opposite.feature b/features/testbot/opposite.feature
index c19755c..de11e5e 100644
--- a/features/testbot/opposite.feature
+++ b/features/testbot/opposite.feature
@@ -13,6 +13,6 @@ Feature: Separate settings for forward/backward direction
| abcd | river |
When I route I should get
- | from | to | route | distance | speed |
- | a | d | abcd | 300 +- 1m | 36 km/h |
- | d | a | abcd | 300 +- 1m | 16 km/h +- 1 |
+ | from | to | route | distance | speed |
+ | a | d | abcd,abcd | 300 +- 1m | 36 km/h |
+ | d | a | abcd,abcd | 300 +- 1m | 16 km/h +- 1 |
diff --git a/features/testbot/origin.feature b/features/testbot/origin.feature
index b5b1945..e56e94d 100644
--- a/features/testbot/origin.feature
+++ b/features/testbot/origin.feature
@@ -17,9 +17,9 @@ Feature: Routing close to the [0,0] origin
| abcd | yes |
When I route I should get
- | from | to | route | distance |
- | b | c | abcd | 100m +-1 |
- | c | b | | |
+ | from | to | route | distance |
+ | b | c | abcd,abcd | 100m +-1 |
+ | c | b | | |
Scenario: North-south oneways close to the origin
Given the node locations
@@ -34,9 +34,9 @@ Feature: Routing close to the [0,0] origin
| abcd | yes |
When I route I should get
- | from | to | route | distance |
- | b | c | abcd | 100m +-1 |
- | c | b | | |
+ | from | to | route | distance |
+ | b | c | abcd,abcd | 100m +-1 |
+ | c | b | | |
Scenario: East-west oneways crossing the origin
Given the node locations
@@ -52,9 +52,9 @@ Feature: Routing close to the [0,0] origin
| abcde | yes |
When I route I should get
- | from | to | route | distance |
- | b | d | abcde | 200m +-2 |
- | d | b | | |
+ | from | to | route | distance |
+ | b | d | abcde,abcde | 200m +-2 |
+ | d | b | | |
Scenario: North-south oneways crossing the origin
Given the node locations
@@ -70,6 +70,6 @@ Feature: Routing close to the [0,0] origin
| abcde | yes |
When I route I should get
- | from | to | route | distance |
- | b | d | abcde | 200m +-2 |
- | d | b | | |
+ | from | to | route | distance |
+ | b | d | abcde,abcde | 200m +-2 |
+ | d | b | | |
diff --git a/features/testbot/penalty.feature b/features/testbot/penalty.feature
index e4f3cb6..8d86a17 100644
--- a/features/testbot/penalty.feature
+++ b/features/testbot/penalty.feature
@@ -20,9 +20,9 @@ Feature: Penalties
| def |
When I route I should get
- | from | to | route | time | distance |
- | a | c | abc | 20s +-1 | 200m +-1 |
- | d | f | def | 27s +-1 | 200m +-1 |
+ | from | to | route | time | distance |
+ | a | c | abc,abc | 20s +-1 | 200m +-1 |
+ | d | f | def,def | 27s +-1 | 200m +-1 |
Scenario: Signal penalty should not depend on way type
Given the node map
@@ -43,10 +43,10 @@ Feature: Penalties
| ghi | tertiary |
When I route I should get
- | from | to | route | time |
- | a | c | abc | 27s +-1 |
- | d | f | def | 47s +-1 |
- | g | i | ghi | 67s +-1 |
+ | from | to | route | time |
+ | a | c | abc,abc | 27s +-1 |
+ | d | f | def,def | 47s +-1 |
+ | g | i | ghi,ghi | 67s +-1 |
Scenario: Passing multiple traffic signals should incur a accumulated delay
Given the node map
@@ -63,8 +63,8 @@ Feature: Penalties
| abcde |
When I route I should get
- | from | to | route | time |
- | a | e | abcde | 61s +-1 |
+ | from | to | route | time |
+ | a | e | abcde,abcde | 61s +-1 |
@todo
Scenario: Signal penalty should not depend on way type
@@ -86,13 +86,13 @@ Feature: Penalties
| ghi | tertiary |
When I route I should get
- | from | to | route | time |
- | a | b | abc | 10s +-1 |
- | a | c | abc | 27s +-1 |
- | d | e | def | 20s +-1 |
- | d | f | def | 47s +-1 |
- | g | h | ghi | 30s +-1 |
- | g | i | ghi | 67s +-1 |
+ | from | to | route | time |
+ | a | b | abc,abc | 10s +-1 |
+ | a | c | abc,abc | 27s +-1 |
+ | d | e | def,def | 20s +-1 |
+ | d | f | def,def | 47s +-1 |
+ | g | h | ghi,ghi | 30s +-1 |
+ | g | i | ghi,ghi | 67s +-1 |
Scenario: Passing multiple traffic signals should incur a accumulated delay
Given the node map
@@ -109,8 +109,8 @@ Feature: Penalties
| abcde |
When I route I should get
- | from | to | route | time |
- | a | e | abcde | 61s +-1 |
+ | from | to | route | time |
+ | a | e | abcde,abcde | 61s +-1 |
@todo
Scenario: Starting or ending at a traffic signal should not incur a delay
@@ -144,9 +144,9 @@ Feature: Penalties
| abcd | primary |
When I route I should get
- | from | to | route | time |
- | b | c | abcd | 10s +-1 |
- | c | b | abcd | 10s +-1 |
+ | from | to | route | time |
+ | b | c | abcd,abcd | 10s +-1 |
+ | c | b | abcd,abcd | 10s +-1 |
Scenario: Prefer faster route without traffic signals
Given a grid size of 50 meters
@@ -164,5 +164,5 @@ Feature: Penalties
| adc | primary |
When I route I should get
- | from | to | route |
- | a | c | adc |
+ | from | to | route |
+ | a | c | adc,adc |
diff --git a/features/testbot/planetary.feature b/features/testbot/planetary.feature
index 19925fe..1fff4bd 100644
--- a/features/testbot/planetary.feature
+++ b/features/testbot/planetary.feature
@@ -13,7 +13,7 @@ Feature: Distance calculation
When I route I should get
| from | to | route | distance |
- | a | b | ab | 8905559m ~0.1% |
+ | a | b | ab,ab | 8905559m ~0.1% |
Scenario: Approximated Longitudinal distances at latitude 45
Given the node locations
@@ -27,7 +27,7 @@ Feature: Distance calculation
When I route I should get
| from | to | route | distance |
- | c | d | cd | 6028844m ~4.5% |
+ | c | d | cd,cd | 6028844m ~4.5% |
Scenario: Approximated Longitudinal distances at latitude 80
Given the node locations
@@ -41,7 +41,7 @@ Feature: Distance calculation
When I route I should get
| from | to | route | distance |
- | c | d | cd | 1431469m ~9.5% |
+ | c | d | cd,cd | 1431469m ~9.5% |
Scenario: Approximated Latitudinal distances at longitude 0
Given the node locations
@@ -55,7 +55,7 @@ Feature: Distance calculation
When I route I should get
| from | to | route | distance |
- | a | b | ab | 8905559m ~0.1% |
+ | a | b | ab,ab | 8905559m ~0.1% |
Scenario: Approximated Latitudinal distances at longitude 45
Given the node locations
@@ -69,7 +69,7 @@ Feature: Distance calculation
When I route I should get
| from | to | route | distance |
- | a | b | ab | 8905559m ~0.1% |
+ | a | b | ab,ab | 8905559m ~0.1% |
Scenario: Approximated Latitudinal distances at longitude 80
Given the node locations
@@ -83,4 +83,4 @@ Feature: Distance calculation
When I route I should get
| from | to | route | distance |
- | a | b | ab | 8905559m ~0.1% |
+ | a | b | ab,ab | 8905559m ~0.1% |
diff --git a/features/testbot/post.feature b/features/testbot/post.feature
deleted file mode 100644
index ac53177..0000000
--- a/features/testbot/post.feature
+++ /dev/null
@@ -1,83 +0,0 @@
- at post @testbot
-Feature: POST request
-
- Background:
- Given the profile "testbot"
- And the HTTP method "POST"
-
- Scenario: Testbot - viaroute POST request
- Given the node locations
- | node | lat | lon |
- | a | 55.68740 | 12.52430 |
- | b | 55.68745 | 12.52409 |
- | c | 55.68711 | 12.52383 |
- | x | -55.68740 | 12.52430 |
- | y | -55.68745 | 12.52409 |
- | z | -55.68711 | 12.52383 |
-
- And the ways
- | nodes |
- | ab |
- | bc |
- | xy |
- | yz |
-
- When I route I should get
- | from | to | route | turns |
- | a | c | ab,bc | head,left,destination |
- | c | a | bc,ab | head,right,destination |
- | x | z | xy,yz | head,right,destination |
- | z | x | yz,xy | head,left,destination |
-
- Scenario: Testbot - match POST request
- Given a grid size of 10 meters
- Given the node map
- | a | b | c | d |
- | e | f | g | h |
-
- And the ways
- | nodes | oneway |
- | abcd | yes |
- | hgfe | yes |
-
- When I match I should get
- | trace | matchings |
- | dcba | hgfe |
-
- Scenario: Testbot - table POST request
- Given the node map
- | x | a | b | y |
- | | d | e | |
-
- And the ways
- | nodes | oneway |
- | abeda | yes |
- | xa | |
- | by | |
-
- When I request a travel time matrix I should get
- | | x | y | d | e |
- | x | 0 | 300 | 400 | 300 |
- | y | 500 | 0 | 300 | 200 |
- | d | 200 | 300 | 0 | 300 |
- | e | 300 | 400 | 100 | 0 |
-
- Scenario: Testbot - nearest POST request
- Given the node locations
- | node | lat | lon |
- | a | -85 | -180 |
- | b | -85 | -160 |
- | c | -85 | -140 |
- | x | -84.999 | -180 |
- | y | -84.999 | -160 |
- | z | -84.999 | -140 |
-
- And the ways
- | nodes |
- | abc |
-
- When I request nearest I should get
- | in | out |
- | x | a |
- | y | b |
- | z | c |
diff --git a/features/testbot/projection.feature b/features/testbot/projection.feature
index d7a0b89..ad4a32b 100644
--- a/features/testbot/projection.feature
+++ b/features/testbot/projection.feature
@@ -23,16 +23,16 @@ Feature: Projection to nearest point on road
Scenario: Projection onto way at high latitudes, 1km distance
When I route I should get
- | from | to | route | compass | bearing | distance |
- | b | a | abc | SW | 225 | 1000m +-7 |
- | b | c | abc | NE | 45 | 1000m +-7 |
- | a | d | abc | NE | 45 | 1000m +-7 |
- | d | a | abc | SW | 225 | 1000m +-7 |
- | c | d | abc | SW | 225 | 1000m +-8 |
- | d | c | abc | NE | 45 +-5 | 1000m +-8 |
+ | from | to | route | bearing | distance |
+ | b | a | abc,abc | 225,0 +-1 | 1000m +- 7 |
+ | b | c | abc,abc | 45,0 +-1 | 1000m +- 7 |
+ | a | d | abc,abc | 45,0 +-1 | 1000m +- 7 |
+ | d | a | abc,abc | 225,0 +-1 | 1000m +- 7 |
+ | c | d | abc,abc | 225,0 +-1 | 1000m +- 8 |
+ | d | c | abc,abc | 45 +-1 | 1000m +- 8 |
Scenario: Projection onto way at high latitudes, no distance
When I route I should get
- | from | to | route | distance |
- | d | b | abc | 0m +-5 |
- | b | d | abc | 0m +-5 |
+ | from | to | route | distance |
+ | d | b | abc,abc | 0m +-5 |
+ | b | d | abc,abc | 0m +-5 |
diff --git a/features/testbot/protobuffer.feature b/features/testbot/protobuffer.feature
deleted file mode 100644
index e32de26..0000000
--- a/features/testbot/protobuffer.feature
+++ /dev/null
@@ -1,156 +0,0 @@
- at routing @pbf @testbot
-Feature: Importing protobuffer (.pbf) format
-# Test normally read .osm, which is faster than .pbf files,
-# since we don't need to use osmosis to first convert to .pbf
-# The scenarios in this file test the ability to import .pbf files,
-# including nodes, way, restictions, and a various special situations.
-
- Background:
- Given the profile "testbot"
- And the import format "pbf"
-
- Scenario: Testbot - Protobuffer import, nodes and ways
- Given the node map
- | | | | d |
- | a | b | c | |
- | | | | e |
-
- And the ways
- | nodes | highway | oneway |
- | abc | primary | |
- | cd | primary | yes |
- | ce | river | |
- | de | primary | |
-
- When I route I should get
- | from | to | route |
- | d | c | de,ce |
- | e | d | de |
-
-
- Scenario: Testbot - Protobuffer import, turn restiction relations
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway |
- | sj | yes |
- | nj | -1 |
- | wj | -1 |
- | ej | -1 |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | wj | j | no_left_turn |
-
- When I route I should get
- | from | to | route |
- | s | w | |
- | s | n | sj,nj |
- | s | e | sj,ej |
-
-
- Scenario: Testbot - Protobuffer import, distances at longitude 45
- Given the node locations
- | node | lat | lon |
- | a | 80 | 45 |
- | b | 0 | 45 |
-
- And the ways
- | nodes |
- | ab |
-
- When I route I should get
- | from | to | route | distance |
- | a | b | ab | 8905559m ~0.1% |
-
- Scenario: Testbot - Protobuffer import, distances at longitude 80
- Given the node locations
- | node | lat | lon |
- | a | 80 | 80 |
- | b | 0 | 80 |
-
- And the ways
- | nodes |
- | ab |
-
- When I route I should get
- | from | to | route | distance |
- | a | b | ab | 8905559m ~0.1% |
-
- Scenario: Testbot - Protobuffer import, empty dataset
- Given the node map
- | |
-
- Given the ways
- | nodes |
-
- When the data has been prepared
- Then "osrm-extract" should return code 1
-
-
- Scenario: Testbot - Protobuffer import, streetnames with UTF characters
- Given the node map
- | a | b | c | d |
-
- And the ways
- | nodes | name |
- | ab | Scandinavian København |
- | bc | Japanese 東京 |
- | cd | Cyrillic Москва |
-
- When I route I should get
- | from | to | route |
- | a | b | Scandinavian København |
- | b | c | Japanese 東京 |
- | c | d | Cyrillic Москва |
-
- Scenario: Testbot - Protobuffer import, bearing af 45 degree intervals
- Given the node map
- | b | a | h |
- | c | x | g |
- | d | e | f |
-
- And the ways
- | nodes |
- | xa |
- | xb |
- | xc |
- | xd |
- | xe |
- | xf |
- | xg |
- | xh |
-
- When I route I should get
- | from | to | route | compass | bearing |
- | x | a | xa | N | 0 |
- | x | b | xb | NW | 315 |
- | x | c | xc | W | 270 |
- | x | d | xd | SW | 225 |
- | x | e | xe | S | 180 |
- | x | f | xf | SE | 135 |
- | x | g | xg | E | 90 |
- | x | h | xh | NE | 45 |
-
-
- Scenario: Testbot - Protobuffer import, rraffic signals should incur a delay
- Given the node map
- | a | b | c |
- | d | e | f |
-
- And the nodes
- | node | highway |
- | e | traffic_signals |
-
- And the ways
- | nodes |
- | abc |
- | def |
-
- When I route I should get
- | from | to | route | time | distance |
- | a | c | abc | 20s +-1 | 200m +-1 |
- | d | f | def | 27s +-1 | 200m +-1 |
diff --git a/features/testbot/roundabout.feature b/features/testbot/roundabout.feature
index 570b14b..90f2fc0 100644
--- a/features/testbot/roundabout.feature
+++ b/features/testbot/roundabout.feature
@@ -21,19 +21,19 @@ Feature: Roundabout Instructions
| abcda | roundabout |
When I route I should get
- | from | to | route | turns |
- | s | t | sa,tb | head,enter_roundabout-1,destination |
- | s | u | sa,uc | head,enter_roundabout-2,destination |
- | s | v | sa,vd | head,enter_roundabout-3,destination |
- | t | u | tb,uc | head,enter_roundabout-1,destination |
- | t | v | tb,vd | head,enter_roundabout-2,destination |
- | t | s | tb,sa | head,enter_roundabout-3,destination |
- | u | v | uc,vd | head,enter_roundabout-1,destination |
- | u | s | uc,sa | head,enter_roundabout-2,destination |
- | u | t | uc,tb | head,enter_roundabout-3,destination |
- | v | s | vd,sa | head,enter_roundabout-1,destination |
- | v | t | vd,tb | head,enter_roundabout-2,destination |
- | v | u | vd,uc | head,enter_roundabout-3,destination |
+ | from | to | route | turns |
+ | s | t | sa,tb,tb | depart,roundabout-exit-1,arrive |
+ | s | u | sa,uc,uc | depart,roundabout-exit-2,arrive |
+ | s | v | sa,vd,vd | depart,roundabout-exit-3,arrive |
+ | t | u | tb,uc,uc | depart,roundabout-exit-1,arrive |
+ | t | v | tb,vd,vd | depart,roundabout-exit-2,arrive |
+ | t | s | tb,sa,sa | depart,roundabout-exit-3,arrive |
+ | u | v | uc,vd,vd | depart,roundabout-exit-1,arrive |
+ | u | s | uc,sa,sa | depart,roundabout-exit-2,arrive |
+ | u | t | uc,tb,tb | depart,roundabout-exit-3,arrive |
+ | v | s | vd,sa,sa | depart,roundabout-exit-1,arrive |
+ | v | t | vd,tb,tb | depart,roundabout-exit-2,arrive |
+ | v | u | vd,uc,uc | depart,roundabout-exit-3,arrive |
Scenario: Testbot - Roundabout with oneway links
Given the node map
@@ -57,20 +57,20 @@ Feature: Roundabout Instructions
| abcdefgha | roundabout | |
When I route I should get
- | from | to | route | turns |
- | j | k | jb,ck | head,enter_roundabout-1,destination |
- | j | m | jb,em | head,enter_roundabout-2,destination |
- | j | o | jb,go | head,enter_roundabout-3,destination |
- | j | i | jb,ai | head,enter_roundabout-4,destination |
- | l | m | ld,em | head,enter_roundabout-1,destination |
- | l | o | ld,go | head,enter_roundabout-2,destination |
- | l | i | ld,ai | head,enter_roundabout-3,destination |
- | l | k | ld,ck | head,enter_roundabout-4,destination |
- | n | o | nf,go | head,enter_roundabout-1,destination |
- | n | i | nf,ai | head,enter_roundabout-2,destination |
- | n | k | nf,ck | head,enter_roundabout-3,destination |
- | n | m | nf,em | head,enter_roundabout-4,destination |
- | p | i | ph,ai | head,enter_roundabout-1,destination |
- | p | k | ph,ck | head,enter_roundabout-2,destination |
- | p | m | ph,em | head,enter_roundabout-3,destination |
- | p | o | ph,go | head,enter_roundabout-4,destination |
+ | from | to | route | turns |
+ | j | k | jb,ck,ck | depart,roundabout-exit-1,arrive |
+ | j | m | jb,em,em | depart,roundabout-exit-2,arrive |
+ | j | o | jb,go,go | depart,roundabout-exit-3,arrive |
+ | j | i | jb,ai,ai | depart,roundabout-exit-4,arrive |
+ | l | m | ld,em,em | depart,roundabout-exit-1,arrive |
+ | l | o | ld,go,go | depart,roundabout-exit-2,arrive |
+ | l | i | ld,ai,ai | depart,roundabout-exit-3,arrive |
+ | l | k | ld,ck,ck | depart,roundabout-exit-4,arrive |
+ | n | o | nf,go,go | depart,roundabout-exit-1,arrive |
+ | n | i | nf,ai,ai | depart,roundabout-exit-2,arrive |
+ | n | k | nf,ck,ck | depart,roundabout-exit-3,arrive |
+ | n | m | nf,em,em | depart,roundabout-exit-4,arrive |
+ | p | i | ph,ai,ai | depart,roundabout-exit-1,arrive |
+ | p | k | ph,ck,ck | depart,roundabout-exit-2,arrive |
+ | p | m | ph,em,em | depart,roundabout-exit-3,arrive |
+ | p | o | ph,go,go | depart,roundabout-exit-4,arrive |
diff --git a/features/testbot/snap.feature b/features/testbot/snap.feature
index 9b7bcbd..80c44bb 100644
--- a/features/testbot/snap.feature
+++ b/features/testbot/snap.feature
@@ -21,14 +21,14 @@ Feature: Snap start/end point to the nearest way
When I route I should get
| from | to | route |
- | 1 | c | nc |
- | 2 | c | nc |
- | 3 | c | ec |
- | 4 | c | ec |
- | 5 | c | sc |
- | 6 | c | sc |
- | 7 | c | wc |
- | 8 | c | wc |
+ | 1 | c | nc,nc |
+ | 2 | c | nc,nc |
+ | 3 | c | ec,ec |
+ | 4 | c | ec,ec |
+ | 5 | c | sc,sc |
+ | 6 | c | sc,sc |
+ | 7 | c | wc,wc |
+ | 8 | c | wc,wc |
Scenario: Snap to nearest edge of a square
Given the node map
@@ -43,11 +43,11 @@ Feature: Snap start/end point to the nearest way
| adb |
When I route I should get
- | from | to | route |
- | 1 | b | adb |
- | 2 | b | adb |
- | 6 | b | aub |
- | 7 | b | aub |
+ | from | to | route |
+ | 1 | b | adb,adb |
+ | 2 | b | adb,adb |
+ | 6 | b | aub,aub |
+ | 7 | b | aub,aub |
Scenario: Snap to edge right under start/end point
Given the node map
@@ -64,17 +64,17 @@ Feature: Snap start/end point to the nearest way
| jkla |
When I route I should get
- | from | to | route |
- | a | b | abcd |
- | a | c | abcd |
- | a | d | abcd |
- | a | e | abcd,defg |
- | a | f | abcd,defg |
- | a | h | jkla,ghij |
- | a | i | jkla,ghij |
- | a | j | jkla |
- | a | k | jkla |
- | a | l | jkla |
+ | from | to | route |
+ | a | b | abcd,abcd |
+ | a | c | abcd,abcd |
+ | a | d | abcd,abcd |
+ | a | e | abcd,defg,defg |
+ | a | f | abcd,defg,defg |
+ | a | h | jkla,ghij,ghij |
+ | a | i | jkla,ghij,ghij |
+ | a | j | jkla,jkla |
+ | a | k | jkla,jkla |
+ | a | l | jkla,jkla |
Scenario: Snapping in viaroute
Given the extract extra arguments "--small-component-size 4"
@@ -92,9 +92,9 @@ Feature: Snap start/end point to the nearest way
When I route I should get
| from | to | route |
- | a | b | ab |
- | a | d | cd |
- | c | d | cd |
+ | a | b | ab,ab |
+ | a | d | cd,cd |
+ | c | d | cd,cd |
Scenario: Snap to correct way at large scales
Given a grid size of 1000 meters
@@ -111,12 +111,12 @@ Feature: Snap start/end point to the nearest way
When I route I should get
| from | to | route |
- | x | a | xa |
- | x | b | xb |
- | x | c | xc |
- | a | x | xa |
- | b | x | xb |
- | c | x | xc |
+ | x | a | xa,xa |
+ | x | b | xb,xb |
+ | x | c | xc,xc |
+ | a | x | xa,xa |
+ | b | x | xb,xb |
+ | c | x | xc,xc |
Scenario: Find edges within 100m, and the same from 1km
Given a grid size of 100 meters
@@ -152,19 +152,19 @@ Feature: Snap start/end point to the nearest way
When I route I should get
| from | to | route |
- | x | 1 | xa |
- | x | 2 | xb |
- | x | 3 | xc |
- | x | 4 | xd |
- | x | 5 | xe |
- | x | 6 | xf |
- | x | 7 | xg |
- | x | 8 | xh |
- | x | i | xa |
- | x | j | xb |
- | x | k | xc |
- | x | l | xd |
- | x | m | xe |
- | x | n | xf |
- | x | o | xg |
- | x | p | xh |
+ | x | 1 | xa,xa |
+ | x | 2 | xb,xb |
+ | x | 3 | xc,xc |
+ | x | 4 | xd,xd |
+ | x | 5 | xe,xe |
+ | x | 6 | xf,xf |
+ | x | 7 | xg,xg |
+ | x | 8 | xh,xh |
+ | x | i | xa,xa |
+ | x | j | xb,xb |
+ | x | k | xc,xc |
+ | x | l | xd,xd |
+ | x | m | xe,xe |
+ | x | n | xf,xf |
+ | x | o | xg,xg |
+ | x | p | xh,xh |
diff --git a/features/testbot/speed.feature b/features/testbot/speed.feature
index 2eb3724..0416419 100644
--- a/features/testbot/speed.feature
+++ b/features/testbot/speed.feature
@@ -26,6 +26,6 @@ Feature: Testbot - speeds
| ab | river |
When I route I should get
- | from | to | route | speed | time | distance |
- | a | b | ab | 36 km/h | 10s | 100m |
- | b | a | ab | 16 km/h +- 1 | 23s | 100m |
+ | from | to | route | speed | time | distance |
+ | a | b | ab,ab | 36 km/h | 10s +-1 | 100m +- 1 |
+ | b | a | ab,ab | 16 km/h +- 1 | 23s +-1 | 100m +- 1 |
diff --git a/features/testbot/status.feature b/features/testbot/status.feature
index 86d8259..41ad18b 100644
--- a/features/testbot/status.feature
+++ b/features/testbot/status.feature
@@ -14,8 +14,8 @@ Feature: Status messages
When I route I should get
| from | to | route | status | message |
- | a | b | ab | 200 | Found route between points |
- | b | a | ab | 200 | Found route between points |
+ | a | b | ab,ab | 200 | |
+ | b | a | ab,ab | 200 | |
Scenario: No route found
Given the node map
@@ -30,38 +30,38 @@ Feature: Status messages
When I route I should get
| from | to | route | status | message |
- | a | b | ab | 200 | Found route between points |
- | c | d | cd | 200 | Found route between points |
- | a | c | | 207 | Impossible route between points |
- | b | d | | 207 | Impossible route between points |
+ | a | b | ab,ab | 200 | |
+ | c | d | cd,cd | 200 | |
+ | a | c | | 400 | Impossible route between points |
+ | b | d | | 400 | Impossible route between points |
Scenario: Malformed requests
Given the node locations
| node | lat | lon |
| a | 1.00 | 1.00 |
- | b | 1.01 | 1.00 |
+ | b | 2.00 | 1.00 |
And the ways
| nodes |
| ab |
When I route I should get
- | request | status | message |
- | viaroute?loc=1,1&loc=1.01,1 | 200 | Found route between points |
- | nonsense | 400 | Service not found |
- | nonsense?loc=1,1&loc=1.01,1 | 400 | Service not found |
- | | 400 | Query string malformed close to position 0 |
- | / | 400 | Query string malformed close to position 0 |
- | ? | 400 | Query string malformed close to position 0 |
- | viaroute?loc= | 400 | Query string malformed close to position 9 |
- | viaroute?loc=1 | 400 | Query string malformed close to position 9 |
- | viaroute?loc=1,1 | 400 | Invalid coordinates |
- | viaroute?loc=1,1,1 | 400 | Query string malformed close to position 17 |
- | viaroute?loc=x | 400 | Query string malformed close to position 9 |
- | viaroute?loc=x,y | 400 | Query string malformed close to position 9 |
- | viaroute?loc=1,1&loc= | 400 | Query string malformed close to position 17 |
- | viaroute?loc=1,1&loc=1 | 400 | Query string malformed close to position 17 |
- | viaroute?loc=1,1&loc=1,1 | 200 | Found route between points |
- | viaroute?loc=1,1&loc=1,1,1 | 400 | Query string malformed close to position 25 |
- | viaroute?loc=1,1&loc=x | 400 | Query string malformed close to position 17 |
- | viaroute?loc=1,1&loc=x,y | 400 | Query string malformed close to position 17 |
+ | request | status | message |
+ | route/v1/driving/1,1;1,2 | 200 | |
+ | nonsense | 400 | URL string malformed close to position 0: "/no" |
+ | nonsense/v1/driving/1,1;1,2 | 400 | Service nonsense not found! |
+ | | 400 | URL string malformed close to position 0: "/" |
+ | / | 400 | URL string malformed close to position 0: "//" |
+ | ? | 400 | URL string malformed close to position 0: "/?" |
+ | route/v1/driving | 400 | URL string malformed close to position 0: "/ro" |
+ | route/v1/driving/ | 400 | URL string malformed close to position 0: "/ro" |
+ | route/v1/driving/1 | 400 | Query string malformed close to position 0 |
+ | route/v1/driving/1,1 | 400 | Number of coordinates needs to be at least two. |
+ | route/v1/driving/1,1,1 | 400 | Query string malformed close to position 3 |
+ | route/v1/driving/x | 400 | Query string malformed close to position 0 |
+ | route/v1/driving/x,y | 400 | Query string malformed close to position 0 |
+ | route/v1/driving/1,1; | 400 | Query string malformed close to position 3 |
+ | route/v1/driving/1,1;1 | 400 | Query string malformed close to position 3 |
+ | route/v1/driving/1,1;1,1,1 | 400 | Query string malformed close to position 7 |
+ | route/v1/driving/1,1;x | 400 | Query string malformed close to position 3 |
+ | route/v1/driving/1,1;x,y | 400 | Query string malformed close to position 3 |
diff --git a/features/testbot/time.feature b/features/testbot/time.feature
index c838796..834b13b 100644
--- a/features/testbot/time.feature
+++ b/features/testbot/time.feature
@@ -27,15 +27,15 @@ Feature: Estimation of travel time
| xh | primary |
When I route I should get
- | from | to | route | time |
- | x | a | xa | 1s +-1 |
- | x | b | xb | 1s +-1 |
- | x | c | xc | 1s +-1 |
- | x | d | xd | 1s +-1 |
- | x | e | xe | 1s +-1 |
- | x | f | xf | 1s +-1 |
- | x | g | xg | 1s +-1 |
- | x | h | xh | 1s +-1 |
+ | from | to | route | time |
+ | x | a | xa,xa | 1s +-1 |
+ | x | b | xb,xb | 1s +-1 |
+ | x | c | xc,xc | 1s +-1 |
+ | x | d | xd,xd | 1s +-1 |
+ | x | e | xe,xe | 1s +-1 |
+ | x | f | xf,xf | 1s +-1 |
+ | x | g | xg,xg | 1s +-1 |
+ | x | h | xh,xh | 1s +-1 |
Scenario: Basic travel time, 100m scale
Given a grid size of 100 meters
@@ -56,15 +56,15 @@ Feature: Estimation of travel time
| xh | primary |
When I route I should get
- | from | to | route | time |
- | x | a | xa | 10s +-1 |
- | x | b | xb | 14s +-1 |
- | x | c | xc | 10s +-1 |
- | x | d | xd | 14s +-1 |
- | x | e | xe | 10s +-1 |
- | x | f | xf | 14s +-1 |
- | x | g | xg | 10s +-1 |
- | x | h | xh | 14s +-1 |
+ | from | to | route | time |
+ | x | a | xa,xa | 10s +-1 |
+ | x | b | xb,xb | 14s +-1 |
+ | x | c | xc,xc | 10s +-1 |
+ | x | d | xd,xd | 14s +-1 |
+ | x | e | xe,xe | 10s +-1 |
+ | x | f | xf,xf | 14s +-1 |
+ | x | g | xg,xg | 10s +-1 |
+ | x | h | xh,xh | 14s +-1 |
Scenario: Basic travel time, 1km scale
Given a grid size of 1000 meters
@@ -85,15 +85,15 @@ Feature: Estimation of travel time
| xh | primary |
When I route I should get
- | from | to | route | time |
- | x | a | xa | 100s +-1 |
- | x | b | xb | 141s +-1 |
- | x | c | xc | 100s +-1 |
- | x | d | xd | 141s +-1 |
- | x | e | xe | 100s +-1 |
- | x | f | xf | 141s +-1 |
- | x | g | xg | 100s +-1 |
- | x | h | xh | 141s +-1 |
+ | from | to | route | time |
+ | x | a | xa,xa | 100s +-1 |
+ | x | b | xb,xb | 141s +-1 |
+ | x | c | xc,xc | 100s +-1 |
+ | x | d | xd,xd | 141s +-1 |
+ | x | e | xe,xe | 100s +-1 |
+ | x | f | xf,xf | 141s +-1 |
+ | x | g | xg,xg | 100s +-1 |
+ | x | h | xh,xh | 141s +-1 |
Scenario: Basic travel time, 10km scale
Given a grid size of 10000 meters
@@ -114,15 +114,15 @@ Feature: Estimation of travel time
| xh | primary |
When I route I should get
- | from | to | route | time |
- | x | a | xa | 1000s +-1 |
- | x | b | xb | 1414s +-1 |
- | x | c | xc | 1000s +-1 |
- | x | d | xd | 1414s +-1 |
- | x | e | xe | 1000s +-1 |
- | x | f | xf | 1414s +-1 |
- | x | g | xg | 1000s +-1 |
- | x | h | xh | 1414s +-1 |
+ | from | to | route | time |
+ | x | a | xa,xa | 1000s +-1 |
+ | x | b | xb,xb | 1414s +-1 |
+ | x | c | xc,xc | 1000s +-1 |
+ | x | d | xd,xd | 1414s +-1 |
+ | x | e | xe,xe | 1000s +-1 |
+ | x | f | xf,xf | 1414s +-1 |
+ | x | g | xg,xg | 1000s +-1 |
+ | x | h | xh,xh | 1414s +-1 |
Scenario: Time of travel depending on way type
Given the node map
@@ -138,10 +138,10 @@ Feature: Estimation of travel time
| ace | something |
When I route I should get
- | from | to | route | time |
- | a | b | ab | 10s +-1 |
- | c | d | cd | 20s +-1 |
- | e | f | ef | 30s +-1 |
+ | from | to | route | time |
+ | a | b | ab,ab | 10s +-1 |
+ | c | d | cd,cd | 20s +-1 |
+ | e | f | ef,ef | 30s +-1 |
Scenario: Time of travel on a series of ways
Given the node map
@@ -155,10 +155,10 @@ Feature: Estimation of travel time
| cd | primary |
When I route I should get
- | from | to | route | time |
- | a | b | ab | 10s +-1 |
- | a | c | ab,bc | 20s +-1 |
- | a | d | ab,bc,cd | 30s +-1 |
+ | from | to | route | time |
+ | a | b | ab,ab | 10s +-1 |
+ | a | c | ab,bc,bc | 20s +-1 |
+ | a | d | ab,bc,cd,cd | 30s +-1 |
Scenario: Time of travel on a winding way
Given the node map
@@ -171,10 +171,10 @@ Feature: Estimation of travel time
| abcdefghi | primary |
When I route I should get
- | from | to | route | time |
- | a | b | abcdefghi | 10s +-1 |
- | a | e | abcdefghi | 40s +-1 |
- | a | i | abcdefghi | 80s +-1 |
+ | from | to | route | time |
+ | a | b | abcdefghi,abcdefghi | 10s +-1 |
+ | a | e | abcdefghi,abcdefghi | 40s +-1 |
+ | a | i | abcdefghi,abcdefghi | 80s +-1 |
Scenario: Time of travel on combination of road types
Given the node map
@@ -188,11 +188,11 @@ Feature: Estimation of travel time
| cde | tertiary |
When I route I should get
- | from | to | route | time |
- | b | c | abc | 10s +-1 |
- | c | e | cde | 60s +-1 |
- | b | d | abc,cde | 40s +-1 |
- | a | e | abc,cde | 80s +-1 |
+ | from | to | route | time |
+ | b | c | abc,abc | 10s +-1 |
+ | c | e | cde,cde | 60s +-1 |
+ | b | d | abc,cde,cde | 40s +-1 |
+ | a | e | abc,cde,cde | 80s +-1 |
Scenario: Time of travel on part of a way
Given the node map
@@ -206,13 +206,13 @@ Feature: Estimation of travel time
| ab | primary |
When I route I should get
- | from | to | route | time |
- | 1 | 2 | ab | 10s +-1 |
- | 1 | 3 | ab | 20s +-1 |
- | 1 | 4 | ab | 30s +-1 |
- | 4 | 3 | ab | 10s +-1 |
- | 4 | 2 | ab | 20s +-1 |
- | 4 | 1 | ab | 30s +-1 |
+ | from | to | route | time |
+ | 1 | 2 | ab,ab | 10s +-1 |
+ | 1 | 3 | ab,ab | 20s +-1 |
+ | 1 | 4 | ab,ab | 30s +-1 |
+ | 4 | 3 | ab,ab | 10s +-1 |
+ | 4 | 2 | ab,ab | 20s +-1 |
+ | 4 | 1 | ab,ab | 30s +-1 |
Scenario: Total travel time should match sum of times of individual ways
Given a grid size of 1000 meters
@@ -228,10 +228,10 @@ Feature: Estimation of travel time
| cd | primary |
When I route I should get
- | from | to | route | distances | distance | times | time |
- | a | b | ab | 1000m +-1 | 1000m +-1 | 100s +-1 | 100s +-1 |
- | b | c | bc | 2000m +-1 | 2000m +-1 | 200s +-1 | 200s +-1 |
- | c | d | cd | 3000m +-1 | 3000m +-1 | 300s +-1 | 300s +-1 |
- | a | c | ab,bc | 1000m,2000m +-1 | 3000m +-1 | 100s,200s +-1 | 300s +-1 |
- | b | d | bc,cd | 2000m,3000m +-1 | 5000m +-1 | 200s,300s +-1 | 500s +-1 |
- | a | d | ab,bc,cd | 1000m,2000m,3000m +-1 | 6000m +-1 | 100s,200s,300s +-1 | 600s +-1 |
+ | from | to | route | distances | distance | times | time |
+ | a | b | ab,ab | 1000m +-1 | 1000m +-1 | 100s +-1 | 100s +-1 |
+ | b | c | bc,bc | 2000m +-1 | 2000m +-1 | 200s +-1 | 200s +-1 |
+ | c | d | cd,cd | 3000m +-1 | 3000m +-1 | 300s +-1 | 300s +-1 |
+ | a | c | ab,bc,bc | 1000m,2000m +-1 | 3000m +-1 | 100s,200s +-1 | 300s +-1 |
+ | b | d | bc,cd,cd | 2000m,3000m +-1 | 5000m +-1 | 200s,300s +-1 | 500s +-1 |
+ | a | d | ab,bc,cd,cd | 1000m,2000m,3000m +-1 | 6000m +-1 | 100s,200s,300s +-1 | 600s +-1 |
diff --git a/features/testbot/trip.feature b/features/testbot/trip.feature
index c9f944b..5f33763 100644
--- a/features/testbot/trip.feature
+++ b/features/testbot/trip.feature
@@ -82,5 +82,20 @@ Feature: Basic trip planning
| waypoints | trips |
| a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p | cbalkjihgfedc,ponm |
+ # Test single node in each component #1850
+ Scenario: Testbot - Trip planning with less than 10 nodes
+ Given the node map
+ | a | 1 | b |
+ | | | |
+ | c | 2 | d |
+
+ And the ways
+ | nodes |
+ | ab |
+ | cd |
+
+ When I plan a trip I should get
+ | waypoints | trips |
+ | 1,2 | |
diff --git a/features/testbot/turn_angles.feature b/features/testbot/turn_angles.feature
new file mode 100644
index 0000000..115fd23
--- /dev/null
+++ b/features/testbot/turn_angles.feature
@@ -0,0 +1,74 @@
+ at routing @testbot @via
+Feature: Via points
+
+ Background:
+ Given the profile "testbot"
+
+ And a grid size of 4 meters
+
+ Scenario: Basic Right Turn
+ Given the node map
+ | a | b | c | d | e | f | g |
+ | | | | | | h | |
+ | | | | | | i | |
+ | | | | | | j | |
+ | | | | | | k | |
+
+ And the ways
+ | nodes | oneway |
+ | abcdefg | yes |
+ | ehijk | yes |
+
+ When I route I should get
+ | from | to | route | distance | turns |
+ | a | k | abcdefg,ehijk,ehijk | 34m +-1 | depart,right,arrive |
+
+ Scenario: Slight Turn
+ Given the node map
+ | a | b | c | d | e | f | g | |
+ | | | | | | h | i | |
+ | | | | | | | | j |
+ | | | | | | | | k |
+
+ And the ways
+ | nodes | oneway |
+ | abcdefg | yes |
+ | ehijk | yes |
+
+ When I route I should get
+ | from | to | route | distance | turns |
+ | a | k | abcdefg,ehijk,ehijk | 35m +-1 | depart,slight right,arrive |
+
+ Scenario: Nearly Slight Turn
+ Given the node map
+ | a | b | c | d | e | f | g | |
+ | | | | | | h | | |
+ | | | | | | | i | |
+ | | | | | | | | j |
+ | | | | | | | | k |
+
+ And the ways
+ | nodes | oneway |
+ | abcdefg | yes |
+ | ehijk | yes |
+
+ When I route I should get
+ | from | to | route | distance | turns |
+ | a | k | abcdefg,ehijk,ehijk | 37m +-1 | depart,right,arrive |
+
+ Scenario: Nearly Slight Turn (Variation)
+ Given the node map
+ | a | b | c | d | e | f | g | |
+ | | | | | | h | | |
+ | | | | | | | i | |
+ | | | | | | | j | |
+ | | | | | | | | k |
+
+ And the ways
+ | nodes | oneway |
+ | abcdefg | yes |
+ | ehijk | yes |
+
+ When I route I should get
+ | from | to | route | distance | turns |
+ | a | k | abcdefg,ehijk,ehijk | 37m +-1 | depart,right,arrive |
diff --git a/features/testbot/turns.feature b/features/testbot/turns.feature
index 6eba4f9..c80bdf7 100644
--- a/features/testbot/turns.feature
+++ b/features/testbot/turns.feature
@@ -14,88 +14,80 @@ Feature: Turn directions/codes
And the ways
| nodes |
- | xa |
- | xb |
- | xc |
- | xd |
- | xe |
- | xf |
- | xg |
- | xh |
| xi |
- | xj |
| xk |
- | xl |
| xm |
- | xn |
| xo |
- | xp |
+ | xa |
+ | xc |
+ | xe |
+ | xg |
When I route I should get
- | from | to | route | turns |
- | i | k | xi,xk | head,sharp_left,destination |
- | i | m | xi,xm | head,left,destination |
- | i | o | xi,xo | head,slight_left,destination |
- | i | a | xi,xa | head,straight,destination |
- | i | c | xi,xc | head,slight_right,destination |
- | i | e | xi,xe | head,right,destination |
- | i | g | xi,xg | head,sharp_right,destination |
+ | from | to | route | turns |
+ | i | k | xi,xk,xk | depart,sharp left,arrive |
+ | i | m | xi,xm,xm | depart,left,arrive |
+ | i | o | xi,xo,xo | depart,slight left,arrive |
+ | i | a | xi,xa,xa | depart,straight,arrive |
+ | i | c | xi,xc,xc | depart,slight right,arrive |
+ | i | e | xi,xe,xe | depart,right,arrive |
+ | i | g | xi,xg,xg | depart,sharp right,arrive |
- | k | m | xk,xm | head,sharp_left,destination |
- | k | o | xk,xo | head,left,destination |
- | k | a | xk,xa | head,slight_left,destination |
- | k | c | xk,xc | head,straight,destination |
- | k | e | xk,xe | head,slight_right,destination |
- | k | g | xk,xg | head,right,destination |
- | k | i | xk,xi | head,sharp_right,destination |
+ | k | m | xk,xm,xm | depart,sharp left,arrive |
+ | k | o | xk,xo,xo | depart,left,arrive |
+ | k | a | xk,xa,xa | depart,slight left,arrive |
+ | k | c | xk,xc,xc | depart,straight,arrive |
+ | k | e | xk,xe,xe | depart,slight right,arrive |
+ | k | g | xk,xg,xg | depart,right,arrive |
+ | k | i | xk,xi,xi | depart,sharp right,arrive |
- | m | o | xm,xo | head,sharp_left,destination |
- | m | a | xm,xa | head,left,destination |
- | m | c | xm,xc | head,slight_left,destination |
- | m | e | xm,xe | head,straight,destination |
- | m | g | xm,xg | head,slight_right,destination |
- | m | i | xm,xi | head,right,destination |
- | m | k | xm,xk | head,sharp_right,destination |
+ | m | o | xm,xo,xo | depart,sharp left,arrive |
+ | m | a | xm,xa,xa | depart,left,arrive |
+ | m | c | xm,xc,xc | depart,slight left,arrive |
+ | m | e | xm,xe,xe | depart,straight,arrive |
+ | m | g | xm,xg,xg | depart,slight right,arrive |
+ | m | i | xm,xi,xi | depart,right,arrive |
+ | m | k | xm,xk,xk | depart,sharp right,arrive |
- | o | a | xo,xa | head,sharp_left,destination |
- | o | c | xo,xc | head,left,destination |
- | o | e | xo,xe | head,slight_left,destination |
- | o | g | xo,xg | head,straight,destination |
- | o | i | xo,xi | head,slight_right,destination |
- | o | k | xo,xk | head,right,destination |
- | o | m | xo,xm | head,sharp_right,destination |
+ | o | a | xo,xa,xa | depart,sharp left,arrive |
+ | o | c | xo,xc,xc | depart,left,arrive |
+ | o | e | xo,xe,xe | depart,slight left,arrive |
+ | o | g | xo,xg,xg | depart,straight,arrive |
+ | o | i | xo,xi,xi | depart,slight right,arrive |
+ | o | k | xo,xk,xk | depart,right,arrive |
+ | o | m | xo,xm,xm | depart,sharp right,arrive |
- | a | c | xa,xc | head,sharp_left,destination |
- | a | e | xa,xe | head,left,destination |
- | a | g | xa,xg | head,slight_left,destination |
- | a | i | xa,xi | head,straight,destination |
- | a | k | xa,xk | head,slight_right,destination |
- | a | m | xa,xm | head,right,destination |
- | a | o | xa,xo | head,sharp_right,destination |
+ | a | c | xa,xc,xc | depart,sharp left,arrive |
+ | a | e | xa,xe,xe | depart,left,arrive |
+ | a | g | xa,xg,xg | depart,slight left,arrive |
+ | a | i | xa,xi,xi | depart,straight,arrive |
+ | a | k | xa,xk,xk | depart,slight right,arrive |
+ | a | m | xa,xm,xm | depart,right,arrive |
+ | a | o | xa,xo,xo | depart,sharp right,arrive |
- | c | e | xc,xe | head,sharp_left,destination |
- | c | g | xc,xg | head,left,destination |
- | c | i | xc,xi | head,slight_left,destination |
- | c | k | xc,xk | head,straight,destination |
- | c | m | xc,xm | head,slight_right,destination |
- | c | o | xc,xo | head,right,destination |
- | c | a | xc,xa | head,sharp_right,destination |
+ | c | e | xc,xe,xe | depart,sharp left,arrive |
+ | c | g | xc,xg,xg | depart,left,arrive |
+ | c | i | xc,xi,xi | depart,slight left,arrive |
+ | c | k | xc,xk,xk | depart,straight,arrive |
+ | c | m | xc,xm,xm | depart,slight right,arrive |
+ | c | o | xc,xo,xo | depart,right,arrive |
+ | c | a | xc,xa,xa | depart,sharp right,arrive |
- | e | g | xe,xg | head,sharp_left,destination |
- | e | i | xe,xi | head,left,destination |
- | e | k | xe,xk | head,slight_left,destination |
- | e | m | xe,xm | head,straight,destination |
- | e | o | xe,xo | head,slight_right,destination |
- | e | a | xe,xa | head,right,destination |
- | e | c | xe,xc | head,sharp_right,destination |
+ | e | g | xe,xg,xg | depart,sharp left,arrive |
+ | e | i | xe,xi,xi | depart,left,arrive |
+ | e | k | xe,xk,xk | depart,slight left,arrive |
+ | e | m | xe,xm,xm | depart,straight,arrive |
+ | e | o | xe,xo,xo | depart,slight right,arrive |
+ | e | a | xe,xa,xa | depart,right,arrive |
+ | e | c | xe,xc,xc | depart,sharp right,arrive |
- | g | i | xg,xi | head,sharp_left,destination |
- | g | k | xg,xk | head,left,destination |
- | g | m | xg,xm | head,slight_left,destination |
- | g | o | xg,xo | head,straight,destination |
- | g | a | xg,xa | head,slight_right,destination |
- | g | c | xg,xc | head,right,destination |
- | g | e | xg,xe | head,sharp_right,destination |
+ | g | i | xg,xi,xi | depart,sharp left,arrive |
+ | g | k | xg,xk,xk | depart,left,arrive |
+ | g | m | xg,xm,xm | depart,slight left,arrive |
+ | g | o | xg,xo,xo | depart,straight,arrive |
+ | g | a | xg,xa,xa | depart,slight right,arrive |
+ | g | c | xg,xc,xc | depart,right,arrive |
+ | g | e | xg,xe,xe | depart,sharp right,arrive |
Scenario: Turn instructions at high latitude
# https://github.com/DennisOSRM/Project-OSRM/issues/532
@@ -116,8 +108,8 @@ Feature: Turn directions/codes
| yz |
When I route I should get
- | from | to | route | turns |
- | a | c | ab,bc | head,left,destination |
- | c | a | bc,ab | head,right,destination |
- | x | z | xy,yz | head,right,destination |
- | z | x | yz,xy | head,left,destination |
+ | from | to | route | turns |
+ | a | c | ab,bc,bc | depart,left,arrive |
+ | c | a | bc,ab,ab | depart,right,arrive |
+ | x | z | xy,yz,yz | depart,right,arrive |
+ | z | x | yz,xy,xy | depart,left,arrive |
diff --git a/features/testbot/utf.feature b/features/testbot/utf.feature
index d979e9f..b537163 100644
--- a/features/testbot/utf.feature
+++ b/features/testbot/utf.feature
@@ -15,7 +15,7 @@ Feature: Handling of UTF characters
| cd | Cyrillic Москва |
When I route I should get
- | from | to | route |
- | a | b | Scandinavian København |
- | b | c | Japanese 東京 |
- | c | d | Cyrillic Москва |
+ | from | to | route |
+ | a | b | Scandinavian København,Scandinavian København |
+ | b | c | Japanese 東京,Japanese 東京 |
+ | c | d | Cyrillic Москва,Cyrillic Москва |
diff --git a/features/testbot/uturn.feature b/features/testbot/uturn.feature
index 26c6818..f00f5fc 100644
--- a/features/testbot/uturn.feature
+++ b/features/testbot/uturn.feature
@@ -20,8 +20,8 @@ Feature: U-turns at via points
| fg |
When I route I should get
- | waypoints | route | turns |
- | a,e,c | ab,be,be,ef,fg,dg,cd | head,right,via,left,straight,left,left,destination |
+ | waypoints | route | turns |
+ | a,e,c | ab,be,be,ef,fg,dg,cd,cd | depart,right,arrive,depart,straight,left,left,arrive |
Scenario: Query param to allow U-turns at all via points
Given the node map
@@ -42,8 +42,8 @@ Feature: U-turns at via points
| fg |
When I route I should get
- | waypoints | route |
- | a,e,c | ab,be,be,bc |
+ | waypoints | route |
+ | a,e,c | ab,be,be,be,bc,bc |
@todo
Scenario: Instructions at via points at u-turns
@@ -65,8 +65,8 @@ Feature: U-turns at via points
| fg |
When I route I should get
- | waypoints | route | turns |
- | a,e,c | ab,be,be,bc | head,right,uturn,right,destination |
+ | waypoints | route | turns |
+ | a,e,c | ab,be,be,bc,bc | depart,right,uturn,right,arrive |
Scenario: u-turn mixed with non-uturn vias
Given the node map
@@ -88,6 +88,6 @@ Feature: U-turns at via points
| fg |
When I route I should get
- | waypoints | route |
- | 1,2,3,4,5 | ab,be,be,bc,bc,cd,dg,dg,cd |
+ | waypoints | route |
+ | 1,2,3,4,5 | ab,be,be,be,bc,bc,bc,be,ef,fg,dg,dg,dg,cd,cd |
diff --git a/features/testbot/via.feature b/features/testbot/via.feature
index a88b0f4..84b939b 100644
--- a/features/testbot/via.feature
+++ b/features/testbot/via.feature
@@ -13,9 +13,23 @@ Feature: Via points
| abc |
When I route I should get
- | waypoints | route |
- | a,b,c | abc,abc |
- | c,b,a | abc,abc |
+ | waypoints | route |
+ | a,b,c | abc,abc,abc,abc |
+
+ Scenario: Simple via point with core factor
+ Given the contract extra arguments "--core 0.8"
+ Given the node map
+ | a | b | c |
+
+ And the ways
+ | nodes |
+ | abc |
+
+ When I route I should get
+ | waypoints | route |
+ | a,b,c | abc,abc,abc,abc |
+ | c,b,a | abc,abc,abc,abc |
+ | c,b,a | abc,abc,abc,abc |
Scenario: Via point at a dead end
Given the node map
@@ -28,10 +42,11 @@ Feature: Via points
| bd |
When I route I should get
- | waypoints | route |
- | a,d,c | abc,bd,bd,bd,abc |
- | c,d,a | abc,bd,bd,bd,abc |
+ | waypoints | route |
+ | a,d,c | abc,bd,bd,bd,abc,abc |
+ | c,d,a | abc,bd,bd,bd,abc,abc |
+ @mokob
Scenario: Multiple via points
Given the node map
| a | | | | e | f | g | |
@@ -48,9 +63,9 @@ Feature: Via points
| dh |
When I route I should get
- | waypoints | route |
- | a,c,f | ab,bcd,bcd,de,efg |
- | a,c,f,h | ab,bcd,bcd,de,efg,efg,gh |
+ | waypoints | route |
+ | a,c,f | ab,bcd,bcd,bcd,de,efg,efg |
+ | a,c,f,h | ab,bcd,bcd,bcd,de,efg,efg,efg,gh,gh |
Scenario: Duplicate via point
@@ -65,8 +80,8 @@ Feature: Via points
| ab |
When I route I should get
- | waypoints | route | turns |
- | 1,1,4 | ab,ab | head,via,destination |
+ | waypoints | route |
+ | 1,1,4 | ab,ab,ab,ab |
Scenario: Via points on ring of oneways
# xa it to avoid only having a single ring, which cna trigger edge cases
@@ -86,12 +101,12 @@ Feature: Via points
| fa | yes |
When I route I should get
- | waypoints | route | distance | turns |
- | 1,3 | ab,bc,cd | 400m +-1 | head,straight,straight,destination |
- | 3,1 | cd,de,ef,fa,ab | 1000m +-1 | head,right,right,right,right,destination |
- | 1,2,3 | ab,bc,bc,cd | 400m +-1 | head,straight,via,straight,destination |
- | 1,3,2 | ab,bc,cd,cd,de,ef,fa,ab,bc | 1600m +-1 | head,straight,straight,via,right,right,right,right,straight,destination |
- | 3,2,1 | cd,de,ef,fa,ab,bc,bc,cd,de,ef,fa,ab | 2400m +-1 | head,right,right,right,right,straight,via,straight,right,right,right,right,destination |
+ | waypoints | route | distance |
+ | 1,3 | ab,bc,cd,cd | 400m +-1 |
+ | 3,1 | cd,de,ef,fa,ab,ab | 1000m +-1 |
+ | 1,2,3 | ab,bc,bc,bc,cd,cd | 400m +-1 |
+ | 1,3,2 | ab,bc,cd,cd,cd,de,ef,fa,ab,bc,bc | 1600m +-1 |
+ | 3,2,1 | cd,de,ef,fa,ab,bc,bc,bc,cd,de,ef,fa,ab,ab | 2400m +-1 |
Scenario: Via points on ring on the same oneway
# xa it to avoid only having a single ring, which cna trigger edge cases
@@ -109,9 +124,95 @@ Feature: Via points
| da | yes |
When I route I should get
- | waypoints | route | distance | turns |
- | 1,3 | ab | 200m +-1 | head,destination |
- | 3,1 | ab,bc,cd,da,ab | 800m +-1 | head,right,right,right,right,destination |
- | 1,2,3 | ab,ab | 200m +-1 | head,via,destination |
- | 1,3,2 | ab,ab,bc,cd,da,ab | 1100m +-1 | head,via,right,right,right,right,destination |
- | 3,2,1 | ab,bc,cd,da,ab,ab,bc,cd,da,ab | 1800m | head,right,right,right,right,via,right,right,right,right,destination |
+ | waypoints | route | distance |
+ | 1,3 | ab,ab | 200m +-1 |
+ | 3,1 | ab,bc,cd,da,ab,ab | 800m +-1 |
+ | 1,2,3 | ab,ab,ab,ab | 200m +-1 |
+ | 1,3,2 | ab,ab,ab,bc,cd,da,ab,ab | 1100m +-1 |
+ | 3,2,1 | ab,bc,cd,da,ab,ab,ab,bc,cd,da,ab,ab | 1800m +-1 |
+
+ # See issue #1896
+ Scenario: Via point at a dead end with oneway
+ Given the node map
+ | a | b | c |
+ | | d | |
+ | | e | |
+
+ And the ways
+ | nodes | oneway |
+ | abc | no |
+ | bd | no |
+ | de | yes |
+
+ When I route I should get
+ | waypoints | route |
+ | a,d,c | abc,bd,bd,bd,abc,abc |
+ | c,d,a | abc,bd,bd,bd,abc,abc |
+
+ # See issue #1896
+ Scenario: Via point at a dead end with barrier
+ Given the profile "car"
+ Given the node map
+ | a | b | c |
+ | | 1 | |
+ | | d | |
+ | | | |
+ | | | |
+ | f | e | |
+
+ And the nodes
+ | node | barrier |
+ | d | bollard |
+
+ And the ways
+ | nodes |
+ | abc |
+ | bd |
+ | afed |
+
+ When I route I should get
+ | waypoints | route |
+ | a,1,c | abc,bd,bd,bd,bd,abc,abc |
+ | c,1,a | abc,bd,bd,bd,bd,abc,abc |
+
+ Scenario: Via points on ring on the same oneway, forces one of the vertices to be top node
+ Given the node map
+ | a | 1 | 2 | b |
+ | 8 | | | 3 |
+ | 7 | | | 4 |
+ | d | 6 | 5 | c |
+
+ And the ways
+ | nodes | oneway |
+ | ab | yes |
+ | bc | yes |
+ | cd | yes |
+ | da | yes |
+
+ When I route I should get
+ | waypoints | route | distance |
+ | 2,1 | ab,bc,cd,da,ab,ab | 1100m +-1 |
+ | 4,3 | bc,cd,da,ab,bc,bc | 1100m +-1 |
+ | 6,5 | cd,da,ab,bc,cd,cd | 1100m +-1 |
+ | 8,7 | da,ab,bc,cd,da,da | 1100m +-1 |
+
+ Scenario: Multiple Via points on ring on the same oneway, forces one of the vertices to be top node
+ Given the node map
+ | a | 1 | 2 | 3 | b |
+ | | | | | 4 |
+ | | | | | 5 |
+ | | | | | 6 |
+ | d | 9 | 8 | 7 | c |
+
+ And the ways
+ | nodes | oneway |
+ | ab | yes |
+ | bc | yes |
+ | cd | yes |
+ | da | yes |
+
+ When I route I should get
+ | waypoints | route | distance |
+ | 3,2,1 | ab,bc,cd,da,ab,ab,ab,bc,cd,da,ab,ab | 3000m +-1 |
+ | 6,5,4 | bc,cd,da,ab,bc,bc,bc,cd,da,ab,bc,bc | 3000m +-1 |
+ | 9,8,7 | cd,da,ab,bc,cd,cd,cd,da,ab,bc,cd,cd | 3000m +-1 |
diff --git a/features/timestamp/timestamp.feature b/features/timestamp/timestamp.feature
deleted file mode 100644
index 70ef91c..0000000
--- a/features/timestamp/timestamp.feature
+++ /dev/null
@@ -1,11 +0,0 @@
- at timestamp
-Feature: Timestamp
-
- Scenario: Request timestamp
- Given the node map
- | a | b |
- And the ways
- | nodes |
- | ab |
- When I request /timestamp
- Then I should get a valid timestamp
diff --git a/include/contractor/contractor.hpp b/include/contractor/contractor.hpp
new file mode 100644
index 0000000..7cfc3dc
--- /dev/null
+++ b/include/contractor/contractor.hpp
@@ -0,0 +1,96 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef CONTRACTOR_CONTRACTOR_HPP
+#define CONTRACTOR_CONTRACTOR_HPP
+
+#include "contractor/contractor_config.hpp"
+#include "contractor/query_edge.hpp"
+#include "extractor/edge_based_edge.hpp"
+#include "extractor/edge_based_node.hpp"
+#include "util/typedefs.hpp"
+#include "util/deallocating_vector.hpp"
+
+#include <vector>
+#include <string>
+
+#include <cstddef>
+
+namespace osrm
+{
+namespace contractor
+{
+
+/// Base class of osrm-contract
+class Contractor
+{
+ public:
+ using EdgeData = QueryEdge::EdgeData;
+
+ explicit Contractor(const ContractorConfig &config_) : config{config_} {}
+
+ Contractor(const Contractor &) = delete;
+ Contractor &operator=(const Contractor &) = delete;
+
+ int Run();
+
+ protected:
+ void ContractGraph(const unsigned max_edge_id,
+ util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
+ util::DeallocatingVector<QueryEdge> &contracted_edge_list,
+ std::vector<EdgeWeight> &&node_weights,
+ std::vector<bool> &is_core_node,
+ std::vector<float> &inout_node_levels) const;
+ void WriteCoreNodeMarker(std::vector<bool> &&is_core_node) const;
+ void WriteNodeLevels(std::vector<float> &&node_levels) const;
+ void ReadNodeLevels(std::vector<float> &contraction_order) const;
+ std::size_t
+ WriteContractedGraph(unsigned number_of_edge_based_nodes,
+ const util::DeallocatingVector<QueryEdge> &contracted_edge_list);
+ void FindComponents(unsigned max_edge_id,
+ const util::DeallocatingVector<extractor::EdgeBasedEdge> &edges,
+ std::vector<extractor::EdgeBasedNode> &nodes) const;
+
+ private:
+ ContractorConfig config;
+
+ std::size_t
+ LoadEdgeExpandedGraph(const std::string &edge_based_graph_path,
+ util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
+ const std::string &edge_segment_lookup_path,
+ const std::string &edge_penalty_path,
+ const std::vector<std::string> &segment_speed_path,
+ const std::string &nodes_filename,
+ const std::string &geometry_filename,
+ const std::string &datasource_names_filename,
+ const std::string &datasource_indexes_filename,
+ const std::string &rtree_leaf_filename);
+};
+}
+}
+
+#endif // PROCESSING_CHAIN_HPP
diff --git a/contractor/contractor_options.hpp b/include/contractor/contractor_config.hpp
similarity index 56%
rename from contractor/contractor_options.hpp
rename to include/contractor/contractor_config.hpp
index 5932b78..f557279 100644
--- a/contractor/contractor_options.hpp
+++ b/include/contractor/contractor_config.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -32,20 +32,33 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
-enum class return_code : unsigned
+namespace osrm
+{
+namespace contractor
{
- ok,
- fail,
- exit
-};
struct ContractorConfig
{
- ContractorConfig() noexcept : requested_num_threads(0) {}
+ ContractorConfig() : requested_num_threads(0) {}
+
+ // Infer the output names from the path of the .osrm file
+ void UseDefaultOutputNames()
+ {
+ level_output_path = osrm_input_path.string() + ".level";
+ core_output_path = osrm_input_path.string() + ".core";
+ graph_output_path = osrm_input_path.string() + ".hsgr";
+ edge_based_graph_path = osrm_input_path.string() + ".ebg";
+ edge_segment_lookup_path = osrm_input_path.string() + ".edge_segment_lookup";
+ edge_penalty_path = osrm_input_path.string() + ".edge_penalties";
+ node_based_graph_path = osrm_input_path.string() + ".nodes";
+ geometry_path = osrm_input_path.string() + ".geometry";
+ rtree_leaf_path = osrm_input_path.string() + ".fileIndex";
+ datasource_names_path = osrm_input_path.string() + ".datasource_names";
+ datasource_indexes_path = osrm_input_path.string() + ".datasource_indexes";
+ }
boost::filesystem::path config_file_path;
boost::filesystem::path osrm_input_path;
- boost::filesystem::path profile_path;
std::string level_output_path;
std::string core_output_path;
@@ -54,28 +67,24 @@ struct ContractorConfig
std::string edge_segment_lookup_path;
std::string edge_penalty_path;
+ std::string node_based_graph_path;
+ std::string geometry_path;
+ std::string rtree_leaf_path;
bool use_cached_priority;
unsigned requested_num_threads;
- //A percentage of vertices that will be contracted for the hierarchy.
- //Offers a trade-off between preprocessing and query time.
- //The remaining vertices form the core of the hierarchy
+ // A percentage of vertices that will be contracted for the hierarchy.
+ // Offers a trade-off between preprocessing and query time.
+ // The remaining vertices form the core of the hierarchy
//(e.g. 0.8 contracts 80 percent of the hierarchy, leaving a core of 20%)
double core_factor;
- std::string segment_speed_lookup_path;
-
-#ifdef DEBUG_GEOMETRY
- std::string debug_geometry_path;
-#endif
-};
-
-struct ContractorOptions
-{
- static return_code ParseArguments(int argc, char *argv[], ContractorConfig &extractor_config);
-
- static void GenerateOutputFilesNames(ContractorConfig &extractor_config);
+ std::vector<std::string> segment_speed_lookup_paths;
+ std::string datasource_indexes_path;
+ std::string datasource_names_path;
};
+}
+}
#endif // EXTRACTOR_OPTIONS_HPP
diff --git a/algorithms/crc32_processor.hpp b/include/contractor/crc32_processor.hpp
similarity index 71%
rename from algorithms/crc32_processor.hpp
rename to include/contractor/crc32_processor.hpp
index a31b4ad..eaef76c 100644
--- a/algorithms/crc32_processor.hpp
+++ b/include/contractor/crc32_processor.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef ITERATOR_BASED_CRC32_H
#define ITERATOR_BASED_CRC32_H
@@ -36,6 +9,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <iterator>
+namespace osrm
+{
+namespace contractor
+{
+
class IteratorbasedCRC32
{
public:
@@ -141,5 +119,7 @@ struct RangebasedCRC32
private:
IteratorbasedCRC32 crc32;
};
+}
+}
#endif /* ITERATOR_BASED_CRC32_H */
diff --git a/contractor/contractor.hpp b/include/contractor/graph_contractor.hpp
similarity index 68%
rename from contractor/contractor.hpp
rename to include/contractor/graph_contractor.hpp
index 07a21dc..26be61d 100644
--- a/contractor/contractor.hpp
+++ b/include/contractor/graph_contractor.hpp
@@ -1,44 +1,17 @@
-/*
-
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef CONTRACTOR_HPP
-#define CONTRACTOR_HPP
-
-#include "../data_structures/binary_heap.hpp"
-#include "../data_structures/deallocating_vector.hpp"
-#include "../data_structures/dynamic_graph.hpp"
-#include "../data_structures/percent.hpp"
-#include "../data_structures/query_edge.hpp"
-#include "../data_structures/xor_fast_hash.hpp"
-#include "../data_structures/xor_fast_hash_storage.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/timing_util.hpp"
-#include "../typedefs.h"
+#ifndef GRAPH_CONTRACTOR_HPP
+#define GRAPH_CONTRACTOR_HPP
+
+#include "util/binary_heap.hpp"
+#include "util/deallocating_vector.hpp"
+#include "util/dynamic_graph.hpp"
+#include "util/percent.hpp"
+#include "contractor/query_edge.hpp"
+#include "util/xor_fast_hash.hpp"
+#include "util/xor_fast_hash_storage.hpp"
+#include "util/integer_range.hpp"
+#include "util/simple_logger.hpp"
+#include "util/timing_util.hpp"
+#include "util/typedefs.hpp"
#include <boost/assert.hpp>
@@ -53,9 +26,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory>
#include <vector>
-class Contractor
+namespace osrm
+{
+namespace contractor
{
+class GraphContractor
+{
private:
struct ContractorEdgeData
{
@@ -86,18 +63,22 @@ class Contractor
struct ContractorHeapData
{
- short hop;
- bool target;
- ContractorHeapData() : hop(0), target(false) {}
- ContractorHeapData(short h, bool t) : hop(h), target(t) {}
+ ContractorHeapData() {}
+ ContractorHeapData(short hop_, bool target_) : hop(hop_), target(target_) {}
+
+ short hop = 0;
+ bool target = false;
};
- using ContractorGraph = DynamicGraph<ContractorEdgeData>;
- // using ContractorHeap = BinaryHeap<NodeID, NodeID, int, ContractorHeapData,
+ using ContractorGraph = util::DynamicGraph<ContractorEdgeData>;
+ // using ContractorHeap = util::BinaryHeap<NodeID, NodeID, int, ContractorHeapData,
// ArrayStorage<NodeID, NodeID>
// >;
- using ContractorHeap =
- BinaryHeap<NodeID, NodeID, int, ContractorHeapData, XORFastHashStorage<NodeID, NodeID>>;
+ using ContractorHeap = util::BinaryHeap<NodeID,
+ NodeID,
+ int,
+ ContractorHeapData,
+ util::XORFastHashStorage<NodeID, NodeID>>;
using ContractorEdge = ContractorGraph::InputEdge;
struct ContractorThreadData
@@ -108,11 +89,7 @@ class Contractor
explicit ContractorThreadData(NodeID nodes) : heap(nodes) {}
};
- struct NodePriorityData
- {
- int depth;
- NodePriorityData() : depth(0) {}
- };
+ using NodeDepth = int;
struct ContractionStats
{
@@ -157,16 +134,18 @@ class Contractor
};
public:
- template <class ContainerT> Contractor(int nodes, ContainerT &input_edge_list)
- : Contractor(nodes, input_edge_list, {}, {})
+ template <class ContainerT>
+ GraphContractor(int nodes, ContainerT &input_edge_list)
+ : GraphContractor(nodes, input_edge_list, {}, {})
{
}
template <class ContainerT>
- Contractor(int nodes,
- ContainerT &input_edge_list,
- std::vector<float> &&node_levels_)
- : node_levels(std::move(node_levels_))
+ GraphContractor(int nodes,
+ ContainerT &input_edge_list,
+ std::vector<float> &&node_levels_,
+ std::vector<EdgeWeight> &&node_weights_)
+ : node_levels(std::move(node_levels_)), node_weights(std::move(node_weights_))
{
std::vector<ContractorEdge> edges;
edges.reserve(input_edge_list.size() * 2);
@@ -179,7 +158,7 @@ class Contractor
#ifndef NDEBUG
if (static_cast<unsigned int>(std::max(diter->weight, 1)) > 24 * 60 * 60 * 10)
{
- SimpleLogger().Write(logWARNING)
+ util::SimpleLogger().Write(logWARNING)
<< "Edge weight large -> "
<< static_cast<unsigned int>(std::max(diter->weight, 1)) << " : "
<< static_cast<unsigned int>(diter->source) << " -> "
@@ -223,8 +202,7 @@ class Contractor
forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
forward_edge.data.id = reverse_edge.data.id = id;
forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1;
- forward_edge.data.distance = reverse_edge.data.distance =
- std::numeric_limits<int>::max();
+ forward_edge.data.distance = reverse_edge.data.distance = INVALID_EDGE_WEIGHT;
// remove parallel edges
while (i < edges.size() && edges[i].source == source && edges[i].target == target)
{
@@ -243,7 +221,7 @@ class Contractor
// merge edges (s,t) and (t,s) into bidirectional edge
if (forward_edge.data.distance == reverse_edge.data.distance)
{
- if ((int)forward_edge.data.distance != std::numeric_limits<int>::max())
+ if ((int)forward_edge.data.distance != INVALID_EDGE_WEIGHT)
{
forward_edge.data.backward = true;
edges[edge++] = forward_edge;
@@ -251,70 +229,47 @@ class Contractor
}
else
{ // insert seperate edges
- if (((int)forward_edge.data.distance) != std::numeric_limits<int>::max())
+ if (((int)forward_edge.data.distance) != INVALID_EDGE_WEIGHT)
{
edges[edge++] = forward_edge;
}
- if ((int)reverse_edge.data.distance != std::numeric_limits<int>::max())
+ if ((int)reverse_edge.data.distance != INVALID_EDGE_WEIGHT)
{
edges[edge++] = reverse_edge;
}
}
}
- std::cout << "merged " << edges.size() - edge << " edges out of " << edges.size()
- << std::endl;
+ util::SimpleLogger().Write() << "merged " << edges.size() - edge << " edges out of "
+ << edges.size();
edges.resize(edge);
contractor_graph = std::make_shared<ContractorGraph>(nodes, edges);
edges.clear();
edges.shrink_to_fit();
BOOST_ASSERT(0 == edges.capacity());
- // unsigned maxdegree = 0;
- // NodeID highestNode = 0;
- //
- // for(unsigned i = 0; i < contractor_graph->GetNumberOfNodes(); ++i) {
- // unsigned degree = contractor_graph->EndEdges(i) -
- // contractor_graph->BeginEdges(i);
- // if(degree > maxdegree) {
- // maxdegree = degree;
- // highestNode = i;
- // }
- // }
- //
- // SimpleLogger().Write() << "edges at node with id " << highestNode << " has degree
- // " << maxdegree;
- // for(unsigned i = contractor_graph->BeginEdges(highestNode); i <
- // contractor_graph->EndEdges(highestNode); ++i) {
- // SimpleLogger().Write() << " ->(" << highestNode << "," <<
- // contractor_graph->GetTarget(i)
- // << "); via: " << contractor_graph->GetEdgeData(i).via;
- // }
-
- std::cout << "contractor finished initalization" << std::endl;
+ util::SimpleLogger().Write() << "contractor finished initalization";
}
- ~Contractor() {}
-
void Run(double core_factor = 1.0)
{
// for the preperation we can use a big grain size, which is much faster (probably cache)
- constexpr size_t InitGrainSize = 100000;
- constexpr size_t PQGrainSize = 100000;
+ const constexpr size_t InitGrainSize = 100000;
+ const constexpr size_t PQGrainSize = 100000;
// auto_partitioner will automatically increase the blocksize if we have
// a lot of data. It is *important* for the last loop iterations
// (which have a very small dataset) that it is devisible.
- constexpr size_t IndependentGrainSize = 1;
- constexpr size_t ContractGrainSize = 1;
- constexpr size_t NeighboursGrainSize = 1;
- constexpr size_t DeleteGrainSize = 1;
+ const constexpr size_t IndependentGrainSize = 1;
+ const constexpr size_t ContractGrainSize = 1;
+ const constexpr size_t NeighboursGrainSize = 1;
+ const constexpr size_t DeleteGrainSize = 1;
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
- Percent p(number_of_nodes);
+ util::Percent p(number_of_nodes);
ThreadDataContainer thread_data_list(number_of_nodes);
NodeID number_of_contracted_nodes = 0;
- std::vector<NodePriorityData> node_data;
+ std::vector<NodeDepth> node_depth;
std::vector<float> node_priorities;
is_core_node.resize(number_of_nodes, false);
@@ -338,20 +293,20 @@ class Contractor
}
else
{
- node_data.resize(number_of_nodes);
+ node_depth.resize(number_of_nodes, 0);
node_priorities.resize(number_of_nodes);
node_levels.resize(number_of_nodes);
std::cout << "initializing elimination PQ ..." << std::flush;
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
- [this, &node_priorities, &node_data, &thread_data_list](
- const tbb::blocked_range<int> &range)
+ [this, &node_priorities, &node_depth,
+ &thread_data_list](const tbb::blocked_range<int> &range)
{
ContractorThreadData *data = thread_data_list.getThreadData();
for (int x = range.begin(), end = range.end(); x != end; ++x)
{
node_priorities[x] =
- this->EvaluateNodePriority(data, &node_data[x], x);
+ this->EvaluateNodePriority(data, node_depth[x], x);
}
});
std::cout << "ok" << std::endl;
@@ -368,9 +323,10 @@ class Contractor
if (!flushed_contractor && (number_of_contracted_nodes >
static_cast<NodeID>(number_of_nodes * 0.65 * core_factor)))
{
- DeallocatingVector<ContractorEdge> new_edge_set; // this one is not explicitely
- // cleared since it goes out of
- // scope anywa
+ util::DeallocatingVector<ContractorEdge>
+ new_edge_set; // this one is not explicitely
+ // cleared since it goes out of
+ // scope anywa
std::cout << " [flush " << number_of_contracted_nodes << " nodes] " << std::flush;
// Delete old heap data to free memory that we need for the coming operations
@@ -378,24 +334,27 @@ class Contractor
// Create new priority array
std::vector<float> new_node_priority(remaining_nodes.size());
+ std::vector<EdgeWeight> new_node_weights(remaining_nodes.size());
// this map gives the old IDs from the new ones, necessary to get a consistent graph
// at the end of contraction
orig_node_id_from_new_node_id_map.resize(remaining_nodes.size());
// this map gives the new IDs from the old ones, necessary to remap targets from the
// remaining graph
- std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, UINT_MAX);
+ std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, SPECIAL_NODEID);
- for (const auto new_node_id : osrm::irange<std::size_t>(0, remaining_nodes.size()))
+ for (const auto new_node_id : util::irange<std::size_t>(0, remaining_nodes.size()))
{
- auto& node = remaining_nodes[new_node_id];
+ auto &node = remaining_nodes[new_node_id];
BOOST_ASSERT(node_priorities.size() > node.id);
new_node_priority[new_node_id] = node_priorities[node.id];
+ BOOST_ASSERT(node_weights.size() > node.id);
+ new_node_weights[new_node_id] = node_weights[node.id];
}
// build forward and backward renumbering map and remap ids in remaining_nodes
- for (const auto new_node_id : osrm::irange<std::size_t>(0, remaining_nodes.size()))
+ for (const auto new_node_id : util::irange<std::size_t>(0, remaining_nodes.size()))
{
- auto& node = remaining_nodes[new_node_id];
+ auto &node = remaining_nodes[new_node_id];
// create renumbering maps in both directions
orig_node_id_from_new_node_id_map[new_node_id] = node.id;
new_node_id_from_orig_id_map[node.id] = new_node_id;
@@ -403,7 +362,7 @@ class Contractor
}
// walk over all nodes
for (const auto source :
- osrm::irange<NodeID>(0, contractor_graph->GetNumberOfNodes()))
+ util::irange<NodeID>(0, contractor_graph->GetNumberOfNodes()))
{
for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(source))
{
@@ -417,15 +376,14 @@ class Contractor
else
{
// node is not yet contracted.
- // add (renumbered) outgoing edges to new DynamicGraph.
+ // add (renumbered) outgoing edges to new util::DynamicGraph.
ContractorEdge new_edge = {new_node_id_from_orig_id_map[source],
- new_node_id_from_orig_id_map[target],
- data};
+ new_node_id_from_orig_id_map[target], data};
new_edge.data.is_original_via_node_ID = true;
- BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[source],
+ BOOST_ASSERT_MSG(SPECIAL_NODEID != new_node_id_from_orig_id_map[source],
"new source id not resolveable");
- BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[target],
+ BOOST_ASSERT_MSG(SPECIAL_NODEID != new_node_id_from_orig_id_map[target],
"new target id not resolveable");
new_edge_set.push_back(new_edge);
}
@@ -439,8 +397,12 @@ class Contractor
// Replace old priorities array by new one
node_priorities.swap(new_node_priority);
// Delete old node_priorities vector
+ // Due to the scope, these should get cleared automatically? @daniel-j-h do you
+ // agree?
new_node_priority.clear();
new_node_priority.shrink_to_fit();
+
+ node_weights.swap(new_node_weights);
// old Graph is removed
contractor_graph.reset();
@@ -457,39 +419,44 @@ class Contractor
thread_data_list.number_of_nodes = contractor_graph->GetNumberOfNodes();
}
- tbb::parallel_for(tbb::blocked_range<std::size_t>(0, remaining_nodes.size(), IndependentGrainSize),
- [this, &node_priorities, &remaining_nodes, &thread_data_list](
- const tbb::blocked_range<std::size_t> &range)
- {
- ContractorThreadData *data = thread_data_list.getThreadData();
- // determine independent node set
- for (auto i = range.begin(), end = range.end(); i != end; ++i)
- {
- const NodeID node = remaining_nodes[i].id;
- remaining_nodes[i].is_independent =
- this->IsNodeIndependent(node_priorities, data, node);
- }
- });
+ tbb::parallel_for(
+ tbb::blocked_range<std::size_t>(0, remaining_nodes.size(), IndependentGrainSize),
+ [this, &node_priorities, &remaining_nodes,
+ &thread_data_list](const tbb::blocked_range<std::size_t> &range)
+ {
+ ContractorThreadData *data = thread_data_list.getThreadData();
+ // determine independent node set
+ for (auto i = range.begin(), end = range.end(); i != end; ++i)
+ {
+ const NodeID node = remaining_nodes[i].id;
+ remaining_nodes[i].is_independent =
+ this->IsNodeIndependent(node_priorities, data, node);
+ }
+ });
// sort all remaining nodes to the beginning of the sequence
- const auto begin_independent_nodes = stable_partition(remaining_nodes.begin(), remaining_nodes.end(),
- [](RemainingNodeData node_data)
- {
- return !node_data.is_independent;
- });
- auto begin_independent_nodes_idx = std::distance(remaining_nodes.begin(), begin_independent_nodes);
+ const auto begin_independent_nodes = stable_partition(
+ remaining_nodes.begin(), remaining_nodes.end(), [](RemainingNodeData node_data)
+ {
+ return !node_data.is_independent;
+ });
+ auto begin_independent_nodes_idx =
+ std::distance(remaining_nodes.begin(), begin_independent_nodes);
auto end_independent_nodes_idx = remaining_nodes.size();
if (!use_cached_node_priorities)
{
// write out contraction level
tbb::parallel_for(
- tbb::blocked_range<std::size_t>(begin_independent_nodes_idx, end_independent_nodes_idx, ContractGrainSize),
- [this, remaining_nodes, flushed_contractor, current_level](const tbb::blocked_range<std::size_t> &range)
+ tbb::blocked_range<std::size_t>(begin_independent_nodes_idx,
+ end_independent_nodes_idx, ContractGrainSize),
+ [this, remaining_nodes, flushed_contractor,
+ current_level](const tbb::blocked_range<std::size_t> &range)
{
if (flushed_contractor)
{
- for (int position = range.begin(), end = range.end(); position != end; ++position)
+ for (int position = range.begin(), end = range.end(); position != end;
+ ++position)
{
const NodeID x = remaining_nodes[position].id;
node_levels[orig_node_id_from_new_node_id_map[x]] = current_level;
@@ -497,7 +464,8 @@ class Contractor
}
else
{
- for (int position = range.begin(), end = range.end(); position != end; ++position)
+ for (int position = range.begin(), end = range.end(); position != end;
+ ++position)
{
const NodeID x = remaining_nodes[position].id;
node_levels[x] = current_level;
@@ -507,24 +475,29 @@ class Contractor
}
// contract independent nodes
- tbb::parallel_for(
- tbb::blocked_range<std::size_t>(begin_independent_nodes_idx, end_independent_nodes_idx, ContractGrainSize),
- [this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<std::size_t> &range)
- {
- ContractorThreadData *data = thread_data_list.getThreadData();
- for (int position = range.begin(), end = range.end(); position != end; ++position)
- {
- const NodeID x = remaining_nodes[position].id;
- this->ContractNode<false>(data, x);
- }
- });
+ tbb::parallel_for(tbb::blocked_range<std::size_t>(begin_independent_nodes_idx,
+ end_independent_nodes_idx,
+ ContractGrainSize),
+ [this, &remaining_nodes,
+ &thread_data_list](const tbb::blocked_range<std::size_t> &range)
+ {
+ ContractorThreadData *data = thread_data_list.getThreadData();
+ for (int position = range.begin(), end = range.end();
+ position != end; ++position)
+ {
+ const NodeID x = remaining_nodes[position].id;
+ this->ContractNode<false>(data, x);
+ }
+ });
tbb::parallel_for(
- tbb::blocked_range<int>(begin_independent_nodes_idx, end_independent_nodes_idx, DeleteGrainSize),
+ tbb::blocked_range<int>(begin_independent_nodes_idx, end_independent_nodes_idx,
+ DeleteGrainSize),
[this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int> &range)
{
ContractorThreadData *data = thread_data_list.getThreadData();
- for (int position = range.begin(), end = range.end(); position != end; ++position)
+ for (int position = range.begin(), end = range.end(); position != end;
+ ++position)
{
const NodeID x = remaining_nodes[position].id;
this->DeleteIncomingEdges(data, x);
@@ -569,15 +542,17 @@ class Contractor
if (!use_cached_node_priorities)
{
tbb::parallel_for(
- tbb::blocked_range<int>(begin_independent_nodes_idx, end_independent_nodes_idx, NeighboursGrainSize),
- [this, &node_priorities, &remaining_nodes, &node_data, &thread_data_list](
- const tbb::blocked_range<int> &range)
+ tbb::blocked_range<int>(begin_independent_nodes_idx, end_independent_nodes_idx,
+ NeighboursGrainSize),
+ [this, &node_priorities, &remaining_nodes, &node_depth,
+ &thread_data_list](const tbb::blocked_range<int> &range)
{
ContractorThreadData *data = thread_data_list.getThreadData();
- for (int position = range.begin(), end = range.end(); position != end; ++position)
+ for (int position = range.begin(), end = range.end(); position != end;
+ ++position)
{
NodeID x = remaining_nodes[position].id;
- this->UpdateNodeNeighbours(node_priorities, node_data, data, x);
+ this->UpdateNodeNeighbours(node_priorities, node_depth, data, x);
}
});
}
@@ -585,30 +560,6 @@ class Contractor
// remove contracted nodes from the pool
number_of_contracted_nodes += end_independent_nodes_idx - begin_independent_nodes_idx;
remaining_nodes.resize(begin_independent_nodes_idx);
- // unsigned maxdegree = 0;
- // unsigned avgdegree = 0;
- // unsigned mindegree = UINT_MAX;
- // unsigned quaddegree = 0;
- //
- // for(unsigned i = 0; i < remaining_nodes.size(); ++i) {
- // unsigned degree = contractor_graph->EndEdges(remaining_nodes[i].id)
- // -
- // contractor_graph->BeginEdges(remaining_nodes[i].first);
- // if(degree > maxdegree)
- // maxdegree = degree;
- // if(degree < mindegree)
- // mindegree = degree;
- //
- // avgdegree += degree;
- // quaddegree += (degree*degree);
- // }
- //
- // avgdegree /= std::max((unsigned)1,(unsigned)remaining_nodes.size() );
- // quaddegree /= std::max((unsigned)1,(unsigned)remaining_nodes.size() );
- //
- // SimpleLogger().Write() << "rest: " << remaining_nodes.size() << ", max: "
- // << maxdegree << ", min: " << mindegree << ", avg: " << avgdegree << ",
- // quad: " << quaddegree;
p.printStatus(number_of_contracted_nodes);
++current_level;
@@ -616,32 +567,31 @@ class Contractor
if (remaining_nodes.size() > 2)
{
- if (orig_node_id_from_new_node_id_map.size() > 0)
- {
- tbb::parallel_for(
- tbb::blocked_range<int>(0, remaining_nodes.size(), InitGrainSize),
- [this, &remaining_nodes](const tbb::blocked_range<int> &range)
- {
- for (int x = range.begin(), end = range.end(); x != end; ++x)
- {
- const auto orig_id = remaining_nodes[x].id;
- is_core_node[orig_node_id_from_new_node_id_map[orig_id]] = true;
- }
- });
- }
- else
- {
- tbb::parallel_for(
- tbb::blocked_range<int>(0, remaining_nodes.size(), InitGrainSize),
- [this, &remaining_nodes](const tbb::blocked_range<int> &range)
- {
- for (int x = range.begin(), end = range.end(); x != end; ++x)
- {
- const auto orig_id = remaining_nodes[x].id;
- is_core_node[orig_id] = true;
- }
- });
- }
+ if (orig_node_id_from_new_node_id_map.size() > 0)
+ {
+ tbb::parallel_for(tbb::blocked_range<int>(0, remaining_nodes.size(), InitGrainSize),
+ [this, &remaining_nodes](const tbb::blocked_range<int> &range)
+ {
+ for (int x = range.begin(), end = range.end(); x != end; ++x)
+ {
+ const auto orig_id = remaining_nodes[x].id;
+ is_core_node[orig_node_id_from_new_node_id_map[orig_id]] =
+ true;
+ }
+ });
+ }
+ else
+ {
+ tbb::parallel_for(tbb::blocked_range<int>(0, remaining_nodes.size(), InitGrainSize),
+ [this, &remaining_nodes](const tbb::blocked_range<int> &range)
+ {
+ for (int x = range.begin(), end = range.end(); x != end; ++x)
+ {
+ const auto orig_id = remaining_nodes[x].id;
+ is_core_node[orig_id] = true;
+ }
+ });
+ }
}
else
{
@@ -650,8 +600,9 @@ class Contractor
is_core_node.clear();
}
- SimpleLogger().Write() << "[core] " << remaining_nodes.size() << " nodes "
- << contractor_graph->GetNumberOfEdges() << " edges." << std::endl;
+ util::SimpleLogger().Write() << "[core] " << remaining_nodes.size() << " nodes "
+ << contractor_graph->GetNumberOfEdges() << " edges."
+ << std::endl;
thread_data_list.data.clear();
}
@@ -666,15 +617,15 @@ class Contractor
out_node_levels.swap(node_levels);
}
- template <class Edge> inline void GetEdges(DeallocatingVector<Edge> &edges)
+ template <class Edge> inline void GetEdges(util::DeallocatingVector<Edge> &edges)
{
- Percent p(contractor_graph->GetNumberOfNodes());
- SimpleLogger().Write() << "Getting edges of minimized graph";
+ util::Percent p(contractor_graph->GetNumberOfNodes());
+ util::SimpleLogger().Write() << "Getting edges of minimized graph";
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
if (contractor_graph->GetNumberOfNodes())
{
Edge new_edge;
- for (const auto node : osrm::irange(0u, number_of_nodes))
+ for (const auto node : util::irange(0u, number_of_nodes))
{
p.printStatus(node);
for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
@@ -691,8 +642,8 @@ class Contractor
new_edge.source = node;
new_edge.target = target;
}
- BOOST_ASSERT_MSG(UINT_MAX != new_edge.source, "Source id invalid");
- BOOST_ASSERT_MSG(UINT_MAX != new_edge.target, "Target id invalid");
+ BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.source, "Source id invalid");
+ BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.target, "Target id invalid");
new_edge.data.distance = data.distance;
new_edge.data.shortcut = data.shortcut;
if (!data.is_original_via_node_ID && !orig_node_id_from_new_node_id_map.empty())
@@ -723,23 +674,55 @@ class Contractor
}
private:
+ inline void RelaxNode(const NodeID node,
+ const NodeID forbidden_node,
+ const int distance,
+ ContractorHeap &heap)
+ {
+ const short current_hop = heap.GetData(node).hop + 1;
+ for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
+ {
+ const ContractorEdgeData &data = contractor_graph->GetEdgeData(edge);
+ if (!data.forward)
+ {
+ continue;
+ }
+ const NodeID to = contractor_graph->GetTarget(edge);
+ if (forbidden_node == to)
+ {
+ continue;
+ }
+ const int to_distance = distance + data.distance;
+
+ // New Node discovered -> Add to Heap + Node Info Storage
+ if (!heap.WasInserted(to))
+ {
+ heap.Insert(to, to_distance, ContractorHeapData{current_hop, false});
+ }
+ // Found a shorter Path -> Update distance
+ else if (to_distance < heap.GetKey(to))
+ {
+ heap.DecreaseKey(to, to_distance);
+ heap.GetData(to).hop = current_hop;
+ }
+ }
+ }
+
inline void Dijkstra(const int max_distance,
const unsigned number_of_targets,
const int maxNodes,
- ContractorThreadData *const data,
+ ContractorThreadData &data,
const NodeID middleNode)
{
- ContractorHeap &heap = data->heap;
+ ContractorHeap &heap = data.heap;
int nodes = 0;
unsigned number_of_targets_found = 0;
while (!heap.Empty())
{
const NodeID node = heap.DeleteMin();
- const int distance = heap.GetKey(node);
- const short current_hop = heap.GetData(node).hop + 1;
-
+ const auto distance = heap.GetKey(node);
if (++nodes > maxNodes)
{
return;
@@ -759,38 +742,12 @@ class Contractor
}
}
- // iterate over all edges of node
- for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
- {
- const ContractorEdgeData &data = contractor_graph->GetEdgeData(edge);
- if (!data.forward)
- {
- continue;
- }
- const NodeID to = contractor_graph->GetTarget(edge);
- if (middleNode == to)
- {
- continue;
- }
- const int to_distance = distance + data.distance;
-
- // New Node discovered -> Add to Heap + Node Info Storage
- if (!heap.WasInserted(to))
- {
- heap.Insert(to, to_distance, ContractorHeapData(current_hop, false));
- }
- // Found a shorter Path -> Update distance
- else if (to_distance < heap.GetKey(to))
- {
- heap.DecreaseKey(to, to_distance);
- heap.GetData(to).hop = current_hop;
- }
- }
+ RelaxNode(node, middleNode, distance, heap);
}
}
inline float EvaluateNodePriority(ContractorThreadData *const data,
- NodePriorityData *const node_data,
+ const NodeDepth node_depth,
const NodeID node)
{
ContractionStats stats;
@@ -802,14 +759,14 @@ class Contractor
float result;
if (0 == (stats.edges_deleted_count * stats.original_edges_deleted_count))
{
- result = 1.f * node_data->depth;
+ result = 1.f * node_depth;
}
else
{
result = 2.f * (((float)stats.edges_added_count) / stats.edges_deleted_count) +
4.f * (((float)stats.original_edges_added_count) /
stats.original_edges_deleted_count) +
- 1.f * node_data->depth;
+ 1.f * node_depth;
}
BOOST_ASSERT(result >= 0);
return result;
@@ -820,13 +777,21 @@ class Contractor
ContractNode(ContractorThreadData *data, const NodeID node, ContractionStats *stats = nullptr)
{
ContractorHeap &heap = data->heap;
- int inserted_edges_size = data->inserted_edges.size();
+ std::size_t inserted_edges_size = data->inserted_edges.size();
std::vector<ContractorEdge> &inserted_edges = data->inserted_edges;
+ const constexpr bool SHORTCUT_ARC = true;
+ const constexpr bool FORWARD_DIRECTION_ENABLED = true;
+ const constexpr bool FORWARD_DIRECTION_DISABLED = false;
+ const constexpr bool REVERSE_DIRECTION_ENABLED = true;
+ const constexpr bool REVERSE_DIRECTION_DISABLED = false;
for (auto in_edge : contractor_graph->GetAdjacentEdgeRange(node))
{
const ContractorEdgeData &in_data = contractor_graph->GetEdgeData(in_edge);
const NodeID source = contractor_graph->GetTarget(in_edge);
+ if (source == node)
+ continue;
+
if (RUNSIMULATION)
{
BOOST_ASSERT(stats != nullptr);
@@ -839,7 +804,7 @@ class Contractor
}
heap.Clear();
- heap.Insert(source, 0, ContractorHeapData());
+ heap.Insert(source, 0, ContractorHeapData{});
int max_distance = 0;
unsigned number_of_targets = 0;
@@ -851,22 +816,64 @@ class Contractor
continue;
}
const NodeID target = contractor_graph->GetTarget(out_edge);
- const int path_distance = in_data.distance + out_data.distance;
+ if (node == target)
+ continue;
+
+ const EdgeWeight path_distance = in_data.distance + out_data.distance;
+ if (target == source)
+ {
+ if (path_distance < node_weights[node])
+ {
+ if (RUNSIMULATION)
+ {
+ // make sure to prune better, but keep inserting this loop if it should
+ // still be the best
+ // CAREFUL: This only works due to the independent node-setting. This
+ // guarantees that source is not connected to another node that is
+ // contracted
+ node_weights[source] = path_distance + 1;
+ BOOST_ASSERT(stats != nullptr);
+ stats->edges_added_count += 2;
+ stats->original_edges_added_count +=
+ 2 * (out_data.originalEdges + in_data.originalEdges);
+ }
+ else
+ {
+ // CAREFUL: This only works due to the independent node-setting. This
+ // guarantees that source is not connected to another node that is
+ // contracted
+ node_weights[source] = path_distance; // make sure to prune better
+ inserted_edges.emplace_back(
+ source, target, path_distance,
+ out_data.originalEdges + in_data.originalEdges, node, SHORTCUT_ARC,
+ FORWARD_DIRECTION_ENABLED, REVERSE_DIRECTION_DISABLED);
+
+ inserted_edges.emplace_back(
+ target, source, path_distance,
+ out_data.originalEdges + in_data.originalEdges, node, SHORTCUT_ARC,
+ FORWARD_DIRECTION_DISABLED, REVERSE_DIRECTION_ENABLED);
+ }
+ }
+ continue;
+ }
max_distance = std::max(max_distance, path_distance);
if (!heap.WasInserted(target))
{
- heap.Insert(target, INT_MAX, ContractorHeapData(0, true));
+ heap.Insert(target, INVALID_EDGE_WEIGHT, ContractorHeapData{0, true});
++number_of_targets;
}
}
if (RUNSIMULATION)
{
- Dijkstra(max_distance, number_of_targets, 1000, data, node);
+ const int constexpr SIMULATION_SEARCH_SPACE_SIZE = 1000;
+ Dijkstra(max_distance, number_of_targets, SIMULATION_SEARCH_SPACE_SIZE, *data,
+ node);
}
else
{
- Dijkstra(max_distance, number_of_targets, 2000, data, node);
+ const int constexpr FULL_SEARCH_SPACE_SIZE = 2000;
+ Dijkstra(max_distance, number_of_targets, FULL_SEARCH_SPACE_SIZE, *data, node);
}
for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
{
@@ -876,6 +883,8 @@ class Contractor
continue;
}
const NodeID target = contractor_graph->GetTarget(out_edge);
+ if (target == node)
+ continue;
const int path_distance = in_data.distance + out_data.distance;
const int distance = heap.GetKey(target);
if (path_distance < distance)
@@ -891,22 +900,26 @@ class Contractor
{
inserted_edges.emplace_back(source, target, path_distance,
out_data.originalEdges + in_data.originalEdges,
- node, true, true, false);
+ node, SHORTCUT_ARC, FORWARD_DIRECTION_ENABLED,
+ REVERSE_DIRECTION_DISABLED);
inserted_edges.emplace_back(target, source, path_distance,
out_data.originalEdges + in_data.originalEdges,
- node, true, false, true);
+ node, SHORTCUT_ARC, FORWARD_DIRECTION_DISABLED,
+ REVERSE_DIRECTION_ENABLED);
}
}
}
}
+ // Check For One-Way Streets to decide on the creation of self-loops
+
if (!RUNSIMULATION)
{
- int iend = inserted_edges.size();
- for (int i = inserted_edges_size; i < iend; ++i)
+ std::size_t iend = inserted_edges.size();
+ for (std::size_t i = inserted_edges_size; i < iend; ++i)
{
bool found = false;
- for (int other = i + 1; other < iend; ++other)
+ for (std::size_t other = i + 1; other < iend; ++other)
{
if (inserted_edges[other].source != inserted_edges[i].source)
{
@@ -957,14 +970,14 @@ class Contractor
std::sort(neighbours.begin(), neighbours.end());
neighbours.resize(std::unique(neighbours.begin(), neighbours.end()) - neighbours.begin());
- for (const auto i : osrm::irange<std::size_t>(0, neighbours.size()))
+ for (const auto i : util::irange<std::size_t>(0, neighbours.size()))
{
contractor_graph->DeleteEdgesTo(neighbours[i], node);
}
}
inline bool UpdateNodeNeighbours(std::vector<float> &priorities,
- std::vector<NodePriorityData> &node_data,
+ std::vector<NodeDepth> &node_depth,
ContractorThreadData *const data,
const NodeID node)
{
@@ -980,7 +993,7 @@ class Contractor
continue;
}
neighbours.push_back(u);
- node_data[u].depth = (std::max)(node_data[node].depth + 1, node_data[u].depth);
+ node_depth[u] = std::max(node_depth[node] + 1, node_depth[u]);
}
// eliminate duplicate entries ( forward + backward edges )
std::sort(neighbours.begin(), neighbours.end());
@@ -989,7 +1002,7 @@ class Contractor
// re-evaluate priorities of neighboring nodes
for (const NodeID u : neighbours)
{
- priorities[u] = EvaluateNodePriority(data, &(node_data)[u], u);
+ priorities[u] = EvaluateNodePriority(data, node_depth[u], u);
}
return true;
}
@@ -1076,8 +1089,17 @@ class Contractor
stxxl::vector<QueryEdge> external_edge_list;
std::vector<NodeID> orig_node_id_from_new_node_id_map;
std::vector<float> node_levels;
+
+ // A list of weights for every node in the graph.
+ // The weight represents the cost for a u-turn on the segment in the base-graph in addition to
+ // its traversal.
+ // During contraction, self-loops are checked against this node weight to ensure that necessary
+ // self-loops are added.
+ std::vector<EdgeWeight> node_weights;
std::vector<bool> is_core_node;
- XORFastHash fast_hash;
+ util::XORFastHash<> fast_hash;
};
+}
+}
#endif // CONTRACTOR_HPP
diff --git a/data_structures/query_edge.hpp b/include/contractor/query_edge.hpp
similarity index 50%
rename from data_structures/query_edge.hpp
rename to include/contractor/query_edge.hpp
index 1c4af03..a3265b8 100644
--- a/data_structures/query_edge.hpp
+++ b/include/contractor/query_edge.hpp
@@ -1,37 +1,15 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef QUERYEDGE_HPP
#define QUERYEDGE_HPP
-#include "../typedefs.h"
+#include "util/typedefs.hpp"
#include <tuple>
+namespace osrm
+{
+namespace contractor
+{
+
struct QueryEdge
{
NodeID source;
@@ -75,5 +53,7 @@ struct QueryEdge
data.id == right.data.id);
}
};
+}
+}
#endif // QUERYEDGE_HPP
diff --git a/include/engine/api/base_api.hpp b/include/engine/api/base_api.hpp
new file mode 100644
index 0000000..8cac72b
--- /dev/null
+++ b/include/engine/api/base_api.hpp
@@ -0,0 +1,64 @@
+#ifndef ENGINE_API_BASE_API_HPP
+#define ENGINE_API_BASE_API_HPP
+
+#include "engine/api/base_parameters.hpp"
+#include "engine/datafacade/datafacade_base.hpp"
+
+#include "engine/api/json_factory.hpp"
+#include "engine/hint.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/range/algorithm/transform.hpp>
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+class BaseAPI
+{
+ public:
+ BaseAPI(const datafacade::BaseDataFacade &facade_, const BaseParameters ¶meters_)
+ : facade(facade_), parameters(parameters_)
+ {
+ }
+
+ util::json::Array MakeWaypoints(const std::vector<PhantomNodes> &segment_end_coordinates) const
+ {
+ BOOST_ASSERT(parameters.coordinates.size() > 0);
+ BOOST_ASSERT(parameters.coordinates.size() == segment_end_coordinates.size() + 1);
+
+ util::json::Array waypoints;
+ waypoints.values.resize(parameters.coordinates.size());
+ waypoints.values[0] = MakeWaypoint(segment_end_coordinates.front().source_phantom);
+
+ auto out_iter = std::next(waypoints.values.begin());
+ boost::range::transform(segment_end_coordinates, out_iter,
+ [this](const PhantomNodes &phantom_pair)
+ {
+ return MakeWaypoint(phantom_pair.target_phantom);
+ });
+ return waypoints;
+ }
+
+ // FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
+ // protected:
+ util::json::Object MakeWaypoint(const PhantomNode &phantom) const
+ {
+ return json::makeWaypoint(phantom.location, facade.GetNameForID(phantom.name_id),
+ Hint{phantom, facade.GetCheckSum()});
+ }
+
+ const datafacade::BaseDataFacade &facade;
+ const BaseParameters ¶meters;
+};
+
+} // ns api
+} // ns engine
+} // ns osrm
+
+#endif
diff --git a/include/engine/api/base_parameters.hpp b/include/engine/api/base_parameters.hpp
new file mode 100644
index 0000000..63239b7
--- /dev/null
+++ b/include/engine/api/base_parameters.hpp
@@ -0,0 +1,90 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef ENGINE_API_BASE_PARAMETERS_HPP
+#define ENGINE_API_BASE_PARAMETERS_HPP
+
+#include "engine/hint.hpp"
+#include "engine/bearing.hpp"
+#include "util/coordinate.hpp"
+
+#include <boost/optional.hpp>
+
+#include <vector>
+#include <algorithm>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+/**
+ * General parameters for OSRM service queries.
+ *
+ * Holds member attributes:
+ * - coordinates: for specifying location(s) to services
+ * - hints: hint for the service to derive the position(s) in the road network more efficiently,
+ * optional per coordinate
+ * - radiuses: limits the search for segments in the road network to given radius(es) in meter,
+ * optional per coordinate
+ * - bearings: limits the search for segments in the road network to given bearing(s) in degree
+ * towards true north in clockwise direction, optional per coordinate
+ *
+ * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
+ * NearestParameters, TripParameters, MatchParameters and TileParameters
+ */
+struct BaseParameters
+{
+ std::vector<util::Coordinate> coordinates;
+ std::vector<boost::optional<Hint>> hints;
+ std::vector<boost::optional<double>> radiuses;
+ std::vector<boost::optional<Bearing>> bearings;
+
+ // FIXME add validation for invalid bearing values
+ bool IsValid() const
+ {
+ return (hints.empty() || hints.size() == coordinates.size()) &&
+ (bearings.empty() || bearings.size() == coordinates.size()) &&
+ (radiuses.empty() || radiuses.size() == coordinates.size()) &&
+ std::all_of(bearings.begin(), bearings.end(),
+ [](const boost::optional<Bearing> bearing_and_range)
+ {
+ if (bearing_and_range)
+ {
+ return bearing_and_range->IsValid();
+ }
+ return true;
+ });
+ }
+};
+}
+}
+}
+
+#endif // ROUTE_PARAMETERS_HPP
diff --git a/include/engine/api/json_factory.hpp b/include/engine/api/json_factory.hpp
new file mode 100644
index 0000000..49e81f2
--- /dev/null
+++ b/include/engine/api/json_factory.hpp
@@ -0,0 +1,81 @@
+#ifndef ENGINE_RESPONSE_OBJECTS_HPP_
+#define ENGINE_RESPONSE_OBJECTS_HPP_
+
+#include "extractor/guidance/turn_instruction.hpp"
+#include "extractor/travel_mode.hpp"
+#include "engine/polyline_compressor.hpp"
+#include "engine/guidance/route_step.hpp"
+#include "engine/guidance/step_maneuver.hpp"
+#include "engine/guidance/route_leg.hpp"
+#include "engine/guidance/route.hpp"
+#include "engine/guidance/leg_geometry.hpp"
+#include "util/coordinate.hpp"
+#include "util/json_container.hpp"
+
+#include <boost/optional.hpp>
+
+#include <string>
+#include <algorithm>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+
+struct Hint;
+
+namespace api
+{
+namespace json
+{
+namespace detail
+{
+
+std::string instructionTypeToString(extractor::guidance::TurnType type);
+std::string instructionModifierToString(extractor::guidance::DirectionModifier modifier);
+
+util::json::Array coordinateToLonLat(const util::Coordinate coordinate);
+
+std::string modeToString(const extractor::TravelMode mode);
+
+} // namespace detail
+
+template <typename ForwardIter> util::json::String makePolyline(ForwardIter begin, ForwardIter end)
+{
+ return {encodePolyline(begin, end)};
+}
+
+template <typename ForwardIter>
+util::json::Object makeGeoJSONLineString(ForwardIter begin, ForwardIter end)
+{
+ util::json::Object geojson;
+ geojson.values["type"] = "LineString";
+ util::json::Array coordinates;
+ std::transform(begin, end, std::back_inserter(coordinates.values), &detail::coordinateToLonLat);
+ geojson.values["coordinates"] = std::move(coordinates);
+ return geojson;
+}
+
+util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver);
+
+util::json::Object makeRouteStep(guidance::RouteStep step,
+ boost::optional<util::json::Value> geometry);
+
+util::json::Object makeRoute(const guidance::Route &route,
+ util::json::Array legs,
+ boost::optional<util::json::Value> geometry);
+
+util::json::Object
+makeWaypoint(const util::Coordinate location, std::string name, const Hint &hint);
+
+util::json::Object makeRouteLeg(guidance::RouteLeg leg, util::json::Array steps);
+
+util::json::Array makeRouteLegs(std::vector<guidance::RouteLeg> legs,
+ std::vector<util::json::Value> step_geometries);
+}
+}
+} // namespace engine
+} // namespace osrm
+
+#endif // ENGINE_GUIDANCE_API_RESPONSE_GENERATOR_HPP_
diff --git a/include/engine/api/match_api.hpp b/include/engine/api/match_api.hpp
new file mode 100644
index 0000000..7ce4fa2
--- /dev/null
+++ b/include/engine/api/match_api.hpp
@@ -0,0 +1,119 @@
+#ifndef ENGINE_API_MATCH_HPP
+#define ENGINE_API_MATCH_HPP
+
+#include "engine/api/route_api.hpp"
+#include "engine/api/match_parameters.hpp"
+
+#include "engine/datafacade/datafacade_base.hpp"
+
+#include "engine/internal_route_result.hpp"
+#include "engine/map_matching/sub_matching.hpp"
+
+#include "util/integer_range.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+class MatchAPI final : public RouteAPI
+{
+ public:
+ MatchAPI(const datafacade::BaseDataFacade &facade_, const MatchParameters ¶meters_)
+ : RouteAPI(facade_, parameters_), parameters(parameters_)
+ {
+ }
+
+ void MakeResponse(const std::vector<map_matching::SubMatching> &sub_matchings,
+ const std::vector<InternalRouteResult> &sub_routes,
+ util::json::Object &response) const
+ {
+ auto number_of_routes = sub_matchings.size();
+ util::json::Array routes;
+ routes.values.reserve(number_of_routes);
+ BOOST_ASSERT(sub_matchings.size() == sub_routes.size());
+ for (auto index : util::irange<std::size_t>(0UL, sub_matchings.size()))
+ {
+ auto route = MakeRoute(sub_routes[index].segment_end_coordinates,
+ sub_routes[index].unpacked_path_segments,
+ sub_routes[index].source_traversed_in_reverse,
+ sub_routes[index].target_traversed_in_reverse);
+ route.values["confidence"] = sub_matchings[index].confidence;
+ routes.values.push_back(std::move(route));
+ }
+ response.values["tracepoints"] = MakeTracepoints(sub_matchings);
+ response.values["matchings"] = std::move(routes);
+ response.values["code"] = "ok";
+ }
+
+ // FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
+ // protected:
+
+ // FIXME this logic is a little backwards. We should change the output format of the
+ // map_matching
+ // routing algorithm to be easier to consume here.
+ util::json::Array
+ MakeTracepoints(const std::vector<map_matching::SubMatching> &sub_matchings) const
+ {
+ util::json::Array waypoints;
+ waypoints.values.reserve(parameters.coordinates.size());
+
+ struct MatchingIndex
+ {
+ MatchingIndex() = default;
+ MatchingIndex(unsigned sub_matching_index_, unsigned point_index_)
+ : sub_matching_index(sub_matching_index_), point_index(point_index_)
+ {
+ }
+
+ unsigned sub_matching_index = std::numeric_limits<unsigned>::max();
+ unsigned point_index = std::numeric_limits<unsigned>::max();
+
+ bool NotMatched()
+ {
+ return sub_matching_index == std::numeric_limits<unsigned>::max() &&
+ point_index == std::numeric_limits<unsigned>::max();
+ }
+ };
+
+ std::vector<MatchingIndex> trace_idx_to_matching_idx(parameters.coordinates.size());
+ for (auto sub_matching_index :
+ util::irange(0u, static_cast<unsigned>(sub_matchings.size())))
+ {
+ for (auto point_index : util::irange(
+ 0u, static_cast<unsigned>(sub_matchings[sub_matching_index].indices.size())))
+ {
+ trace_idx_to_matching_idx[sub_matchings[sub_matching_index].indices[point_index]] =
+ MatchingIndex{sub_matching_index, point_index};
+ }
+ }
+
+ for (auto trace_index : util::irange(0UL, parameters.coordinates.size()))
+ {
+ auto matching_index = trace_idx_to_matching_idx[trace_index];
+ if (matching_index.NotMatched())
+ {
+ waypoints.values.push_back(util::json::Null());
+ continue;
+ }
+ const auto &phantom =
+ sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index];
+ auto waypoint = BaseAPI::MakeWaypoint(phantom);
+ waypoint.values["matchings_index"] = matching_index.sub_matching_index;
+ waypoint.values["waypoint_index"] = matching_index.point_index;
+ waypoints.values.push_back(std::move(waypoint));
+ }
+
+ return waypoints;
+ }
+
+ const MatchParameters ¶meters;
+};
+
+} // ns api
+} // ns engine
+} // ns osrm
+
+#endif
diff --git a/util/json_logger.hpp b/include/engine/api/match_parameters.hpp
similarity index 51%
rename from util/json_logger.hpp
rename to include/engine/api/match_parameters.hpp
index 8726f78..0cb4741 100644
--- a/util/json_logger.hpp
+++ b/include/engine/api/match_parameters.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,67 +25,55 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef JSON_LOGGER_HPP
-#define JSON_LOGGER_HPP
+#ifndef ENGINE_API_MATCH_PARAMETERS_HPP
+#define ENGINE_API_MATCH_PARAMETERS_HPP
-#include <osrm/json_container.hpp>
+#include "engine/api/route_parameters.hpp"
-#include <boost/thread/tss.hpp>
-
-#include <string>
-#include <unordered_map>
+#include <vector>
namespace osrm
{
-namespace json
+namespace engine
{
-
-// Used to append additional debugging information to the JSON response in a
-// thread safe manner.
-class Logger
+namespace api
{
- using MapT = std::unordered_map<std::string, osrm::json::Value>;
- public:
- static Logger* get()
+/**
+ * Parameters specific to the OSRM Match service.
+ *
+ * Holds member attributes:
+ * - timestamps: timestamp(s) for the corresponding input coordinate(s)
+ *
+ * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
+ * NearestParameters, TripParameters, MatchParameters and TileParameters
+ */
+struct MatchParameters : public RouteParameters
+{
+ MatchParameters()
+ : RouteParameters(false,
+ false,
+ RouteParameters::GeometriesType::Polyline,
+ RouteParameters::OverviewType::Simplified,
+ {})
{
- static Logger logger;
-
- bool return_logger = true;
-#ifdef NDEBUG
- return_logger = false;
-#endif
-#ifdef ENABLE_JSON_LOGGING
- return_logger = true;
-#endif
-
- if (return_logger)
- {
- return &logger;
- }
-
- return nullptr;
}
- void initialize(const std::string& name)
+ template <typename... Args>
+ MatchParameters(std::vector<unsigned> timestamps_, Args... args_)
+ : RouteParameters{std::forward<Args>(args_)...}, timestamps{std::move(timestamps_)}
{
- if (!map.get())
- {
- map.reset(new MapT());
- }
- (*map)[name] = Object();
}
- void render(const std::string& name, Object& obj) const
+ std::vector<unsigned> timestamps;
+ bool IsValid() const
{
- obj.values["debug"] = map->at(name);
+ return RouteParameters::IsValid() &&
+ (timestamps.empty() || timestamps.size() == coordinates.size());
}
-
- boost::thread_specific_ptr<MapT> map;
};
-
-
+}
}
}
-#endif /* JSON_LOGGER_HPP */
+#endif
diff --git a/include/engine/api/nearest_api.hpp b/include/engine/api/nearest_api.hpp
new file mode 100644
index 0000000..ab3747e
--- /dev/null
+++ b/include/engine/api/nearest_api.hpp
@@ -0,0 +1,57 @@
+#ifndef ENGINE_API_NEAREST_API_HPP
+#define ENGINE_API_NEAREST_API_HPP
+
+#include "engine/api/base_api.hpp"
+#include "engine/api/nearest_parameters.hpp"
+
+#include "engine/api/json_factory.hpp"
+#include "engine/phantom_node.hpp"
+
+#include <boost/assert.hpp>
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+class NearestAPI final : public BaseAPI
+{
+ public:
+ NearestAPI(const datafacade::BaseDataFacade &facade_, const NearestParameters ¶meters_)
+ : BaseAPI(facade_, parameters_), parameters(parameters_)
+ {
+ }
+
+ void MakeResponse(const std::vector<std::vector<PhantomNodeWithDistance>> &phantom_nodes,
+ util::json::Object &response) const
+ {
+ BOOST_ASSERT(phantom_nodes.size() == 1);
+ BOOST_ASSERT(parameters.coordinates.size() == 1);
+
+ util::json::Array waypoints;
+ waypoints.values.resize(phantom_nodes.front().size());
+ std::transform(phantom_nodes.front().begin(), phantom_nodes.front().end(),
+ waypoints.values.begin(),
+ [this](const PhantomNodeWithDistance &phantom_with_distance)
+ {
+ auto waypoint = MakeWaypoint(phantom_with_distance.phantom_node);
+ waypoint.values["distance"] = phantom_with_distance.distance;
+ return waypoint;
+ });
+
+ response.values["code"] = "ok";
+ response.values["waypoints"] = std::move(waypoints);
+ }
+
+ const NearestParameters ¶meters;
+};
+
+} // ns api
+} // ns engine
+} // ns osrm
+
+#endif
diff --git a/util/osrm_exception.hpp b/include/engine/api/nearest_parameters.hpp
similarity index 62%
rename from util/osrm_exception.hpp
rename to include/engine/api/nearest_parameters.hpp
index 369433f..6a6dad7 100644
--- a/util/osrm_exception.hpp
+++ b/include/engine/api/nearest_parameters.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,28 +25,35 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef OSRM_EXCEPTION_HPP
-#define OSRM_EXCEPTION_HPP
+#ifndef ENGINE_API_NEAREST_PARAMETERS_HPP
+#define ENGINE_API_NEAREST_PARAMETERS_HPP
-#include <exception>
-#include <string>
-#include <utility>
+#include "engine/api/base_parameters.hpp"
namespace osrm
{
-class exception final : public std::exception
+namespace engine
{
- public:
- explicit exception(const char *message) : message(message) {}
- explicit exception(std::string message) : message(std::move(message)) {}
-
- private:
- // This function exists to 'anchor' the class, and stop the compiler from
- // copying vtable and RTTI info into every object file that includes
- // this header. (Caught by -Wweak-vtables under Clang.)
- virtual void anchor() const;
- const char *what() const noexcept override { return message.c_str(); }
- const std::string message;
+namespace api
+{
+
+/**
+ * Parameters specific to the OSRM Nearest service.
+ *
+ * Holds member attributes:
+ * - number of results: number of nearest segments that should be returned
+ *
+ * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
+ * NearestParameters, TripParameters, MatchParameters and TileParameters
+ */
+struct NearestParameters : public BaseParameters
+{
+ unsigned number_of_results = 1;
+
+ bool IsValid() const { return BaseParameters::IsValid() && number_of_results >= 1; }
};
}
-#endif /* OSRM_EXCEPTION_HPP */
+}
+}
+
+#endif // ENGINE_API_NEAREST_PARAMETERS_HPP
diff --git a/include/engine/api/route_api.hpp b/include/engine/api/route_api.hpp
new file mode 100644
index 0000000..e3b9ff8
--- /dev/null
+++ b/include/engine/api/route_api.hpp
@@ -0,0 +1,190 @@
+#ifndef ENGINE_API_ROUTE_HPP
+#define ENGINE_API_ROUTE_HPP
+
+#include "engine/api/base_api.hpp"
+#include "engine/api/route_parameters.hpp"
+#include "engine/api/json_factory.hpp"
+
+#include "engine/datafacade/datafacade_base.hpp"
+
+#include "engine/guidance/assemble_leg.hpp"
+#include "engine/guidance/assemble_route.hpp"
+#include "engine/guidance/assemble_geometry.hpp"
+#include "engine/guidance/assemble_overview.hpp"
+#include "engine/guidance/assemble_steps.hpp"
+#include "engine/guidance/post_processing.hpp"
+
+#include "engine/internal_route_result.hpp"
+
+#include "util/coordinate.hpp"
+#include "util/integer_range.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+class RouteAPI : public BaseAPI
+{
+ public:
+ RouteAPI(const datafacade::BaseDataFacade &facade_, const RouteParameters ¶meters_)
+ : BaseAPI(facade_, parameters_), parameters(parameters_)
+ {
+ }
+
+ void MakeResponse(const InternalRouteResult &raw_route, util::json::Object &response) const
+ {
+ auto number_of_routes = raw_route.has_alternative() ? 2UL : 1UL;
+ util::json::Array routes;
+ routes.values.resize(number_of_routes);
+ routes.values[0] =
+ MakeRoute(raw_route.segment_end_coordinates, raw_route.unpacked_path_segments,
+ raw_route.source_traversed_in_reverse, raw_route.target_traversed_in_reverse);
+ if (raw_route.has_alternative())
+ {
+ std::vector<std::vector<PathData>> wrapped_leg(1);
+ wrapped_leg.front() = std::move(raw_route.unpacked_alternative);
+ routes.values[1] = MakeRoute(raw_route.segment_end_coordinates, wrapped_leg,
+ raw_route.alt_source_traversed_in_reverse,
+ raw_route.alt_target_traversed_in_reverse);
+ }
+ response.values["waypoints"] = BaseAPI::MakeWaypoints(raw_route.segment_end_coordinates);
+ response.values["routes"] = std::move(routes);
+ response.values["code"] = "ok";
+ }
+
+ // FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
+ // protected:
+ template <typename ForwardIter>
+ util::json::Value MakeGeometry(ForwardIter begin, ForwardIter end) const
+ {
+ if (parameters.geometries == RouteParameters::GeometriesType::Polyline)
+ {
+ return json::makePolyline(begin, end);
+ }
+
+ BOOST_ASSERT(parameters.geometries == RouteParameters::GeometriesType::GeoJSON);
+ return json::makeGeoJSONLineString(begin, end);
+ }
+
+ util::json::Object MakeRoute(const std::vector<PhantomNodes> &segment_end_coordinates,
+ const std::vector<std::vector<PathData>> &unpacked_path_segments,
+ const std::vector<bool> &source_traversed_in_reverse,
+ const std::vector<bool> &target_traversed_in_reverse) const
+ {
+ std::vector<guidance::RouteLeg> legs;
+ std::vector<guidance::LegGeometry> leg_geometries;
+ auto number_of_legs = segment_end_coordinates.size();
+ legs.reserve(number_of_legs);
+ leg_geometries.reserve(number_of_legs);
+
+ for (auto idx : util::irange(0UL, number_of_legs))
+ {
+ const auto &phantoms = segment_end_coordinates[idx];
+ const auto &path_data = unpacked_path_segments[idx];
+
+ const bool reversed_source = source_traversed_in_reverse[idx];
+ const bool reversed_target = target_traversed_in_reverse[idx];
+
+ auto leg_geometry = guidance::assembleGeometry(
+ BaseAPI::facade, path_data, phantoms.source_phantom, phantoms.target_phantom);
+ auto leg = guidance::assembleLeg(BaseAPI::facade, path_data, leg_geometry,
+ phantoms.source_phantom, phantoms.target_phantom, reversed_target);
+
+ if (parameters.steps)
+ {
+ auto steps = guidance::assembleSteps(
+ BaseAPI::facade, path_data, leg_geometry, phantoms.source_phantom,
+ phantoms.target_phantom, reversed_source, reversed_target);
+
+ /* Perform step-based post-processing.
+ *
+ * Using post-processing on basis of route-steps for a single leg at a time
+ * comes at the cost that we cannot count the correct exit for roundabouts.
+ * We can only emit the exit nr/intersections up to/starting at a part of the leg.
+ * If a roundabout is not terminated in a leg, we will end up with a
+ *enter-roundabout
+ * and exit-roundabout-nr where the exit nr is out of sync with the previous enter.
+ *
+ * | S |
+ * * *
+ * ----* * ----
+ * T
+ * ----* * ----
+ * V * *
+ * | |
+ * | |
+ *
+ * Coming from S via V to T, we end up with the legs S->V and V->T. V-T will say to
+ *take
+ * the second exit, even though counting from S it would be the third.
+ * For S, we only emit `roundabout` without an exit number, showing that we enter a
+ *roundabout
+ * to find a via point.
+ * The same exit will be emitted, though, if we should start routing at S, making
+ * the overall response consistent.
+ */
+
+ guidance::trimShortSegments(steps, leg_geometry);
+ leg.steps = guidance::postProcess(std::move(steps));
+ leg.steps = guidance::assignRelativeLocations(std::move(leg.steps), leg_geometry,
+ phantoms.source_phantom,
+ phantoms.target_phantom);
+ leg_geometry = guidance::resyncGeometry(std::move(leg_geometry), leg.steps);
+ }
+
+ leg_geometries.push_back(std::move(leg_geometry));
+ legs.push_back(std::move(leg));
+ }
+
+ auto route = guidance::assembleRoute(legs);
+ boost::optional<util::json::Value> json_overview;
+ if (parameters.overview != RouteParameters::OverviewType::False)
+ {
+ const auto use_simplification =
+ parameters.overview == RouteParameters::OverviewType::Simplified;
+ BOOST_ASSERT(use_simplification ||
+ parameters.overview == RouteParameters::OverviewType::Full);
+
+ auto overview = guidance::assembleOverview(leg_geometries, use_simplification);
+ json_overview = MakeGeometry(overview.begin(), overview.end());
+ }
+
+ std::vector<util::json::Value> step_geometries;
+ for (const auto idx : util::irange(0UL, legs.size()))
+ {
+ auto &leg_geometry = leg_geometries[idx];
+ std::transform(
+ legs[idx].steps.begin(), legs[idx].steps.end(), std::back_inserter(step_geometries),
+ [this, &leg_geometry](const guidance::RouteStep &step)
+ {
+ if (parameters.geometries == RouteParameters::GeometriesType::Polyline)
+ {
+ return static_cast<util::json::Value>(
+ json::makePolyline(leg_geometry.locations.begin() + step.geometry_begin,
+ leg_geometry.locations.begin() + step.geometry_end));
+ }
+ BOOST_ASSERT(parameters.geometries == RouteParameters::GeometriesType::GeoJSON);
+ return static_cast<util::json::Value>(json::makeGeoJSONLineString(
+ leg_geometry.locations.begin() + step.geometry_begin,
+ leg_geometry.locations.begin() + step.geometry_end));
+ });
+ }
+
+ return json::makeRoute(route,
+ json::makeRouteLegs(std::move(legs), std::move(step_geometries)),
+ std::move(json_overview));
+ }
+
+ const RouteParameters ¶meters;
+};
+
+} // ns api
+} // ns engine
+} // ns osrm
+
+#endif
diff --git a/include/engine/api/route_parameters.hpp b/include/engine/api/route_parameters.hpp
new file mode 100644
index 0000000..b8704fc
--- /dev/null
+++ b/include/engine/api/route_parameters.hpp
@@ -0,0 +1,96 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef ENGINE_API_ROUTE_PARAMETERS_HPP
+#define ENGINE_API_ROUTE_PARAMETERS_HPP
+
+#include "engine/api/base_parameters.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+/**
+ * Parameters specific to the OSRM Route service.
+ *
+ * Holds member attributes:
+ * - steps: return route step for each route leg
+ * - alternatives: tries to find alternative routes
+ * - geometries: route geometry encoded in Polyline or GeoJSON
+ * - overview: adds overview geometry either Full, Simplified (according to highest zoom level) or
+ * False (not at all)
+ * - uturns: enable or disable uturns (disabled by default)
+ *
+ * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
+ * NearestParameters, TripParameters, MatchParameters and TileParameters
+ */
+struct RouteParameters : public BaseParameters
+{
+ enum class GeometriesType
+ {
+ Polyline,
+ GeoJSON
+ };
+ enum class OverviewType
+ {
+ Simplified,
+ Full,
+ False
+ };
+
+ RouteParameters() = default;
+
+ template <typename... Args>
+ RouteParameters(const bool steps_,
+ const bool alternatives_,
+ const GeometriesType geometries_,
+ const OverviewType overview_,
+ const boost::optional<bool> uturns_,
+ Args... args_)
+ : BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_},
+ geometries{geometries_}, overview{overview_}, uturns{uturns_}
+ {
+ }
+
+ bool steps = true;
+ bool alternatives = true;
+ GeometriesType geometries = GeometriesType::Polyline;
+ OverviewType overview = OverviewType::Simplified;
+ boost::optional<bool> uturns;
+
+ bool IsValid() const { return coordinates.size() >= 2 && BaseParameters::IsValid(); }
+};
+}
+}
+}
+
+#endif
diff --git a/include/engine/api/table_api.hpp b/include/engine/api/table_api.hpp
new file mode 100644
index 0000000..ac683c9
--- /dev/null
+++ b/include/engine/api/table_api.hpp
@@ -0,0 +1,133 @@
+#ifndef ENGINE_API_TABLE_HPP
+#define ENGINE_API_TABLE_HPP
+
+#include "engine/api/base_api.hpp"
+#include "engine/api/table_parameters.hpp"
+#include "engine/api/json_factory.hpp"
+
+#include "engine/datafacade/datafacade_base.hpp"
+
+#include "engine/guidance/assemble_leg.hpp"
+#include "engine/guidance/assemble_route.hpp"
+#include "engine/guidance/assemble_geometry.hpp"
+#include "engine/guidance/assemble_overview.hpp"
+#include "engine/guidance/assemble_steps.hpp"
+
+#include "engine/internal_route_result.hpp"
+
+#include "util/integer_range.hpp"
+
+#include <boost/range/algorithm/transform.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+class TableAPI final : public BaseAPI
+{
+ public:
+ TableAPI(const datafacade::BaseDataFacade &facade_, const TableParameters ¶meters_)
+ : BaseAPI(facade_, parameters_), parameters(parameters_)
+ {
+ }
+
+ virtual void MakeResponse(const std::vector<EdgeWeight> &durations,
+ const std::vector<PhantomNode> &phantoms,
+ util::json::Object &response) const
+ {
+ auto number_of_sources = parameters.sources.size();
+ auto number_of_destinations = parameters.destinations.size();
+ ;
+
+ // symmetric case
+ if (parameters.sources.empty())
+ {
+ response.values["sources"] = MakeWaypoints(phantoms);
+ number_of_sources = phantoms.size();
+ }
+ else
+ {
+ response.values["sources"] = MakeWaypoints(phantoms, parameters.sources);
+ }
+
+ if (parameters.destinations.empty())
+ {
+ response.values["destinations"] = MakeWaypoints(phantoms);
+ number_of_destinations = phantoms.size();
+ }
+ else
+ {
+ response.values["destinations"] = MakeWaypoints(phantoms, parameters.destinations);
+ }
+
+ response.values["durations"] =
+ MakeTable(durations, number_of_sources, number_of_destinations);
+ response.values["code"] = "ok";
+ }
+
+ // FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
+ // protected:
+ virtual util::json::Array MakeWaypoints(const std::vector<PhantomNode> &phantoms) const
+ {
+ util::json::Array json_waypoints;
+ json_waypoints.values.reserve(phantoms.size());
+ BOOST_ASSERT(phantoms.size() == parameters.coordinates.size());
+
+ boost::range::transform(phantoms, std::back_inserter(json_waypoints.values),
+ [this](const PhantomNode &phantom)
+ {
+ return BaseAPI::MakeWaypoint(phantom);
+ });
+ return json_waypoints;
+ }
+
+ virtual util::json::Array MakeWaypoints(const std::vector<PhantomNode> &phantoms,
+ const std::vector<std::size_t> &indices) const
+ {
+ util::json::Array json_waypoints;
+ json_waypoints.values.reserve(indices.size());
+ boost::range::transform(indices, std::back_inserter(json_waypoints.values),
+ [this, phantoms](const std::size_t idx)
+ {
+ BOOST_ASSERT(idx < phantoms.size());
+ return BaseAPI::MakeWaypoint(phantoms[idx]);
+ });
+ return json_waypoints;
+ }
+
+ virtual util::json::Array MakeTable(const std::vector<EdgeWeight> &values,
+ std::size_t number_of_rows,
+ std::size_t number_of_columns) const
+ {
+ util::json::Array json_table;
+ for (const auto row : util::irange<std::size_t>(0, number_of_rows))
+ {
+ util::json::Array json_row;
+ auto row_begin_iterator = values.begin() + (row * number_of_columns);
+ auto row_end_iterator = values.begin() + ((row + 1) * number_of_columns);
+ json_row.values.resize(number_of_columns);
+ std::transform(row_begin_iterator, row_end_iterator, json_row.values.begin(),
+ [](const EdgeWeight duration)
+ {
+ if (duration == INVALID_EDGE_WEIGHT)
+ {
+ return util::json::Value(util::json::Null());
+ }
+ return util::json::Value(util::json::Number(duration / 10.));
+ });
+ json_table.values.push_back(std::move(json_row));
+ }
+ return json_table;
+ }
+
+ const TableParameters ¶meters;
+};
+
+} // ns api
+} // ns engine
+} // ns osrm
+
+#endif
diff --git a/include/engine/api/table_parameters.hpp b/include/engine/api/table_parameters.hpp
new file mode 100644
index 0000000..d4d3fd3
--- /dev/null
+++ b/include/engine/api/table_parameters.hpp
@@ -0,0 +1,110 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef ENGINE_API_TABLE_PARAMETERS_HPP
+#define ENGINE_API_TABLE_PARAMETERS_HPP
+
+#include "engine/api/base_parameters.hpp"
+
+#include <cstddef>
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+/**
+ * Parameters specific to the OSRM Table service.
+ *
+ * Holds member attributes:
+ * - sources: indices into coordinates indicating sources for the Table service, no sources means
+ * use all coordinates as sources
+ * - destinations: indices into coordinates indicating destinations for the Table service, no
+ * destinations means use all coordinates as destinations
+ *
+ * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
+ * NearestParameters, TripParameters, MatchParameters and TileParameters
+ */
+struct TableParameters : public BaseParameters
+{
+ std::vector<std::size_t> sources;
+ std::vector<std::size_t> destinations;
+
+ TableParameters() = default;
+ template <typename... Args>
+ TableParameters(std::vector<std::size_t> sources_,
+ std::vector<std::size_t> destinations_,
+ Args... args_)
+ : BaseParameters{std::forward<Args>(args_)...}, sources{std::move(sources_)},
+ destinations{std::move(destinations_)}
+ {
+ }
+
+ bool IsValid() const
+ {
+ if (!BaseParameters::IsValid())
+ return false;
+
+ // Distance Table makes only sense with 2+ coodinates
+ if (coordinates.size() < 2)
+ return false;
+
+ // 1/ The user is able to specify duplicates in srcs and dsts, in that case it's her fault
+
+ // 2/ len(srcs) and len(dsts) smaller or equal to len(locations)
+ if (sources.size() > coordinates.size())
+ return false;
+
+ if (destinations.size() > coordinates.size())
+ return false;
+
+ // 3/ 0 <= index < len(locations)
+ const auto not_in_range = [this](const std::size_t x)
+ {
+ return x >= coordinates.size();
+ };
+
+ if (std::any_of(begin(sources), end(sources), not_in_range))
+ return false;
+
+ if (std::any_of(begin(destinations), end(destinations), not_in_range))
+ return false;
+
+ return true;
+ }
+};
+}
+}
+}
+
+#endif // ENGINE_API_TABLE_PARAMETERS_HPP
diff --git a/algorithms/trip_tabu_search.hpp b/include/engine/api/tile_parameters.hpp
similarity index 50%
rename from algorithms/trip_tabu_search.hpp
rename to include/engine/api/tile_parameters.hpp
index 32f50fc..34c949a 100644
--- a/algorithms/trip_tabu_search.hpp
+++ b/include/engine/api/tile_parameters.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,40 +25,52 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TRIP_BRUTE_FORCE_HPP
-#define TRIP_BRUTE_FORCE_HPP
+#ifndef ENGINE_API_TILE_PARAMETERS_HPP
+#define ENGINE_API_TILE_PARAMETERS_HPP
-#include "../data_structures/search_engine.hpp"
-#include "../util/simple_logger.hpp"
-
-#include <osrm/json_container.hpp>
-
-#include <cstdlib>
-#include <algorithm>
-#include <string>
-#include <vector>
-#include <limits>
+#include <cmath>
namespace osrm
{
-namespace trip
+namespace engine
{
-
-// todo: yet to be implemented
-void TabuSearchTrip(std::vector<unsigned> &location,
- const PhantomNodeArray &phantom_node_vector,
- const std::vector<EdgeWeight> &dist_table,
- InternalRouteResult &min_route,
- std::vector<int> &min_loc_permutation)
+namespace api
{
-}
-void TabuSearchTrip(const PhantomNodeArray &phantom_node_vector,
- const std::vector<EdgeWeight> &dist_table,
- InternalRouteResult &min_route,
- std::vector<int> &min_loc_permutation)
+/**
+ * Parameters specific to the OSRM Tile service.
+ *
+ * Holds member attributes:
+ * - x: the x location for the tile
+ * - y: the y location for the tile
+ * - z: the zoom level for the tile
+ *
+ * The parameters x,y and z have to conform to the Slippy Map Tilenames specification:
+ * - https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Zoom_levels
+ * - https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#X_and_Y
+ *
+ * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
+ * NearestParameters, TripParameters, MatchParameters and TileParameters
+ */
+struct TileParameters final
{
+ unsigned x;
+ unsigned y;
+ unsigned z;
+
+ bool IsValid() const
+ {
+ // https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Zoom_levels
+ // https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#X_and_Y
+ const auto valid_x = x <= static_cast<unsigned>(std::pow(2., z)) - 1;
+ const auto valid_y = y <= static_cast<unsigned>(std::pow(2., z)) - 1;
+ const auto valid_z = z < 20;
+
+ return valid_x && valid_y && valid_z;
+ };
+};
}
}
}
-#endif // TRIP_BRUTE_FORCE_HPP
\ No newline at end of file
+
+#endif
diff --git a/include/engine/api/trip_api.hpp b/include/engine/api/trip_api.hpp
new file mode 100644
index 0000000..aea7676
--- /dev/null
+++ b/include/engine/api/trip_api.hpp
@@ -0,0 +1,111 @@
+#ifndef ENGINE_API_TRIP_HPP
+#define ENGINE_API_TRIP_HPP
+
+#include "engine/api/route_api.hpp"
+#include "engine/api/trip_parameters.hpp"
+
+#include "engine/datafacade/datafacade_base.hpp"
+
+#include "engine/internal_route_result.hpp"
+
+#include "util/integer_range.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+
+class TripAPI final : public RouteAPI
+{
+ public:
+ TripAPI(const datafacade::BaseDataFacade &facade_, const TripParameters ¶meters_)
+ : RouteAPI(facade_, parameters_), parameters(parameters_)
+ {
+ }
+
+ void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
+ const std::vector<InternalRouteResult> &sub_routes,
+ const std::vector<PhantomNode> &phantoms,
+ util::json::Object &response) const
+ {
+ auto number_of_routes = sub_trips.size();
+ util::json::Array routes;
+ routes.values.reserve(number_of_routes);
+ BOOST_ASSERT(sub_trips.size() == sub_routes.size());
+ for (auto index : util::irange<std::size_t>(0UL, sub_trips.size()))
+ {
+ auto route = MakeRoute(sub_routes[index].segment_end_coordinates,
+ sub_routes[index].unpacked_path_segments,
+ sub_routes[index].source_traversed_in_reverse,
+ sub_routes[index].target_traversed_in_reverse);
+ routes.values.push_back(std::move(route));
+ }
+ response.values["waypoints"] = MakeWaypoints(sub_trips, phantoms);
+ response.values["trips"] = std::move(routes);
+ response.values["code"] = "ok";
+ }
+
+ // FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
+ // protected:
+
+ // FIXME this logic is a little backwards. We should change the output format of the
+ // trip plugin routing algorithm to be easier to consume here.
+ util::json::Array MakeWaypoints(const std::vector<std::vector<NodeID>> &sub_trips,
+ const std::vector<PhantomNode> &phantoms) const
+ {
+ util::json::Array waypoints;
+ waypoints.values.reserve(parameters.coordinates.size());
+
+ struct TripIndex
+ {
+ TripIndex() = default;
+ TripIndex(unsigned sub_trip_index_, unsigned point_index_)
+ : sub_trip_index(sub_trip_index_), point_index(point_index_)
+ {
+ }
+
+ unsigned sub_trip_index = std::numeric_limits<unsigned>::max();
+ unsigned point_index = std::numeric_limits<unsigned>::max();
+
+ bool NotUsed()
+ {
+ return sub_trip_index == std::numeric_limits<unsigned>::max() &&
+ point_index == std::numeric_limits<unsigned>::max();
+ }
+ };
+
+ std::vector<TripIndex> input_idx_to_trip_idx(parameters.coordinates.size());
+ for (auto sub_trip_index : util::irange(0u, static_cast<unsigned>(sub_trips.size())))
+ {
+ for (auto point_index :
+ util::irange(0u, static_cast<unsigned>(sub_trips[sub_trip_index].size())))
+ {
+ input_idx_to_trip_idx[sub_trips[sub_trip_index][point_index]] =
+ TripIndex{sub_trip_index, point_index};
+ }
+ }
+
+ for (auto input_index : util::irange(0UL, parameters.coordinates.size()))
+ {
+ auto trip_index = input_idx_to_trip_idx[input_index];
+ BOOST_ASSERT(!trip_index.NotUsed());
+
+ auto waypoint = BaseAPI::MakeWaypoint(phantoms[input_index]);
+ waypoint.values["trips_index"] = trip_index.sub_trip_index;
+ waypoint.values["waypoint_index"] = trip_index.point_index;
+ waypoints.values.push_back(std::move(waypoint));
+ }
+
+ return waypoints;
+ }
+
+ const TripParameters ¶meters;
+};
+
+} // ns api
+} // ns engine
+} // ns osrm
+
+#endif
diff --git a/algorithms/polyline_formatter.hpp b/include/engine/api/trip_parameters.hpp
similarity index 69%
rename from algorithms/polyline_formatter.hpp
rename to include/engine/api/trip_parameters.hpp
index 68cc702..53c9f42 100644
--- a/algorithms/polyline_formatter.hpp
+++ b/include/engine/api/trip_parameters.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,21 +25,32 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef POLYLINE_FORMATTER_HPP
-#define POLYLINE_FORMATTER_HPP
+#ifndef ENGINE_API_TRIP_PARAMETERS_HPP
+#define ENGINE_API_TRIP_PARAMETERS_HPP
-struct SegmentInformation;
+#include "engine/api/route_parameters.hpp"
-#include <osrm/json_container.hpp>
-
-#include <string>
#include <vector>
-struct PolylineFormatter
+namespace osrm
+{
+namespace engine
+{
+namespace api
{
- osrm::json::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
- osrm::json::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
+/**
+ * Parameters specific to the OSRM Trip service.
+ *
+ * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters,
+ * NearestParameters, TripParameters, MatchParameters and TileParameters
+ */
+struct TripParameters : public RouteParameters
+{
+ // bool IsValid() const; Falls back to base class
};
+}
+}
+}
-#endif /* POLYLINE_FORMATTER_HPP */
+#endif
diff --git a/include/engine/base64.hpp b/include/engine/base64.hpp
new file mode 100644
index 0000000..6482961
--- /dev/null
+++ b/include/engine/base64.hpp
@@ -0,0 +1,141 @@
+#ifndef OSRM_BASE64_HPP
+#define OSRM_BASE64_HPP
+
+#include <string>
+#include <vector>
+#include <iterator>
+#include <type_traits>
+
+#include <cstddef>
+#include <climits>
+
+#include <boost/archive/iterators/binary_from_base64.hpp>
+#include <boost/archive/iterators/base64_from_binary.hpp>
+#include <boost/archive/iterators/transform_width.hpp>
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/range/algorithm/copy.hpp>
+
+// RFC 4648 "The Base16, Base32, and Base64 Data Encodings"
+// See: https://tools.ietf.org/html/rfc4648
+
+namespace detail
+{
+// The C++ standard guarantees none of this by default, but we need it in the following.
+static_assert(CHAR_BIT == 8u, "we assume a byte holds 8 bits");
+static_assert(sizeof(char) == 1u, "we assume a char is one byte large");
+
+using Base64FromBinary = boost::archive::iterators::base64_from_binary<
+ boost::archive::iterators::transform_width<const char *, // sequence of chars
+ 6, // get view of 6 bit
+ 8 // from sequence of 8 bit
+ >>;
+
+using BinaryFromBase64 = boost::archive::iterators::transform_width<
+ boost::archive::iterators::binary_from_base64<std::string::const_iterator>,
+ 8, // get a view of 8 bit
+ 6 // from a sequence of 6 bit
+ >;
+} // ns detail
+
+namespace osrm
+{
+namespace engine
+{
+
+// Encoding Implementation
+
+// Encodes a chunk of memory to Base64.
+inline std::string encodeBase64(const unsigned char *first, std::size_t size)
+{
+ std::vector<unsigned char> bytes{first, first + size};
+ BOOST_ASSERT(!bytes.empty());
+
+ std::size_t bytes_to_pad{0};
+
+ while (bytes.size() % 3 != 0)
+ {
+ bytes_to_pad += 1;
+ bytes.push_back(0);
+ }
+
+ BOOST_ASSERT(bytes_to_pad == 0 || bytes_to_pad == 1 || bytes_to_pad == 2);
+ BOOST_ASSERT_MSG(0 == bytes.size() % 3, "base64 input data size is not a multiple of 3");
+
+ std::string encoded{detail::Base64FromBinary{bytes.data()},
+ detail::Base64FromBinary{bytes.data() + (bytes.size() - bytes_to_pad)}};
+
+ return encoded.append(bytes_to_pad, '=');
+}
+
+// C++11 standard 3.9.1/1: Plain char, signed char, and unsigned char are three distinct types
+
+// Overload for signed char catches (not only but also) C-string literals.
+inline std::string encodeBase64(const signed char *first, std::size_t size)
+{
+ return encodeBase64(reinterpret_cast<const unsigned char *>(first), size);
+}
+
+// Overload for char catches (not only but also) C-string literals.
+inline std::string encodeBase64(const char *first, std::size_t size)
+{
+ return encodeBase64(reinterpret_cast<const unsigned char *>(first), size);
+}
+
+// Convenience specialization, encoding from string instead of byte-dumping it.
+inline std::string encodeBase64(const std::string &x) { return encodeBase64(x.data(), x.size()); }
+
+// Encode any sufficiently trivial object to Base64.
+template <typename T> std::string encodeBase64Bytewise(const T &x)
+{
+#if not defined __GNUC__ or __GNUC__ > 4
+ static_assert(std::is_trivially_copyable<T>::value, "requires a trivially copyable type");
+#endif
+
+ return encodeBase64(reinterpret_cast<const unsigned char *>(&x), sizeof(T));
+}
+
+// Decoding Implementation
+
+// Decodes into a chunk of memory that is at least as large as the input.
+template <typename OutputIter> void decodeBase64(const std::string &encoded, OutputIter out)
+{
+ auto unpadded = encoded;
+
+ const auto num_padded = std::count(begin(encoded), end(encoded), '=');
+ std::replace(begin(unpadded), end(unpadded), '=', 'A'); // A_64 == \0
+
+ std::string decoded{detail::BinaryFromBase64{begin(unpadded)},
+ detail::BinaryFromBase64{begin(unpadded) + unpadded.length()}};
+
+ decoded.erase(end(decoded) - num_padded, end(decoded));
+ std::copy(begin(decoded), end(decoded), out);
+}
+
+// Convenience specialization, filling string instead of byte-dumping into it.
+inline std::string decodeBase64(const std::string &encoded)
+{
+ std::string rv;
+
+ decodeBase64(encoded, std::back_inserter(rv));
+
+ return rv;
+}
+
+// Decodes from Base 64 to any sufficiently trivial object.
+template <typename T> T decodeBase64Bytewise(const std::string &encoded)
+{
+#if not defined __GNUC__ or __GNUC__ > 4
+ static_assert(std::is_trivially_copyable<T>::value, "requires a trivially copyable type");
+#endif
+
+ T x;
+
+ decodeBase64(encoded, reinterpret_cast<unsigned char *>(&x));
+
+ return x;
+}
+
+} // ns engine
+} // ns osrm
+
+#endif /* OSRM_BASE64_HPP */
diff --git a/util/range_algorithms.hpp b/include/engine/bearing.hpp
similarity index 72%
rename from util/range_algorithms.hpp
rename to include/engine/bearing.hpp
index 4d01d29..3b99962 100644
--- a/util/range_algorithms.hpp
+++ b/include/engine/bearing.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,25 +25,28 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef RANGE_ALGORITHMS_HPP
-#define RANGE_ALGORITHMS_HPP
-
-#include <algorithm>
+#ifndef OSRM_ENGINE_BEARING_HPP
+#define OSRM_ENGINE_BEARING_HPP
namespace osrm
{
+namespace engine
+{
-template <class Container>
-auto max_element(const Container &c) -> decltype(std::max_element(c.begin(), c.end()))
+struct Bearing
{
- return std::max_element(c.begin(), c.end());
-}
+ short bearing;
+ short range;
-template <class Container>
-auto max_element(const Container &c) -> decltype(std::max_element(c.cbegin(), c.cend()))
+ bool IsValid() const { return bearing >= 0 && bearing <= 360 && range >= 0 && range <= 180; }
+};
+
+inline bool operator==(const Bearing lhs, const Bearing rhs)
{
- return std::max_element(c.cbegin(), c.cend());
+ return lhs.bearing == rhs.bearing && lhs.range == rhs.range;
+}
+inline bool operator!=(const Bearing lhs, const Bearing rhs) { return !(lhs == rhs); }
}
}
-#endif // RANGE_ALGORITHMS_HPP
+#endif
diff --git a/include/engine/datafacade/datafacade_base.hpp b/include/engine/datafacade/datafacade_base.hpp
new file mode 100644
index 0000000..f4cb0c4
--- /dev/null
+++ b/include/engine/datafacade/datafacade_base.hpp
@@ -0,0 +1,153 @@
+#ifndef DATAFACADE_BASE_HPP
+#define DATAFACADE_BASE_HPP
+
+// Exposes all data access interfaces to the algorithms via base class ptr
+
+#include "extractor/edge_based_node.hpp"
+#include "extractor/external_memory_node.hpp"
+#include "contractor/query_edge.hpp"
+#include "engine/phantom_node.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+#include "util/integer_range.hpp"
+#include "util/exception.hpp"
+#include "util/string_util.hpp"
+#include "util/typedefs.hpp"
+
+#include "osrm/coordinate.hpp"
+
+#include <cstddef>
+
+#include <vector>
+#include <utility>
+#include <string>
+
+namespace osrm
+{
+namespace engine
+{
+namespace datafacade
+{
+
+using EdgeRange = util::range<EdgeID>;
+
+class BaseDataFacade
+{
+ public:
+ using EdgeData = contractor::QueryEdge::EdgeData;
+ using RTreeLeaf = extractor::EdgeBasedNode;
+ BaseDataFacade() {}
+ virtual ~BaseDataFacade() {}
+
+ // search graph access
+ virtual unsigned GetNumberOfNodes() const = 0;
+
+ virtual unsigned GetNumberOfEdges() const = 0;
+
+ virtual unsigned GetOutDegree(const NodeID n) const = 0;
+
+ virtual NodeID GetTarget(const EdgeID e) const = 0;
+
+ virtual const EdgeData &GetEdgeData(const EdgeID e) const = 0;
+
+ virtual EdgeID BeginEdges(const NodeID n) const = 0;
+
+ virtual EdgeID EndEdges(const NodeID n) const = 0;
+
+ virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
+
+ // searches for a specific edge
+ virtual EdgeID FindEdge(const NodeID from, const NodeID to) const = 0;
+
+ virtual EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const = 0;
+
+ virtual EdgeID
+ FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const = 0;
+
+ // node and edge information access
+ virtual util::Coordinate GetCoordinateOfNode(const unsigned id) const = 0;
+
+ virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const = 0;
+
+ virtual void GetUncompressedGeometry(const EdgeID id,
+ std::vector<NodeID> &result_nodes) const = 0;
+
+ // Gets the weight values for each segment in an uncompressed geometry.
+ // Should always be 1 shorter than GetUncompressedGeometry
+ virtual void GetUncompressedWeights(const EdgeID id,
+ std::vector<EdgeWeight> &result_weights) const = 0;
+
+ // Returns the data source ids that were used to supply the edge
+ // weights. Will return an empty array when only the base profile is used.
+ virtual void GetUncompressedDatasources(const EdgeID id,
+ std::vector<uint8_t> &data_sources) const = 0;
+
+ // Gets the name of a datasource
+ virtual std::string GetDatasourceName(const uint8_t datasource_name_id) const = 0;
+
+ virtual extractor::guidance::TurnInstruction
+ GetTurnInstructionForEdgeID(const unsigned id) const = 0;
+
+ virtual extractor::TravelMode GetTravelModeForEdgeID(const unsigned id) const = 0;
+
+ virtual std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate south_west,
+ const util::Coordinate north_east) = 0;
+
+ virtual std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
+ const float max_distance,
+ const int bearing,
+ const int bearing_range) = 0;
+ virtual std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
+ const float max_distance) = 0;
+
+ virtual std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate,
+ const unsigned max_results,
+ const double max_distance,
+ const int bearing,
+ const int bearing_range) = 0;
+ virtual std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate,
+ const unsigned max_results,
+ const int bearing,
+ const int bearing_range) = 0;
+ virtual std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate, const unsigned max_results) = 0;
+ virtual std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate,
+ const unsigned max_results,
+ const double max_distance) = 0;
+
+ virtual std::pair<PhantomNode, PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate) = 0;
+ virtual std::pair<PhantomNode, PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+ const double max_distance) = 0;
+ virtual std::pair<PhantomNode, PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+ const double max_distance,
+ const int bearing,
+ const int bearing_range) = 0;
+ virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
+ const util::Coordinate input_coordinate, const int bearing, const int bearing_range) = 0;
+
+ virtual unsigned GetCheckSum() const = 0;
+
+ virtual bool IsCoreNode(const NodeID id) const = 0;
+
+ virtual unsigned GetNameIndexFromEdgeID(const unsigned id) const = 0;
+
+ virtual std::string GetNameForID(const unsigned name_id) const = 0;
+
+ virtual std::size_t GetCoreSize() const = 0;
+
+ virtual std::string GetTimestamp() const = 0;
+
+ virtual bool GetUTurnsDefault() const = 0;
+};
+}
+}
+}
+
+#endif // DATAFACADE_BASE_HPP
diff --git a/include/engine/datafacade/internal_datafacade.hpp b/include/engine/datafacade/internal_datafacade.hpp
new file mode 100644
index 0000000..302af30
--- /dev/null
+++ b/include/engine/datafacade/internal_datafacade.hpp
@@ -0,0 +1,658 @@
+#ifndef INTERNAL_DATAFACADE_HPP
+#define INTERNAL_DATAFACADE_HPP
+
+// implements all data storage when shared memory is _NOT_ used
+
+#include "engine/datafacade/datafacade_base.hpp"
+
+#include "extractor/guidance/turn_instruction.hpp"
+
+#include "engine/geospatial_query.hpp"
+#include "extractor/original_edge_data.hpp"
+#include "extractor/profile_properties.hpp"
+#include "extractor/query_node.hpp"
+#include "contractor/query_edge.hpp"
+#include "util/shared_memory_vector_wrapper.hpp"
+#include "util/static_graph.hpp"
+#include "util/static_rtree.hpp"
+#include "util/range_table.hpp"
+#include "util/graph_loader.hpp"
+#include "util/simple_logger.hpp"
+#include "util/rectangle.hpp"
+#include "extractor/compressed_edge_container.hpp"
+
+#include "osrm/coordinate.hpp"
+
+#include <cstddef>
+#include <cstdlib>
+
+#include <algorithm>
+#include <fstream>
+#include <ios>
+#include <limits>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/thread/tss.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace datafacade
+{
+
+class InternalDataFacade final : public BaseDataFacade
+{
+
+ private:
+ using super = BaseDataFacade;
+ using QueryGraph = util::StaticGraph<typename super::EdgeData>;
+ using InputEdge = typename QueryGraph::InputEdge;
+ using RTreeLeaf = typename super::RTreeLeaf;
+ using InternalRTree =
+ util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, false>::vector, false>;
+ using InternalGeospatialQuery = GeospatialQuery<InternalRTree, BaseDataFacade>;
+
+ InternalDataFacade() {}
+
+ unsigned m_check_sum;
+ unsigned m_number_of_nodes;
+ std::unique_ptr<QueryGraph> m_query_graph;
+ std::string m_timestamp;
+
+ std::shared_ptr<util::ShM<util::Coordinate, false>::vector> m_coordinate_list;
+ util::ShM<NodeID, false>::vector m_via_node_list;
+ util::ShM<unsigned, false>::vector m_name_ID_list;
+ util::ShM<extractor::guidance::TurnInstruction, false>::vector m_turn_instruction_list;
+ util::ShM<extractor::TravelMode, false>::vector m_travel_mode_list;
+ util::ShM<char, false>::vector m_names_char_list;
+ util::ShM<unsigned, false>::vector m_geometry_indices;
+ util::ShM<extractor::CompressedEdgeContainer::CompressedEdge, false>::vector m_geometry_list;
+ util::ShM<bool, false>::vector m_is_core_node;
+ util::ShM<unsigned, false>::vector m_segment_weights;
+ util::ShM<uint8_t, false>::vector m_datasource_list;
+ util::ShM<std::string, false>::vector m_datasource_names;
+ extractor::ProfileProperties m_profile_properties;
+
+ boost::thread_specific_ptr<InternalRTree> m_static_rtree;
+ boost::thread_specific_ptr<InternalGeospatialQuery> m_geospatial_query;
+ boost::filesystem::path ram_index_path;
+ boost::filesystem::path file_index_path;
+ util::RangeTable<16, false> m_name_table;
+
+ void LoadProfileProperties(const boost::filesystem::path &properties_path)
+ {
+ boost::filesystem::ifstream in_stream(properties_path);
+ if (!in_stream)
+ {
+ throw util::exception("Could not open " + properties_path.string() + " for reading.");
+ }
+
+ in_stream.read(reinterpret_cast<char*>(&m_profile_properties), sizeof(m_profile_properties));
+ }
+
+ void LoadTimestamp(const boost::filesystem::path ×tamp_path)
+ {
+ util::SimpleLogger().Write() << "Loading Timestamp";
+ boost::filesystem::ifstream timestamp_stream(timestamp_path);
+ if (!timestamp_stream)
+ {
+ throw util::exception("Could not open " + timestamp_path.string() + " for reading.");
+ }
+ getline(timestamp_stream, m_timestamp);
+ }
+
+ void LoadGraph(const boost::filesystem::path &hsgr_path)
+ {
+ typename util::ShM<typename QueryGraph::NodeArrayEntry, false>::vector node_list;
+ typename util::ShM<typename QueryGraph::EdgeArrayEntry, false>::vector edge_list;
+
+ util::SimpleLogger().Write() << "loading graph from " << hsgr_path.string();
+
+ m_number_of_nodes = readHSGRFromStream(hsgr_path, node_list, edge_list, &m_check_sum);
+
+ BOOST_ASSERT_MSG(0 != node_list.size(), "node list empty");
+ // BOOST_ASSERT_MSG(0 != edge_list.size(), "edge list empty");
+ util::SimpleLogger().Write() << "loaded " << node_list.size() << " nodes and "
+ << edge_list.size() << " edges";
+ m_query_graph = std::unique_ptr<QueryGraph>(new QueryGraph(node_list, edge_list));
+
+ BOOST_ASSERT_MSG(0 == node_list.size(), "node list not flushed");
+ BOOST_ASSERT_MSG(0 == edge_list.size(), "edge list not flushed");
+ util::SimpleLogger().Write() << "Data checksum is " << m_check_sum;
+ }
+
+ void LoadNodeAndEdgeInformation(const boost::filesystem::path &nodes_file,
+ const boost::filesystem::path &edges_file)
+ {
+ boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
+
+ extractor::QueryNode current_node;
+ unsigned number_of_coordinates = 0;
+ nodes_input_stream.read((char *)&number_of_coordinates, sizeof(unsigned));
+ m_coordinate_list = std::make_shared<std::vector<util::Coordinate>>(number_of_coordinates);
+ for (unsigned i = 0; i < number_of_coordinates; ++i)
+ {
+ nodes_input_stream.read((char *)¤t_node, sizeof(extractor::QueryNode));
+ m_coordinate_list->at(i) = util::Coordinate(current_node.lon, current_node.lat);
+ BOOST_ASSERT(m_coordinate_list->at(i).IsValid());
+ }
+
+ boost::filesystem::ifstream edges_input_stream(edges_file, std::ios::binary);
+ unsigned number_of_edges = 0;
+ edges_input_stream.read((char *)&number_of_edges, sizeof(unsigned));
+ m_via_node_list.resize(number_of_edges);
+ m_name_ID_list.resize(number_of_edges);
+ m_turn_instruction_list.resize(number_of_edges);
+ m_travel_mode_list.resize(number_of_edges);
+
+ extractor::OriginalEdgeData current_edge_data;
+ for (unsigned i = 0; i < number_of_edges; ++i)
+ {
+ edges_input_stream.read((char *)&(current_edge_data),
+ sizeof(extractor::OriginalEdgeData));
+ m_via_node_list[i] = current_edge_data.via_node;
+ m_name_ID_list[i] = current_edge_data.name_id;
+ m_turn_instruction_list[i] = current_edge_data.turn_instruction;
+ m_travel_mode_list[i] = current_edge_data.travel_mode;
+ }
+ }
+
+ void LoadCoreInformation(const boost::filesystem::path &core_data_file)
+ {
+ std::ifstream core_stream(core_data_file.string().c_str(), std::ios::binary);
+ unsigned number_of_markers;
+ core_stream.read((char *)&number_of_markers, sizeof(unsigned));
+
+ std::vector<char> unpacked_core_markers(number_of_markers);
+ core_stream.read((char *)unpacked_core_markers.data(), sizeof(char) * number_of_markers);
+
+ // in this case we have nothing to do
+ if (number_of_markers <= 0)
+ {
+ return;
+ }
+
+ m_is_core_node.resize(number_of_markers);
+ for (auto i = 0u; i < number_of_markers; ++i)
+ {
+ BOOST_ASSERT(unpacked_core_markers[i] == 0 || unpacked_core_markers[i] == 1);
+ m_is_core_node[i] = unpacked_core_markers[i] == 1;
+ }
+ }
+
+ void LoadGeometries(const boost::filesystem::path &geometry_file)
+ {
+ std::ifstream geometry_stream(geometry_file.string().c_str(), std::ios::binary);
+ unsigned number_of_indices = 0;
+ unsigned number_of_compressed_geometries = 0;
+
+ geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
+
+ m_geometry_indices.resize(number_of_indices);
+ if (number_of_indices > 0)
+ {
+ geometry_stream.read((char *)&(m_geometry_indices[0]),
+ number_of_indices * sizeof(unsigned));
+ }
+
+ geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
+
+ BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
+ m_geometry_list.resize(number_of_compressed_geometries);
+
+ if (number_of_compressed_geometries > 0)
+ {
+ geometry_stream.read((char *)&(m_geometry_list[0]),
+ number_of_compressed_geometries *
+ sizeof(extractor::CompressedEdgeContainer::CompressedEdge));
+ }
+ }
+
+ void LoadDatasourceInfo(const boost::filesystem::path &datasource_names_file,
+ const boost::filesystem::path &datasource_indexes_file)
+ {
+ boost::filesystem::ifstream datasources_stream(datasource_indexes_file, std::ios::binary);
+ if (!datasources_stream)
+ {
+ throw util::exception("Could not open " + datasource_indexes_file.string() + " for reading!");
+ }
+ BOOST_ASSERT(datasources_stream);
+
+ std::size_t number_of_datasources = 0;
+ datasources_stream.read(reinterpret_cast<char *>(&number_of_datasources),
+ sizeof(std::size_t));
+ if (number_of_datasources > 0)
+ {
+ m_datasource_list.resize(number_of_datasources);
+ datasources_stream.read(reinterpret_cast<char *>(&(m_datasource_list[0])),
+ number_of_datasources * sizeof(uint8_t));
+ }
+
+ boost::filesystem::ifstream datasourcenames_stream(datasource_names_file, std::ios::binary);
+ if (!datasourcenames_stream)
+ {
+ throw util::exception("Could not open " + datasource_names_file.string() + " for reading!");
+ }
+ BOOST_ASSERT(datasourcenames_stream);
+ std::string name;
+ while (std::getline(datasourcenames_stream, name))
+ {
+ m_datasource_names.push_back(std::move(name));
+ }
+ }
+
+ void LoadRTree()
+ {
+ BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
+
+ m_static_rtree.reset(new InternalRTree(ram_index_path, file_index_path, m_coordinate_list));
+ m_geospatial_query.reset(
+ new InternalGeospatialQuery(*m_static_rtree, m_coordinate_list, *this));
+ }
+
+ void LoadStreetNames(const boost::filesystem::path &names_file)
+ {
+ boost::filesystem::ifstream name_stream(names_file, std::ios::binary);
+
+ name_stream >> m_name_table;
+
+ unsigned number_of_chars = 0;
+ name_stream.read((char *)&number_of_chars, sizeof(unsigned));
+ BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
+ m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
+ name_stream.read((char *)&m_names_char_list[0], number_of_chars * sizeof(char));
+ if (0 == m_names_char_list.size())
+ {
+ util::SimpleLogger().Write(logWARNING) << "list of street names is empty";
+ }
+ }
+
+ public:
+ virtual ~InternalDataFacade()
+ {
+ m_static_rtree.reset();
+ m_geospatial_query.reset();
+ }
+
+ explicit InternalDataFacade(const storage::StorageConfig& config)
+ {
+ ram_index_path = config.ram_index_path;
+ file_index_path = config.file_index_path;
+
+ util::SimpleLogger().Write() << "loading graph data";
+ LoadGraph(config.hsgr_data_path);
+
+ util::SimpleLogger().Write() << "loading edge information";
+ LoadNodeAndEdgeInformation(config.nodes_data_path, config.edges_data_path);
+
+ util::SimpleLogger().Write() << "loading core information";
+ LoadCoreInformation(config.core_data_path);
+
+ util::SimpleLogger().Write() << "loading geometries";
+ LoadGeometries(config.geometries_path);
+
+ util::SimpleLogger().Write() << "loading datasource info";
+ LoadDatasourceInfo(config.datasource_names_path,
+ config.datasource_indexes_path);
+
+ util::SimpleLogger().Write() << "loading timestamp";
+ LoadTimestamp(config.timestamp_path);
+
+ util::SimpleLogger().Write() << "loading profile properties";
+ LoadProfileProperties(config.properties_path);
+
+ util::SimpleLogger().Write() << "loading street names";
+ LoadStreetNames(config.names_data_path);
+ }
+
+ // search graph access
+ unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); }
+
+ unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); }
+
+ unsigned GetOutDegree(const NodeID n) const override final
+ {
+ return m_query_graph->GetOutDegree(n);
+ }
+
+ NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
+
+ EdgeData &GetEdgeData(const EdgeID e) const override final
+ {
+ return m_query_graph->GetEdgeData(e);
+ }
+
+ EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); }
+
+ EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); }
+
+ EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
+ {
+ return m_query_graph->GetAdjacentEdgeRange(node);
+ }
+
+ // searches for a specific edge
+ EdgeID FindEdge(const NodeID from, const NodeID to) const override final
+ {
+ return m_query_graph->FindEdge(from, to);
+ }
+
+ EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const override final
+ {
+ return m_query_graph->FindEdgeInEitherDirection(from, to);
+ }
+
+ EdgeID
+ FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const override final
+ {
+ return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
+ }
+
+ // node and edge information access
+ util::Coordinate GetCoordinateOfNode(const unsigned id) const override final
+ {
+ return m_coordinate_list->at(id);
+ }
+
+ extractor::guidance::TurnInstruction
+ GetTurnInstructionForEdgeID(const unsigned id) const override final
+ {
+ return m_turn_instruction_list.at(id);
+ }
+
+ extractor::TravelMode GetTravelModeForEdgeID(const unsigned id) const override final
+ {
+ return m_travel_mode_list.at(id);
+ }
+
+ std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate south_west,
+ const util::Coordinate north_east) override final
+ {
+ if (!m_static_rtree.get())
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+ const util::RectangleInt2D bbox{south_west.lon, north_east.lon, south_west.lat,
+ north_east.lat};
+ return m_geospatial_query->Search(bbox);
+ }
+
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
+ const float max_distance) override final
+ {
+ if (!m_static_rtree.get())
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance);
+ }
+
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
+ const float max_distance,
+ const int bearing,
+ const int bearing_range) override final
+ {
+ if (!m_static_rtree.get())
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance,
+ bearing, bearing_range);
+ }
+
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate,
+ const unsigned max_results) override final
+ {
+ if (!m_static_rtree.get())
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results);
+ }
+
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate,
+ const unsigned max_results,
+ const double max_distance) override final
+ {
+ if (!m_static_rtree.get())
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, max_distance);
+ }
+
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate,
+ const unsigned max_results,
+ const int bearing,
+ const int bearing_range) override final
+ {
+ if (!m_static_rtree.get())
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, bearing,
+ bearing_range);
+ }
+
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate,
+ const unsigned max_results,
+ const double max_distance,
+ const int bearing,
+ const int bearing_range) override final
+ {
+ if (!m_static_rtree.get())
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, max_distance,
+ bearing, bearing_range);
+ }
+
+ std::pair<PhantomNode, PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+ const double max_distance) override final
+ {
+ if (!m_static_rtree.get())
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+ input_coordinate, max_distance);
+ }
+
+ std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
+ const util::Coordinate input_coordinate) override final
+ {
+ if (!m_static_rtree.get())
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+ input_coordinate);
+ }
+
+ std::pair<PhantomNode, PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+ const double max_distance,
+ const int bearing,
+ const int bearing_range) override final
+ {
+ if (!m_static_rtree.get())
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+ input_coordinate, max_distance, bearing, bearing_range);
+ }
+
+ std::pair<PhantomNode, PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+ const int bearing,
+ const int bearing_range) override final
+ {
+ if (!m_static_rtree.get())
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+ input_coordinate, bearing, bearing_range);
+ }
+
+ unsigned GetCheckSum() const override final { return m_check_sum; }
+
+ unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
+ {
+ return m_name_ID_list.at(id);
+ }
+
+ std::string GetNameForID(const unsigned name_id) const override final
+ {
+ if (std::numeric_limits<unsigned>::max() == name_id)
+ {
+ return "";
+ }
+ auto range = m_name_table.GetRange(name_id);
+
+ std::string result;
+ result.reserve(range.size());
+ if (range.begin() != range.end())
+ {
+ result.resize(range.back() - range.front() + 1);
+ std::copy(m_names_char_list.begin() + range.front(),
+ m_names_char_list.begin() + range.back() + 1, result.begin());
+ }
+ return result;
+ }
+
+ virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const override final
+ {
+ return m_via_node_list.at(id);
+ }
+
+ virtual std::size_t GetCoreSize() const override final { return m_is_core_node.size(); }
+
+ virtual bool IsCoreNode(const NodeID id) const override final
+ {
+ if (m_is_core_node.size() > 0)
+ {
+ return m_is_core_node[id];
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ virtual void GetUncompressedGeometry(const EdgeID id,
+ std::vector<NodeID> &result_nodes) const override final
+ {
+ const unsigned begin = m_geometry_indices.at(id);
+ const unsigned end = m_geometry_indices.at(id + 1);
+
+ result_nodes.clear();
+ result_nodes.reserve(end - begin);
+ std::for_each(m_geometry_list.begin() + begin, m_geometry_list.begin() + end,
+ [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge)
+ {
+ result_nodes.emplace_back(edge.node_id);
+ });
+ }
+
+ virtual void
+ GetUncompressedWeights(const EdgeID id,
+ std::vector<EdgeWeight> &result_weights) const override final
+ {
+ const unsigned begin = m_geometry_indices.at(id);
+ const unsigned end = m_geometry_indices.at(id + 1);
+
+ result_weights.clear();
+ result_weights.reserve(end - begin);
+ std::for_each(m_geometry_list.begin() + begin, m_geometry_list.begin() + end,
+ [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge)
+ {
+ result_weights.emplace_back(edge.weight);
+ });
+ }
+
+ // Returns the data source ids that were used to supply the edge
+ // weights.
+ virtual void
+ GetUncompressedDatasources(const EdgeID id,
+ std::vector<uint8_t> &result_datasources) const override final
+ {
+ const unsigned begin = m_geometry_indices.at(id);
+ const unsigned end = m_geometry_indices.at(id + 1);
+
+ result_datasources.clear();
+ result_datasources.reserve(end - begin);
+
+ // If there was no datasource info, return an array of 0's.
+ if (m_datasource_list.empty())
+ {
+ for (unsigned i = 0; i < end - begin; ++i)
+ {
+ result_datasources.push_back(0);
+ }
+ }
+ else
+ {
+ std::for_each(m_datasource_list.begin() + begin, m_datasource_list.begin() + end,
+ [&](const uint8_t &datasource_id)
+ {
+ result_datasources.push_back(datasource_id);
+ });
+ }
+ }
+
+ virtual std::string GetDatasourceName(const uint8_t datasource_name_id) const override final
+ {
+ BOOST_ASSERT(m_datasource_names.size() >= 1);
+ BOOST_ASSERT(m_datasource_names.size() > datasource_name_id);
+ return m_datasource_names[datasource_name_id];
+ }
+
+ std::string GetTimestamp() const override final { return m_timestamp; }
+
+ bool GetUTurnsDefault() const override final { return m_profile_properties.allow_u_turn_at_via; }
+};
+}
+}
+}
+
+#endif // INTERNAL_DATAFACADE_HPP
diff --git a/include/engine/datafacade/shared_datafacade.hpp b/include/engine/datafacade/shared_datafacade.hpp
new file mode 100644
index 0000000..dbb14bb
--- /dev/null
+++ b/include/engine/datafacade/shared_datafacade.hpp
@@ -0,0 +1,717 @@
+#ifndef SHARED_DATAFACADE_HPP
+#define SHARED_DATAFACADE_HPP
+
+// implements all data storage when shared memory _IS_ used
+
+#include "engine/datafacade/datafacade_base.hpp"
+#include "storage/shared_datatype.hpp"
+#include "storage/shared_memory.hpp"
+
+#include "extractor/guidance/turn_instruction.hpp"
+#include "extractor/profile_properties.hpp"
+
+#include "engine/geospatial_query.hpp"
+#include "util/range_table.hpp"
+#include "util/static_graph.hpp"
+#include "util/static_rtree.hpp"
+#include "util/make_unique.hpp"
+#include "util/simple_logger.hpp"
+#include "util/rectangle.hpp"
+
+#include <cstddef>
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/thread/tss.hpp>
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/thread/lock_guard.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace datafacade
+{
+
+class SharedDataFacade final : public BaseDataFacade
+{
+
+ private:
+ using super = BaseDataFacade;
+ using QueryGraph = util::StaticGraph<EdgeData, true>;
+ using GraphNode = typename QueryGraph::NodeArrayEntry;
+ using GraphEdge = typename QueryGraph::EdgeArrayEntry;
+ using NameIndexBlock = typename util::RangeTable<16, true>::BlockT;
+ using InputEdge = typename QueryGraph::InputEdge;
+ using RTreeLeaf = typename super::RTreeLeaf;
+ using SharedRTree =
+ util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, true>::vector, true>;
+ using SharedGeospatialQuery = GeospatialQuery<SharedRTree, BaseDataFacade>;
+ using TimeStampedRTreePair = std::pair<unsigned, std::shared_ptr<SharedRTree>>;
+ using RTreeNode = typename SharedRTree::TreeNode;
+
+ storage::SharedDataLayout *data_layout;
+ char *shared_memory;
+ storage::SharedDataTimestamp *data_timestamp_ptr;
+
+ storage::SharedDataType CURRENT_LAYOUT;
+ storage::SharedDataType CURRENT_DATA;
+ unsigned CURRENT_TIMESTAMP;
+
+ unsigned m_check_sum;
+ std::unique_ptr<QueryGraph> m_query_graph;
+ std::unique_ptr<storage::SharedMemory> m_layout_memory;
+ std::unique_ptr<storage::SharedMemory> m_large_memory;
+ std::string m_timestamp;
+ extractor::ProfileProperties* m_profile_properties;
+
+ std::shared_ptr<util::ShM<util::Coordinate, true>::vector> m_coordinate_list;
+ util::ShM<NodeID, true>::vector m_via_node_list;
+ util::ShM<unsigned, true>::vector m_name_ID_list;
+ util::ShM<extractor::guidance::TurnInstruction, true>::vector m_turn_instruction_list;
+ util::ShM<extractor::TravelMode, true>::vector m_travel_mode_list;
+ util::ShM<char, true>::vector m_names_char_list;
+ util::ShM<unsigned, true>::vector m_name_begin_indices;
+ util::ShM<unsigned, true>::vector m_geometry_indices;
+ util::ShM<extractor::CompressedEdgeContainer::CompressedEdge, true>::vector m_geometry_list;
+ util::ShM<bool, true>::vector m_is_core_node;
+ util::ShM<uint8_t, true>::vector m_datasource_list;
+
+ util::ShM<char, true>::vector m_datasource_name_data;
+ util::ShM<std::size_t, true>::vector m_datasource_name_offsets;
+ util::ShM<std::size_t, true>::vector m_datasource_name_lengths;
+
+ boost::thread_specific_ptr<std::pair<unsigned, std::shared_ptr<SharedRTree>>> m_static_rtree;
+ boost::thread_specific_ptr<SharedGeospatialQuery> m_geospatial_query;
+ boost::filesystem::path file_index_path;
+
+ std::shared_ptr<util::RangeTable<16, true>> m_name_table;
+
+ void LoadChecksum()
+ {
+ m_check_sum = *data_layout->GetBlockPtr<unsigned>(shared_memory,
+ storage::SharedDataLayout::HSGR_CHECKSUM);
+ util::SimpleLogger().Write() << "set checksum: " << m_check_sum;
+ }
+
+ void LoadProfileProperties()
+ {
+ m_profile_properties =
+ data_layout->GetBlockPtr<extractor::ProfileProperties>(shared_memory, storage::SharedDataLayout::PROPERTIES);
+ }
+
+ void LoadTimestamp()
+ {
+ auto timestamp_ptr =
+ data_layout->GetBlockPtr<char>(shared_memory, storage::SharedDataLayout::TIMESTAMP);
+ m_timestamp.resize(data_layout->GetBlockSize(storage::SharedDataLayout::TIMESTAMP));
+ std::copy(timestamp_ptr,
+ timestamp_ptr + data_layout->GetBlockSize(storage::SharedDataLayout::TIMESTAMP),
+ m_timestamp.begin());
+ }
+
+ void LoadRTree()
+ {
+ BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
+
+ auto tree_ptr = data_layout->GetBlockPtr<RTreeNode>(
+ shared_memory, storage::SharedDataLayout::R_SEARCH_TREE);
+ m_static_rtree.reset(new TimeStampedRTreePair(
+ CURRENT_TIMESTAMP,
+ util::make_unique<SharedRTree>(
+ tree_ptr, data_layout->num_entries[storage::SharedDataLayout::R_SEARCH_TREE],
+ file_index_path, m_coordinate_list)));
+ m_geospatial_query.reset(
+ new SharedGeospatialQuery(*m_static_rtree->second, m_coordinate_list, *this));
+ }
+
+ void LoadGraph()
+ {
+ auto graph_nodes_ptr = data_layout->GetBlockPtr<GraphNode>(
+ shared_memory, storage::SharedDataLayout::GRAPH_NODE_LIST);
+
+ auto graph_edges_ptr = data_layout->GetBlockPtr<GraphEdge>(
+ shared_memory, storage::SharedDataLayout::GRAPH_EDGE_LIST);
+
+ typename util::ShM<GraphNode, true>::vector node_list(
+ graph_nodes_ptr, data_layout->num_entries[storage::SharedDataLayout::GRAPH_NODE_LIST]);
+ typename util::ShM<GraphEdge, true>::vector edge_list(
+ graph_edges_ptr, data_layout->num_entries[storage::SharedDataLayout::GRAPH_EDGE_LIST]);
+ m_query_graph.reset(new QueryGraph(node_list, edge_list));
+ }
+
+ void LoadNodeAndEdgeInformation()
+ {
+ auto coordinate_list_ptr = data_layout->GetBlockPtr<util::Coordinate>(
+ shared_memory, storage::SharedDataLayout::COORDINATE_LIST);
+ m_coordinate_list = util::make_unique<util::ShM<util::Coordinate, true>::vector>(
+ coordinate_list_ptr,
+ data_layout->num_entries[storage::SharedDataLayout::COORDINATE_LIST]);
+
+ auto travel_mode_list_ptr = data_layout->GetBlockPtr<extractor::TravelMode>(
+ shared_memory, storage::SharedDataLayout::TRAVEL_MODE);
+ typename util::ShM<extractor::TravelMode, true>::vector travel_mode_list(
+ travel_mode_list_ptr, data_layout->num_entries[storage::SharedDataLayout::TRAVEL_MODE]);
+ m_travel_mode_list = std::move(travel_mode_list);
+
+ auto turn_instruction_list_ptr =
+ data_layout->GetBlockPtr<extractor::guidance::TurnInstruction>(
+ shared_memory, storage::SharedDataLayout::TURN_INSTRUCTION);
+ typename util::ShM<extractor::guidance::TurnInstruction, true>::vector
+ turn_instruction_list(
+ turn_instruction_list_ptr,
+ data_layout->num_entries[storage::SharedDataLayout::TURN_INSTRUCTION]);
+ m_turn_instruction_list = std::move(turn_instruction_list);
+
+ auto name_id_list_ptr = data_layout->GetBlockPtr<unsigned>(
+ shared_memory, storage::SharedDataLayout::NAME_ID_LIST);
+ typename util::ShM<unsigned, true>::vector name_id_list(
+ name_id_list_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_ID_LIST]);
+ m_name_ID_list = std::move(name_id_list);
+ }
+
+ void LoadViaNodeList()
+ {
+ auto via_node_list_ptr = data_layout->GetBlockPtr<NodeID>(
+ shared_memory, storage::SharedDataLayout::VIA_NODE_LIST);
+ typename util::ShM<NodeID, true>::vector via_node_list(
+ via_node_list_ptr, data_layout->num_entries[storage::SharedDataLayout::VIA_NODE_LIST]);
+ m_via_node_list = std::move(via_node_list);
+ }
+
+ void LoadNames()
+ {
+ auto offsets_ptr = data_layout->GetBlockPtr<unsigned>(
+ shared_memory, storage::SharedDataLayout::NAME_OFFSETS);
+ auto blocks_ptr = data_layout->GetBlockPtr<NameIndexBlock>(
+ shared_memory, storage::SharedDataLayout::NAME_BLOCKS);
+ typename util::ShM<unsigned, true>::vector name_offsets(
+ offsets_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_OFFSETS]);
+ typename util::ShM<NameIndexBlock, true>::vector name_blocks(
+ blocks_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_BLOCKS]);
+
+ auto names_list_ptr = data_layout->GetBlockPtr<char>(
+ shared_memory, storage::SharedDataLayout::NAME_CHAR_LIST);
+ typename util::ShM<char, true>::vector names_char_list(
+ names_list_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_CHAR_LIST]);
+ m_name_table = util::make_unique<util::RangeTable<16, true>>(
+ name_offsets, name_blocks, static_cast<unsigned>(names_char_list.size()));
+
+ m_names_char_list = std::move(names_char_list);
+ }
+
+ void LoadCoreInformation()
+ {
+ if (data_layout->num_entries[storage::SharedDataLayout::CORE_MARKER] <= 0)
+ {
+ return;
+ }
+
+ auto core_marker_ptr = data_layout->GetBlockPtr<unsigned>(
+ shared_memory, storage::SharedDataLayout::CORE_MARKER);
+ typename util::ShM<bool, true>::vector is_core_node(
+ core_marker_ptr, data_layout->num_entries[storage::SharedDataLayout::CORE_MARKER]);
+ m_is_core_node = std::move(is_core_node);
+ }
+
+ void LoadGeometries()
+ {
+ auto geometries_index_ptr = data_layout->GetBlockPtr<unsigned>(
+ shared_memory, storage::SharedDataLayout::GEOMETRIES_INDEX);
+ typename util::ShM<unsigned, true>::vector geometry_begin_indices(
+ geometries_index_ptr,
+ data_layout->num_entries[storage::SharedDataLayout::GEOMETRIES_INDEX]);
+ m_geometry_indices = std::move(geometry_begin_indices);
+
+ auto geometries_list_ptr =
+ data_layout->GetBlockPtr<extractor::CompressedEdgeContainer::CompressedEdge>(
+ shared_memory, storage::SharedDataLayout::GEOMETRIES_LIST);
+ typename util::ShM<extractor::CompressedEdgeContainer::CompressedEdge, true>::vector
+ geometry_list(geometries_list_ptr,
+ data_layout->num_entries[storage::SharedDataLayout::GEOMETRIES_LIST]);
+ m_geometry_list = std::move(geometry_list);
+
+ auto datasources_list_ptr = data_layout->GetBlockPtr<uint8_t>(
+ shared_memory, storage::SharedDataLayout::DATASOURCES_LIST);
+ typename util::ShM<uint8_t, true>::vector datasources_list(
+ datasources_list_ptr,
+ data_layout->num_entries[storage::SharedDataLayout::DATASOURCES_LIST]);
+ m_datasource_list = std::move(datasources_list);
+
+ auto datasource_name_data_ptr = data_layout->GetBlockPtr<char>(
+ shared_memory, storage::SharedDataLayout::DATASOURCE_NAME_DATA);
+ typename util::ShM<char, true>::vector datasource_name_data(
+ datasource_name_data_ptr,
+ data_layout->num_entries[storage::SharedDataLayout::DATASOURCE_NAME_DATA]);
+ m_datasource_name_data = std::move(datasource_name_data);
+
+ auto datasource_name_offsets_ptr = data_layout->GetBlockPtr<std::size_t>(
+ shared_memory, storage::SharedDataLayout::DATASOURCE_NAME_OFFSETS);
+ typename util::ShM<std::size_t, true>::vector datasource_name_offsets(
+ datasource_name_offsets_ptr,
+ data_layout->num_entries[storage::SharedDataLayout::DATASOURCE_NAME_OFFSETS]);
+ m_datasource_name_offsets = std::move(datasource_name_offsets);
+
+ auto datasource_name_lengths_ptr = data_layout->GetBlockPtr<std::size_t>(
+ shared_memory, storage::SharedDataLayout::DATASOURCE_NAME_LENGTHS);
+ typename util::ShM<std::size_t, true>::vector datasource_name_lengths(
+ datasource_name_lengths_ptr,
+ data_layout->num_entries[storage::SharedDataLayout::DATASOURCE_NAME_LENGTHS]);
+ m_datasource_name_lengths = std::move(datasource_name_lengths);
+ }
+
+ public:
+ virtual ~SharedDataFacade() {}
+
+ boost::shared_mutex data_mutex;
+
+ SharedDataFacade()
+ {
+ if (!storage::SharedMemory::RegionExists(storage::CURRENT_REGIONS))
+ {
+ throw util::exception(
+ "No shared memory blocks found, have you forgotten to run osrm-datastore?");
+ }
+ data_timestamp_ptr = static_cast<storage::SharedDataTimestamp *>(
+ storage::makeSharedMemory(storage::CURRENT_REGIONS,
+ sizeof(storage::SharedDataTimestamp), false, false)
+ ->Ptr());
+ CURRENT_LAYOUT = storage::LAYOUT_NONE;
+ CURRENT_DATA = storage::DATA_NONE;
+ CURRENT_TIMESTAMP = 0;
+
+ // load data
+ CheckAndReloadFacade();
+ }
+
+ void CheckAndReloadFacade()
+ {
+ if (CURRENT_LAYOUT != data_timestamp_ptr->layout ||
+ CURRENT_DATA != data_timestamp_ptr->data ||
+ CURRENT_TIMESTAMP != data_timestamp_ptr->timestamp)
+ {
+ // Get exclusive lock
+ util::SimpleLogger().Write(logDEBUG) << "Updates available, getting exclusive lock";
+ const boost::lock_guard<boost::shared_mutex> lock(data_mutex);
+
+ if (CURRENT_LAYOUT != data_timestamp_ptr->layout ||
+ CURRENT_DATA != data_timestamp_ptr->data)
+ {
+ // release the previous shared memory segments
+ storage::SharedMemory::Remove(CURRENT_LAYOUT);
+ storage::SharedMemory::Remove(CURRENT_DATA);
+
+ CURRENT_LAYOUT = data_timestamp_ptr->layout;
+ CURRENT_DATA = data_timestamp_ptr->data;
+ CURRENT_TIMESTAMP = 0; // Force trigger a reload
+
+ util::SimpleLogger().Write(logDEBUG)
+ << "Current layout was different to new layout, swapping";
+ }
+ else
+ {
+ util::SimpleLogger().Write(logDEBUG)
+ << "Current layout was same to new layout, not swapping";
+ }
+
+ if (CURRENT_TIMESTAMP != data_timestamp_ptr->timestamp)
+ {
+ CURRENT_TIMESTAMP = data_timestamp_ptr->timestamp;
+
+ util::SimpleLogger().Write(logDEBUG) << "Performing data reload";
+ m_layout_memory.reset(storage::makeSharedMemory(CURRENT_LAYOUT));
+
+ data_layout = static_cast<storage::SharedDataLayout *>(m_layout_memory->Ptr());
+
+ m_large_memory.reset(storage::makeSharedMemory(CURRENT_DATA));
+ shared_memory = (char *)(m_large_memory->Ptr());
+
+ const auto file_index_ptr = data_layout->GetBlockPtr<char>(
+ shared_memory, storage::SharedDataLayout::FILE_INDEX_PATH);
+ file_index_path = boost::filesystem::path(file_index_ptr);
+ if (!boost::filesystem::exists(file_index_path))
+ {
+ util::SimpleLogger().Write(logDEBUG) << "Leaf file name "
+ << file_index_path.string();
+ throw util::exception("Could not load leaf index file. "
+ "Is any data loaded into shared memory?");
+ }
+
+ LoadGraph();
+ LoadChecksum();
+ LoadNodeAndEdgeInformation();
+ LoadGeometries();
+ LoadTimestamp();
+ LoadViaNodeList();
+ LoadNames();
+ LoadCoreInformation();
+ LoadProfileProperties();
+
+ util::SimpleLogger().Write() << "number of geometries: "
+ << m_coordinate_list->size();
+ for (unsigned i = 0; i < m_coordinate_list->size(); ++i)
+ {
+ if (!GetCoordinateOfNode(i).IsValid())
+ {
+ util::SimpleLogger().Write() << "coordinate " << i << " not valid";
+ }
+ }
+ }
+ util::SimpleLogger().Write(logDEBUG) << "Releasing exclusive lock";
+ }
+ }
+
+ // search graph access
+ unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); }
+
+ unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); }
+
+ unsigned GetOutDegree(const NodeID n) const override final
+ {
+ return m_query_graph->GetOutDegree(n);
+ }
+
+ NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
+
+ EdgeData &GetEdgeData(const EdgeID e) const override final
+ {
+ return m_query_graph->GetEdgeData(e);
+ }
+
+ EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); }
+
+ EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); }
+
+ EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
+ {
+ return m_query_graph->GetAdjacentEdgeRange(node);
+ }
+
+ // searches for a specific edge
+ EdgeID FindEdge(const NodeID from, const NodeID to) const override final
+ {
+ return m_query_graph->FindEdge(from, to);
+ }
+
+ EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const override final
+ {
+ return m_query_graph->FindEdgeInEitherDirection(from, to);
+ }
+
+ EdgeID
+ FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const override final
+ {
+ return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
+ }
+
+ // node and edge information access
+ util::Coordinate GetCoordinateOfNode(const NodeID id) const override final
+ {
+ return m_coordinate_list->at(id);
+ }
+
+ virtual void GetUncompressedGeometry(const EdgeID id,
+ std::vector<NodeID> &result_nodes) const override final
+ {
+ const unsigned begin = m_geometry_indices.at(id);
+ const unsigned end = m_geometry_indices.at(id + 1);
+
+ result_nodes.clear();
+ result_nodes.reserve(end - begin);
+ std::for_each(m_geometry_list.begin() + begin, m_geometry_list.begin() + end,
+ [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge)
+ {
+ result_nodes.emplace_back(edge.node_id);
+ });
+ }
+
+ virtual void
+ GetUncompressedWeights(const EdgeID id,
+ std::vector<EdgeWeight> &result_weights) const override final
+ {
+ const unsigned begin = m_geometry_indices.at(id);
+ const unsigned end = m_geometry_indices.at(id + 1);
+
+ result_weights.clear();
+ result_weights.reserve(end - begin);
+ std::for_each(m_geometry_list.begin() + begin, m_geometry_list.begin() + end,
+ [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge)
+ {
+ result_weights.emplace_back(edge.weight);
+ });
+ }
+
+ virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const override final
+ {
+ return m_via_node_list.at(id);
+ }
+
+ extractor::guidance::TurnInstruction
+ GetTurnInstructionForEdgeID(const unsigned id) const override final
+ {
+ return m_turn_instruction_list.at(id);
+ }
+
+ extractor::TravelMode GetTravelModeForEdgeID(const unsigned id) const override final
+ {
+ return m_travel_mode_list.at(id);
+ }
+
+ std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate south_west,
+ const util::Coordinate north_east) override final
+ {
+ if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+ const util::RectangleInt2D bbox{south_west.lon, north_east.lon, south_west.lat,
+ north_east.lat};
+ return m_geospatial_query->Search(bbox);
+ }
+
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
+ const float max_distance) override final
+ {
+ if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance);
+ }
+
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
+ const float max_distance,
+ const int bearing,
+ const int bearing_range) override final
+ {
+ if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance,
+ bearing, bearing_range);
+ }
+
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate,
+ const unsigned max_results) override final
+ {
+ if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results);
+ }
+
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate,
+ const unsigned max_results,
+ const double max_distance) override final
+ {
+ if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, max_distance);
+ }
+
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate,
+ const unsigned max_results,
+ const int bearing,
+ const int bearing_range) override final
+ {
+ if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, bearing,
+ bearing_range);
+ }
+
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate,
+ const unsigned max_results,
+ const double max_distance,
+ const int bearing,
+ const int bearing_range) override final
+ {
+ if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, max_distance,
+ bearing, bearing_range);
+ }
+
+ std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
+ const util::Coordinate input_coordinate) override final
+ {
+ if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+ input_coordinate);
+ }
+
+ std::pair<PhantomNode, PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+ const double max_distance) override final
+ {
+ if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+ input_coordinate, max_distance);
+ }
+
+ std::pair<PhantomNode, PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+ const double max_distance,
+ const int bearing,
+ const int bearing_range) override final
+ {
+ if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+ input_coordinate, max_distance, bearing, bearing_range);
+ }
+
+ std::pair<PhantomNode, PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+ const int bearing,
+ const int bearing_range) override final
+ {
+ if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+ {
+ LoadRTree();
+ BOOST_ASSERT(m_geospatial_query.get());
+ }
+
+ return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
+ input_coordinate, bearing, bearing_range);
+ }
+
+ unsigned GetCheckSum() const override final { return m_check_sum; }
+
+ unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
+ {
+ return m_name_ID_list.at(id);
+ }
+
+ std::string GetNameForID(const unsigned name_id) const override final
+ {
+ if (std::numeric_limits<unsigned>::max() == name_id)
+ {
+ return "";
+ }
+ auto range = m_name_table->GetRange(name_id);
+
+ std::string result;
+ result.reserve(range.size());
+ if (range.begin() != range.end())
+ {
+ result.resize(range.back() - range.front() + 1);
+ std::copy(m_names_char_list.begin() + range.front(),
+ m_names_char_list.begin() + range.back() + 1, result.begin());
+ }
+ return result;
+ }
+
+ bool IsCoreNode(const NodeID id) const override final
+ {
+ if (m_is_core_node.size() > 0)
+ {
+ return m_is_core_node.at(id);
+ }
+
+ return false;
+ }
+
+ virtual std::size_t GetCoreSize() const override final { return m_is_core_node.size(); }
+
+ // Returns the data source ids that were used to supply the edge
+ // weights.
+ virtual void
+ GetUncompressedDatasources(const EdgeID id,
+ std::vector<uint8_t> &result_datasources) const override final
+ {
+ const unsigned begin = m_geometry_indices.at(id);
+ const unsigned end = m_geometry_indices.at(id + 1);
+
+ result_datasources.clear();
+ result_datasources.reserve(end - begin);
+
+ // If there was no datasource info, return an array of 0's.
+ if (m_datasource_list.empty())
+ {
+ for (unsigned i = 0; i < end - begin; ++i)
+ {
+ result_datasources.push_back(0);
+ }
+ }
+ else
+ {
+ std::for_each(m_datasource_list.begin() + begin, m_datasource_list.begin() + end,
+ [&](const uint8_t &datasource_id)
+ {
+ result_datasources.push_back(datasource_id);
+ });
+ }
+ }
+
+ virtual std::string GetDatasourceName(const uint8_t datasource_name_id) const override final
+ {
+ BOOST_ASSERT(m_datasource_name_offsets.size() >= 1);
+ BOOST_ASSERT(m_datasource_name_offsets.size() > datasource_name_id);
+
+ std::string result;
+ result.reserve(m_datasource_name_lengths[datasource_name_id]);
+ std::copy(m_datasource_name_data.begin() + m_datasource_name_offsets[datasource_name_id],
+ m_datasource_name_data.begin() + m_datasource_name_offsets[datasource_name_id] +
+ m_datasource_name_lengths[datasource_name_id],
+ std::back_inserter(result));
+
+ return result;
+ }
+
+ std::string GetTimestamp() const override final { return m_timestamp; }
+
+ bool GetUTurnsDefault() const override final { return m_profile_properties->allow_u_turn_at_via; }
+};
+}
+}
+}
+
+#endif // SHARED_DATAFACADE_HPP
diff --git a/include/engine/douglas_peucker.hpp b/include/engine/douglas_peucker.hpp
new file mode 100644
index 0000000..468c6c7
--- /dev/null
+++ b/include/engine/douglas_peucker.hpp
@@ -0,0 +1,60 @@
+#ifndef DOUGLAS_PEUCKER_HPP_
+#define DOUGLAS_PEUCKER_HPP_
+
+#include "util/coordinate.hpp"
+
+#include <vector>
+#include <iterator>
+
+namespace osrm
+{
+namespace engine
+{
+namespace detail
+{
+const constexpr int DOUGLAS_PEUCKER_THRESHOLDS[19] = {
+ 512440, // z0
+ 256720, // z1
+ 122560, // z2
+ 56780, // z3
+ 28800, // z4
+ 14400, // z5
+ 7200, // z6
+ 3200, // z7
+ 2400, // z8
+ 1000, // z9
+ 600, // z10
+ 120, // z11
+ 60, // z12
+ 45, // z13
+ 36, // z14
+ 20, // z15
+ 8, // z16
+ 6, // z17
+ 4, // z18
+};
+
+const constexpr auto DOUGLAS_PEUCKER_THRESHOLDS_SIZE =
+ sizeof(DOUGLAS_PEUCKER_THRESHOLDS) / sizeof(*DOUGLAS_PEUCKER_THRESHOLDS);
+} // ns detail
+
+// These functions compute the bitvector of indicating generalized input
+// points according to the (Ramer-)Douglas-Peucker algorithm.
+//
+// Input is vector of pairs. Each pair consists of the point information and a
+// bit indicating if the points is present in the generalization.
+// Note: points may also be pre-selected*/
+std::vector<util::Coordinate> douglasPeucker(std::vector<util::Coordinate>::const_iterator begin,
+ std::vector<util::Coordinate>::const_iterator end,
+ const unsigned zoom_level);
+
+// Convenience range-based function
+inline std::vector<util::Coordinate> douglasPeucker(const std::vector<util::Coordinate> &geometry,
+ const unsigned zoom_level)
+{
+ return douglasPeucker(begin(geometry), end(geometry), zoom_level);
+}
+}
+}
+
+#endif /* DOUGLAS_PEUCKER_HPP_ */
diff --git a/include/engine/engine.hpp b/include/engine/engine.hpp
new file mode 100644
index 0000000..027320b
--- /dev/null
+++ b/include/engine/engine.hpp
@@ -0,0 +1,88 @@
+#ifndef ENGINE_HPP
+#define ENGINE_HPP
+
+#include "engine/status.hpp"
+#include "storage/shared_barriers.hpp"
+#include "util/json_container.hpp"
+
+#include <memory>
+#include <unordered_map>
+#include <string>
+
+namespace osrm
+{
+
+namespace util
+{
+namespace json
+{
+struct Object;
+}
+}
+
+// Fwd decls
+namespace engine
+{
+struct EngineConfig;
+namespace api
+{
+struct RouteParameters;
+struct TableParameters;
+struct NearestParameters;
+struct TripParameters;
+struct MatchParameters;
+struct TileParameters;
+}
+namespace plugins
+{
+class ViaRoutePlugin;
+class TablePlugin;
+class NearestPlugin;
+class TripPlugin;
+class MatchPlugin;
+class TilePlugin;
+}
+// End fwd decls
+
+namespace datafacade
+{
+class BaseDataFacade;
+}
+
+class Engine final
+{
+ public:
+ // Needs to be public
+ struct EngineLock;
+
+ explicit Engine(EngineConfig &config);
+
+ Engine(Engine &&) noexcept;
+ Engine &operator=(Engine &&) noexcept;
+
+ // Impl. in cpp since for unique_ptr of incomplete types
+ ~Engine();
+
+ Status Route(const api::RouteParameters ¶meters, util::json::Object &result);
+ Status Table(const api::TableParameters ¶meters, util::json::Object &result);
+ Status Nearest(const api::NearestParameters ¶meters, util::json::Object &result);
+ Status Trip(const api::TripParameters ¶meters, util::json::Object &result);
+ Status Match(const api::MatchParameters ¶meters, util::json::Object &result);
+ Status Tile(const api::TileParameters ¶meters, std::string &result);
+
+ private:
+ std::unique_ptr<EngineLock> lock;
+
+ std::unique_ptr<plugins::ViaRoutePlugin> route_plugin;
+ std::unique_ptr<plugins::TablePlugin> table_plugin;
+ std::unique_ptr<plugins::NearestPlugin> nearest_plugin;
+ std::unique_ptr<plugins::TripPlugin> trip_plugin;
+ std::unique_ptr<plugins::MatchPlugin> match_plugin;
+ std::unique_ptr<plugins::TilePlugin> tile_plugin;
+
+ std::unique_ptr<datafacade::BaseDataFacade> query_data_facade;
+};
+}
+}
+
+#endif // OSRM_IMPL_HPP
diff --git a/include/osrm/libosrm_config.hpp b/include/engine/engine_config.hpp
similarity index 68%
rename from include/osrm/libosrm_config.hpp
rename to include/engine/engine_config.hpp
index 677450a..eb62719 100644
--- a/include/osrm/libosrm_config.hpp
+++ b/include/engine/engine_config.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,22 +25,49 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef LIBOSRM_CONFIG_HPP
-#define LIBOSRM_CONFIG_HPP
+#ifndef ENGINE_CONFIG_HPP
+#define ENGINE_CONFIG_HPP
+
+#include "storage/storage_config.hpp"
#include <boost/filesystem/path.hpp>
-#include <unordered_map>
#include <string>
-struct LibOSRMConfig
+namespace osrm
+{
+
+namespace engine
{
- std::unordered_map<std::string, boost::filesystem::path> server_paths;
+
+/**
+ * Configures an OSRM instance.
+ *
+ * You can customize the storage OSRM uses for auxiliary files specifying a storage config.
+ *
+ * You can further set service constraints.
+ * These are the maximum number of allowed locations (-1 for unlimited) for the services:
+ * - Trip
+ * - Route
+ * - Table
+ * - Match
+ *
+ * In addition, shared memory can be used for datasets loaded with osrm-datastore.
+ *
+ * \see OSRM, StorageConfig
+ */
+struct EngineConfig final
+{
+ bool IsValid() const;
+
+ storage::StorageConfig storage_config;
int max_locations_trip = -1;
int max_locations_viaroute = -1;
int max_locations_distance_table = -1;
int max_locations_map_matching = -1;
bool use_shared_memory = true;
};
+}
+}
#endif // SERVER_CONFIG_HPP
diff --git a/include/engine/geospatial_query.hpp b/include/engine/geospatial_query.hpp
new file mode 100644
index 0000000..e880139
--- /dev/null
+++ b/include/engine/geospatial_query.hpp
@@ -0,0 +1,467 @@
+#ifndef GEOSPATIAL_QUERY_HPP
+#define GEOSPATIAL_QUERY_HPP
+
+#include "util/coordinate_calculation.hpp"
+#include "util/typedefs.hpp"
+#include "engine/phantom_node.hpp"
+#include "util/bearing.hpp"
+#include "util/rectangle.hpp"
+
+#include "osrm/coordinate.hpp"
+
+#include <algorithm>
+#include <cmath>
+#include <memory>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+
+// Implements complex queries on top of an RTree and builds PhantomNodes from it.
+//
+// Only holds a weak reference on the RTree!
+template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
+{
+ using EdgeData = typename RTreeT::EdgeData;
+ using CoordinateList = typename RTreeT::CoordinateList;
+ using CandidateSegment = typename RTreeT::CandidateSegment;
+
+ public:
+ GeospatialQuery(RTreeT &rtree_,
+ std::shared_ptr<CoordinateList> coordinates_,
+ DataFacadeT &datafacade_)
+ : rtree(rtree_), coordinates(std::move(coordinates_)), datafacade(datafacade_)
+ {
+ }
+
+ std::vector<EdgeData> Search(const util::RectangleInt2D &bbox)
+ {
+ return rtree.SearchInBox(bbox);
+ }
+
+ // Returns nearest PhantomNodes in the given bearing range within max_distance.
+ // Does not filter by small/big component!
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodesInRange(const util::Coordinate input_coordinate, const double max_distance)
+ {
+ auto results =
+ rtree.Nearest(input_coordinate,
+ [](const CandidateSegment &)
+ {
+ return std::make_pair(true, true);
+ },
+ [this, max_distance, input_coordinate](const std::size_t,
+ const CandidateSegment &segment)
+ {
+ return checkSegmentDistance(input_coordinate, segment, max_distance);
+ });
+
+ return MakePhantomNodes(input_coordinate, results);
+ }
+
+ // Returns nearest PhantomNodes in the given bearing range within max_distance.
+ // Does not filter by small/big component!
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
+ const double max_distance,
+ const int bearing,
+ const int bearing_range)
+ {
+ auto results = rtree.Nearest(
+ input_coordinate,
+ [this, bearing, bearing_range, max_distance](const CandidateSegment &segment)
+ {
+ return checkSegmentBearing(segment, bearing, bearing_range);
+ },
+ [this, max_distance, input_coordinate](const std::size_t,
+ const CandidateSegment &segment)
+ {
+ return checkSegmentDistance(input_coordinate, segment, max_distance);
+ });
+
+ return MakePhantomNodes(input_coordinate, results);
+ }
+
+ // Returns max_results nearest PhantomNodes in the given bearing range.
+ // Does not filter by small/big component!
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate,
+ const unsigned max_results,
+ const int bearing,
+ const int bearing_range)
+ {
+ auto results =
+ rtree.Nearest(input_coordinate,
+ [this, bearing, bearing_range](const CandidateSegment &segment)
+ {
+ return checkSegmentBearing(segment, bearing, bearing_range);
+ },
+ [max_results](const std::size_t num_results, const CandidateSegment &)
+ {
+ return num_results >= max_results;
+ });
+
+ return MakePhantomNodes(input_coordinate, results);
+ }
+
+ // Returns max_results nearest PhantomNodes in the given bearing range within the maximum
+ // distance.
+ // Does not filter by small/big component!
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate,
+ const unsigned max_results,
+ const double max_distance,
+ const int bearing,
+ const int bearing_range)
+ {
+ auto results =
+ rtree.Nearest(input_coordinate,
+ [this, bearing, bearing_range](const CandidateSegment &segment)
+ {
+ return checkSegmentBearing(segment, bearing, bearing_range);
+ },
+ [this, max_distance, max_results, input_coordinate](
+ const std::size_t num_results, const CandidateSegment &segment)
+ {
+ return num_results >= max_results ||
+ checkSegmentDistance(input_coordinate, segment, max_distance);
+ });
+
+ return MakePhantomNodes(input_coordinate, results);
+ }
+
+ // Returns max_results nearest PhantomNodes.
+ // Does not filter by small/big component!
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate, const unsigned max_results)
+ {
+ auto results =
+ rtree.Nearest(input_coordinate,
+ [](const CandidateSegment &)
+ {
+ return std::make_pair(true, true);
+ },
+ [max_results](const std::size_t num_results, const CandidateSegment &)
+ {
+ return num_results >= max_results;
+ });
+
+ return MakePhantomNodes(input_coordinate, results);
+ }
+
+ // Returns max_results nearest PhantomNodes in the given max distance.
+ // Does not filter by small/big component!
+ std::vector<PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate input_coordinate,
+ const unsigned max_results,
+ const double max_distance)
+ {
+ auto results =
+ rtree.Nearest(input_coordinate,
+ [](const CandidateSegment &)
+ {
+ return std::make_pair(true, true);
+ },
+ [this, max_distance, max_results, input_coordinate](
+ const std::size_t num_results, const CandidateSegment &segment)
+ {
+ return num_results >= max_results ||
+ checkSegmentDistance(input_coordinate, segment, max_distance);
+ });
+
+ return MakePhantomNodes(input_coordinate, results);
+ }
+
+ // Returns the nearest phantom node. If this phantom node is not from a big component
+ // a second phantom node is return that is the nearest coordinate in a big component.
+ std::pair<PhantomNode, PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+ const double max_distance)
+ {
+ bool has_small_component = false;
+ bool has_big_component = false;
+ auto results = rtree.Nearest(
+ input_coordinate,
+ [&has_big_component, &has_small_component](const CandidateSegment &segment)
+ {
+ auto use_segment = (!has_small_component ||
+ (!has_big_component && !segment.data.component.is_tiny));
+ auto use_directions = std::make_pair(use_segment, use_segment);
+
+ has_big_component = has_big_component || !segment.data.component.is_tiny;
+ has_small_component = has_small_component || segment.data.component.is_tiny;
+
+ return use_directions;
+ },
+ [this, &has_big_component, max_distance,
+ input_coordinate](const std::size_t num_results, const CandidateSegment &segment)
+ {
+ return (num_results > 0 && has_big_component) ||
+ checkSegmentDistance(input_coordinate, segment, max_distance);
+ });
+
+ if (results.size() == 0)
+ {
+ return std::make_pair(PhantomNode{}, PhantomNode{});
+ }
+
+ BOOST_ASSERT(results.size() == 1 || results.size() == 2);
+ return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
+ MakePhantomNode(input_coordinate, results.back()).phantom_node);
+ }
+
+ // Returns the nearest phantom node. If this phantom node is not from a big component
+ // a second phantom node is return that is the nearest coordinate in a big component.
+ std::pair<PhantomNode, PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate)
+ {
+ bool has_small_component = false;
+ bool has_big_component = false;
+ auto results = rtree.Nearest(
+ input_coordinate,
+ [&has_big_component, &has_small_component](const CandidateSegment &segment)
+ {
+ auto use_segment = (!has_small_component ||
+ (!has_big_component && !segment.data.component.is_tiny));
+ auto use_directions = std::make_pair(use_segment, use_segment);
+
+ has_big_component = has_big_component || !segment.data.component.is_tiny;
+ has_small_component = has_small_component || segment.data.component.is_tiny;
+
+ return use_directions;
+ },
+ [&has_big_component](const std::size_t num_results, const CandidateSegment &)
+ {
+ return num_results > 0 && has_big_component;
+ });
+
+ if (results.size() == 0)
+ {
+ return std::make_pair(PhantomNode{}, PhantomNode{});
+ }
+
+ BOOST_ASSERT(results.size() == 1 || results.size() == 2);
+ return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
+ MakePhantomNode(input_coordinate, results.back()).phantom_node);
+ }
+
+ // Returns the nearest phantom node. If this phantom node is not from a big component
+ // a second phantom node is return that is the nearest coordinate in a big component.
+ std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
+ const util::Coordinate input_coordinate, const int bearing, const int bearing_range)
+ {
+ bool has_small_component = false;
+ bool has_big_component = false;
+ auto results = rtree.Nearest(
+ input_coordinate,
+ [this, bearing, bearing_range, &has_big_component,
+ &has_small_component](const CandidateSegment &segment)
+ {
+ auto use_segment = (!has_small_component ||
+ (!has_big_component && !segment.data.component.is_tiny));
+ auto use_directions = std::make_pair(use_segment, use_segment);
+
+ if (use_segment)
+ {
+ use_directions = checkSegmentBearing(segment, bearing, bearing_range);
+ if (use_directions.first || use_directions.second)
+ {
+ has_big_component = has_big_component || !segment.data.component.is_tiny;
+ has_small_component = has_small_component || segment.data.component.is_tiny;
+ }
+ }
+
+ return use_directions;
+ },
+ [&has_big_component](const std::size_t num_results, const CandidateSegment &)
+ {
+ return num_results > 0 && has_big_component;
+ });
+
+ if (results.size() == 0)
+ {
+ return std::make_pair(PhantomNode{}, PhantomNode{});
+ }
+
+ BOOST_ASSERT(results.size() > 0);
+ return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
+ MakePhantomNode(input_coordinate, results.back()).phantom_node);
+ }
+
+ // Returns the nearest phantom node. If this phantom node is not from a big component
+ // a second phantom node is return that is the nearest coordinate in a big component.
+ std::pair<PhantomNode, PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
+ const double max_distance,
+ const int bearing,
+ const int bearing_range)
+ {
+ bool has_small_component = false;
+ bool has_big_component = false;
+ auto results = rtree.Nearest(
+ input_coordinate,
+ [this, bearing, bearing_range, &has_big_component,
+ &has_small_component](const CandidateSegment &segment)
+ {
+ auto use_segment = (!has_small_component ||
+ (!has_big_component && !segment.data.component.is_tiny));
+ auto use_directions = std::make_pair(use_segment, use_segment);
+
+ if (use_segment)
+ {
+ use_directions = checkSegmentBearing(segment, bearing, bearing_range);
+ if (use_directions.first || use_directions.second)
+ {
+ has_big_component = has_big_component || !segment.data.component.is_tiny;
+ has_small_component = has_small_component || segment.data.component.is_tiny;
+ }
+ }
+
+ return use_directions;
+ },
+ [this, &has_big_component, max_distance,
+ input_coordinate](const std::size_t num_results, const CandidateSegment &segment)
+ {
+ return (num_results > 0 && has_big_component) ||
+ checkSegmentDistance(input_coordinate, segment, max_distance);
+ });
+
+ if (results.size() == 0)
+ {
+ return std::make_pair(PhantomNode{}, PhantomNode{});
+ }
+
+ BOOST_ASSERT(results.size() > 0);
+ return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
+ MakePhantomNode(input_coordinate, results.back()).phantom_node);
+ }
+
+ private:
+ std::vector<PhantomNodeWithDistance>
+ MakePhantomNodes(const util::Coordinate input_coordinate,
+ const std::vector<EdgeData> &results) const
+ {
+ std::vector<PhantomNodeWithDistance> distance_and_phantoms(results.size());
+ std::transform(results.begin(), results.end(), distance_and_phantoms.begin(),
+ [this, &input_coordinate](const EdgeData &data)
+ {
+ return MakePhantomNode(input_coordinate, data);
+ });
+ return distance_and_phantoms;
+ }
+
+ PhantomNodeWithDistance MakePhantomNode(const util::Coordinate input_coordinate,
+ const EdgeData &data) const
+ {
+ util::Coordinate point_on_segment;
+ double ratio;
+ const auto current_perpendicular_distance =
+ util::coordinate_calculation::perpendicularDistance(
+ coordinates->at(data.u), coordinates->at(data.v), input_coordinate,
+ point_on_segment, ratio);
+
+ // Find the node-based-edge that this belongs to, and directly
+ // calculate the forward_weight, forward_offset, reverse_weight, reverse_offset
+
+ int forward_offset = 0, forward_weight = 0;
+ int reverse_offset = 0, reverse_weight = 0;
+
+ if (data.forward_packed_geometry_id != SPECIAL_EDGEID)
+ {
+ std::vector<EdgeWeight> forward_weight_vector;
+ datafacade.GetUncompressedWeights(data.forward_packed_geometry_id,
+ forward_weight_vector);
+ for (std::size_t i = 0; i < data.fwd_segment_position; i++)
+ {
+ forward_offset += forward_weight_vector[i];
+ }
+ forward_weight = forward_weight_vector[data.fwd_segment_position];
+ }
+
+ if (data.reverse_packed_geometry_id != SPECIAL_EDGEID)
+ {
+ std::vector<EdgeWeight> reverse_weight_vector;
+ datafacade.GetUncompressedWeights(data.reverse_packed_geometry_id,
+ reverse_weight_vector);
+
+ BOOST_ASSERT(data.fwd_segment_position < reverse_weight_vector.size());
+
+ for (std::size_t i = 0;
+ i < reverse_weight_vector.size() - data.fwd_segment_position - 1; i++)
+ {
+ reverse_offset += reverse_weight_vector[i];
+ }
+ reverse_weight =
+ reverse_weight_vector[reverse_weight_vector.size() - data.fwd_segment_position - 1];
+ }
+
+ ratio = std::min(1.0, std::max(0.0, ratio));
+ if (data.forward_segment_id.id != SPECIAL_SEGMENTID)
+ {
+ forward_weight *= ratio;
+ }
+ if (data.reverse_segment_id.id != SPECIAL_SEGMENTID)
+ {
+ reverse_weight *= 1.0 - ratio;
+ }
+
+ auto transformed = PhantomNodeWithDistance{PhantomNode{data, forward_weight, forward_offset,
+ reverse_weight, reverse_offset,
+ point_on_segment, input_coordinate},
+ current_perpendicular_distance};
+
+ return transformed;
+ }
+
+ bool checkSegmentDistance(const Coordinate input_coordinate,
+ const CandidateSegment &segment,
+ const double max_distance)
+ {
+ BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID ||
+ !segment.data.forward_segment_id.enabled);
+ BOOST_ASSERT(segment.data.reverse_segment_id.id != SPECIAL_SEGMENTID ||
+ !segment.data.reverse_segment_id.enabled);
+
+ Coordinate wsg84_coordinate = util::coordinate_calculation::mercator::toWGS84(
+ segment.fixed_projected_coordinate);
+
+ return util::coordinate_calculation::haversineDistance(input_coordinate, wsg84_coordinate) > max_distance;
+ }
+
+ std::pair<bool, bool> checkSegmentBearing(const CandidateSegment &segment,
+ const int filter_bearing,
+ const int filter_bearing_range)
+ {
+ BOOST_ASSERT(segment.data.forward_segment_id.id != SPECIAL_SEGMENTID ||
+ !segment.data.forward_segment_id.enabled);
+ BOOST_ASSERT(segment.data.reverse_segment_id.id != SPECIAL_SEGMENTID ||
+ !segment.data.reverse_segment_id.enabled);
+
+ const double forward_edge_bearing = util::coordinate_calculation::bearing(
+ coordinates->at(segment.data.u), coordinates->at(segment.data.v));
+
+ const double backward_edge_bearing = (forward_edge_bearing + 180) > 360
+ ? (forward_edge_bearing - 180)
+ : (forward_edge_bearing + 180);
+
+ const bool forward_bearing_valid =
+ util::bearing::CheckInBounds(std::round(forward_edge_bearing), filter_bearing,
+ filter_bearing_range) &&
+ segment.data.forward_segment_id.enabled;
+ const bool backward_bearing_valid =
+ util::bearing::CheckInBounds(std::round(backward_edge_bearing), filter_bearing,
+ filter_bearing_range) &&
+ segment.data.reverse_segment_id.enabled;
+ return std::make_pair(forward_bearing_valid, backward_bearing_valid);
+ }
+
+ RTreeT &rtree;
+ const std::shared_ptr<CoordinateList> coordinates;
+ DataFacadeT &datafacade;
+};
+}
+}
+
+#endif
diff --git a/include/engine/guidance/assemble_geometry.hpp b/include/engine/guidance/assemble_geometry.hpp
new file mode 100644
index 0000000..4fd84cb
--- /dev/null
+++ b/include/engine/guidance/assemble_geometry.hpp
@@ -0,0 +1,81 @@
+#ifndef ENGINE_GUIDANCE_ASSEMBLE_GEOMETRY_HPP
+#define ENGINE_GUIDANCE_ASSEMBLE_GEOMETRY_HPP
+
+#include "engine/internal_route_result.hpp"
+#include "engine/phantom_node.hpp"
+#include "engine/guidance/route_step.hpp"
+#include "engine/guidance/leg_geometry.hpp"
+#include "engine/guidance/toolkit.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/coordinate.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+#include "extractor/travel_mode.hpp"
+
+#include <vector>
+#include <utility>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+// Extracts the geometry for each segment and calculates the traveled distance
+// Combines the geometry form the phantom node with the PathData
+// to the full route geometry.
+//
+// turn 0 1 2 3 4
+// s...x...y...z...t
+// |---|segment 0
+// |---| segment 1
+// |---| segment 2
+// |---| segment 3
+template <typename DataFacadeT>
+LegGeometry assembleGeometry(const DataFacadeT &facade,
+ const std::vector<PathData> &leg_data,
+ const PhantomNode &source_node,
+ const PhantomNode &target_node)
+{
+ LegGeometry geometry;
+
+ // segment 0 first and last
+ geometry.segment_offsets.push_back(0);
+ geometry.locations.push_back(source_node.location);
+
+ auto current_distance = 0.;
+ auto prev_coordinate = geometry.locations.front();
+ for (const auto &path_point : leg_data)
+ {
+ auto coordinate = facade.GetCoordinateOfNode(path_point.turn_via_node);
+ current_distance +=
+ util::coordinate_calculation::haversineDistance(prev_coordinate, coordinate);
+
+ // all changes to this check have to be matched with assemble_steps
+ if (path_point.turn_instruction.type != extractor::guidance::TurnType::NoTurn)
+ {
+ geometry.segment_distances.push_back(current_distance);
+ geometry.segment_offsets.push_back(geometry.locations.size());
+ current_distance = 0.;
+ }
+
+ prev_coordinate = coordinate;
+ geometry.locations.push_back(std::move(coordinate));
+ }
+ current_distance +=
+ util::coordinate_calculation::haversineDistance(prev_coordinate, target_node.location);
+ // segment leading to the target node
+ geometry.segment_distances.push_back(current_distance);
+ geometry.segment_offsets.push_back(geometry.locations.size());
+ geometry.locations.push_back(target_node.location);
+
+ BOOST_ASSERT(geometry.segment_distances.size() == geometry.segment_offsets.size() - 1);
+ BOOST_ASSERT(geometry.locations.size() > geometry.segment_distances.size());
+
+ return geometry;
+}
+}
+}
+}
+
+#endif
diff --git a/include/engine/guidance/assemble_leg.hpp b/include/engine/guidance/assemble_leg.hpp
new file mode 100644
index 0000000..bf34d74
--- /dev/null
+++ b/include/engine/guidance/assemble_leg.hpp
@@ -0,0 +1,169 @@
+#ifndef ENGINE_GUIDANCE_ASSEMBLE_LEG_HPP_
+#define ENGINE_GUIDANCE_ASSEMBLE_LEG_HPP_
+
+#include "engine/guidance/route_leg.hpp"
+#include "engine/guidance/route_step.hpp"
+#include "engine/guidance/leg_geometry.hpp"
+#include "engine/internal_route_result.hpp"
+
+#include <cstddef>
+#include <cstdint>
+
+#include <vector>
+#include <array>
+#include <string>
+#include <utility>
+#include <numeric>
+#include <algorithm>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+namespace detail
+{
+const constexpr std::size_t MAX_USED_SEGMENTS = 2;
+struct NamedSegment
+{
+ double duration;
+ std::uint32_t position;
+ std::uint32_t name_id;
+};
+
+template <std::size_t SegmentNumber>
+std::array<std::uint32_t, SegmentNumber> summarizeRoute(const std::vector<PathData> &route_data)
+{
+ // merges segments with same name id
+ const auto collapse_segments = [](std::vector<NamedSegment> &segments)
+ {
+ auto out = segments.begin();
+ auto end = segments.end();
+ for (auto in = segments.begin(); in != end; ++in)
+ {
+ if (in->name_id == out->name_id)
+ {
+ out->duration += in->duration;
+ }
+ else
+ {
+ ++out;
+ BOOST_ASSERT(out != end);
+ *out = *in;
+ }
+ }
+ return out;
+ };
+
+ std::vector<NamedSegment> segments(route_data.size());
+ std::uint32_t index = 0;
+ std::transform(
+ route_data.begin(), route_data.end(), segments.begin(), [&index](const PathData &point)
+ {
+ return NamedSegment{point.duration_until_turn / 10.0, index++, point.name_id};
+ });
+ // this makes sure that the segment with the lowest position comes first
+ std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
+ {
+ return lhs.name_id < rhs.name_id ||
+ (lhs.name_id == rhs.name_id && lhs.position < rhs.position);
+ });
+ auto new_end = collapse_segments(segments);
+ segments.resize(new_end - segments.begin());
+ // sort descending
+ std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
+ {
+ return lhs.duration > rhs.duration;
+ });
+
+ // make sure the segments are sorted by position
+ segments.resize(std::min(segments.size(), SegmentNumber));
+ std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
+ {
+ return lhs.position < rhs.position;
+ });
+
+ std::array<std::uint32_t, SegmentNumber> summary;
+ std::fill(summary.begin(), summary.end(), 0);
+ std::transform(segments.begin(), segments.end(), summary.begin(),
+ [](const NamedSegment &segment)
+ {
+ return segment.name_id;
+ });
+ return summary;
+}
+}
+
+template <typename DataFacadeT>
+RouteLeg assembleLeg(const DataFacadeT &facade,
+ const std::vector<PathData> &route_data,
+ const LegGeometry &leg_geometry,
+ const PhantomNode &source_node,
+ const PhantomNode &target_node,
+ const bool target_traversed_in_reverse)
+{
+ const auto target_duration =
+ (target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight) /
+ 10.;
+
+ auto distance = std::accumulate(leg_geometry.segment_distances.begin(),
+ leg_geometry.segment_distances.end(), 0.);
+ auto duration = std::accumulate(route_data.begin(), route_data.end(), 0.,
+ [](const double sum, const PathData &data)
+ {
+ return sum + data.duration_until_turn;
+ }) /
+ 10.;
+
+ // s
+ // |
+ // Given a route a---b---c where there is a right turn at c.
+ // |
+ // d
+ // |--t
+ // e
+ // (a, b, c) gets compressed to (a,c)
+ // (c, d, e) gets compressed to (c,e)
+ // The duration of the turn (a,c) -> (c,e) will be the duration of (a,c) (e.g. the duration
+ // of (a,b,c)).
+ // The phantom node of s will contain:
+ // `forward_weight`: duration of (a,s)
+ // `forward_offset`: 0 (its the first segment)
+ // The phantom node of t will contain:
+ // `forward_weight`: duration of (d,t)
+ // `forward_offset`: duration of (c, d)
+ // path_data will have entries for (s,b), (b, c), (c, d) but (d, t) is only
+ // caputed by the phantom node. So we need to add the target duration here.
+ // On local segments, the target duration is already part of the duration, however.
+
+ duration = duration + target_duration;
+ if (route_data.empty())
+ {
+ duration -=
+ (target_traversed_in_reverse ? source_node.reverse_weight : source_node.forward_weight) / 10;
+ }
+ auto summary_array = detail::summarizeRoute<detail::MAX_USED_SEGMENTS>(route_data);
+
+ BOOST_ASSERT(detail::MAX_USED_SEGMENTS > 0);
+ BOOST_ASSERT(summary_array.begin() != summary_array.end());
+ std::string summary =
+ std::accumulate(std::next(summary_array.begin()), summary_array.end(),
+ facade.GetNameForID(summary_array.front()),
+ [&facade](std::string previous, const std::uint32_t name_id)
+ {
+ if (name_id != 0)
+ {
+ previous += ", " + facade.GetNameForID(name_id);
+ }
+ return previous;
+ });
+
+ return RouteLeg{duration, distance, summary, {}};
+}
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
+
+#endif // ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
diff --git a/include/engine/guidance/assemble_overview.hpp b/include/engine/guidance/assemble_overview.hpp
new file mode 100644
index 0000000..f801d6c
--- /dev/null
+++ b/include/engine/guidance/assemble_overview.hpp
@@ -0,0 +1,24 @@
+#ifndef ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
+#define ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
+
+#include "engine/guidance/leg_geometry.hpp"
+
+#include "util/coordinate.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+std::vector<util::Coordinate> assembleOverview(const std::vector<LegGeometry> &leg_geometries,
+ const bool use_simplification);
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
+
+#endif
diff --git a/include/engine/guidance/assemble_route.hpp b/include/engine/guidance/assemble_route.hpp
new file mode 100644
index 0000000..ff1c905
--- /dev/null
+++ b/include/engine/guidance/assemble_route.hpp
@@ -0,0 +1,22 @@
+#ifndef ENGINE_GUIDANCE_ASSEMBLE_ROUTE_HPP
+#define ENGINE_GUIDANCE_ASSEMBLE_ROUTE_HPP
+
+#include "engine/guidance/route_leg.hpp"
+#include "engine/guidance/route.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+Route assembleRoute(const std::vector<RouteLeg> &route_legs);
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
+
+#endif
diff --git a/include/engine/guidance/assemble_steps.hpp b/include/engine/guidance/assemble_steps.hpp
new file mode 100644
index 0000000..c6d19ee
--- /dev/null
+++ b/include/engine/guidance/assemble_steps.hpp
@@ -0,0 +1,157 @@
+#ifndef ENGINE_GUIDANCE_ASSEMBLE_STEPS_HPP_
+#define ENGINE_GUIDANCE_ASSEMBLE_STEPS_HPP_
+
+#include "engine/guidance/route_step.hpp"
+#include "engine/guidance/step_maneuver.hpp"
+#include "engine/guidance/leg_geometry.hpp"
+#include "engine/guidance/toolkit.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+#include "engine/internal_route_result.hpp"
+#include "engine/phantom_node.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/coordinate.hpp"
+#include "util/bearing.hpp"
+#include "extractor/travel_mode.hpp"
+
+#include <vector>
+#include <boost/optional.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+namespace detail
+{
+StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
+ const LegGeometry &leg_geometry,
+ const std::size_t segment_index);
+
+StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
+ const WaypointType waypoint_type,
+ const LegGeometry &leg_geometry);
+
+} // ns detail
+
+template <typename DataFacadeT>
+std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
+ const std::vector<PathData> &leg_data,
+ const LegGeometry &leg_geometry,
+ const PhantomNode &source_node,
+ const PhantomNode &target_node,
+ const bool source_traversed_in_reverse,
+ const bool target_traversed_in_reverse)
+{
+ const double constexpr ZERO_DURATION = 0., ZERO_DISTANCE = 0.;
+ const EdgeWeight source_duration =
+ source_traversed_in_reverse ? source_node.reverse_weight : source_node.forward_weight;
+ const auto source_mode = source_traversed_in_reverse ? source_node.backward_travel_mode
+ : source_node.forward_travel_mode;
+
+ const EdgeWeight target_duration =
+ target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight;
+ const auto target_mode = target_traversed_in_reverse ? target_node.backward_travel_mode
+ : target_node.forward_travel_mode;
+
+ const auto number_of_segments = leg_geometry.GetNumberOfSegments();
+
+ std::vector<RouteStep> steps;
+ steps.reserve(number_of_segments);
+
+ std::size_t segment_index = 0;
+ BOOST_ASSERT(leg_geometry.locations.size() >= 2);
+
+ if (leg_data.size() > 0)
+ {
+
+ StepManeuver maneuver = detail::stepManeuverFromGeometry(
+ extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Depart, leg_geometry);
+ maneuver.location = source_node.location;
+
+ // PathData saves the information we need of the segment _before_ the turn,
+ // but a RouteStep is with regard to the segment after the turn.
+ // We need to skip the first segment because it is already covered by the
+ // initial start of a route
+ int segment_duration = 0;
+ for (const auto &path_point : leg_data)
+ {
+ segment_duration += path_point.duration_until_turn;
+
+ // all changes to this check have to be matched with assemble_geometry
+ if (path_point.turn_instruction.type != extractor::guidance::TurnType::NoTurn)
+ {
+ BOOST_ASSERT(segment_duration >= 0);
+ const auto name = facade.GetNameForID(path_point.name_id);
+ const auto distance = leg_geometry.segment_distances[segment_index];
+ steps.push_back(RouteStep{path_point.name_id,
+ name,
+ segment_duration / 10.0,
+ distance,
+ path_point.travel_mode,
+ maneuver,
+ leg_geometry.FrontIndex(segment_index),
+ leg_geometry.BackIndex(segment_index) + 1});
+ maneuver = detail::stepManeuverFromGeometry(path_point.turn_instruction,
+ leg_geometry, segment_index);
+ segment_index++;
+ segment_duration = 0;
+ }
+ }
+ const auto distance = leg_geometry.segment_distances[segment_index];
+ const int duration = segment_duration + target_duration;
+ BOOST_ASSERT(duration >= 0);
+ steps.push_back(RouteStep{target_node.name_id,
+ facade.GetNameForID(target_node.name_id),
+ duration / 10.,
+ distance,
+ target_mode,
+ maneuver,
+ leg_geometry.FrontIndex(segment_index),
+ leg_geometry.BackIndex(segment_index) + 1});
+ }
+ // In this case the source + target are on the same edge segment
+ else
+ {
+ BOOST_ASSERT(source_node.fwd_segment_position == target_node.fwd_segment_position);
+ // s t
+ // u-------------v
+ // |---| source_duration
+ // |---------| target_duration
+
+ StepManeuver maneuver = detail::stepManeuverFromGeometry(
+ extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Depart, leg_geometry);
+ int duration = target_duration - source_duration;
+ BOOST_ASSERT(duration >= 0);
+
+ steps.push_back(RouteStep{source_node.name_id,
+ facade.GetNameForID(source_node.name_id),
+ duration / 10.,
+ leg_geometry.segment_distances[segment_index],
+ source_mode,
+ std::move(maneuver),
+ leg_geometry.FrontIndex(segment_index),
+ leg_geometry.BackIndex(segment_index) + 1});
+ }
+
+ BOOST_ASSERT(segment_index == number_of_segments - 1);
+ // This step has length zero, the only reason we need it is the target location
+ auto final_maneuver = detail::stepManeuverFromGeometry(
+ extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Arrive, leg_geometry);
+ steps.push_back(RouteStep{target_node.name_id,
+ facade.GetNameForID(target_node.name_id),
+ ZERO_DURATION,
+ ZERO_DISTANCE,
+ target_mode,
+ final_maneuver,
+ leg_geometry.locations.size(),
+ leg_geometry.locations.size()});
+
+ return steps;
+}
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
+
+#endif // ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
diff --git a/include/engine/guidance/leg_geometry.hpp b/include/engine/guidance/leg_geometry.hpp
new file mode 100644
index 0000000..622e40f
--- /dev/null
+++ b/include/engine/guidance/leg_geometry.hpp
@@ -0,0 +1,54 @@
+#ifndef ENGINE_GUIDANCE_LEG_GEOMETRY_HPP
+#define ENGINE_GUIDANCE_LEG_GEOMETRY_HPP
+
+#include "util/coordinate.hpp"
+#include "util/integer_range.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cstddef>
+
+#include <vector>
+#include <cstdlib>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+// locations 0---1---2-...-n-1---n
+// turns s x y t
+// segment | 0 | 1 | 2 | sentinel
+// offsets 0 2 n-1 n
+struct LegGeometry
+{
+ std::vector<util::Coordinate> locations;
+ // segment_offset[i] .. segment_offset[i+1] (inclusive)
+ // contains the geometry of segment i
+ std::vector<std::size_t> segment_offsets;
+ // length of the segment in meters
+ std::vector<double> segment_distances;
+
+ std::size_t FrontIndex(std::size_t segment_index) const
+ {
+ return segment_offsets[segment_index];
+ }
+
+ std::size_t BackIndex(std::size_t segment_index) const
+ {
+ return segment_offsets[segment_index + 1];
+ }
+
+ std::size_t GetNumberOfSegments() const
+ {
+ BOOST_ASSERT(segment_offsets.size() > 0);
+ return segment_offsets.size() - 1;
+ }
+};
+}
+}
+}
+
+#endif
diff --git a/include/engine/guidance/post_processing.hpp b/include/engine/guidance/post_processing.hpp
new file mode 100644
index 0000000..32f6ee5
--- /dev/null
+++ b/include/engine/guidance/post_processing.hpp
@@ -0,0 +1,44 @@
+#ifndef ENGINE_GUIDANCE_POST_PROCESSING_HPP
+#define ENGINE_GUIDANCE_POST_PROCESSING_HPP
+
+#include "engine/phantom_node.hpp"
+#include "engine/guidance/route_step.hpp"
+#include "engine/guidance/leg_geometry.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+// passed as none-reference to modify in-place and move out again
+std::vector<RouteStep> postProcess(std::vector<RouteStep> steps);
+
+// trim initial/final segment of very short length.
+// This function uses in/out parameter passing to modify both steps and geometry in place.
+// We use this method since both steps and geometry are closely coupled logically but
+// are not coupled in the same way in the background. To avoid the additional overhead
+// of introducing intermediate structions, we resolve to the in/out scheme at this point.
+void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry);
+
+// assign relative locations to depart/arrive instructions
+std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
+ const LegGeometry &geometry,
+ const PhantomNode &source_node,
+ const PhantomNode &target_node);
+
+// postProcess will break the connection between the leg geometry
+// for which a segment is supposed to represent exactly the coordinates
+// between routing maneuvers and the route steps itself.
+// If required, we can get both in sync again using this function.
+// Move in LegGeometry for modification in place.
+LegGeometry resyncGeometry(LegGeometry leg_geometry, const std::vector<RouteStep> &steps);
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
+
+#endif // ENGINE_GUIDANCE_POST_PROCESSING_HPP
diff --git a/include/engine/guidance/route.hpp b/include/engine/guidance/route.hpp
new file mode 100644
index 0000000..bde2d5f
--- /dev/null
+++ b/include/engine/guidance/route.hpp
@@ -0,0 +1,20 @@
+#ifndef ROUTE_HPP
+#define ROUTE_HPP
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+struct Route
+{
+ double duration;
+ double distance;
+};
+}
+}
+}
+
+#endif
diff --git a/include/engine/guidance/route_leg.hpp b/include/engine/guidance/route_leg.hpp
new file mode 100644
index 0000000..5ecca4f
--- /dev/null
+++ b/include/engine/guidance/route_leg.hpp
@@ -0,0 +1,29 @@
+#ifndef ROUTE_LEG_HPP
+#define ROUTE_LEG_HPP
+
+#include "engine/guidance/route_step.hpp"
+
+#include <boost/optional.hpp>
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+struct RouteLeg
+{
+ double duration;
+ double distance;
+ std::string summary;
+ std::vector<RouteStep> steps;
+};
+}
+}
+}
+
+#endif
diff --git a/include/engine/guidance/route_step.hpp b/include/engine/guidance/route_step.hpp
new file mode 100644
index 0000000..1a53579
--- /dev/null
+++ b/include/engine/guidance/route_step.hpp
@@ -0,0 +1,40 @@
+#ifndef ROUTE_STEP_HPP
+#define ROUTE_STEP_HPP
+
+#include "extractor/travel_mode.hpp"
+#include "engine/guidance/step_maneuver.hpp"
+
+#include <cstddef>
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+// Given the following turn from a,b to b,c over b:
+// a --> b --> c
+// this struct saves the information of the segment b,c.
+// Notable exceptions are Departure and Arrival steps.
+// Departue: s --> a --> b. Represents the segment s,a with location being s.
+// Arrive: a --> b --> t. The segment (b,t) is already covered by the previous segment.
+struct RouteStep
+{
+ unsigned name_id;
+ std::string name;
+ double duration;
+ double distance;
+ extractor::TravelMode mode;
+ StepManeuver maneuver;
+ // indices into the locations array stored the LegGeometry
+ std::size_t geometry_begin;
+ std::size_t geometry_end;
+};
+}
+}
+}
+
+#endif
diff --git a/include/engine/guidance/step_maneuver.hpp b/include/engine/guidance/step_maneuver.hpp
new file mode 100644
index 0000000..5ae70f9
--- /dev/null
+++ b/include/engine/guidance/step_maneuver.hpp
@@ -0,0 +1,45 @@
+#ifndef ENGINE_GUIDANCE_STEP_MANEUVER_HPP
+#define ENGINE_GUIDANCE_STEP_MANEUVER_HPP
+
+#include "util/coordinate.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+
+#include <cstdint>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+enum class WaypointType : std::uint8_t
+{
+ None,
+ Arrive,
+ Depart,
+};
+
+//A represenetation of intermediate intersections
+struct IntermediateIntersection
+{
+ double duration;
+ double distance;
+ util::Coordinate location;
+};
+
+struct StepManeuver
+{
+ util::Coordinate location;
+ double bearing_before;
+ double bearing_after;
+ extractor::guidance::TurnInstruction instruction;
+ WaypointType waypoint_type;
+ unsigned exit;
+ std::vector<IntermediateIntersection> intersections;
+};
+} // namespace guidance
+} // namespace engine
+} // namespace osrmn
+#endif
diff --git a/include/engine/guidance/toolkit.hpp b/include/engine/guidance/toolkit.hpp
new file mode 100644
index 0000000..e9cbcf5
--- /dev/null
+++ b/include/engine/guidance/toolkit.hpp
@@ -0,0 +1,63 @@
+#ifndef OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_
+#define OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_
+
+#include "extractor/guidance/turn_instruction.hpp"
+#include "util/bearing.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+// Silent Turn Instructions are not to be mentioned to the outside world but
+inline bool isSilent(const extractor::guidance::TurnInstruction instruction)
+{
+ return instruction.type == extractor::guidance::TurnType::NoTurn ||
+ instruction.type == extractor::guidance::TurnType::Suppressed ||
+ instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
+}
+
+inline bool entersRoundabout(const extractor::guidance::TurnInstruction instruction)
+{
+ return (instruction.type == extractor::guidance::TurnType::EnterRoundabout ||
+ instruction.type == extractor::guidance::TurnType::EnterRotary ||
+ instruction.type == extractor::guidance::TurnType::EnterRoundaboutAtExit ||
+ instruction.type == extractor::guidance::TurnType::EnterRotaryAtExit ||
+ instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
+ instruction.type == extractor::guidance::TurnType::EnterAndExitRotary);
+}
+
+inline bool leavesRoundabout(const extractor::guidance::TurnInstruction instruction)
+{
+ return (instruction.type == extractor::guidance::TurnType::ExitRoundabout ||
+ instruction.type == extractor::guidance::TurnType::ExitRotary ||
+ instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
+ instruction.type == extractor::guidance::TurnType::EnterAndExitRotary);
+}
+
+inline bool staysOnRoundabout(const extractor::guidance::TurnInstruction instruction)
+{
+ return instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
+}
+
+inline extractor::guidance::DirectionModifier angleToDirectionModifier(const double bearing)
+{
+ if (bearing < 135)
+ {
+ return extractor::guidance::DirectionModifier::Right;
+ }
+
+ if (bearing <= 225)
+ {
+ return extractor::guidance::DirectionModifier::Straight;
+ }
+ return extractor::guidance::DirectionModifier::Left;
+}
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
+
+#endif /* OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ */
diff --git a/include/engine/hint.hpp b/include/engine/hint.hpp
new file mode 100644
index 0000000..0ecaff6
--- /dev/null
+++ b/include/engine/hint.hpp
@@ -0,0 +1,81 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef ENGINE_HINT_HPP
+#define ENGINE_HINT_HPP
+
+#include "engine/phantom_node.hpp"
+
+#include "util/coordinate.hpp"
+
+#include <string>
+#include <cstdint>
+#include <iosfwd>
+
+namespace osrm
+{
+namespace engine
+{
+
+// Fwd. decls.
+namespace datafacade
+{
+class BaseDataFacade;
+}
+
+// Is returned as a temporary identifier for snapped coodinates
+struct Hint
+{
+ PhantomNode phantom;
+ std::uint32_t data_checksum;
+
+ bool IsValid(const util::Coordinate new_input_coordinates,
+ const datafacade::BaseDataFacade &facade) const;
+
+ std::string ToBase64() const;
+ static Hint FromBase64(const std::string &base64Hint);
+
+ friend bool operator==(const Hint &, const Hint &);
+ friend std::ostream &operator<<(std::ostream &, const Hint &);
+};
+
+#ifndef _MSC_VER
+static_assert(sizeof(Hint) == 60 + 4, "Hint is bigger than expected");
+constexpr std::size_t ENCODED_HINT_SIZE = 88;
+static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
+ "ENCODED_HINT_SIZE does not match size of Hint");
+#else
+// PhantomNode is bigger under windows because MSVC does not support bit packing
+static_assert(sizeof(Hint) == 64 + 4, "Hint is bigger than expected");
+constexpr std::size_t ENCODED_HINT_SIZE = 92;
+static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
+ "ENCODED_HINT_SIZE does not match size of Hint");
+#endif
+}
+}
+
+#endif
diff --git a/include/engine/internal_route_result.hpp b/include/engine/internal_route_result.hpp
new file mode 100644
index 0000000..d1666e1
--- /dev/null
+++ b/include/engine/internal_route_result.hpp
@@ -0,0 +1,63 @@
+#ifndef RAW_ROUTE_DATA_H
+#define RAW_ROUTE_DATA_H
+
+#include "engine/phantom_node.hpp"
+#include "extractor/travel_mode.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+#include "util/typedefs.hpp"
+
+#include "osrm/coordinate.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+
+const constexpr unsigned INVALID_EXIT_NR = 0;
+
+struct PathData
+{
+ // id of via node of the turn
+ NodeID turn_via_node;
+ // name of the street that leads to the turn
+ unsigned name_id;
+ // duration that is traveled on the segment until the turn is reached
+ EdgeWeight duration_until_turn;
+ // instruction to execute at the turn
+ extractor::guidance::TurnInstruction turn_instruction;
+ // travel mode of the street that leads to the turn
+ extractor::TravelMode travel_mode : 4;
+};
+
+struct InternalRouteResult
+{
+ std::vector<std::vector<PathData>> unpacked_path_segments;
+ std::vector<PathData> unpacked_alternative;
+ std::vector<PhantomNodes> segment_end_coordinates;
+ std::vector<bool> source_traversed_in_reverse;
+ std::vector<bool> target_traversed_in_reverse;
+ std::vector<bool> alt_source_traversed_in_reverse;
+ std::vector<bool> alt_target_traversed_in_reverse;
+ int shortest_path_length;
+ int alternative_path_length;
+
+ bool is_valid() const { return INVALID_EDGE_WEIGHT != shortest_path_length; }
+
+ bool has_alternative() const { return INVALID_EDGE_WEIGHT != alternative_path_length; }
+
+ bool is_via_leg(const std::size_t leg) const
+ {
+ return (leg != unpacked_path_segments.size() - 1);
+ }
+
+ InternalRouteResult()
+ : shortest_path_length(INVALID_EDGE_WEIGHT), alternative_path_length(INVALID_EDGE_WEIGHT)
+ {
+ }
+};
+}
+}
+
+#endif // RAW_ROUTE_DATA_H
diff --git a/algorithms/bayes_classifier.hpp b/include/engine/map_matching/bayes_classifier.hpp
similarity index 63%
rename from algorithms/bayes_classifier.hpp
rename to include/engine/map_matching/bayes_classifier.hpp
index ea300c1..c77fa84 100644
--- a/algorithms/bayes_classifier.hpp
+++ b/include/engine/map_matching/bayes_classifier.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef BAYES_CLASSIFIER_HPP
#define BAYES_CLASSIFIER_HPP
@@ -33,6 +6,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <vector>
#include <utility>
+#include <boost/math/constants/constants.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace map_matching
+{
+
struct NormalDistribution
{
NormalDistribution(const double mean, const double standard_deviation)
@@ -40,11 +22,13 @@ struct NormalDistribution
{
}
- // FIXME implement log-probability version since its faster
+ // FIXME implement log-probability version since it's faster
double density_function(const double val) const
{
+ using namespace boost::math::constants;
+
const double x = val - mean;
- return 1.0 / (std::sqrt(2. * M_PI) * standard_deviation) *
+ return 1.0 / (std::sqrt(two_pi<double>()) * standard_deviation) *
std::exp(-x * x / (standard_deviation * standard_deviation));
}
@@ -59,7 +43,7 @@ struct LaplaceDistribution
{
}
- // FIXME implement log-probability version since its faster
+ // FIXME implement log-probability version since it's faster
double density_function(const double val) const
{
const double x = std::abs(val - location);
@@ -114,5 +98,8 @@ class BayesClassifier
double positive_apriori_probability;
double negative_apriori_probability;
};
+}
+}
+}
#endif // BAYES_CLASSIFIER_HPP
diff --git a/data_structures/hidden_markov_model.hpp b/include/engine/map_matching/hidden_markov_model.hpp
similarity index 50%
rename from data_structures/hidden_markov_model.hpp
rename to include/engine/map_matching/hidden_markov_model.hpp
index e3efcea..303a835 100644
--- a/data_structures/hidden_markov_model.hpp
+++ b/include/engine/map_matching/hidden_markov_model.hpp
@@ -1,36 +1,10 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef HIDDEN_MARKOV_MODEL
#define HIDDEN_MARKOV_MODEL
-#include "../util/integer_range.hpp"
+#include "util/integer_range.hpp"
#include <boost/assert.hpp>
+#include <boost/math/constants/constants.hpp>
#include <cmath>
@@ -39,14 +13,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace osrm
{
-namespace matching
+namespace engine
{
-static const double log_2_pi = std::log(2. * M_PI);
+namespace map_matching
+{
+
+static const double log_2_pi = std::log(2. * boost::math::constants::pi<double>());
static const double IMPOSSIBLE_LOG_PROB = -std::numeric_limits<double>::infinity();
static const double MINIMAL_LOG_PROB = std::numeric_limits<double>::lowest();
static const std::size_t INVALID_STATE = std::numeric_limits<std::size_t>::max();
-} // namespace matching
-} // namespace osrm
// closures to precompute log -> only simple floating point operations
struct EmissionLogProbability
@@ -60,8 +35,7 @@ struct EmissionLogProbability
double operator()(const double distance) const
{
- return -0.5 * (osrm::matching::log_2_pi + (distance / sigma_z) * (distance / sigma_z)) -
- log_sigma_z;
+ return -0.5 * (log_2_pi + (distance / sigma_z) * (distance / sigma_z)) - log_sigma_z;
}
};
@@ -78,35 +52,32 @@ template <class CandidateLists> struct HiddenMarkovModel
{
std::vector<std::vector<double>> viterbi;
std::vector<std::vector<std::pair<unsigned, unsigned>>> parents;
- std::vector<std::vector<float>> path_lengths;
+ std::vector<std::vector<float>> path_distances;
std::vector<std::vector<bool>> pruned;
- std::vector<std::vector<bool>> suspicious;
std::vector<bool> breakage;
const CandidateLists &candidates_list;
- const EmissionLogProbability &emission_log_probability;
+ const std::vector<std::vector<double>> &emission_log_probabilities;
HiddenMarkovModel(const CandidateLists &candidates_list,
- const EmissionLogProbability &emission_log_probability)
+ const std::vector<std::vector<double>> &emission_log_probabilities)
: breakage(candidates_list.size()), candidates_list(candidates_list),
- emission_log_probability(emission_log_probability)
+ emission_log_probabilities(emission_log_probabilities)
{
viterbi.resize(candidates_list.size());
parents.resize(candidates_list.size());
- path_lengths.resize(candidates_list.size());
- suspicious.resize(candidates_list.size());
+ path_distances.resize(candidates_list.size());
pruned.resize(candidates_list.size());
breakage.resize(candidates_list.size());
- for (const auto i : osrm::irange<std::size_t>(0u, candidates_list.size()))
+ for (const auto i : util::irange<std::size_t>(0u, candidates_list.size()))
{
- const auto& num_candidates = candidates_list[i].size();
+ const auto &num_candidates = candidates_list[i].size();
// add empty vectors
if (num_candidates > 0)
{
viterbi[i].resize(num_candidates);
parents[i].resize(num_candidates);
- path_lengths[i].resize(num_candidates);
- suspicious[i].resize(num_candidates);
+ path_distances[i].resize(num_candidates);
pruned[i].resize(num_candidates);
}
}
@@ -116,15 +87,14 @@ template <class CandidateLists> struct HiddenMarkovModel
void clear(std::size_t initial_timestamp)
{
- BOOST_ASSERT(viterbi.size() == parents.size() && parents.size() == path_lengths.size() &&
- path_lengths.size() == pruned.size() && pruned.size() == breakage.size());
+ BOOST_ASSERT(viterbi.size() == parents.size() && parents.size() == path_distances.size() &&
+ path_distances.size() == pruned.size() && pruned.size() == breakage.size());
- for (const auto t : osrm::irange(initial_timestamp, viterbi.size()))
+ for (const auto t : util::irange(initial_timestamp, viterbi.size()))
{
- std::fill(viterbi[t].begin(), viterbi[t].end(), osrm::matching::IMPOSSIBLE_LOG_PROB);
+ std::fill(viterbi[t].begin(), viterbi[t].end(), IMPOSSIBLE_LOG_PROB);
std::fill(parents[t].begin(), parents[t].end(), std::make_pair(0u, 0u));
- std::fill(path_lengths[t].begin(), path_lengths[t].end(), 0);
- std::fill(suspicious[t].begin(), suspicious[t].end(), true);
+ std::fill(path_distances[t].begin(), path_distances[t].end(), 0);
std::fill(pruned[t].begin(), pruned[t].end(), true);
}
std::fill(breakage.begin() + initial_timestamp, breakage.end(), true);
@@ -137,14 +107,11 @@ template <class CandidateLists> struct HiddenMarkovModel
{
BOOST_ASSERT(initial_timestamp < num_points);
- for (const auto s : osrm::irange<std::size_t>(0u, viterbi[initial_timestamp].size()))
+ for (const auto s : util::irange<std::size_t>(0u, viterbi[initial_timestamp].size()))
{
- viterbi[initial_timestamp][s] =
- emission_log_probability(candidates_list[initial_timestamp][s].distance);
+ viterbi[initial_timestamp][s] = emission_log_probabilities[initial_timestamp][s];
parents[initial_timestamp][s] = std::make_pair(initial_timestamp, s);
- pruned[initial_timestamp][s] =
- viterbi[initial_timestamp][s] < osrm::matching::MINIMAL_LOG_PROB;
- suspicious[initial_timestamp][s] = false;
+ pruned[initial_timestamp][s] = viterbi[initial_timestamp][s] < MINIMAL_LOG_PROB;
breakage[initial_timestamp] =
breakage[initial_timestamp] && pruned[initial_timestamp][s];
@@ -155,7 +122,7 @@ template <class CandidateLists> struct HiddenMarkovModel
if (initial_timestamp >= num_points)
{
- return osrm::matching::INVALID_STATE;
+ return INVALID_STATE;
}
BOOST_ASSERT(initial_timestamp > 0);
@@ -166,5 +133,8 @@ template <class CandidateLists> struct HiddenMarkovModel
return initial_timestamp;
}
};
+}
+}
+}
#endif // HIDDEN_MARKOV_MODEL
diff --git a/include/engine/map_matching/matching_confidence.hpp b/include/engine/map_matching/matching_confidence.hpp
new file mode 100644
index 0000000..03613b0
--- /dev/null
+++ b/include/engine/map_matching/matching_confidence.hpp
@@ -0,0 +1,58 @@
+#ifndef ENGINE_MAP_MATCHING_CONFIDENCE_HPP
+#define ENGINE_MAP_MATCHING_CONFIDENCE_HPP
+
+#include "engine/map_matching/bayes_classifier.hpp"
+
+#include <cmath>
+
+namespace osrm
+{
+namespace engine
+{
+namespace map_matching
+{
+
+struct MatchingConfidence
+{
+ private:
+ using ClassifierT = BayesClassifier<LaplaceDistribution, LaplaceDistribution, double>;
+ using TraceClassification = ClassifierT::ClassificationT;
+
+ public:
+ MatchingConfidence()
+ : // the values were derived from fitting a laplace distribution
+ // to the values of manually classified traces
+ classifier(map_matching::LaplaceDistribution(0.005986, 0.016646),
+ map_matching::LaplaceDistribution(0.054385, 0.458432),
+ 0.696774) // valid apriori probability
+ {
+ }
+
+ double operator()(const float trace_length, const float matched_length) const
+ {
+ const double distance_feature = -std::log(trace_length) + std::log(matched_length);
+
+ // matched to the same point
+ if (!std::isfinite(distance_feature))
+ {
+ return 0;
+ }
+
+ const auto label_with_confidence = classifier.classify(distance_feature);
+ if (label_with_confidence.first == ClassifierT::ClassLabel::POSITIVE)
+ {
+ return label_with_confidence.second;
+ }
+
+ BOOST_ASSERT(label_with_confidence.first == ClassifierT::ClassLabel::NEGATIVE);
+ return 1 - label_with_confidence.second;
+ }
+
+ private:
+ ClassifierT classifier;
+};
+}
+}
+}
+
+#endif
diff --git a/include/engine/map_matching/sub_matching.hpp b/include/engine/map_matching/sub_matching.hpp
new file mode 100644
index 0000000..22c1803
--- /dev/null
+++ b/include/engine/map_matching/sub_matching.hpp
@@ -0,0 +1,25 @@
+#ifndef MAP_MATCHING_SUB_MATCHING_HPP
+#define MAP_MATCHING_SUB_MATCHING_HPP
+
+#include "engine/phantom_node.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace map_matching
+{
+
+struct SubMatching
+{
+ std::vector<PhantomNode> nodes;
+ std::vector<unsigned> indices;
+ double confidence;
+};
+}
+}
+}
+
+#endif
diff --git a/include/engine/phantom_node.hpp b/include/engine/phantom_node.hpp
new file mode 100644
index 0000000..244276c
--- /dev/null
+++ b/include/engine/phantom_node.hpp
@@ -0,0 +1,214 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef PHANTOM_NODES_H
+#define PHANTOM_NODES_H
+
+#include "extractor/travel_mode.hpp"
+#include "util/typedefs.hpp"
+
+#include "util/coordinate.hpp"
+
+#include <boost/assert.hpp>
+
+#include <iostream>
+#include <utility>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+
+struct PhantomNode
+{
+ PhantomNode(SegmentID forward_segment_id,
+ SegmentID reverse_segment_id,
+ unsigned name_id,
+ int forward_weight,
+ int reverse_weight,
+ int forward_offset,
+ int reverse_offset,
+ unsigned forward_packed_geometry_id_,
+ unsigned reverse_packed_geometry_id_,
+ bool is_tiny_component,
+ unsigned component_id,
+ util::Coordinate location,
+ util::Coordinate input_location,
+ unsigned short fwd_segment_position,
+ extractor::TravelMode forward_travel_mode,
+ extractor::TravelMode backward_travel_mode)
+ : forward_segment_id(forward_segment_id), reverse_segment_id(reverse_segment_id),
+ name_id(name_id), forward_weight(forward_weight), reverse_weight(reverse_weight),
+ forward_offset(forward_offset), reverse_offset(reverse_offset),
+ forward_packed_geometry_id(forward_packed_geometry_id_),
+ reverse_packed_geometry_id(reverse_packed_geometry_id_),
+ component{component_id, is_tiny_component}, location(std::move(location)),
+ input_location(std::move(input_location)), fwd_segment_position(fwd_segment_position),
+ forward_travel_mode(forward_travel_mode), backward_travel_mode(backward_travel_mode)
+ {
+ }
+
+ PhantomNode()
+ : forward_segment_id{SPECIAL_SEGMENTID, false},
+ reverse_segment_id{SPECIAL_SEGMENTID, false},
+ name_id(std::numeric_limits<unsigned>::max()), forward_weight(INVALID_EDGE_WEIGHT),
+ reverse_weight(INVALID_EDGE_WEIGHT), forward_offset(0), reverse_offset(0),
+ forward_packed_geometry_id(SPECIAL_EDGEID), reverse_packed_geometry_id(SPECIAL_EDGEID),
+ component{INVALID_COMPONENTID, false}, fwd_segment_position(0),
+ forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
+ backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
+ {
+ }
+
+ int GetForwardWeightPlusOffset() const
+ {
+ BOOST_ASSERT(forward_segment_id.enabled);
+ return forward_offset + forward_weight;
+ }
+
+ int GetReverseWeightPlusOffset() const
+ {
+ BOOST_ASSERT(reverse_segment_id.enabled);
+ return reverse_offset + reverse_weight;
+ }
+
+ bool IsBidirected() const { return forward_segment_id.enabled && reverse_segment_id.enabled; }
+
+ bool IsValid(const unsigned number_of_nodes) const
+ {
+ return location.IsValid() && ((forward_segment_id.id < number_of_nodes) ||
+ (reverse_segment_id.id < number_of_nodes)) &&
+ ((forward_weight != INVALID_EDGE_WEIGHT) ||
+ (reverse_weight != INVALID_EDGE_WEIGHT)) &&
+ (component.id != INVALID_COMPONENTID) && (name_id != INVALID_NAMEID);
+ }
+
+ bool IsValid(const unsigned number_of_nodes, const util::Coordinate queried_coordinate) const
+ {
+ return queried_coordinate == input_location && IsValid(number_of_nodes);
+ }
+
+ bool IsValid() const { return location.IsValid() && (name_id != INVALID_NAMEID); }
+
+ bool operator==(const PhantomNode &other) const { return location == other.location; }
+
+ template <class OtherT>
+ explicit PhantomNode(const OtherT &other,
+ int forward_weight_,
+ int forward_offset_,
+ int reverse_weight_,
+ int reverse_offset_,
+ const util::Coordinate location_,
+ const util::Coordinate input_location_)
+ : forward_segment_id{other.forward_segment_id},
+ reverse_segment_id{other.reverse_segment_id}, name_id{other.name_id},
+ forward_weight{forward_weight_}, reverse_weight{reverse_weight_},
+ forward_offset{forward_offset_}, reverse_offset{reverse_offset_},
+ forward_packed_geometry_id{other.forward_packed_geometry_id},
+ reverse_packed_geometry_id{other.reverse_packed_geometry_id},
+ component{other.component.id, other.component.is_tiny}, location{location_},
+ input_location{input_location_}, fwd_segment_position{other.fwd_segment_position},
+ forward_travel_mode{other.forward_travel_mode},
+ backward_travel_mode{other.backward_travel_mode}
+ {
+ }
+
+ SegmentID forward_segment_id;
+ SegmentID reverse_segment_id;
+ unsigned name_id;
+ int forward_weight;
+ int reverse_weight;
+ int forward_offset;
+ int reverse_offset;
+ unsigned forward_packed_geometry_id;
+ unsigned reverse_packed_geometry_id;
+ struct ComponentType
+ {
+ uint32_t id : 31;
+ bool is_tiny : 1;
+ } component;
+// bit-fields are broken on Windows
+#ifndef _MSC_VER
+ static_assert(sizeof(ComponentType) == 4, "ComponentType needs to be 4 bytes big");
+#endif
+ util::Coordinate location;
+ util::Coordinate input_location;
+ unsigned short fwd_segment_position;
+ // note 4 bits would suffice for each,
+ // but the saved byte would be padding anyway
+ extractor::TravelMode forward_travel_mode;
+ extractor::TravelMode backward_travel_mode;
+};
+
+#ifndef _MSC_VER
+static_assert(sizeof(PhantomNode) == 60, "PhantomNode has more padding then expected");
+#else
+static_assert(sizeof(PhantomNode) == 64, "PhantomNode has more padding then expected");
+#endif
+
+using PhantomNodePair = std::pair<PhantomNode, PhantomNode>;
+
+struct PhantomNodeWithDistance
+{
+ PhantomNode phantom_node;
+ double distance;
+};
+
+struct PhantomNodes
+{
+ PhantomNode source_phantom;
+ PhantomNode target_phantom;
+};
+
+inline std::ostream &operator<<(std::ostream &out, const PhantomNodes &pn)
+{
+ out << "source_coord: " << pn.source_phantom.location << "\n";
+ out << "target_coord: " << pn.target_phantom.location << std::endl;
+ return out;
+}
+
+inline std::ostream &operator<<(std::ostream &out, const PhantomNode &pn)
+{
+ out << "node1: " << pn.forward_segment_id.id << ", "
+ << "node2: " << pn.reverse_segment_id.id << ", "
+ << "name: " << pn.name_id << ", "
+ << "fwd-w: " << pn.forward_weight << ", "
+ << "rev-w: " << pn.reverse_weight << ", "
+ << "fwd-o: " << pn.forward_offset << ", "
+ << "rev-o: " << pn.reverse_offset << ", "
+ << "fwd_geom: " << pn.forward_packed_geometry_id << ", "
+ << "rev_geom: " << pn.reverse_packed_geometry_id << ", "
+ << "comp: " << pn.component.is_tiny << " / " << pn.component.id << ", "
+ << "pos: " << pn.fwd_segment_position << ", "
+ << "loc: " << pn.location;
+ return out;
+}
+}
+}
+
+#endif // PHANTOM_NODES_H
diff --git a/include/engine/plugins/match.hpp b/include/engine/plugins/match.hpp
new file mode 100644
index 0000000..57f556a
--- /dev/null
+++ b/include/engine/plugins/match.hpp
@@ -0,0 +1,48 @@
+#ifndef MATCH_HPP
+#define MATCH_HPP
+
+#include "engine/plugins/plugin_base.hpp"
+#include "engine/api/match_parameters.hpp"
+
+#include "engine/map_matching/bayes_classifier.hpp"
+#include "engine/routing_algorithms/map_matching.hpp"
+#include "engine/routing_algorithms/shortest_path.hpp"
+#include "util/json_util.hpp"
+
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+class MatchPlugin : public BasePlugin
+{
+ public:
+ using SubMatching = map_matching::SubMatching;
+ using SubMatchingList = routing_algorithms::SubMatchingList;
+ using CandidateLists = routing_algorithms::CandidateLists;
+ static const constexpr double DEFAULT_GPS_PRECISION = 5;
+ static const constexpr double RADIUS_MULTIPLIER = 3;
+
+ MatchPlugin(datafacade::BaseDataFacade &facade_, const int max_locations_map_matching)
+ : BasePlugin(facade_), map_matching(&facade_, heaps, DEFAULT_GPS_PRECISION),
+ shortest_path(&facade_, heaps), max_locations_map_matching(max_locations_map_matching)
+ {
+ }
+
+ Status HandleRequest(const api::MatchParameters ¶meters, util::json::Object &json_result);
+
+ private:
+ SearchEngineData heaps;
+ routing_algorithms::MapMatching<datafacade::BaseDataFacade> map_matching;
+ routing_algorithms::ShortestPathRouting<datafacade::BaseDataFacade> shortest_path;
+ int max_locations_map_matching;
+};
+}
+}
+}
+
+#endif // MATCH_HPP
diff --git a/include/engine/plugins/nearest.hpp b/include/engine/plugins/nearest.hpp
new file mode 100644
index 0000000..103b789
--- /dev/null
+++ b/include/engine/plugins/nearest.hpp
@@ -0,0 +1,26 @@
+#ifndef NEAREST_HPP
+#define NEAREST_HPP
+
+#include "engine/plugins/plugin_base.hpp"
+#include "engine/api/nearest_parameters.hpp"
+#include "osrm/json_container.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+class NearestPlugin final : public BasePlugin
+{
+ public:
+ explicit NearestPlugin(datafacade::BaseDataFacade &facade);
+
+ Status HandleRequest(const api::NearestParameters ¶ms, util::json::Object &result);
+};
+}
+}
+}
+
+#endif /* NEAREST_HPP */
diff --git a/include/engine/plugins/plugin_base.hpp b/include/engine/plugins/plugin_base.hpp
new file mode 100644
index 0000000..aec9dd0
--- /dev/null
+++ b/include/engine/plugins/plugin_base.hpp
@@ -0,0 +1,284 @@
+#ifndef BASE_PLUGIN_HPP
+#define BASE_PLUGIN_HPP
+
+#include "engine/datafacade/datafacade_base.hpp"
+#include "engine/api/base_parameters.hpp"
+#include "engine/phantom_node.hpp"
+#include "engine/status.hpp"
+
+#include "util/coordinate.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/json_container.hpp"
+#include "util/integer_range.hpp"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+class BasePlugin
+{
+ protected:
+ datafacade::BaseDataFacade &facade;
+ BasePlugin(datafacade::BaseDataFacade &facade_) : facade(facade_) {}
+
+ bool CheckAllCoordinates(const std::vector<util::Coordinate> &coordinates)
+ {
+ return !std::any_of(std::begin(coordinates), std::end(coordinates),
+ [](const util::Coordinate coordinate)
+ {
+ return !coordinate.IsValid();
+ });
+ }
+
+ Status Error(const std::string &code,
+ const std::string &message,
+ util::json::Object &json_result) const
+ {
+ json_result.values["code"] = code;
+ json_result.values["message"] = message;
+ return Status::Error;
+ }
+
+ // Decides whether to use the phantom node from a big or small component if both are found.
+ // Returns true if all phantom nodes are in the same component after snapping.
+ std::vector<PhantomNode>
+ SnapPhantomNodes(const std::vector<PhantomNodePair> &phantom_node_pair_list) const
+ {
+ const auto check_component_id_is_tiny =
+ [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
+ {
+ return phantom_pair.first.component.is_tiny;
+ };
+
+ // are all phantoms from a tiny cc?
+ const auto check_all_in_same_component =
+ [](const std::vector<std::pair<PhantomNode, PhantomNode>> &nodes)
+ {
+ const auto component_id = nodes.front().first.component.id;
+
+ return std::all_of(std::begin(nodes), std::end(nodes),
+ [component_id](const PhantomNodePair &phantom_pair)
+ {
+ return component_id == phantom_pair.first.component.id;
+ });
+ };
+
+ const auto fallback_to_big_component =
+ [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
+ {
+ if (phantom_pair.first.component.is_tiny && phantom_pair.second.IsValid() &&
+ !phantom_pair.second.component.is_tiny)
+ {
+ return phantom_pair.second;
+ }
+ return phantom_pair.first;
+ };
+
+ const auto use_closed_phantom = [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
+ {
+ return phantom_pair.first;
+ };
+
+ const bool every_phantom_is_in_tiny_cc =
+ std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
+ check_component_id_is_tiny);
+ auto all_in_same_component = check_all_in_same_component(phantom_node_pair_list);
+
+ std::vector<PhantomNode> snapped_phantoms;
+ snapped_phantoms.reserve(phantom_node_pair_list.size());
+
+ // The only case we don't snap to the big component if all phantoms are in the same small
+ // component
+ if (every_phantom_is_in_tiny_cc && all_in_same_component)
+ {
+ std::transform(phantom_node_pair_list.begin(), phantom_node_pair_list.end(),
+ std::back_inserter(snapped_phantoms), use_closed_phantom);
+ }
+ else
+ {
+ std::transform(phantom_node_pair_list.begin(), phantom_node_pair_list.end(),
+ std::back_inserter(snapped_phantoms), fallback_to_big_component);
+ }
+
+ return snapped_phantoms;
+ }
+
+ // Falls back to default_radius for non-set radii
+ std::vector<std::vector<PhantomNodeWithDistance>>
+ GetPhantomNodesInRange(const api::BaseParameters ¶meters,
+ const std::vector<double> radiuses) const
+ {
+ std::vector<std::vector<PhantomNodeWithDistance>> phantom_nodes(
+ parameters.coordinates.size());
+ BOOST_ASSERT(radiuses.size() == parameters.coordinates.size());
+
+ const bool use_hints = !parameters.hints.empty();
+ const bool use_bearings = !parameters.bearings.empty();
+
+ for (const auto i : util::irange<std::size_t>(0, parameters.coordinates.size()))
+ {
+ if (use_hints && parameters.hints[i] &&
+ parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
+ {
+ phantom_nodes[i].push_back(PhantomNodeWithDistance{
+ parameters.hints[i]->phantom,
+ util::coordinate_calculation::haversineDistance(
+ parameters.coordinates[i], parameters.hints[i]->phantom.location),
+ });
+ continue;
+ }
+ if (use_bearings && parameters.bearings[i])
+ {
+ phantom_nodes[i] = facade.NearestPhantomNodesInRange(
+ parameters.coordinates[i], radiuses[i], parameters.bearings[i]->bearing,
+ parameters.bearings[i]->range);
+ }
+ else
+ {
+ phantom_nodes[i] =
+ facade.NearestPhantomNodesInRange(parameters.coordinates[i], radiuses[i]);
+ }
+ }
+
+ return phantom_nodes;
+ }
+
+ std::vector<std::vector<PhantomNodeWithDistance>>
+ GetPhantomNodes(const api::BaseParameters ¶meters, unsigned number_of_results)
+ {
+ std::vector<std::vector<PhantomNodeWithDistance>> phantom_nodes(
+ parameters.coordinates.size());
+
+ const bool use_hints = !parameters.hints.empty();
+ const bool use_bearings = !parameters.bearings.empty();
+ const bool use_radiuses = !parameters.radiuses.empty();
+
+ BOOST_ASSERT(parameters.IsValid());
+ for (const auto i : util::irange<std::size_t>(0, parameters.coordinates.size()))
+ {
+ if (use_hints && parameters.hints[i] &&
+ parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
+ {
+ phantom_nodes[i].push_back(PhantomNodeWithDistance{
+ parameters.hints[i]->phantom,
+ util::coordinate_calculation::haversineDistance(
+ parameters.coordinates[i], parameters.hints[i]->phantom.location),
+ });
+ continue;
+ }
+
+ if (use_bearings && parameters.bearings[i])
+ {
+ if (use_radiuses && parameters.radiuses[i])
+ {
+ phantom_nodes[i] = facade.NearestPhantomNodes(
+ parameters.coordinates[i], number_of_results, *parameters.radiuses[i],
+ parameters.bearings[i]->bearing, parameters.bearings[i]->range);
+ }
+ else
+ {
+ phantom_nodes[i] = facade.NearestPhantomNodes(
+ parameters.coordinates[i], number_of_results,
+ parameters.bearings[i]->bearing, parameters.bearings[i]->range);
+ }
+ }
+ else
+ {
+ if (use_radiuses && parameters.radiuses[i])
+ {
+ phantom_nodes[i] = facade.NearestPhantomNodes(
+ parameters.coordinates[i], number_of_results, *parameters.radiuses[i]);
+ }
+ else
+ {
+ phantom_nodes[i] =
+ facade.NearestPhantomNodes(parameters.coordinates[i], number_of_results);
+ }
+ }
+
+ // we didn't find a fitting node, return error
+ if (phantom_nodes[i].empty())
+ {
+ break;
+ }
+ }
+ return phantom_nodes;
+ }
+
+ std::vector<PhantomNodePair> GetPhantomNodes(const api::BaseParameters ¶meters)
+ {
+ std::vector<PhantomNodePair> phantom_node_pairs(parameters.coordinates.size());
+
+ const bool use_hints = !parameters.hints.empty();
+ const bool use_bearings = !parameters.bearings.empty();
+ const bool use_radiuses = !parameters.radiuses.empty();
+
+ BOOST_ASSERT(parameters.IsValid());
+ for (const auto i : util::irange<std::size_t>(0, parameters.coordinates.size()))
+ {
+ if (use_hints && parameters.hints[i] &&
+ parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
+ {
+ phantom_node_pairs[i].first = parameters.hints[i]->phantom;
+ // we don't set the second one - it will be marked as invalid
+ continue;
+ }
+
+ if (use_bearings && parameters.bearings[i])
+ {
+ if (use_radiuses && parameters.radiuses[i])
+ {
+ phantom_node_pairs[i] =
+ facade.NearestPhantomNodeWithAlternativeFromBigComponent(
+ parameters.coordinates[i], *parameters.radiuses[i],
+ parameters.bearings[i]->bearing, parameters.bearings[i]->range);
+ }
+ else
+ {
+ phantom_node_pairs[i] =
+ facade.NearestPhantomNodeWithAlternativeFromBigComponent(
+ parameters.coordinates[i], parameters.bearings[i]->bearing,
+ parameters.bearings[i]->range);
+ }
+ }
+ else
+ {
+ if (use_radiuses && parameters.radiuses[i])
+ {
+ phantom_node_pairs[i] =
+ facade.NearestPhantomNodeWithAlternativeFromBigComponent(
+ parameters.coordinates[i], *parameters.radiuses[i]);
+ }
+ else
+ {
+ phantom_node_pairs[i] =
+ facade.NearestPhantomNodeWithAlternativeFromBigComponent(
+ parameters.coordinates[i]);
+ }
+ }
+
+ // we didn't find a fitting node, return error
+ if (!phantom_node_pairs[i].first.IsValid(facade.GetNumberOfNodes()))
+ {
+ // TODO document why?
+ phantom_node_pairs.pop_back();
+ break;
+ }
+ BOOST_ASSERT(phantom_node_pairs[i].first.IsValid(facade.GetNumberOfNodes()));
+ BOOST_ASSERT(phantom_node_pairs[i].second.IsValid(facade.GetNumberOfNodes()));
+ }
+ return phantom_node_pairs;
+ }
+};
+}
+}
+}
+
+#endif /* BASE_PLUGIN_HPP */
diff --git a/include/engine/plugins/table.hpp b/include/engine/plugins/table.hpp
new file mode 100644
index 0000000..09f9761
--- /dev/null
+++ b/include/engine/plugins/table.hpp
@@ -0,0 +1,35 @@
+#ifndef TABLE_HPP
+#define TABLE_HPP
+
+#include "engine/plugins/plugin_base.hpp"
+
+#include "engine/api/table_parameters.hpp"
+#include "engine/routing_algorithms/many_to_many.hpp"
+#include "engine/search_engine_data.hpp"
+#include "util/json_container.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+class TablePlugin final : public BasePlugin
+{
+ public:
+ explicit TablePlugin(datafacade::BaseDataFacade &facade,
+ const int max_locations_distance_table);
+
+ Status HandleRequest(const api::TableParameters ¶ms, util::json::Object &result);
+
+ private:
+ SearchEngineData heaps;
+ routing_algorithms::ManyToManyRouting<datafacade::BaseDataFacade> distance_table;
+ int max_locations_distance_table;
+};
+}
+}
+}
+
+#endif // TABLE_HPP
diff --git a/include/engine/plugins/tile.hpp b/include/engine/plugins/tile.hpp
new file mode 100644
index 0000000..77ba357
--- /dev/null
+++ b/include/engine/plugins/tile.hpp
@@ -0,0 +1,35 @@
+#ifndef TILEPLUGIN_HPP
+#define TILEPLUGIN_HPP
+
+#include "engine/plugins/plugin_base.hpp"
+#include "engine/api/tile_parameters.hpp"
+
+#include <string>
+
+/*
+ * This plugin generates Mapbox Vector tiles that show the internal
+ * routing geometry and speed values on all road segments.
+ * You can use this along with a vector-tile viewer, like Mapbox GL,
+ * to display maps that show the exact road network that
+ * OSRM is routing. This is very useful for debugging routing
+ * errors
+ */
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+class TilePlugin final : public BasePlugin
+{
+ public:
+ TilePlugin(datafacade::BaseDataFacade &facade) : BasePlugin(facade) {}
+
+ Status HandleRequest(const api::TileParameters ¶meters, std::string &pbf_buffer);
+};
+}
+}
+}
+
+#endif /* TILEPLUGIN_HPP */
diff --git a/include/engine/plugins/trip.hpp b/include/engine/plugins/trip.hpp
new file mode 100644
index 0000000..cf36884
--- /dev/null
+++ b/include/engine/plugins/trip.hpp
@@ -0,0 +1,54 @@
+#ifndef TRIP_HPP
+#define TRIP_HPP
+
+#include "engine/plugins/plugin_base.hpp"
+
+#include "engine/api/trip_parameters.hpp"
+#include "engine/routing_algorithms/shortest_path.hpp"
+#include "engine/routing_algorithms/many_to_many.hpp"
+
+#include "osrm/json_container.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cstdlib>
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+#include <iterator>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+class TripPlugin final : public BasePlugin
+{
+ private:
+ SearchEngineData heaps;
+ routing_algorithms::ShortestPathRouting<datafacade::BaseDataFacade> shortest_path;
+ routing_algorithms::ManyToManyRouting<datafacade::BaseDataFacade> duration_table;
+ int max_locations_trip;
+
+ InternalRouteResult ComputeRoute(const std::vector<PhantomNode> &phantom_node_list,
+ const api::TripParameters ¶meters,
+ const std::vector<NodeID> &trip);
+
+ public:
+ explicit TripPlugin(datafacade::BaseDataFacade &facade_, const int max_locations_trip_)
+ : BasePlugin(facade_), shortest_path(&facade_, heaps), duration_table(&facade_, heaps),
+ max_locations_trip(max_locations_trip_)
+ {
+ }
+
+ Status HandleRequest(const api::TripParameters ¶meters, util::json::Object &json_result);
+};
+}
+}
+}
+
+#endif // TRIP_HPP
diff --git a/include/engine/plugins/viaroute.hpp b/include/engine/plugins/viaroute.hpp
new file mode 100644
index 0000000..f73dcc6
--- /dev/null
+++ b/include/engine/plugins/viaroute.hpp
@@ -0,0 +1,47 @@
+#ifndef VIA_ROUTE_HPP
+#define VIA_ROUTE_HPP
+
+#include "engine/datafacade/datafacade_base.hpp"
+#include "engine/plugins/plugin_base.hpp"
+#include "engine/api/route_api.hpp"
+
+#include "engine/search_engine_data.hpp"
+#include "engine/routing_algorithms/shortest_path.hpp"
+#include "engine/routing_algorithms/alternative_path.hpp"
+#include "engine/routing_algorithms/direct_shortest_path.hpp"
+#include "util/json_container.hpp"
+
+#include <cstdlib>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+class ViaRoutePlugin final : public BasePlugin
+{
+ private:
+ SearchEngineData heaps;
+ routing_algorithms::ShortestPathRouting<datafacade::BaseDataFacade> shortest_path;
+ routing_algorithms::AlternativeRouting<datafacade::BaseDataFacade> alternative_path;
+ routing_algorithms::DirectShortestPathRouting<datafacade::BaseDataFacade> direct_shortest_path;
+ int max_locations_viaroute;
+
+ public:
+ explicit ViaRoutePlugin(datafacade::BaseDataFacade &facade, int max_locations_viaroute);
+
+ Status HandleRequest(const api::RouteParameters &route_parameters,
+ util::json::Object &json_result);
+};
+}
+}
+}
+
+#endif // VIA_ROUTE_HPP
diff --git a/include/engine/polyline_compressor.hpp b/include/engine/polyline_compressor.hpp
new file mode 100644
index 0000000..4ecf941
--- /dev/null
+++ b/include/engine/polyline_compressor.hpp
@@ -0,0 +1,31 @@
+#ifndef POLYLINECOMPRESSOR_H_
+#define POLYLINECOMPRESSOR_H_
+
+#include "util/coordinate.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace detail
+{
+constexpr double POLYLINE_PRECISION = 1e5;
+constexpr double COORDINATE_TO_POLYLINE = POLYLINE_PRECISION / COORDINATE_PRECISION;
+constexpr double POLYLINE_TO_COORDINATE = COORDINATE_PRECISION / POLYLINE_PRECISION;
+}
+
+using CoordVectorForwardIter = std::vector<util::Coordinate>::const_iterator;
+// Encodes geometry into polyline format.
+// See: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
+std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter end);
+
+// Decodes geometry from polyline format
+// See: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
+std::vector<util::Coordinate> decodePolyline(const std::string &polyline);
+}
+}
+
+#endif /* POLYLINECOMPRESSOR_H_ */
diff --git a/routing_algorithms/alternative_path.hpp b/include/engine/routing_algorithms/alternative_path.hpp
similarity index 86%
rename from routing_algorithms/alternative_path.hpp
rename to include/engine/routing_algorithms/alternative_path.hpp
index 59b772e..8dcc123 100644
--- a/routing_algorithms/alternative_path.hpp
+++ b/include/engine/routing_algorithms/alternative_path.hpp
@@ -1,45 +1,26 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef ALTERNATIVE_PATH_ROUTING_HPP
#define ALTERNATIVE_PATH_ROUTING_HPP
-#include "routing_base.hpp"
-#include "../data_structures/search_engine_data.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/container.hpp"
+#include "engine/routing_algorithms/routing_base.hpp"
+#include "engine/search_engine_data.hpp"
+#include "util/integer_range.hpp"
#include <boost/assert.hpp>
+#include <algorithm>
+#include <iterator>
#include <unordered_map>
#include <unordered_set>
#include <vector>
+namespace osrm
+{
+namespace engine
+{
+namespace routing_algorithms
+{
+
const double VIAPATH_ALPHA = 0.10;
const double VIAPATH_EPSILON = 0.15; // alternative at most 15% longer
const double VIAPATH_GAMMA = 0.75; // alternative shares at most 75% with the shortest.
@@ -103,45 +84,37 @@ class AlternativeRouting final
int upper_bound_to_shortest_path_distance = INVALID_EDGE_WEIGHT;
NodeID middle_node = SPECIAL_NODEID;
const EdgeWeight min_edge_offset =
- std::min(-phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
- -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
+ std::min(phantom_node_pair.source_phantom.forward_segment_id.enabled ? -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset() : 0,
+ phantom_node_pair.source_phantom.reverse_segment_id.enabled ? -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset() : 0);
- if (phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID)
+ if (phantom_node_pair.source_phantom.forward_segment_id.enabled)
{
- // SimpleLogger().Write(logDEBUG) << "fwd-a insert: " <<
- // phantom_node_pair.source_phantom.forward_node_id << ", w: " <<
- // -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset();
- forward_heap1.Insert(phantom_node_pair.source_phantom.forward_node_id,
+ BOOST_ASSERT(phantom_node_pair.source_phantom.forward_segment_id.id != SPECIAL_SEGMENTID);
+ forward_heap1.Insert(phantom_node_pair.source_phantom.forward_segment_id.id,
-phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
- phantom_node_pair.source_phantom.forward_node_id);
+ phantom_node_pair.source_phantom.forward_segment_id.id);
}
- if (phantom_node_pair.source_phantom.reverse_node_id != SPECIAL_NODEID)
+ if (phantom_node_pair.source_phantom.reverse_segment_id.enabled)
{
- // SimpleLogger().Write(logDEBUG) << "fwd-b insert: " <<
- // phantom_node_pair.source_phantom.reverse_node_id << ", w: " <<
- // -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset();
- forward_heap1.Insert(phantom_node_pair.source_phantom.reverse_node_id,
+ BOOST_ASSERT(phantom_node_pair.source_phantom.reverse_segment_id.id != SPECIAL_SEGMENTID);
+ forward_heap1.Insert(phantom_node_pair.source_phantom.reverse_segment_id.id,
-phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
- phantom_node_pair.source_phantom.reverse_node_id);
+ phantom_node_pair.source_phantom.reverse_segment_id.id);
}
- if (phantom_node_pair.target_phantom.forward_node_id != SPECIAL_NODEID)
+ if (phantom_node_pair.target_phantom.forward_segment_id.enabled)
{
- // SimpleLogger().Write(logDEBUG) << "rev-a insert: " <<
- // phantom_node_pair.target_phantom.forward_node_id << ", w: " <<
- // phantom_node_pair.target_phantom.GetForwardWeightPlusOffset();
- reverse_heap1.Insert(phantom_node_pair.target_phantom.forward_node_id,
+ BOOST_ASSERT(phantom_node_pair.target_phantom.forward_segment_id.id != SPECIAL_SEGMENTID);
+ reverse_heap1.Insert(phantom_node_pair.target_phantom.forward_segment_id.id,
phantom_node_pair.target_phantom.GetForwardWeightPlusOffset(),
- phantom_node_pair.target_phantom.forward_node_id);
+ phantom_node_pair.target_phantom.forward_segment_id.id);
}
- if (phantom_node_pair.target_phantom.reverse_node_id != SPECIAL_NODEID)
+ if (phantom_node_pair.target_phantom.reverse_segment_id.enabled)
{
- // SimpleLogger().Write(logDEBUG) << "rev-b insert: " <<
- // phantom_node_pair.target_phantom.reverse_node_id << ", w: " <<
- // phantom_node_pair.target_phantom.GetReverseWeightPlusOffset();
- reverse_heap1.Insert(phantom_node_pair.target_phantom.reverse_node_id,
+ BOOST_ASSERT(phantom_node_pair.target_phantom.reverse_segment_id.id != SPECIAL_SEGMENTID);
+ reverse_heap1.Insert(phantom_node_pair.target_phantom.reverse_segment_id.id,
phantom_node_pair.target_phantom.GetReverseWeightPlusOffset(),
- phantom_node_pair.target_phantom.reverse_node_id);
+ phantom_node_pair.target_phantom.reverse_segment_id.id);
}
// search from s and t till new_min/(1+epsilon) > length_of_shortest_path
@@ -168,13 +141,32 @@ class AlternativeRouting final
return;
}
- osrm::sort_unique_resize(via_node_candidate_list);
+ std::sort(begin(via_node_candidate_list), end(via_node_candidate_list));
+ auto unique_end = std::unique(begin(via_node_candidate_list), end(via_node_candidate_list));
+ via_node_candidate_list.resize(unique_end - begin(via_node_candidate_list));
std::vector<NodeID> packed_forward_path;
std::vector<NodeID> packed_reverse_path;
- super::RetrievePackedPathFromSingleHeap(forward_heap1, middle_node, packed_forward_path);
- super::RetrievePackedPathFromSingleHeap(reverse_heap1, middle_node, packed_reverse_path);
+ const bool path_is_a_loop =
+ upper_bound_to_shortest_path_distance !=
+ forward_heap1.GetKey(middle_node) + reverse_heap1.GetKey(middle_node);
+ if (path_is_a_loop)
+ {
+ // Self Loop
+ BOOST_ASSERT(forward_heap1.GetData(middle_node).parent == middle_node &&
+ reverse_heap1.GetData(middle_node).parent == middle_node);
+ packed_forward_path.push_back(middle_node);
+ packed_forward_path.push_back(middle_node);
+ }
+ else
+ {
+
+ super::RetrievePackedPathFromSingleHeap(forward_heap1, middle_node,
+ packed_forward_path);
+ super::RetrievePackedPathFromSingleHeap(reverse_heap1, middle_node,
+ packed_reverse_path);
+ }
// this set is is used as an indicator if a node is on the shortest path
std::unordered_set<NodeID> nodes_in_path(packed_forward_path.size() +
@@ -231,16 +223,18 @@ class AlternativeRouting final
}
}
- // SimpleLogger().Write(logDEBUG) << "fwd_search_space size: " <<
+ // util::SimpleLogger().Write(logDEBUG) << "fwd_search_space size: " <<
// forward_search_space.size() << ", marked " << approximated_forward_sharing.size() << "
// nodes";
- // SimpleLogger().Write(logDEBUG) << "rev_search_space size: " <<
+ // util::SimpleLogger().Write(logDEBUG) << "rev_search_space size: " <<
// reverse_search_space.size() << ", marked " << approximated_reverse_sharing.size() << "
// nodes";
std::vector<NodeID> preselected_node_list;
for (const NodeID node : via_node_candidate_list)
{
+ if (node == middle_node)
+ continue;
const auto fwd_iterator = approximated_forward_sharing.find(node);
const int fwd_sharing =
(fwd_iterator != approximated_forward_sharing.end()) ? fwd_iterator->second : 0;
@@ -267,10 +261,13 @@ class AlternativeRouting final
}
std::vector<NodeID> &packed_shortest_path = packed_forward_path;
- std::reverse(packed_shortest_path.begin(), packed_shortest_path.end());
- packed_shortest_path.emplace_back(middle_node);
- packed_shortest_path.insert(packed_shortest_path.end(), packed_reverse_path.begin(),
- packed_reverse_path.end());
+ if (!path_is_a_loop)
+ {
+ std::reverse(packed_shortest_path.begin(), packed_shortest_path.end());
+ packed_shortest_path.emplace_back(middle_node);
+ packed_shortest_path.insert(packed_shortest_path.end(), packed_reverse_path.begin(),
+ packed_reverse_path.end());
+ }
std::vector<RankedCandidateNode> ranked_candidates_list;
// prioritizing via nodes for deep inspection
@@ -311,9 +308,9 @@ class AlternativeRouting final
BOOST_ASSERT(!packed_shortest_path.empty());
raw_route_data.unpacked_path_segments.resize(1);
raw_route_data.source_traversed_in_reverse.push_back(
- (packed_shortest_path.front() != phantom_node_pair.source_phantom.forward_node_id));
+ (packed_shortest_path.front() != phantom_node_pair.source_phantom.forward_segment_id.id));
raw_route_data.target_traversed_in_reverse.push_back(
- (packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_node_id));
+ (packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_segment_id.id));
super::UnpackPath(
// -- packed input
@@ -333,9 +330,9 @@ class AlternativeRouting final
s_v_middle, v_t_middle, packed_alternate_path);
raw_route_data.alt_source_traversed_in_reverse.push_back((
- packed_alternate_path.front() != phantom_node_pair.source_phantom.forward_node_id));
+ packed_alternate_path.front() != phantom_node_pair.source_phantom.forward_segment_id.id));
raw_route_data.alt_target_traversed_in_reverse.push_back(
- (packed_alternate_path.back() != phantom_node_pair.target_phantom.forward_node_id));
+ (packed_alternate_path.back() != phantom_node_pair.target_phantom.forward_segment_id.id));
// unpack the alternate path
super::UnpackPath(packed_alternate_path.begin(), packed_alternate_path.end(),
@@ -399,10 +396,13 @@ class AlternativeRouting final
int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
new_reverse_heap.Insert(via_node, 0, via_node);
// compute path <s,..,v> by reusing forward search from s
+ const bool constexpr STALLING_ENABLED = true;
+ const bool constexpr DO_NOT_FORCE_LOOPS = false;
while (!new_reverse_heap.Empty())
{
super::RoutingStep(new_reverse_heap, existing_forward_heap, s_v_middle,
- upper_bound_s_v_path_length, min_edge_offset, false);
+ upper_bound_s_v_path_length, min_edge_offset, false,
+ STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
}
// compute path <v,..,t> by reusing backward search from node t
NodeID v_t_middle = SPECIAL_NODEID;
@@ -411,7 +411,8 @@ class AlternativeRouting final
while (!new_forward_heap.Empty())
{
super::RoutingStep(new_forward_heap, existing_reverse_heap, v_t_middle,
- upper_bound_of_v_t_path_length, min_edge_offset, true);
+ upper_bound_of_v_t_path_length, min_edge_offset, true,
+ STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
}
*real_length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
@@ -430,7 +431,7 @@ class AlternativeRouting final
// First partially unpack s-->v until paths deviate, note length of common path.
const int64_t s_v_min_path_size =
static_cast<int64_t>(std::min(packed_s_v_path.size(), packed_shortest_path.size())) - 1;
- for (const int64_t current_node : osrm::irange<int64_t>(0, s_v_min_path_size))
+ for (const int64_t current_node : util::irange<int64_t>(0, s_v_min_path_size))
{
if (packed_s_v_path[current_node] == packed_shortest_path[current_node] &&
packed_s_v_path[current_node + 1] == packed_shortest_path[current_node + 1])
@@ -546,7 +547,7 @@ class AlternativeRouting final
// //compute forward sharing
// while( (packed_alternate_path[aindex] == packed_shortest_path[aindex]) &&
// (packed_alternate_path[aindex+1] == packed_shortest_path[aindex+1]) ) {
- // // SimpleLogger().Write() << "retrieving edge (" <<
+ // // util::SimpleLogger().Write() << "retrieving edge (" <<
// packed_alternate_path[aindex] << "," << packed_alternate_path[aindex+1] << ")";
// EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_alternate_path[aindex],
// packed_alternate_path[aindex+1]);
@@ -584,7 +585,8 @@ class AlternativeRouting final
const NodeID node = forward_heap.DeleteMin();
const int distance = forward_heap.GetKey(node);
// const NodeID parentnode = forward_heap.GetData(node).parent;
- // SimpleLogger().Write() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled edge ("
+ // util::SimpleLogger().Write() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled
+ // edge ("
// << parentnode << "," << node << "), dist: " << distance;
const int scaled_distance =
@@ -608,12 +610,26 @@ class AlternativeRouting final
{
*middle_node = node;
*upper_bound_to_shortest_path_distance = new_distance;
- // SimpleLogger().Write() << "accepted middle_node " << *middle_node << " at
+ // util::SimpleLogger().Write() << "accepted middle_node " << *middle_node
+ // << " at
// distance " << new_distance;
// } else {
- // SimpleLogger().Write() << "discarded middle_node " << *middle_node << "
+ // util::SimpleLogger().Write() << "discarded middle_node " << *middle_node
+ // << "
// at distance " << new_distance;
}
+ else
+ {
+ // check whether there is a loop present at the node
+ const auto loop_distance = super::GetLoopWeight(node);
+ const int new_distance_with_loop = new_distance + loop_distance;
+ if (loop_distance != INVALID_EDGE_WEIGHT &&
+ new_distance_with_loop <= *upper_bound_to_shortest_path_distance)
+ {
+ *middle_node = node;
+ *upper_bound_to_shortest_path_distance = loop_distance;
+ }
+ }
}
}
@@ -669,10 +685,13 @@ class AlternativeRouting final
int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
// compute path <s,..,v> by reusing forward search from s
new_reverse_heap.Insert(candidate.node, 0, candidate.node);
+ const bool constexpr STALLING_ENABLED = true;
+ const bool constexpr DO_NOT_FORCE_LOOPS = false;
while (new_reverse_heap.Size() > 0)
{
super::RoutingStep(new_reverse_heap, existing_forward_heap, *s_v_middle,
- upper_bound_s_v_path_length, min_edge_offset, false);
+ upper_bound_s_v_path_length, min_edge_offset, false,
+ STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
}
if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_length)
@@ -687,7 +706,8 @@ class AlternativeRouting final
while (new_forward_heap.Size() > 0)
{
super::RoutingStep(new_forward_heap, existing_reverse_heap, *v_t_middle,
- upper_bound_of_v_t_path_length, min_edge_offset, true);
+ upper_bound_of_v_t_path_length, min_edge_offset, true,
+ STALLING_ENABLED, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
}
if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_length)
@@ -855,16 +875,21 @@ class AlternativeRouting final
if (!forward_heap3.Empty())
{
super::RoutingStep(forward_heap3, reverse_heap3, middle, upper_bound,
- min_edge_offset, true);
+ min_edge_offset, true, STALLING_ENABLED, DO_NOT_FORCE_LOOPS,
+ DO_NOT_FORCE_LOOPS);
}
if (!reverse_heap3.Empty())
{
super::RoutingStep(reverse_heap3, forward_heap3, middle, upper_bound,
- min_edge_offset, false);
+ min_edge_offset, false, STALLING_ENABLED, DO_NOT_FORCE_LOOPS,
+ DO_NOT_FORCE_LOOPS);
}
}
return (upper_bound <= t_test_path_length);
}
};
+}
+}
+}
#endif /* ALTERNATIVE_PATH_ROUTING_HPP */
diff --git a/routing_algorithms/direct_shortest_path.hpp b/include/engine/routing_algorithms/direct_shortest_path.hpp
similarity index 54%
rename from routing_algorithms/direct_shortest_path.hpp
rename to include/engine/routing_algorithms/direct_shortest_path.hpp
index 2237d68..970949e 100644
--- a/routing_algorithms/direct_shortest_path.hpp
+++ b/include/engine/routing_algorithms/direct_shortest_path.hpp
@@ -1,41 +1,21 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef DIRECT_SHORTEST_PATH_HPP
#define DIRECT_SHORTEST_PATH_HPP
#include <boost/assert.hpp>
#include <iterator>
-#include "routing_base.hpp"
-#include "../data_structures/search_engine_data.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/timing_util.hpp"
-#include "../typedefs.h"
+#include "engine/routing_algorithms/routing_base.hpp"
+#include "engine/search_engine_data.hpp"
+#include "util/integer_range.hpp"
+#include "util/timing_util.hpp"
+#include "util/typedefs.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+namespace routing_algorithms
+{
/// This is a striped down version of the general shortest path algorithm.
/// The general algorithm always computes two queries for each leg. This is only
@@ -60,17 +40,15 @@ class DirectShortestPathRouting final
~DirectShortestPathRouting() {}
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
- const std::vector<bool> &uturn_indicators,
InternalRouteResult &raw_route_data) const
{
- (void)uturn_indicators; // unused
-
// Get distance to next pair of target nodes.
BOOST_ASSERT_MSG(1 == phantom_nodes_vector.size(),
- "Direct Shortest Path Query only accepts a single source and target pair. Multiple ones have been specified.");
- const auto& phantom_node_pair = phantom_nodes_vector.front();
- const auto& source_phantom = phantom_node_pair.source_phantom;
- const auto& target_phantom = phantom_node_pair.target_phantom;
+ "Direct Shortest Path Query only accepts a single source and target pair. "
+ "Multiple ones have been specified.");
+ const auto &phantom_node_pair = phantom_nodes_vector.front();
+ const auto &source_phantom = phantom_node_pair.source_phantom;
+ const auto &target_phantom = phantom_node_pair.target_phantom;
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
super::facade->GetNumberOfNodes());
@@ -79,39 +57,42 @@ class DirectShortestPathRouting final
forward_heap.Clear();
reverse_heap.Clear();
- BOOST_ASSERT(source_phantom.is_valid());
- BOOST_ASSERT(target_phantom.is_valid());
+ BOOST_ASSERT(source_phantom.IsValid());
+ BOOST_ASSERT(target_phantom.IsValid());
- if (source_phantom.forward_node_id != SPECIAL_NODEID)
+ if (source_phantom.forward_segment_id.enabled)
{
- forward_heap.Insert(source_phantom.forward_node_id,
+ forward_heap.Insert(source_phantom.forward_segment_id.id,
-source_phantom.GetForwardWeightPlusOffset(),
- source_phantom.forward_node_id);
+ source_phantom.forward_segment_id.id);
}
- if (source_phantom.reverse_node_id != SPECIAL_NODEID)
+ if (source_phantom.reverse_segment_id.enabled)
{
- forward_heap.Insert(source_phantom.reverse_node_id,
+ forward_heap.Insert(source_phantom.reverse_segment_id.id,
-source_phantom.GetReverseWeightPlusOffset(),
- source_phantom.reverse_node_id);
+ source_phantom.reverse_segment_id.id);
}
- if (target_phantom.forward_node_id != SPECIAL_NODEID)
+ if (target_phantom.forward_segment_id.enabled)
{
- reverse_heap.Insert(target_phantom.forward_node_id,
+ reverse_heap.Insert(target_phantom.forward_segment_id.id,
target_phantom.GetForwardWeightPlusOffset(),
- target_phantom.forward_node_id);
+ target_phantom.forward_segment_id.id);
}
- if (target_phantom.reverse_node_id != SPECIAL_NODEID)
+ if (target_phantom.reverse_segment_id.enabled)
{
- reverse_heap.Insert(target_phantom.reverse_node_id,
+ reverse_heap.Insert(target_phantom.reverse_segment_id.id,
target_phantom.GetReverseWeightPlusOffset(),
- target_phantom.reverse_node_id);
+ target_phantom.reverse_segment_id.id);
}
int distance = INVALID_EDGE_WEIGHT;
std::vector<NodeID> packed_leg;
+ const bool constexpr DO_NOT_FORCE_LOOPS =
+ false; // prevents forcing of loops, since offsets are set correctly
+
if (super::facade->GetCoreSize() > 0)
{
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
@@ -121,13 +102,13 @@ class DirectShortestPathRouting final
forward_core_heap.Clear();
reverse_core_heap.Clear();
-
super::SearchWithCore(forward_heap, reverse_heap, forward_core_heap, reverse_core_heap,
- distance, packed_leg);
+ distance, packed_leg, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS);
}
else
{
- super::Search(forward_heap, reverse_heap, distance, packed_leg);
+ super::Search(forward_heap, reverse_heap, distance, packed_leg, DO_NOT_FORCE_LOOPS,
+ DO_NOT_FORCE_LOOPS);
}
// No path found for both target nodes?
@@ -143,13 +124,16 @@ class DirectShortestPathRouting final
raw_route_data.shortest_path_length = distance;
raw_route_data.unpacked_path_segments.resize(1);
raw_route_data.source_traversed_in_reverse.push_back(
- (packed_leg.front() != phantom_node_pair.source_phantom.forward_node_id));
+ (packed_leg.front() != phantom_node_pair.source_phantom.forward_segment_id.id));
raw_route_data.target_traversed_in_reverse.push_back(
- (packed_leg.back() != phantom_node_pair.target_phantom.forward_node_id));
-
- super::UnpackPath(packed_leg.begin(), packed_leg.end(), phantom_node_pair, raw_route_data.unpacked_path_segments.front());
+ (packed_leg.back() != phantom_node_pair.target_phantom.forward_segment_id.id));
+ super::UnpackPath(packed_leg.begin(), packed_leg.end(), phantom_node_pair,
+ raw_route_data.unpacked_path_segments.front());
}
};
+}
+}
+}
#endif /* DIRECT_SHORTEST_PATH_HPP */
diff --git a/routing_algorithms/many_to_many.hpp b/include/engine/routing_algorithms/many_to_many.hpp
similarity index 59%
rename from routing_algorithms/many_to_many.hpp
rename to include/engine/routing_algorithms/many_to_many.hpp
index c5dfb7c..e09a91d 100644
--- a/routing_algorithms/many_to_many.hpp
+++ b/include/engine/routing_algorithms/many_to_many.hpp
@@ -1,36 +1,9 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef MANY_TO_MANY_ROUTING_HPP
#define MANY_TO_MANY_ROUTING_HPP
-#include "routing_base.hpp"
-#include "../data_structures/search_engine_data.hpp"
-#include "../typedefs.h"
+#include "engine/routing_algorithms/routing_base.hpp"
+#include "engine/search_engine_data.hpp"
+#include "util/typedefs.hpp"
#include <boost/assert.hpp>
@@ -39,6 +12,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unordered_map>
#include <vector>
+namespace osrm
+{
+namespace engine
+{
+namespace routing_algorithms
+{
+
template <class DataFacadeT>
class ManyToManyRouting final
: public BasicRoutingInterface<DataFacadeT, ManyToManyRouting<DataFacadeT>>
@@ -56,6 +36,8 @@ class ManyToManyRouting final
{
}
};
+
+ // FIXME This should be replaced by an std::unordered_multimap, though this needs benchmarking
using SearchSpaceWithBuckets = std::unordered_map<NodeID, std::vector<NodeBucket>>;
public:
@@ -64,16 +46,17 @@ class ManyToManyRouting final
{
}
- ~ManyToManyRouting() {}
-
- std::shared_ptr<std::vector<EdgeWeight>>
- operator()(const std::vector<PhantomNode> &phantom_sources_array, const std::vector<PhantomNode> &phantom_targets_array) const
+ std::vector<EdgeWeight> operator()(const std::vector<PhantomNode> &phantom_nodes,
+ const std::vector<std::size_t> &source_indices,
+ const std::vector<std::size_t> &target_indices) const
{
- const auto number_of_sources = phantom_sources_array.size();
- const auto number_of_targets = phantom_targets_array.size();
- std::shared_ptr<std::vector<EdgeWeight>> result_table =
- std::make_shared<std::vector<EdgeWeight>>(number_of_targets * number_of_sources,
- std::numeric_limits<EdgeWeight>::max());
+ const auto number_of_sources =
+ source_indices.empty() ? phantom_nodes.size() : source_indices.size();
+ const auto number_of_targets =
+ target_indices.empty() ? phantom_nodes.size() : target_indices.size();
+ const auto number_of_entries = number_of_sources * number_of_targets;
+ std::vector<EdgeWeight> result_table(number_of_entries,
+ std::numeric_limits<EdgeWeight>::max());
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
super::facade->GetNumberOfNodes());
@@ -82,71 +65,102 @@ class ManyToManyRouting final
SearchSpaceWithBuckets search_space_with_buckets;
- unsigned target_id = 0;
- for (const auto &phantom : phantom_targets_array)
+ unsigned column_idx = 0;
+ const auto search_target_phantom = [&](const PhantomNode &phantom)
{
query_heap.Clear();
// insert target(s) at distance 0
- if (SPECIAL_NODEID != phantom.forward_node_id)
+ if (phantom.forward_segment_id.enabled)
{
- query_heap.Insert(phantom.forward_node_id,
+ query_heap.Insert(phantom.forward_segment_id.id,
phantom.GetForwardWeightPlusOffset(),
- phantom.forward_node_id);
+ phantom.forward_segment_id.id);
}
- if (SPECIAL_NODEID != phantom.reverse_node_id)
+ if (phantom.reverse_segment_id.enabled)
{
- query_heap.Insert(phantom.reverse_node_id,
+ query_heap.Insert(phantom.reverse_segment_id.id,
phantom.GetReverseWeightPlusOffset(),
- phantom.reverse_node_id);
+ phantom.reverse_segment_id.id);
}
// explore search space
while (!query_heap.Empty())
{
- BackwardRoutingStep(target_id, query_heap, search_space_with_buckets);
+ BackwardRoutingStep(column_idx, query_heap, search_space_with_buckets);
}
- ++target_id;
- }
+ ++column_idx;
+ };
// for each source do forward search
- unsigned source_id = 0;
- for (const auto &phantom : phantom_sources_array)
+ unsigned row_idx = 0;
+ const auto search_source_phantom = [&](const PhantomNode &phantom)
{
query_heap.Clear();
// insert target(s) at distance 0
- if (SPECIAL_NODEID != phantom.forward_node_id)
+ if (phantom.forward_segment_id.enabled)
{
- query_heap.Insert(phantom.forward_node_id,
- -phantom.GetForwardWeightPlusOffset(),
- phantom.forward_node_id);
+ query_heap.Insert(phantom.forward_segment_id.id,
+ -phantom.GetForwardWeightPlusOffset(),
+ phantom.forward_segment_id.id);
}
- if (SPECIAL_NODEID != phantom.reverse_node_id)
+ if (phantom.reverse_segment_id.enabled)
{
- query_heap.Insert(phantom.reverse_node_id,
- -phantom.GetReverseWeightPlusOffset(),
- phantom.reverse_node_id);
+ query_heap.Insert(phantom.reverse_segment_id.id,
+ -phantom.GetReverseWeightPlusOffset(),
+ phantom.reverse_segment_id.id);
}
// explore search space
while (!query_heap.Empty())
{
- ForwardRoutingStep(source_id, number_of_targets, query_heap,
+ ForwardRoutingStep(row_idx, number_of_targets, query_heap,
search_space_with_buckets, result_table);
}
+ ++row_idx;
+ };
- ++source_id;
+ if (target_indices.empty())
+ {
+ for (const auto &phantom : phantom_nodes)
+ {
+ search_target_phantom(phantom);
+ }
}
- // BOOST_ASSERT(source_id == target_id);
+ else
+ {
+ for (const auto index : target_indices)
+ {
+ const auto &phantom = phantom_nodes[index];
+ search_target_phantom(phantom);
+ }
+ }
+
+ if (source_indices.empty())
+ {
+ for (const auto &phantom : phantom_nodes)
+ {
+ search_source_phantom(phantom);
+ }
+ }
+ else
+ {
+ for (const auto index : source_indices)
+ {
+ const auto &phantom = phantom_nodes[index];
+ search_source_phantom(phantom);
+ }
+ }
+
return result_table;
}
- void ForwardRoutingStep(const unsigned source_id,
+ void ForwardRoutingStep(const unsigned row_idx,
const unsigned number_of_targets,
QueryHeap &query_heap,
const SearchSpaceWithBuckets &search_space_with_buckets,
- std::shared_ptr<std::vector<EdgeWeight>> result_table) const
+ std::vector<EdgeWeight> &result_table) const
{
const NodeID node = query_heap.DeleteMin();
const int source_distance = query_heap.GetKey(node);
@@ -160,16 +174,23 @@ class ManyToManyRouting final
for (const NodeBucket ¤t_bucket : bucket_list)
{
// get target id from bucket entry
- const unsigned target_id = current_bucket.target_id;
+ const unsigned column_idx = current_bucket.target_id;
const int target_distance = current_bucket.distance;
- const EdgeWeight current_distance =
- (*result_table)[source_id * number_of_targets + target_id];
+ auto ¤t_distance = result_table[row_idx * number_of_targets + column_idx];
// check if new distance is better
const EdgeWeight new_distance = source_distance + target_distance;
- if (new_distance >= 0 && new_distance < current_distance)
+ if (new_distance < 0)
+ {
+ const EdgeWeight loop_weight = super::GetLoopWeight(node);
+ const int new_distance_with_loop = new_distance + loop_weight;
+ if (loop_weight != INVALID_EDGE_WEIGHT && new_distance_with_loop >= 0)
+ {
+ current_distance = std::min(current_distance, new_distance_with_loop);
+ }
+ }
+ else if (new_distance < current_distance)
{
- (*result_table)[source_id * number_of_targets + target_id] =
- (source_distance + target_distance);
+ result_table[row_idx * number_of_targets + column_idx] = new_distance;
}
}
}
@@ -180,7 +201,7 @@ class ManyToManyRouting final
RelaxOutgoingEdges<true>(node, source_distance, query_heap);
}
- void BackwardRoutingStep(const unsigned target_id,
+ void BackwardRoutingStep(const unsigned column_idx,
QueryHeap &query_heap,
SearchSpaceWithBuckets &search_space_with_buckets) const
{
@@ -188,7 +209,7 @@ class ManyToManyRouting final
const int target_distance = query_heap.GetKey(node);
// store settled nodes in search space bucket
- search_space_with_buckets[node].emplace_back(target_id, target_distance);
+ search_space_with_buckets[node].emplace_back(column_idx, target_distance);
if (StallAtNode<false>(node, target_distance, query_heap))
{
@@ -256,4 +277,8 @@ class ManyToManyRouting final
return false;
}
};
+}
+}
+}
+
#endif
diff --git a/routing_algorithms/map_matching.hpp b/include/engine/routing_algorithms/map_matching.hpp
similarity index 55%
rename from routing_algorithms/map_matching.hpp
rename to include/engine/routing_algorithms/map_matching.hpp
index 430682d..7d8b04e 100644
--- a/routing_algorithms/map_matching.hpp
+++ b/include/engine/routing_algorithms/map_matching.hpp
@@ -1,39 +1,15 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef MAP_MATCHING_HPP
#define MAP_MATCHING_HPP
-#include "routing_base.hpp"
+#include "engine/routing_algorithms/routing_base.hpp"
-#include "../algorithms/coordinate_calculation.hpp"
-#include "../data_structures/hidden_markov_model.hpp"
-#include "../util/json_logger.hpp"
-#include "../util/matching_debug_info.hpp"
+#include "engine/map_matching/hidden_markov_model.hpp"
+#include "engine/map_matching/sub_matching.hpp"
+#include "engine/map_matching/matching_confidence.hpp"
+
+#include "util/coordinate_calculation.hpp"
+#include "util/json_logger.hpp"
+#include "util/for_each_pair.hpp"
#include <cstddef>
@@ -46,28 +22,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace osrm
{
-namespace matching
+namespace engine
{
-
-struct SubMatching
+namespace routing_algorithms
{
- std::vector<PhantomNode> nodes;
- std::vector<unsigned> indices;
- double length;
- double confidence;
-};
using CandidateList = std::vector<PhantomNodeWithDistance>;
using CandidateLists = std::vector<CandidateList>;
-using HMM = HiddenMarkovModel<CandidateLists>;
-using SubMatchingList = std::vector<SubMatching>;
+using HMM = map_matching::HiddenMarkovModel<CandidateLists>;
+using SubMatchingList = std::vector<map_matching::SubMatching>;
constexpr static const unsigned MAX_BROKEN_STATES = 10;
-
constexpr static const double MAX_SPEED = 180 / 3.6; // 180km -> m/s
-constexpr static const unsigned SUSPICIOUS_DISTANCE_DELTA = 100;
-}
-}
+static const constexpr double MATCHING_BETA = 10;
+constexpr static const double MAX_DISTANCE_DELTA = 2000.;
// implements a hidden markov model map matching algorithm
template <class DataFacadeT>
@@ -76,8 +44,11 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
using super = BasicRoutingInterface<DataFacadeT, MapMatching<DataFacadeT>>;
using QueryHeap = SearchEngineData::QueryHeap;
SearchEngineData &engine_working_data;
+ map_matching::EmissionLogProbability default_emission_log_probability;
+ map_matching::TransitionLogProbability transition_log_probability;
+ map_matching::MatchingConfidence confidence;
- unsigned GetMedianSampleTime(const std::vector<unsigned>& timestamps) const
+ unsigned GetMedianSampleTime(const std::vector<unsigned> ×tamps) const
{
BOOST_ASSERT(timestamps.size() > 1);
@@ -87,30 +58,36 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
// don't use first element of sample_times -> will not be a difference.
auto first_elem = std::next(sample_times.begin());
- auto median = first_elem + std::distance(first_elem, sample_times.end())/2;
+ auto median = first_elem + std::distance(first_elem, sample_times.end()) / 2;
std::nth_element(first_elem, median, sample_times.end());
return *median;
}
public:
- MapMatching(DataFacadeT *facade, SearchEngineData &engine_working_data)
- : super(facade), engine_working_data(engine_working_data)
+ MapMatching(DataFacadeT *facade,
+ SearchEngineData &engine_working_data,
+ const double default_gps_precision)
+ : super(facade), engine_working_data(engine_working_data),
+ default_emission_log_probability(default_gps_precision),
+ transition_log_probability(MATCHING_BETA)
{
}
- void operator()(const osrm::matching::CandidateLists &candidates_list,
- const std::vector<FixedPointCoordinate> &trace_coordinates,
- const std::vector<unsigned> &trace_timestamps,
- const double matching_beta,
- const double gps_precision,
- osrm::matching::SubMatchingList &sub_matchings) const
+ SubMatchingList
+ operator()(const CandidateLists &candidates_list,
+ const std::vector<util::Coordinate> &trace_coordinates,
+ const std::vector<unsigned> &trace_timestamps,
+ const std::vector<boost::optional<double>> &trace_gps_precision) const
{
+ SubMatchingList sub_matchings;
+
BOOST_ASSERT(candidates_list.size() == trace_coordinates.size());
BOOST_ASSERT(candidates_list.size() > 1);
const bool use_timestamps = trace_timestamps.size() > 1;
- const auto median_sample_time = [&]() {
+ const auto median_sample_time = [&]
+ {
if (use_timestamps)
{
return std::max(1u, GetMedianSampleTime(trace_timestamps));
@@ -120,40 +97,81 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
return 1u;
}
}();
- const auto max_broken_time = median_sample_time * osrm::matching::MAX_BROKEN_STATES;
- const auto max_distance_delta = [&]() {
+ const auto max_broken_time = median_sample_time * MAX_BROKEN_STATES;
+ const auto max_distance_delta = [&]
+ {
if (use_timestamps)
{
- return median_sample_time * osrm::matching::MAX_SPEED;
+ return median_sample_time * MAX_SPEED;
}
else
{
- return std::numeric_limits<double>::max();
+ return MAX_DISTANCE_DELTA;
}
}();
- // TODO replace default values with table lookup based on sampling frequency
- EmissionLogProbability emission_log_probability(gps_precision);
- TransitionLogProbability transition_log_probability(matching_beta);
+ std::vector<std::vector<double>> emission_log_probabilities(trace_coordinates.size());
+ if (trace_gps_precision.empty())
+ {
+ for (auto t = 0UL; t < candidates_list.size(); ++t)
+ {
+ emission_log_probabilities[t].resize(candidates_list[t].size());
+ std::transform(candidates_list[t].begin(), candidates_list[t].end(),
+ emission_log_probabilities[t].begin(),
+ [this](const PhantomNodeWithDistance &candidate)
+ {
+ return default_emission_log_probability(candidate.distance);
+ });
+ }
+ }
+ else
+ {
+ for (auto t = 0UL; t < candidates_list.size(); ++t)
+ {
+ emission_log_probabilities[t].resize(candidates_list[t].size());
+ if (trace_gps_precision[t])
+ {
+ map_matching::EmissionLogProbability emission_log_probability(
+ *trace_gps_precision[t]);
+ std::transform(
+ candidates_list[t].begin(), candidates_list[t].end(),
+ emission_log_probabilities[t].begin(),
+ [&emission_log_probability](const PhantomNodeWithDistance &candidate)
+ {
+ return emission_log_probability(candidate.distance);
+ });
+ }
+ else
+ {
+ std::transform(candidates_list[t].begin(), candidates_list[t].end(),
+ emission_log_probabilities[t].begin(),
+ [this](const PhantomNodeWithDistance &candidate)
+ {
+ return default_emission_log_probability(candidate.distance);
+ });
+ }
+ }
+ }
- osrm::matching::HMM model(candidates_list, emission_log_probability);
+ HMM model(candidates_list, emission_log_probabilities);
std::size_t initial_timestamp = model.initialize(0);
- if (initial_timestamp == osrm::matching::INVALID_STATE)
+ if (initial_timestamp == map_matching::INVALID_STATE)
{
- return;
+ return sub_matchings;
}
- MatchingDebugInfo matching_debug(osrm::json::Logger::get());
- matching_debug.initialize(candidates_list);
-
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
super::facade->GetNumberOfNodes());
+ engine_working_data.InitializeOrClearSecondThreadLocalStorage(
+ super::facade->GetNumberOfNodes());
QueryHeap &forward_heap = *(engine_working_data.forward_heap_1);
QueryHeap &reverse_heap = *(engine_working_data.reverse_heap_1);
+ QueryHeap &forward_core_heap = *(engine_working_data.forward_heap_2);
+ QueryHeap &reverse_core_heap = *(engine_working_data.reverse_heap_2);
- std::size_t breakage_begin = osrm::matching::INVALID_STATE;
+ std::size_t breakage_begin = map_matching::INVALID_STATE;
std::vector<std::size_t> split_points;
std::vector<std::size_t> prev_unbroken_timestamps;
prev_unbroken_timestamps.reserve(candidates_list.size());
@@ -173,17 +191,17 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
}
else
{
- trace_split = trace_split || (t - prev_unbroken_timestamps.back() >
- osrm::matching::MAX_BROKEN_STATES);
+ trace_split =
+ trace_split || (t - prev_unbroken_timestamps.back() > MAX_BROKEN_STATES);
}
if (trace_split)
{
std::size_t split_index = t;
- if (breakage_begin != osrm::matching::INVALID_STATE)
+ if (breakage_begin != map_matching::INVALID_STATE)
{
split_index = breakage_begin;
- breakage_begin = osrm::matching::INVALID_STATE;
+ breakage_begin = map_matching::INVALID_STATE;
}
split_points.push_back(split_index);
@@ -191,7 +209,7 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
model.clear(split_index);
std::size_t new_start = model.initialize(split_index);
// no new start was found -> stop viterbi calculation
- if (new_start == osrm::matching::INVALID_STATE)
+ if (new_start == map_matching::INVALID_STATE)
{
break;
}
@@ -214,28 +232,28 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
auto ¤t_viterbi = model.viterbi[t];
auto ¤t_pruned = model.pruned[t];
- auto ¤t_suspicious = model.suspicious[t];
auto ¤t_parents = model.parents[t];
- auto ¤t_lengths = model.path_lengths[t];
+ auto ¤t_lengths = model.path_distances[t];
const auto ¤t_timestamps_list = candidates_list[t];
const auto ¤t_coordinate = trace_coordinates[t];
- const auto haversine_distance = coordinate_calculation::haversine_distance(prev_coordinate, current_coordinate);
+ const auto haversine_distance = util::coordinate_calculation::haversineDistance(
+ prev_coordinate, current_coordinate);
+ // assumes minumum of 0.1 m/s
+ const int duration_uppder_bound =
+ ((haversine_distance + max_distance_delta) * 0.25) * 10;
// compute d_t for this timestamp and the next one
- for (const auto s : osrm::irange<std::size_t>(0u, prev_viterbi.size()))
+ for (const auto s : util::irange<std::size_t>(0u, prev_viterbi.size()))
{
if (prev_pruned[s])
{
continue;
}
- for (const auto s_prime : osrm::irange<std::size_t>(0u, current_viterbi.size()))
+ for (const auto s_prime : util::irange<std::size_t>(0u, current_viterbi.size()))
{
- // how likely is candidate s_prime at time t to be emitted?
- // FIXME this can be pre-computed
- const double emission_pr =
- emission_log_probability(candidates_list[t][s_prime].distance);
+ const double emission_pr = emission_log_probabilities[t][s_prime];
double new_value = prev_viterbi[s] + emission_pr;
if (current_viterbi[s_prime] > new_value)
{
@@ -245,11 +263,25 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
forward_heap.Clear();
reverse_heap.Clear();
- // get distance diff between loc1/2 and locs/s_prime
- const auto network_distance = super::get_network_distance(
- forward_heap, reverse_heap, prev_unbroken_timestamps_list[s].phantom_node,
- current_timestamps_list[s_prime].phantom_node);
+ double network_distance;
+ if (super::facade->GetCoreSize() > 0)
+ {
+ forward_core_heap.Clear();
+ reverse_core_heap.Clear();
+ network_distance = super::GetNetworkDistanceWithCore(
+ forward_heap, reverse_heap, forward_core_heap, reverse_core_heap,
+ prev_unbroken_timestamps_list[s].phantom_node,
+ current_timestamps_list[s_prime].phantom_node, duration_uppder_bound);
+ }
+ else
+ {
+ network_distance = super::GetNetworkDistance(
+ forward_heap, reverse_heap,
+ prev_unbroken_timestamps_list[s].phantom_node,
+ current_timestamps_list[s_prime].phantom_node);
+ }
+ // get distance diff between loc1/2 and locs/s_prime
const auto d_t = std::abs(network_distance - haversine_distance);
// very low probability transition -> prune
@@ -261,17 +293,12 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
const double transition_pr = transition_log_probability(d_t);
new_value += transition_pr;
- matching_debug.add_transition_info(prev_unbroken_timestamp, t, s, s_prime,
- prev_viterbi[s], emission_pr, transition_pr,
- network_distance, haversine_distance);
-
if (new_value > current_viterbi[s_prime])
{
current_viterbi[s_prime] = new_value;
current_parents[s_prime] = std::make_pair(prev_unbroken_timestamp, s);
current_lengths[s_prime] = network_distance;
current_pruned[s_prime] = false;
- current_suspicious[s_prime] = d_t > osrm::matching::SUSPICIOUS_DISTANCE_DELTA;
model.breakage[t] = false;
}
}
@@ -295,8 +322,6 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
}
}
- matching_debug.set_viterbi(model.viterbi, model.pruned, model.suspicious);
-
if (!prev_unbroken_timestamps.empty())
{
split_points.push_back(prev_unbroken_timestamps.back() + 1);
@@ -305,7 +330,7 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
std::size_t sub_matching_begin = initial_timestamp;
for (const auto sub_matching_end : split_points)
{
- osrm::matching::SubMatching matching;
+ map_matching::SubMatching matching;
std::size_t parent_timestamp_index = sub_matching_end - 1;
while (parent_timestamp_index >= sub_matching_begin &&
@@ -313,8 +338,7 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
{
--parent_timestamp_index;
}
- while (sub_matching_begin < sub_matching_end &&
- model.breakage[sub_matching_begin])
+ while (sub_matching_begin < sub_matching_end && model.breakage[sub_matching_begin])
{
++sub_matching_begin;
}
@@ -359,27 +383,41 @@ class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<
continue;
}
- matching.length = 0.0f;
- matching.nodes.resize(reconstructed_indices.size());
- matching.indices.resize(reconstructed_indices.size());
- for (const auto i : osrm::irange<std::size_t>(0u, reconstructed_indices.size()))
+ auto matching_distance = 0.0;
+ auto trace_distance = 0.0;
+ matching.nodes.reserve(reconstructed_indices.size());
+ matching.indices.reserve(reconstructed_indices.size());
+ for (const auto idx : reconstructed_indices)
{
- const auto timestamp_index = reconstructed_indices[i].first;
- const auto location_index = reconstructed_indices[i].second;
-
- matching.indices[i] = timestamp_index;
- matching.nodes[i] = candidates_list[timestamp_index][location_index].phantom_node;
- matching.length += model.path_lengths[timestamp_index][location_index];
+ const auto timestamp_index = idx.first;
+ const auto location_index = idx.second;
- matching_debug.add_chosen(timestamp_index, location_index);
+ matching.indices.push_back(timestamp_index);
+ matching.nodes.push_back(
+ candidates_list[timestamp_index][location_index].phantom_node);
+ matching_distance += model.path_distances[timestamp_index][location_index];
}
+ util::for_each_pair(
+ reconstructed_indices, [&trace_distance, &trace_coordinates](
+ const std::pair<std::size_t, std::size_t> &prev,
+ const std::pair<std::size_t, std::size_t> &curr)
+ {
+ trace_distance += util::coordinate_calculation::haversineDistance(
+ trace_coordinates[prev.first], trace_coordinates[curr.first]);
+ });
+
+ matching.confidence = confidence(trace_distance, matching_distance);
sub_matchings.push_back(matching);
sub_matching_begin = sub_matching_end;
}
- matching_debug.add_breakage(model.breakage);
+
+ return sub_matchings;
}
};
+}
+}
+}
//[1] "Hidden Markov Map Matching Through Noise and Sparseness"; P. Newson and J. Krumm; 2009; ACM
// GIS
diff --git a/include/engine/routing_algorithms/routing_base.hpp b/include/engine/routing_algorithms/routing_base.hpp
new file mode 100644
index 0000000..0a9b1f2
--- /dev/null
+++ b/include/engine/routing_algorithms/routing_base.hpp
@@ -0,0 +1,906 @@
+#ifndef ROUTING_BASE_HPP
+#define ROUTING_BASE_HPP
+
+#include "util/coordinate_calculation.hpp"
+#include "engine/internal_route_result.hpp"
+#include "engine/search_engine_data.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+#include "util/typedefs.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cstddef>
+#include <cstdint>
+
+#include <algorithm>
+#include <iterator>
+#include <utility>
+#include <vector>
+#include <stack>
+#include <numeric>
+
+namespace osrm
+{
+namespace engine
+{
+
+namespace routing_algorithms
+{
+
+template <class DataFacadeT, class Derived> class BasicRoutingInterface
+{
+ private:
+ using EdgeData = typename DataFacadeT::EdgeData;
+
+ protected:
+ DataFacadeT *facade;
+
+ public:
+ explicit BasicRoutingInterface(DataFacadeT *facade) : facade(facade) {}
+ ~BasicRoutingInterface() {}
+
+ BasicRoutingInterface(const BasicRoutingInterface &) = delete;
+ BasicRoutingInterface &operator=(const BasicRoutingInterface &) = delete;
+
+ /*
+ min_edge_offset is needed in case we use multiple
+ nodes as start/target nodes with different (even negative) offsets.
+ In that case the termination criterion is not correct
+ anymore.
+
+ Example:
+ forward heap: a(-100), b(0),
+ reverse heap: c(0), d(100)
+
+ a --- d
+ \ /
+ / \
+ b --- c
+
+ This is equivalent to running a bi-directional Dijkstra on the following graph:
+
+ a --- d
+ / \ / \
+ y x z
+ \ / \ /
+ b --- c
+
+ The graph is constructed by inserting nodes y and z that are connected to the initial nodes
+ using edges (y, a) with weight -100, (y, b) with weight 0 and,
+ (d, z) with weight 100, (c, z) with weight 0 corresponding.
+ Since we are dealing with a graph that contains _negative_ edges,
+ we need to add an offset to the termination criterion.
+ */
+ void RoutingStep(SearchEngineData::QueryHeap &forward_heap,
+ SearchEngineData::QueryHeap &reverse_heap,
+ NodeID &middle_node_id,
+ std::int32_t &upper_bound,
+ std::int32_t min_edge_offset,
+ const bool forward_direction,
+ const bool stalling,
+ const bool force_loop_forward,
+ const bool force_loop_reverse) const
+ {
+ const NodeID node = forward_heap.DeleteMin();
+ const std::int32_t distance = forward_heap.GetKey(node);
+
+ if (reverse_heap.WasInserted(node))
+ {
+ const std::int32_t new_distance = reverse_heap.GetKey(node) + distance;
+ if (new_distance < upper_bound)
+ {
+ // if loops are forced, they are so at the source
+ if (new_distance >= 0 &&
+ (!force_loop_forward || forward_heap.GetData(node).parent != node) &&
+ (!force_loop_reverse || reverse_heap.GetData(node).parent != node))
+ {
+ middle_node_id = node;
+ upper_bound = new_distance;
+ }
+ else
+ {
+ // check whether there is a loop present at the node
+ for (const auto edge : facade->GetAdjacentEdgeRange(node))
+ {
+ const EdgeData &data = facade->GetEdgeData(edge);
+ bool forward_directionFlag =
+ (forward_direction ? data.forward : data.backward);
+ if (forward_directionFlag)
+ {
+ const NodeID to = facade->GetTarget(edge);
+ if (to == node)
+ {
+ const EdgeWeight edge_weight = data.distance;
+ const std::int32_t loop_distance = new_distance + edge_weight;
+ if (loop_distance >= 0 && loop_distance < upper_bound)
+ {
+ middle_node_id = node;
+ upper_bound = loop_distance;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // make sure we don't terminate too early if we initialize the distance
+ // for the nodes in the forward heap with the forward/reverse offset
+ BOOST_ASSERT(min_edge_offset <= 0);
+ if (distance + min_edge_offset > upper_bound)
+ {
+ forward_heap.DeleteAll();
+ return;
+ }
+
+ // Stalling
+ if (stalling)
+ {
+ for (const auto edge : facade->GetAdjacentEdgeRange(node))
+ {
+ const EdgeData &data = facade->GetEdgeData(edge);
+ const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
+ if (reverse_flag)
+ {
+ const NodeID to = facade->GetTarget(edge);
+ const EdgeWeight edge_weight = data.distance;
+
+ BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
+
+ if (forward_heap.WasInserted(to))
+ {
+ if (forward_heap.GetKey(to) + edge_weight < distance)
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ for (const auto edge : facade->GetAdjacentEdgeRange(node))
+ {
+ const EdgeData &data = facade->GetEdgeData(edge);
+ bool forward_directionFlag = (forward_direction ? data.forward : data.backward);
+ if (forward_directionFlag)
+ {
+
+ const NodeID to = facade->GetTarget(edge);
+ const EdgeWeight edge_weight = data.distance;
+
+ BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
+ const int to_distance = distance + edge_weight;
+
+ // New Node discovered -> Add to Heap + Node Info Storage
+ if (!forward_heap.WasInserted(to))
+ {
+ forward_heap.Insert(to, to_distance, node);
+ }
+ // Found a shorter Path -> Update distance
+ else if (to_distance < forward_heap.GetKey(to))
+ {
+ // new parent
+ forward_heap.GetData(to).parent = node;
+ forward_heap.DecreaseKey(to, to_distance);
+ }
+ }
+ }
+ }
+
+ inline EdgeWeight GetLoopWeight(NodeID node) const
+ {
+ EdgeWeight loop_weight = INVALID_EDGE_WEIGHT;
+ for (auto edge : facade->GetAdjacentEdgeRange(node))
+ {
+ const auto &data = facade->GetEdgeData(edge);
+ if (data.forward)
+ {
+ const NodeID to = facade->GetTarget(edge);
+ if (to == node)
+ {
+ loop_weight = std::min(loop_weight, data.distance);
+ }
+ }
+ }
+ return loop_weight;
+ }
+
+ template <typename RandomIter>
+ void UnpackPath(RandomIter packed_path_begin,
+ RandomIter packed_path_end,
+ const PhantomNodes &phantom_node_pair,
+ std::vector<PathData> &unpacked_path) const
+ {
+ const bool start_traversed_in_reverse =
+ (*packed_path_begin != phantom_node_pair.source_phantom.forward_segment_id.id);
+ const bool target_traversed_in_reverse =
+ (*std::prev(packed_path_end) != phantom_node_pair.target_phantom.forward_segment_id.id);
+
+ BOOST_ASSERT(std::distance(packed_path_begin, packed_path_end) > 0);
+ std::stack<std::pair<NodeID, NodeID>> recursion_stack;
+
+ // We have to push the path in reverse order onto the stack because it's LIFO.
+ for (auto current = std::prev(packed_path_end); current != packed_path_begin;
+ current = std::prev(current))
+ {
+ recursion_stack.emplace(*std::prev(current), *current);
+ }
+
+ std::pair<NodeID, NodeID> edge;
+ while (!recursion_stack.empty())
+ {
+ // edge.first edge.second
+ // *------------------>*
+ // edge_id
+ edge = recursion_stack.top();
+ recursion_stack.pop();
+
+ // Contraction might introduce double edges by inserting shortcuts
+ // this searching for the smallest upwards edge found by the forward search
+ EdgeID smaller_edge_id = SPECIAL_EDGEID;
+ EdgeWeight edge_weight = std::numeric_limits<EdgeWeight>::max();
+ for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
+ {
+ const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
+ if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
+ facade->GetEdgeData(edge_id).forward)
+ {
+ smaller_edge_id = edge_id;
+ edge_weight = weight;
+ }
+ }
+
+ // edge.first edge.second
+ // *<------------------*
+ // edge_id
+ // if we don't find a forward edge, this edge must have been an downwards edge
+ // found by the reverse search.
+ if (SPECIAL_EDGEID == smaller_edge_id)
+ {
+ for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
+ {
+ const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
+ if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
+ facade->GetEdgeData(edge_id).backward)
+ {
+ smaller_edge_id = edge_id;
+ edge_weight = weight;
+ }
+ }
+ }
+ BOOST_ASSERT_MSG(edge_weight != INVALID_EDGE_WEIGHT, "edge id invalid");
+
+ const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
+ if (ed.shortcut)
+ { // unpack
+ const NodeID middle_node_id = ed.id;
+ // again, we need to this in reversed order
+ recursion_stack.emplace(middle_node_id, edge.second);
+ recursion_stack.emplace(edge.first, middle_node_id);
+ }
+ else
+ {
+ BOOST_ASSERT_MSG(!ed.shortcut, "original edge flagged as shortcut");
+ unsigned name_index = facade->GetNameIndexFromEdgeID(ed.id);
+ const auto turn_instruction = facade->GetTurnInstructionForEdgeID(ed.id);
+ const extractor::TravelMode travel_mode =
+ (unpacked_path.empty() && start_traversed_in_reverse)
+ ? phantom_node_pair.source_phantom.backward_travel_mode
+ : facade->GetTravelModeForEdgeID(ed.id);
+
+ std::vector<NodeID> id_vector;
+ facade->GetUncompressedGeometry(facade->GetGeometryIndexForEdgeID(ed.id),
+ id_vector);
+ BOOST_ASSERT(id_vector.size() > 0);
+
+ std::vector<EdgeWeight> weight_vector;
+ facade->GetUncompressedWeights(facade->GetGeometryIndexForEdgeID(ed.id),
+ weight_vector);
+ BOOST_ASSERT(weight_vector.size() > 0);
+
+ auto total_weight = std::accumulate(weight_vector.begin(), weight_vector.end(), 0);
+
+ BOOST_ASSERT(weight_vector.size() == id_vector.size());
+ // ed.distance should be total_weight + penalties (turn, stop, etc)
+ BOOST_ASSERT(ed.distance >= total_weight);
+ const bool is_first_segment = unpacked_path.empty();
+
+ const std::size_t start_index =
+ (is_first_segment
+ ? ((start_traversed_in_reverse)
+ ? id_vector.size() -
+ phantom_node_pair.source_phantom.fwd_segment_position - 1
+ : phantom_node_pair.source_phantom.fwd_segment_position)
+ : 0);
+ const std::size_t end_index = id_vector.size();
+
+ BOOST_ASSERT(start_index >= 0);
+ BOOST_ASSERT(start_index < end_index);
+ for (std::size_t i = start_index; i < end_index; ++i)
+ {
+ unpacked_path.push_back(
+ PathData{id_vector[i],
+ name_index,
+ weight_vector[i],
+ extractor::guidance::TurnInstruction::NO_TURN(),
+ travel_mode});
+ }
+ BOOST_ASSERT(unpacked_path.size() > 0);
+ unpacked_path.back().turn_instruction = turn_instruction;
+ unpacked_path.back().duration_until_turn += (ed.distance - total_weight);
+ }
+ }
+ std::size_t start_index = 0, end_index = 0;
+ std::vector<unsigned> id_vector;
+ std::vector<EdgeWeight> weight_vector;
+ const bool is_local_path = (phantom_node_pair.source_phantom.forward_packed_geometry_id ==
+ phantom_node_pair.target_phantom.forward_packed_geometry_id) &&
+ unpacked_path.empty();
+
+ if (target_traversed_in_reverse)
+ {
+ facade->GetUncompressedGeometry(
+ phantom_node_pair.target_phantom.reverse_packed_geometry_id, id_vector);
+
+ facade->GetUncompressedWeights(
+ phantom_node_pair.target_phantom.reverse_packed_geometry_id, weight_vector);
+
+ if (is_local_path)
+ {
+ start_index =
+ id_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position - 1;
+ }
+ end_index = id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position - 1;
+ }
+ else
+ {
+ if (is_local_path)
+ {
+ start_index = phantom_node_pair.source_phantom.fwd_segment_position;
+ }
+ end_index = phantom_node_pair.target_phantom.fwd_segment_position;
+ facade->GetUncompressedGeometry(
+ phantom_node_pair.target_phantom.forward_packed_geometry_id, id_vector);
+
+ facade->GetUncompressedWeights(
+ phantom_node_pair.target_phantom.forward_packed_geometry_id, weight_vector);
+ }
+
+ // Given the following compressed geometry:
+ // U---v---w---x---y---Z
+ // s t
+ // s: fwd_segment 0
+ // t: fwd_segment 3
+ // -> (U, v), (v, w), (w, x)
+ // note that (x, t) is _not_ included but needs to be added later.
+ BOOST_ASSERT(start_index <= end_index);
+ for (std::size_t i = start_index; i != end_index; ++i)
+ {
+ BOOST_ASSERT(i < id_vector.size());
+ BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode > 0);
+ unpacked_path.push_back(
+ PathData{id_vector[i],
+ phantom_node_pair.target_phantom.name_id,
+ weight_vector[i],
+ extractor::guidance::TurnInstruction::NO_TURN(),
+ target_traversed_in_reverse
+ ? phantom_node_pair.target_phantom.backward_travel_mode
+ : phantom_node_pair.target_phantom.forward_travel_mode});
+ }
+
+ if (unpacked_path.size() > 0)
+ {
+ const auto source_weight = start_traversed_in_reverse
+ ? phantom_node_pair.source_phantom.reverse_weight
+ : phantom_node_pair.source_phantom.forward_weight;
+ // The above code will create segments for (v, w), (w,x), (x, y) and (y, Z).
+ // However the first segment duration needs to be adjusted to the fact that the source
+ // phantom is in the middle of the segment. We do this by subtracting v--s from the
+ // duration.
+ BOOST_ASSERT(unpacked_path.front().duration_until_turn >= source_weight);
+ unpacked_path.front().duration_until_turn -= source_weight;
+ }
+
+ // there is no equivalent to a node-based node in an edge-expanded graph.
+ // two equivalent routes may start (or end) at different node-based edges
+ // as they are added with the offset how much "distance" on the edge
+ // has already been traversed. Depending on offset one needs to remove
+ // the last node.
+ if (unpacked_path.size() > 1)
+ {
+ const std::size_t last_index = unpacked_path.size() - 1;
+ const std::size_t second_to_last_index = last_index - 1;
+
+ if (unpacked_path[last_index].turn_via_node ==
+ unpacked_path[second_to_last_index].turn_via_node)
+ {
+ unpacked_path.pop_back();
+ }
+ BOOST_ASSERT(!unpacked_path.empty());
+ }
+ }
+
+ void UnpackEdge(const NodeID s, const NodeID t, std::vector<NodeID> &unpacked_path) const
+ {
+ std::stack<std::pair<NodeID, NodeID>> recursion_stack;
+ recursion_stack.emplace(s, t);
+
+ std::pair<NodeID, NodeID> edge;
+ while (!recursion_stack.empty())
+ {
+ edge = recursion_stack.top();
+ recursion_stack.pop();
+
+ EdgeID smaller_edge_id = SPECIAL_EDGEID;
+ EdgeWeight edge_weight = std::numeric_limits<EdgeWeight>::max();
+ for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
+ {
+ const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
+ if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
+ facade->GetEdgeData(edge_id).forward)
+ {
+ smaller_edge_id = edge_id;
+ edge_weight = weight;
+ }
+ }
+
+ if (SPECIAL_EDGEID == smaller_edge_id)
+ {
+ for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
+ {
+ const EdgeWeight weight = facade->GetEdgeData(edge_id).distance;
+ if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
+ facade->GetEdgeData(edge_id).backward)
+ {
+ smaller_edge_id = edge_id;
+ edge_weight = weight;
+ }
+ }
+ }
+ BOOST_ASSERT_MSG(edge_weight != std::numeric_limits<EdgeWeight>::max(),
+ "edge weight invalid");
+
+ const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
+ if (ed.shortcut)
+ { // unpack
+ const NodeID middle_node_id = ed.id;
+ // again, we need to this in reversed order
+ recursion_stack.emplace(middle_node_id, edge.second);
+ recursion_stack.emplace(edge.first, middle_node_id);
+ }
+ else
+ {
+ BOOST_ASSERT_MSG(!ed.shortcut, "edge must be shortcut");
+ unpacked_path.emplace_back(edge.first);
+ }
+ }
+ unpacked_path.emplace_back(t);
+ }
+
+ void RetrievePackedPathFromHeap(const SearchEngineData::QueryHeap &forward_heap,
+ const SearchEngineData::QueryHeap &reverse_heap,
+ const NodeID middle_node_id,
+ std::vector<NodeID> &packed_path) const
+ {
+ RetrievePackedPathFromSingleHeap(forward_heap, middle_node_id, packed_path);
+ std::reverse(packed_path.begin(), packed_path.end());
+ packed_path.emplace_back(middle_node_id);
+ RetrievePackedPathFromSingleHeap(reverse_heap, middle_node_id, packed_path);
+ }
+
+ void RetrievePackedPathFromSingleHeap(const SearchEngineData::QueryHeap &search_heap,
+ const NodeID middle_node_id,
+ std::vector<NodeID> &packed_path) const
+ {
+ NodeID current_node_id = middle_node_id;
+ while (current_node_id != search_heap.GetData(current_node_id).parent)
+ {
+ current_node_id = search_heap.GetData(current_node_id).parent;
+ packed_path.emplace_back(current_node_id);
+ }
+ }
+
+ // assumes that heaps are already setup correctly.
+ // ATTENTION: This only works if no additional offset is supplied next to the Phantom Node
+ // Offsets.
+ // In case additional offsets are supplied, you might have to force a loop first.
+ // A forced loop might be necessary, if source and target are on the same segment.
+ // If this is the case and the offsets of the respective direction are larger for the source
+ // than the target
+ // then a force loop is required (e.g. source_phantom.forward_segment_id ==
+ // target_phantom.forward_segment_id
+ // && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
+ // requires
+ // a force loop, if the heaps have been initialized with positive offsets.
+ void Search(SearchEngineData::QueryHeap &forward_heap,
+ SearchEngineData::QueryHeap &reverse_heap,
+ std::int32_t &distance,
+ std::vector<NodeID> &packed_leg,
+ const bool force_loop_forward,
+ const bool force_loop_reverse,
+ const int duration_upper_bound = INVALID_EDGE_WEIGHT) const
+ {
+ NodeID middle = SPECIAL_NODEID;
+ distance = duration_upper_bound;
+
+ // get offset to account for offsets on phantom nodes on compressed edges
+ const auto min_edge_offset = std::min(0, forward_heap.MinKey());
+ BOOST_ASSERT(min_edge_offset <= 0);
+ // we only every insert negative offsets for nodes in the forward heap
+ BOOST_ASSERT(reverse_heap.MinKey() >= 0);
+
+ // run two-Target Dijkstra routing step.
+ const constexpr bool STALLING_ENABLED = true;
+ while (0 < (forward_heap.Size() + reverse_heap.Size()))
+ {
+ if (!forward_heap.Empty())
+ {
+ RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, true,
+ STALLING_ENABLED, force_loop_forward, force_loop_reverse);
+ }
+ if (!reverse_heap.Empty())
+ {
+ RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset, false,
+ STALLING_ENABLED, force_loop_reverse, force_loop_forward);
+ }
+ }
+
+ // No path found for both target nodes?
+ if (duration_upper_bound <= distance || SPECIAL_NODEID == middle)
+ {
+ distance = INVALID_EDGE_WEIGHT;
+ return;
+ }
+
+ // Was a paths over one of the forward/reverse nodes not found?
+ BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance),
+ "no path found");
+
+ // make sure to correctly unpack loops
+ if (distance != forward_heap.GetKey(middle) + reverse_heap.GetKey(middle))
+ {
+ // self loop
+ BOOST_ASSERT(forward_heap.GetData(middle).parent == middle &&
+ reverse_heap.GetData(middle).parent == middle);
+ packed_leg.push_back(middle);
+ packed_leg.push_back(middle);
+ }
+ else
+ {
+ RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
+ }
+ }
+
+ // assumes that heaps are already setup correctly.
+ // A forced loop might be necessary, if source and target are on the same segment.
+ // If this is the case and the offsets of the respective direction are larger for the source
+ // than the target
+ // then a force loop is required (e.g. source_phantom.forward_segment_id ==
+ // target_phantom.forward_segment_id
+ // && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
+ // requires
+ // a force loop, if the heaps have been initialized with positive offsets.
+ void SearchWithCore(SearchEngineData::QueryHeap &forward_heap,
+ SearchEngineData::QueryHeap &reverse_heap,
+ SearchEngineData::QueryHeap &forward_core_heap,
+ SearchEngineData::QueryHeap &reverse_core_heap,
+ int &distance,
+ std::vector<NodeID> &packed_leg,
+ const bool force_loop_forward,
+ const bool force_loop_reverse,
+ int duration_upper_bound = INVALID_EDGE_WEIGHT) const
+ {
+ NodeID middle = SPECIAL_NODEID;
+ distance = duration_upper_bound;
+
+ std::vector<std::pair<NodeID, EdgeWeight>> forward_entry_points;
+ std::vector<std::pair<NodeID, EdgeWeight>> reverse_entry_points;
+
+ // get offset to account for offsets on phantom nodes on compressed edges
+ const auto min_edge_offset = std::min(0, forward_heap.MinKey());
+ // we only every insert negative offsets for nodes in the forward heap
+ BOOST_ASSERT(reverse_heap.MinKey() >= 0);
+
+ const constexpr bool STALLING_ENABLED = true;
+ // run two-Target Dijkstra routing step.
+ while (0 < (forward_heap.Size() + reverse_heap.Size()))
+ {
+ if (!forward_heap.Empty())
+ {
+ if (facade->IsCoreNode(forward_heap.Min()))
+ {
+ const NodeID node = forward_heap.DeleteMin();
+ const int key = forward_heap.GetKey(node);
+ forward_entry_points.emplace_back(node, key);
+ }
+ else
+ {
+ RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, true,
+ STALLING_ENABLED, force_loop_forward, force_loop_reverse);
+ }
+ }
+ if (!reverse_heap.Empty())
+ {
+ if (facade->IsCoreNode(reverse_heap.Min()))
+ {
+ const NodeID node = reverse_heap.DeleteMin();
+ const int key = reverse_heap.GetKey(node);
+ reverse_entry_points.emplace_back(node, key);
+ }
+ else
+ {
+ RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset,
+ false, STALLING_ENABLED, force_loop_reverse, force_loop_forward);
+ }
+ }
+ }
+ // TODO check if unordered_set might be faster
+ // sort by id and increasing by distance
+ auto entry_point_comparator =
+ [](const std::pair<NodeID, EdgeWeight> &lhs, const std::pair<NodeID, EdgeWeight> &rhs)
+ {
+ return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second < rhs.second);
+ };
+ std::sort(forward_entry_points.begin(), forward_entry_points.end(), entry_point_comparator);
+ std::sort(reverse_entry_points.begin(), reverse_entry_points.end(), entry_point_comparator);
+
+ NodeID last_id = SPECIAL_NODEID;
+ forward_core_heap.Clear();
+ reverse_core_heap.Clear();
+ for (const auto &p : forward_entry_points)
+ {
+ if (p.first == last_id)
+ {
+ continue;
+ }
+ forward_core_heap.Insert(p.first, p.second, p.first);
+ last_id = p.first;
+ }
+ last_id = SPECIAL_NODEID;
+ for (const auto &p : reverse_entry_points)
+ {
+ if (p.first == last_id)
+ {
+ continue;
+ }
+ reverse_core_heap.Insert(p.first, p.second, p.first);
+ last_id = p.first;
+ }
+
+ // get offset to account for offsets on phantom nodes on compressed edges
+ int min_core_edge_offset = 0;
+ if (forward_core_heap.Size() > 0)
+ {
+ min_core_edge_offset = std::min(min_core_edge_offset, forward_core_heap.MinKey());
+ }
+ if (reverse_core_heap.Size() > 0 && reverse_core_heap.MinKey() < 0)
+ {
+ min_core_edge_offset = std::min(min_core_edge_offset, reverse_core_heap.MinKey());
+ }
+ BOOST_ASSERT(min_core_edge_offset <= 0);
+
+ // run two-target Dijkstra routing step on core with termination criterion
+ const constexpr bool STALLING_DISABLED = false;
+ while (0 < forward_core_heap.Size() && 0 < reverse_core_heap.Size() &&
+ distance > (forward_core_heap.MinKey() + reverse_core_heap.MinKey()))
+ {
+ RoutingStep(forward_core_heap, reverse_core_heap, middle, distance,
+ min_core_edge_offset, true, STALLING_DISABLED, force_loop_forward,
+ force_loop_reverse);
+
+ RoutingStep(reverse_core_heap, forward_core_heap, middle, distance,
+ min_core_edge_offset, false, STALLING_DISABLED, force_loop_reverse,
+ force_loop_forward);
+ }
+
+ // No path found for both target nodes?
+ if (duration_upper_bound <= distance || SPECIAL_NODEID == middle)
+ {
+ distance = INVALID_EDGE_WEIGHT;
+ return;
+ }
+
+ // Was a paths over one of the forward/reverse nodes not found?
+ BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance),
+ "no path found");
+
+ // we need to unpack sub path from core heaps
+ if (facade->IsCoreNode(middle))
+ {
+ if (distance != forward_core_heap.GetKey(middle) + reverse_core_heap.GetKey(middle))
+ {
+ // self loop
+ BOOST_ASSERT(forward_core_heap.GetData(middle).parent == middle &&
+ reverse_core_heap.GetData(middle).parent == middle);
+ packed_leg.push_back(middle);
+ packed_leg.push_back(middle);
+ }
+ else
+ {
+ std::vector<NodeID> packed_core_leg;
+ RetrievePackedPathFromHeap(forward_core_heap, reverse_core_heap, middle,
+ packed_core_leg);
+ BOOST_ASSERT(packed_core_leg.size() > 0);
+ RetrievePackedPathFromSingleHeap(forward_heap, packed_core_leg.front(), packed_leg);
+ std::reverse(packed_leg.begin(), packed_leg.end());
+ packed_leg.insert(packed_leg.end(), packed_core_leg.begin(), packed_core_leg.end());
+ RetrievePackedPathFromSingleHeap(reverse_heap, packed_core_leg.back(), packed_leg);
+ }
+ }
+ else
+ {
+ if (distance != forward_heap.GetKey(middle) + reverse_heap.GetKey(middle))
+ {
+ // self loop
+ BOOST_ASSERT(forward_heap.GetData(middle).parent == middle &&
+ reverse_heap.GetData(middle).parent == middle);
+ packed_leg.push_back(middle);
+ packed_leg.push_back(middle);
+ }
+ else
+ {
+ RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
+ }
+ }
+ }
+
+ bool NeedsLoopForward(const PhantomNode &source_phantom,
+ const PhantomNode &target_phantom) const
+ {
+ return source_phantom.forward_segment_id.enabled &&
+ target_phantom.forward_segment_id.enabled &&
+ source_phantom.forward_segment_id.id == target_phantom.forward_segment_id.id &&
+ source_phantom.GetForwardWeightPlusOffset() >
+ target_phantom.GetForwardWeightPlusOffset();
+ }
+
+ bool NeedsLoopBackwards(const PhantomNode &source_phantom,
+ const PhantomNode &target_phantom) const
+ {
+ return source_phantom.reverse_segment_id.enabled &&
+ target_phantom.reverse_segment_id.enabled &&
+ source_phantom.reverse_segment_id.id == target_phantom.reverse_segment_id.id &&
+ source_phantom.GetReverseWeightPlusOffset() >
+ target_phantom.GetReverseWeightPlusOffset();
+ }
+
+ double GetPathDistance(const std::vector<NodeID> &packed_path,
+ const PhantomNode &source_phantom,
+ const PhantomNode &target_phantom) const
+ {
+ std::vector<PathData> unpacked_path;
+ PhantomNodes nodes;
+ nodes.source_phantom = source_phantom;
+ nodes.target_phantom = target_phantom;
+ UnpackPath(packed_path.begin(), packed_path.end(), nodes, unpacked_path);
+
+ util::Coordinate previous_coordinate = source_phantom.location;
+ util::Coordinate current_coordinate;
+ double distance = 0;
+ for (const auto &p : unpacked_path)
+ {
+ current_coordinate = facade->GetCoordinateOfNode(p.turn_via_node);
+ distance += util::coordinate_calculation::haversineDistance(previous_coordinate,
+ current_coordinate);
+ previous_coordinate = current_coordinate;
+ }
+ distance += util::coordinate_calculation::haversineDistance(previous_coordinate,
+ target_phantom.location);
+ return distance;
+ }
+
+ // Requires the heaps for be empty
+ // If heaps should be adjusted to be initialized outside of this function,
+ // the addition of force_loop parameters might be required
+ double GetNetworkDistanceWithCore(SearchEngineData::QueryHeap &forward_heap,
+ SearchEngineData::QueryHeap &reverse_heap,
+ SearchEngineData::QueryHeap &forward_core_heap,
+ SearchEngineData::QueryHeap &reverse_core_heap,
+ const PhantomNode &source_phantom,
+ const PhantomNode &target_phantom,
+ int duration_upper_bound = INVALID_EDGE_WEIGHT) const
+ {
+ BOOST_ASSERT(forward_heap.Empty());
+ BOOST_ASSERT(reverse_heap.Empty());
+
+ if (source_phantom.forward_segment_id.enabled)
+ {
+ forward_heap.Insert(source_phantom.forward_segment_id.id,
+ -source_phantom.GetForwardWeightPlusOffset(),
+ source_phantom.forward_segment_id.id);
+ }
+ if (source_phantom.reverse_segment_id.enabled)
+ {
+ forward_heap.Insert(source_phantom.reverse_segment_id.id,
+ -source_phantom.GetReverseWeightPlusOffset(),
+ source_phantom.reverse_segment_id.id);
+ }
+
+ if (target_phantom.forward_segment_id.enabled)
+ {
+ reverse_heap.Insert(target_phantom.forward_segment_id.id,
+ target_phantom.GetForwardWeightPlusOffset(),
+ target_phantom.forward_segment_id.id);
+ }
+ if (target_phantom.reverse_segment_id.enabled)
+ {
+ reverse_heap.Insert(target_phantom.reverse_segment_id.id,
+ target_phantom.GetReverseWeightPlusOffset(),
+ target_phantom.reverse_segment_id.id);
+ }
+
+ const bool constexpr DO_NOT_FORCE_LOOPS =
+ false; // prevents forcing of loops, since offsets are set correctly
+
+ int duration = INVALID_EDGE_WEIGHT;
+ std::vector<NodeID> packed_path;
+ SearchWithCore(forward_heap, reverse_heap, forward_core_heap, reverse_core_heap, duration,
+ packed_path, DO_NOT_FORCE_LOOPS, DO_NOT_FORCE_LOOPS, duration_upper_bound);
+
+ double distance = std::numeric_limits<double>::max();
+ if (duration != INVALID_EDGE_WEIGHT)
+ {
+ return GetPathDistance(packed_path, source_phantom, target_phantom);
+ }
+ return distance;
+ }
+
+ // Requires the heaps for be empty
+ // If heaps should be adjusted to be initialized outside of this function,
+ // the addition of force_loop parameters might be required
+ double GetNetworkDistance(SearchEngineData::QueryHeap &forward_heap,
+ SearchEngineData::QueryHeap &reverse_heap,
+ const PhantomNode &source_phantom,
+ const PhantomNode &target_phantom,
+ int duration_upper_bound = INVALID_EDGE_WEIGHT) const
+ {
+ BOOST_ASSERT(forward_heap.Empty());
+ BOOST_ASSERT(reverse_heap.Empty());
+
+ if (source_phantom.forward_segment_id.enabled)
+ {
+ forward_heap.Insert(source_phantom.forward_segment_id.id,
+ -source_phantom.GetForwardWeightPlusOffset(),
+ source_phantom.forward_segment_id.id);
+ }
+ if (source_phantom.reverse_segment_id.enabled)
+ {
+ forward_heap.Insert(source_phantom.reverse_segment_id.id,
+ -source_phantom.GetReverseWeightPlusOffset(),
+ source_phantom.reverse_segment_id.id);
+ }
+
+ if (target_phantom.forward_segment_id.enabled)
+ {
+ reverse_heap.Insert(target_phantom.forward_segment_id.id,
+ target_phantom.GetForwardWeightPlusOffset(),
+ target_phantom.forward_segment_id.id);
+ }
+ if (target_phantom.reverse_segment_id.enabled)
+ {
+ reverse_heap.Insert(target_phantom.reverse_segment_id.id,
+ target_phantom.GetReverseWeightPlusOffset(),
+ target_phantom.reverse_segment_id.id);
+ }
+
+ const bool constexpr DO_NOT_FORCE_LOOPS =
+ false; // prevents forcing of loops, since offsets are set correctly
+
+ int duration = INVALID_EDGE_WEIGHT;
+ std::vector<NodeID> packed_path;
+ Search(forward_heap, reverse_heap, duration, packed_path, DO_NOT_FORCE_LOOPS,
+ DO_NOT_FORCE_LOOPS, duration_upper_bound);
+
+ if (duration == INVALID_EDGE_WEIGHT)
+ {
+ return std::numeric_limits<double>::max();
+ }
+
+ return GetPathDistance(packed_path, source_phantom, target_phantom);
+ }
+};
+}
+}
+}
+
+#endif // ROUTING_BASE_HPP
diff --git a/routing_algorithms/shortest_path.hpp b/include/engine/routing_algorithms/shortest_path.hpp
similarity index 58%
rename from routing_algorithms/shortest_path.hpp
rename to include/engine/routing_algorithms/shortest_path.hpp
index 601e394..9720931 100644
--- a/routing_algorithms/shortest_path.hpp
+++ b/include/engine/routing_algorithms/shortest_path.hpp
@@ -1,41 +1,22 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef SHORTEST_PATH_HPP
#define SHORTEST_PATH_HPP
-#include "../typedefs.h"
+#include "util/typedefs.hpp"
-#include "routing_base.hpp"
+#include "engine/routing_algorithms/routing_base.hpp"
-#include "../data_structures/search_engine_data.hpp"
-#include "../util/integer_range.hpp"
+#include "engine/search_engine_data.hpp"
+#include "util/integer_range.hpp"
#include <boost/assert.hpp>
+#include <boost/optional.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace routing_algorithms
+{
template <class DataFacadeT>
class ShortestPathRouting final
@@ -44,6 +25,7 @@ class ShortestPathRouting final
using super = BasicRoutingInterface<DataFacadeT, ShortestPathRouting<DataFacadeT>>;
using QueryHeap = SearchEngineData::QueryHeap;
SearchEngineData &engine_working_data;
+ const static constexpr bool DO_NOT_FORCE_LOOP = false;
public:
ShortestPathRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
@@ -57,6 +39,8 @@ class ShortestPathRouting final
// searches source forward/reverse -> target forward/reverse
void SearchWithUTurn(QueryHeap &forward_heap,
QueryHeap &reverse_heap,
+ QueryHeap &forward_core_heap,
+ QueryHeap &reverse_core_heap,
const bool search_from_forward_node,
const bool search_from_reverse_node,
const bool search_to_forward_node,
@@ -72,136 +56,57 @@ class ShortestPathRouting final
reverse_heap.Clear();
if (search_from_forward_node)
{
- forward_heap.Insert(source_phantom.forward_node_id,
+ forward_heap.Insert(source_phantom.forward_segment_id.id,
total_distance_to_forward -
source_phantom.GetForwardWeightPlusOffset(),
- source_phantom.forward_node_id);
+ source_phantom.forward_segment_id.id);
}
if (search_from_reverse_node)
{
- forward_heap.Insert(source_phantom.reverse_node_id,
+ forward_heap.Insert(source_phantom.reverse_segment_id.id,
total_distance_to_reverse -
source_phantom.GetReverseWeightPlusOffset(),
- source_phantom.reverse_node_id);
+ source_phantom.reverse_segment_id.id);
}
if (search_to_forward_node)
{
- reverse_heap.Insert(target_phantom.forward_node_id,
+ reverse_heap.Insert(target_phantom.forward_segment_id.id,
target_phantom.GetForwardWeightPlusOffset(),
- target_phantom.forward_node_id);
+ target_phantom.forward_segment_id.id);
}
if (search_to_reverse_node)
{
- reverse_heap.Insert(target_phantom.reverse_node_id,
+ reverse_heap.Insert(target_phantom.reverse_segment_id.id,
target_phantom.GetReverseWeightPlusOffset(),
- target_phantom.reverse_node_id);
+ target_phantom.reverse_segment_id.id);
}
+
BOOST_ASSERT(forward_heap.Size() > 0);
BOOST_ASSERT(reverse_heap.Size() > 0);
- super::Search(forward_heap, reverse_heap, new_total_distance, leg_packed_path);
- }
- // If source and target are reverse on a oneway we need to find a path
- // that connects the two. This is _not_ the shortest path in our model,
- // as source and target are on the same edge based node.
- // We force a detour by inserting "virtaul vias", which means we search a path
- // from all nodes that are connected by outgoing edges to all nodes that are connected by
- // incoming edges.
- // ------^
- // | ^source
- // | ^
- // | ^target
- // ------^
- void SearchLoop(QueryHeap &forward_heap,
- QueryHeap &reverse_heap,
- const bool search_forward_node,
- const bool search_reverse_node,
- const PhantomNode &source_phantom,
- const PhantomNode &target_phantom,
- const int total_distance_to_forward,
- const int total_distance_to_reverse,
- int &new_total_distance_to_forward,
- int &new_total_distance_to_reverse,
- std::vector<NodeID> &leg_packed_path_forward,
- std::vector<NodeID> &leg_packed_path_reverse) const
- {
- BOOST_ASSERT(source_phantom.forward_node_id == target_phantom.forward_node_id);
- BOOST_ASSERT(source_phantom.reverse_node_id == target_phantom.reverse_node_id);
-
- if (search_forward_node)
+ // this is only relevent if source and target are on the same compressed edge
+ auto is_oneway_source = !(search_from_forward_node && search_from_reverse_node);
+ auto is_oneway_target = !(search_to_forward_node && search_to_reverse_node);
+ // we only enable loops here if we can't search from forward to backward node
+ auto needs_loop_forwad =
+ is_oneway_source && super::NeedsLoopForward(source_phantom, target_phantom);
+ auto needs_loop_backwards =
+ is_oneway_target && super::NeedsLoopBackwards(source_phantom, target_phantom);
+ if (super::facade->GetCoreSize() > 0)
{
- forward_heap.Clear();
- reverse_heap.Clear();
-
- auto node_id = source_phantom.forward_node_id;
-
- for (const auto edge : super::facade->GetAdjacentEdgeRange(node_id))
- {
- const auto& data = super::facade->GetEdgeData(edge);
- if (data.forward)
- {
- auto target = super::facade->GetTarget(edge);
- auto offset = total_distance_to_forward + data.distance - source_phantom.GetForwardWeightPlusOffset();
- forward_heap.Insert(target, offset, target);
- }
-
- if (data.backward)
- {
- auto target = super::facade->GetTarget(edge);
- auto offset = data.distance + target_phantom.GetForwardWeightPlusOffset();
- reverse_heap.Insert(target, offset, target);
- }
- }
-
- BOOST_ASSERT(forward_heap.Size() > 0);
- BOOST_ASSERT(reverse_heap.Size() > 0);
- super::Search(forward_heap, reverse_heap, new_total_distance_to_forward,
- leg_packed_path_forward);
-
- // insert node to both endpoints to close the leg
- leg_packed_path_forward.push_back(node_id);
- std::reverse(leg_packed_path_forward.begin(), leg_packed_path_forward.end());
- leg_packed_path_forward.push_back(node_id);
- std::reverse(leg_packed_path_forward.begin(), leg_packed_path_forward.end());
+ forward_core_heap.Clear();
+ reverse_core_heap.Clear();
+ BOOST_ASSERT(forward_core_heap.Size() == 0);
+ BOOST_ASSERT(reverse_core_heap.Size() == 0);
+ super::SearchWithCore(forward_heap, reverse_heap, forward_core_heap, reverse_core_heap,
+ new_total_distance, leg_packed_path, needs_loop_forwad,
+ needs_loop_backwards);
}
-
- if (search_reverse_node)
+ else
{
- forward_heap.Clear();
- reverse_heap.Clear();
-
- auto node_id = source_phantom.reverse_node_id;
-
- for (const auto edge : super::facade->GetAdjacentEdgeRange(node_id))
- {
- const auto& data = super::facade->GetEdgeData(edge);
- if (data.forward)
- {
- auto target = super::facade->GetTarget(edge);
- auto offset = total_distance_to_reverse + data.distance - source_phantom.GetReverseWeightPlusOffset();
- forward_heap.Insert(target, offset, target);
- }
-
- if (data.backward)
- {
- auto target = super::facade->GetTarget(edge);
- auto offset = data.distance + target_phantom.GetReverseWeightPlusOffset();
- reverse_heap.Insert(target, offset, target);
- }
- }
-
- BOOST_ASSERT(forward_heap.Size() > 0);
- BOOST_ASSERT(reverse_heap.Size() > 0);
- super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse,
- leg_packed_path_reverse);
-
- // insert node to both endpoints to close the leg
- leg_packed_path_reverse.push_back(node_id);
- std::reverse(leg_packed_path_reverse.begin(), leg_packed_path_reverse.end());
- leg_packed_path_reverse.push_back(node_id);
- std::reverse(leg_packed_path_reverse.begin(), leg_packed_path_reverse.end());
+ super::Search(forward_heap, reverse_heap, new_total_distance, leg_packed_path,
+ needs_loop_forwad, needs_loop_backwards);
}
-
}
// searches shortest path between:
@@ -209,6 +114,8 @@ class ShortestPathRouting final
// source forward/reverse -> target reverse
void Search(QueryHeap &forward_heap,
QueryHeap &reverse_heap,
+ QueryHeap &forward_core_heap,
+ QueryHeap &reverse_core_heap,
const bool search_from_forward_node,
const bool search_from_reverse_node,
const bool search_to_forward_node,
@@ -226,55 +133,87 @@ class ShortestPathRouting final
{
forward_heap.Clear();
reverse_heap.Clear();
- reverse_heap.Insert(target_phantom.forward_node_id,
+ reverse_heap.Insert(target_phantom.forward_segment_id.id,
target_phantom.GetForwardWeightPlusOffset(),
- target_phantom.forward_node_id);
+ target_phantom.forward_segment_id.id);
if (search_from_forward_node)
{
- forward_heap.Insert(source_phantom.forward_node_id,
+ forward_heap.Insert(source_phantom.forward_segment_id.id,
total_distance_to_forward -
source_phantom.GetForwardWeightPlusOffset(),
- source_phantom.forward_node_id);
+ source_phantom.forward_segment_id.id);
}
if (search_from_reverse_node)
{
- forward_heap.Insert(source_phantom.reverse_node_id,
+ forward_heap.Insert(source_phantom.reverse_segment_id.id,
total_distance_to_reverse -
source_phantom.GetReverseWeightPlusOffset(),
- source_phantom.reverse_node_id);
+ source_phantom.reverse_segment_id.id);
}
BOOST_ASSERT(forward_heap.Size() > 0);
BOOST_ASSERT(reverse_heap.Size() > 0);
- super::Search(forward_heap, reverse_heap, new_total_distance_to_forward,
- leg_packed_path_forward);
+
+ if (super::facade->GetCoreSize() > 0)
+ {
+ forward_core_heap.Clear();
+ reverse_core_heap.Clear();
+ BOOST_ASSERT(forward_core_heap.Size() == 0);
+ BOOST_ASSERT(reverse_core_heap.Size() == 0);
+ super::SearchWithCore(
+ forward_heap, reverse_heap, forward_core_heap, reverse_core_heap,
+ new_total_distance_to_forward, leg_packed_path_forward,
+ super::NeedsLoopForward(source_phantom, target_phantom), DO_NOT_FORCE_LOOP);
+ }
+ else
+ {
+ super::Search(forward_heap, reverse_heap, new_total_distance_to_forward,
+ leg_packed_path_forward,
+ super::NeedsLoopForward(source_phantom, target_phantom),
+ DO_NOT_FORCE_LOOP);
+ }
}
if (search_to_reverse_node)
{
forward_heap.Clear();
reverse_heap.Clear();
- reverse_heap.Insert(target_phantom.reverse_node_id,
+ reverse_heap.Insert(target_phantom.reverse_segment_id.id,
target_phantom.GetReverseWeightPlusOffset(),
- target_phantom.reverse_node_id);
+ target_phantom.reverse_segment_id.id);
if (search_from_forward_node)
{
- forward_heap.Insert(source_phantom.forward_node_id,
+ forward_heap.Insert(source_phantom.forward_segment_id.id,
total_distance_to_forward -
source_phantom.GetForwardWeightPlusOffset(),
- source_phantom.forward_node_id);
+ source_phantom.forward_segment_id.id);
}
if (search_from_reverse_node)
{
- forward_heap.Insert(source_phantom.reverse_node_id,
+ forward_heap.Insert(source_phantom.reverse_segment_id.id,
total_distance_to_reverse -
source_phantom.GetReverseWeightPlusOffset(),
- source_phantom.reverse_node_id);
+ source_phantom.reverse_segment_id.id);
}
BOOST_ASSERT(forward_heap.Size() > 0);
BOOST_ASSERT(reverse_heap.Size() > 0);
- super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse,
- leg_packed_path_reverse);
+ if (super::facade->GetCoreSize() > 0)
+ {
+ forward_core_heap.Clear();
+ reverse_core_heap.Clear();
+ BOOST_ASSERT(forward_core_heap.Size() == 0);
+ BOOST_ASSERT(reverse_core_heap.Size() == 0);
+ super::SearchWithCore(forward_heap, reverse_heap, forward_core_heap,
+ reverse_core_heap, new_total_distance_to_reverse,
+ leg_packed_path_reverse, DO_NOT_FORCE_LOOP,
+ super::NeedsLoopBackwards(source_phantom, target_phantom));
+ }
+ else
+ {
+ super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse,
+ leg_packed_path_reverse, DO_NOT_FORCE_LOOP,
+ super::NeedsLoopBackwards(source_phantom, target_phantom));
+ }
}
}
@@ -288,7 +227,7 @@ class ShortestPathRouting final
raw_route_data.shortest_path_length = shortest_path_length;
- for (const auto current_leg : osrm::irange<std::size_t>(0, packed_leg_begin.size() - 1))
+ for (const auto current_leg : util::irange<std::size_t>(0, packed_leg_begin.size() - 1))
{
auto leg_begin = total_packed_path.begin() + packed_leg_begin[current_leg];
auto leg_end = total_packed_path.begin() + packed_leg_begin[current_leg + 1];
@@ -297,28 +236,36 @@ class ShortestPathRouting final
raw_route_data.unpacked_path_segments[current_leg]);
raw_route_data.source_traversed_in_reverse.push_back(
- (*leg_begin != phantom_nodes_vector[current_leg].source_phantom.forward_node_id));
+ (*leg_begin !=
+ phantom_nodes_vector[current_leg].source_phantom.forward_segment_id.id));
raw_route_data.target_traversed_in_reverse.push_back(
(*std::prev(leg_end) !=
- phantom_nodes_vector[current_leg].target_phantom.forward_node_id));
+ phantom_nodes_vector[current_leg].target_phantom.forward_segment_id.id));
}
}
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
- const std::vector<bool> &uturn_indicators,
+ const boost::optional<bool> uturns,
InternalRouteResult &raw_route_data) const
{
- BOOST_ASSERT(uturn_indicators.size() == phantom_nodes_vector.size() + 1);
+ const bool allow_u_turn_at_via = uturns ? *uturns : super::facade->GetUTurnsDefault();
+
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
super::facade->GetNumberOfNodes());
+ engine_working_data.InitializeOrClearSecondThreadLocalStorage(
+ super::facade->GetNumberOfNodes());
QueryHeap &forward_heap = *(engine_working_data.forward_heap_1);
QueryHeap &reverse_heap = *(engine_working_data.reverse_heap_1);
+ QueryHeap &forward_core_heap = *(engine_working_data.forward_heap_2);
+ QueryHeap &reverse_core_heap = *(engine_working_data.reverse_heap_2);
int total_distance_to_forward = 0;
int total_distance_to_reverse = 0;
- bool search_from_forward_node = phantom_nodes_vector.front().source_phantom.forward_node_id != SPECIAL_NODEID;
- bool search_from_reverse_node = phantom_nodes_vector.front().source_phantom.reverse_node_id != SPECIAL_NODEID;
+ bool search_from_forward_node =
+ phantom_nodes_vector.front().source_phantom.forward_segment_id.enabled;
+ bool search_from_reverse_node =
+ phantom_nodes_vector.front().source_phantom.reverse_segment_id.enabled;
std::vector<NodeID> prev_packed_leg_to_forward;
std::vector<NodeID> prev_packed_leg_to_reverse;
@@ -342,47 +289,34 @@ class ShortestPathRouting final
const auto &source_phantom = phantom_node_pair.source_phantom;
const auto &target_phantom = phantom_node_pair.target_phantom;
+ bool search_to_forward_node = target_phantom.forward_segment_id.enabled;
+ bool search_to_reverse_node = target_phantom.reverse_segment_id.enabled;
- BOOST_ASSERT(current_leg + 1 < uturn_indicators.size());
- const bool allow_u_turn_at_via = uturn_indicators[current_leg + 1];
-
- bool search_to_forward_node = target_phantom.forward_node_id != SPECIAL_NODEID;
- bool search_to_reverse_node = target_phantom.reverse_node_id != SPECIAL_NODEID;
-
- BOOST_ASSERT(!search_from_forward_node || source_phantom.forward_node_id != SPECIAL_NODEID);
- BOOST_ASSERT(!search_from_reverse_node || source_phantom.reverse_node_id != SPECIAL_NODEID);
-
- if (source_phantom.forward_node_id == target_phantom.forward_node_id &&
- source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
- {
- search_to_forward_node = search_from_reverse_node;
- }
- if (source_phantom.reverse_node_id == target_phantom.reverse_node_id &&
- source_phantom.GetReverseWeightPlusOffset() > target_phantom.GetReverseWeightPlusOffset())
- {
- search_to_reverse_node = search_from_forward_node;
- }
+ BOOST_ASSERT(!search_from_forward_node || source_phantom.forward_segment_id.enabled);
+ BOOST_ASSERT(!search_from_reverse_node || source_phantom.reverse_segment_id.enabled);
BOOST_ASSERT(search_from_forward_node || search_from_reverse_node);
- if(search_to_reverse_node || search_to_forward_node)
+ if (search_to_reverse_node || search_to_forward_node)
{
if (allow_u_turn_at_via)
{
- SearchWithUTurn(forward_heap, reverse_heap, search_from_forward_node,
+ SearchWithUTurn(forward_heap, reverse_heap, forward_core_heap,
+ reverse_core_heap, search_from_forward_node,
search_from_reverse_node, search_to_forward_node,
search_to_reverse_node, source_phantom, target_phantom,
total_distance_to_forward, total_distance_to_reverse,
new_total_distance_to_forward, packed_leg_to_forward);
- // if only the reverse node is valid (e.g. when using the match plugin) we actually need to move
- if (target_phantom.forward_node_id == SPECIAL_NODEID)
+ // if only the reverse node is valid (e.g. when using the match plugin) we
+ // actually need to move
+ if (target_phantom.forward_segment_id.enabled)
{
- BOOST_ASSERT(target_phantom.reverse_node_id != SPECIAL_NODEID);
+ BOOST_ASSERT(target_phantom.reverse_segment_id.enabled);
new_total_distance_to_reverse = new_total_distance_to_forward;
packed_leg_to_reverse = std::move(packed_leg_to_forward);
new_total_distance_to_forward = INVALID_EDGE_WEIGHT;
}
- else if (target_phantom.reverse_node_id != SPECIAL_NODEID)
+ else if (target_phantom.reverse_segment_id.enabled)
{
new_total_distance_to_reverse = new_total_distance_to_forward;
packed_leg_to_reverse = packed_leg_to_forward;
@@ -390,24 +324,14 @@ class ShortestPathRouting final
}
else
{
- Search(forward_heap, reverse_heap, search_from_forward_node,
- search_from_reverse_node, search_to_forward_node, search_to_reverse_node,
- source_phantom, target_phantom, total_distance_to_forward,
- total_distance_to_reverse, new_total_distance_to_forward,
- new_total_distance_to_reverse, packed_leg_to_forward, packed_leg_to_reverse);
+ Search(forward_heap, reverse_heap, forward_core_heap, reverse_core_heap,
+ search_from_forward_node, search_from_reverse_node,
+ search_to_forward_node, search_to_reverse_node, source_phantom,
+ target_phantom, total_distance_to_forward, total_distance_to_reverse,
+ new_total_distance_to_forward, new_total_distance_to_reverse,
+ packed_leg_to_forward, packed_leg_to_reverse);
}
}
- else
- {
- search_to_forward_node = target_phantom.forward_node_id != SPECIAL_NODEID;
- search_to_reverse_node = target_phantom.reverse_node_id != SPECIAL_NODEID;
- BOOST_ASSERT(search_from_reverse_node == search_to_reverse_node);
- BOOST_ASSERT(search_from_forward_node == search_to_forward_node);
- SearchLoop(forward_heap, reverse_heap, search_from_forward_node,
- search_from_reverse_node, source_phantom, target_phantom, total_distance_to_forward,
- total_distance_to_reverse, new_total_distance_to_forward,
- new_total_distance_to_reverse, packed_leg_to_forward, packed_leg_to_reverse);
- }
// No path found for both target nodes?
if ((INVALID_EDGE_WEIGHT == new_total_distance_to_forward) &&
@@ -423,16 +347,16 @@ class ShortestPathRouting final
{
bool forward_to_forward =
(new_total_distance_to_forward != INVALID_EDGE_WEIGHT) &&
- packed_leg_to_forward.front() == source_phantom.forward_node_id;
+ packed_leg_to_forward.front() == source_phantom.forward_segment_id.id;
bool reverse_to_forward =
(new_total_distance_to_forward != INVALID_EDGE_WEIGHT) &&
- packed_leg_to_forward.front() == source_phantom.reverse_node_id;
+ packed_leg_to_forward.front() == source_phantom.reverse_segment_id.id;
bool forward_to_reverse =
(new_total_distance_to_reverse != INVALID_EDGE_WEIGHT) &&
- packed_leg_to_reverse.front() == source_phantom.forward_node_id;
+ packed_leg_to_reverse.front() == source_phantom.forward_segment_id.id;
bool reverse_to_reverse =
(new_total_distance_to_reverse != INVALID_EDGE_WEIGHT) &&
- packed_leg_to_reverse.front() == source_phantom.reverse_node_id;
+ packed_leg_to_reverse.front() == source_phantom.reverse_segment_id.id;
BOOST_ASSERT(!forward_to_forward || !reverse_to_forward);
BOOST_ASSERT(!forward_to_reverse || !reverse_to_reverse);
@@ -467,7 +391,7 @@ class ShortestPathRouting final
if (new_total_distance_to_forward != INVALID_EDGE_WEIGHT)
{
- BOOST_ASSERT(target_phantom.forward_node_id != SPECIAL_NODEID);
+ BOOST_ASSERT(target_phantom.forward_segment_id.enabled);
packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size());
total_packed_path_to_forward.insert(total_packed_path_to_forward.end(),
@@ -484,7 +408,7 @@ class ShortestPathRouting final
if (new_total_distance_to_reverse != INVALID_EDGE_WEIGHT)
{
- BOOST_ASSERT(target_phantom.reverse_node_id != SPECIAL_NODEID);
+ BOOST_ASSERT(target_phantom.reverse_segment_id.enabled);
packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size());
total_packed_path_to_reverse.insert(total_packed_path_to_reverse.end(),
@@ -532,5 +456,8 @@ class ShortestPathRouting final
}
}
};
+}
+}
+}
#endif /* SHORTEST_PATH_HPP */
diff --git a/include/engine/search_engine_data.hpp b/include/engine/search_engine_data.hpp
new file mode 100644
index 0000000..3112a78
--- /dev/null
+++ b/include/engine/search_engine_data.hpp
@@ -0,0 +1,42 @@
+#ifndef SEARCH_ENGINE_DATA_HPP
+#define SEARCH_ENGINE_DATA_HPP
+
+#include <boost/thread/tss.hpp>
+
+#include "util/typedefs.hpp"
+#include "util/binary_heap.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+
+struct HeapData
+{
+ NodeID parent;
+ /* explicit */ HeapData(NodeID p) : parent(p) {}
+};
+
+struct SearchEngineData
+{
+ using QueryHeap =
+ util::BinaryHeap<NodeID, NodeID, int, HeapData, util::UnorderedMapStorage<NodeID, int>>;
+ using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
+
+ static SearchEngineHeapPtr forward_heap_1;
+ static SearchEngineHeapPtr reverse_heap_1;
+ static SearchEngineHeapPtr forward_heap_2;
+ static SearchEngineHeapPtr reverse_heap_2;
+ static SearchEngineHeapPtr forward_heap_3;
+ static SearchEngineHeapPtr reverse_heap_3;
+
+ void InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes);
+
+ void InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes);
+
+ void InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes);
+};
+}
+}
+
+#endif // SEARCH_ENGINE_DATA_HPP
diff --git a/server/http/compression_type.hpp b/include/engine/status.hpp
similarity index 83%
rename from server/http/compression_type.hpp
rename to include/engine/status.hpp
index f0dc692..4a0fc9a 100644
--- a/server/http/compression_type.hpp
+++ b/include/engine/status.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,18 +25,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef COMPRESSION_TYPE_HPP
-#define COMPRESSION_TYPE_HPP
+#ifndef ENGINE_STATUS_HPP
+#define ENGINE_STATUS_HPP
-namespace http
+namespace osrm
+{
+namespace engine
{
-enum compression_type
+/**
+ * Status for indicating query success or failure.
+ * \see OSRM
+ */
+enum class Status
{
- no_compression,
- gzip_rfc1952,
- deflate_rfc1951
+ Ok,
+ Error
};
}
+}
-#endif // COMPRESSION_TYPE_HPP
+#endif
diff --git a/algorithms/trip_brute_force.hpp b/include/engine/trip/trip_brute_force.hpp
similarity index 57%
rename from algorithms/trip_brute_force.hpp
rename to include/engine/trip/trip_brute_force.hpp
index 601971c..b8fe8ec 100644
--- a/algorithms/trip_brute_force.hpp
+++ b/include/engine/trip/trip_brute_force.hpp
@@ -1,38 +1,11 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef TRIP_BRUTE_FORCE_HPP
#define TRIP_BRUTE_FORCE_HPP
-#include "../data_structures/search_engine.hpp"
-#include "../util/dist_table_wrapper.hpp"
-#include "../util/simple_logger.hpp"
+#include "util/typedefs.hpp"
+#include "util/dist_table_wrapper.hpp"
+#include "util/simple_logger.hpp"
-#include <osrm/json_container.hpp>
+#include "osrm/json_container.hpp"
#include <cstdlib>
#include <algorithm>
@@ -43,11 +16,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace osrm
{
+namespace engine
+{
namespace trip
{
// computes the distance of a given permutation
-EdgeWeight ReturnDistance(const DistTableWrapper<EdgeWeight> &dist_table,
+EdgeWeight ReturnDistance(const util::DistTableWrapper<EdgeWeight> &dist_table,
const std::vector<NodeID> &location_order,
const EdgeWeight min_route_dist,
const std::size_t component_size)
@@ -71,7 +46,7 @@ template <typename NodeIDIterator>
std::vector<NodeID> BruteForceTrip(const NodeIDIterator start,
const NodeIDIterator end,
const std::size_t number_of_locations,
- const DistTableWrapper<EdgeWeight> &dist_table)
+ const util::DistTableWrapper<EdgeWeight> &dist_table)
{
(void)number_of_locations; // unused
@@ -102,7 +77,8 @@ std::vector<NodeID> BruteForceTrip(const NodeIDIterator start,
return route;
}
+}
+}
+}
-} // end namespace trip
-} // end namespace osrm
#endif // TRIP_BRUTE_FORCE_HPP
diff --git a/algorithms/trip_farthest_insertion.hpp b/include/engine/trip/trip_farthest_insertion.hpp
similarity index 80%
rename from algorithms/trip_farthest_insertion.hpp
rename to include/engine/trip/trip_farthest_insertion.hpp
index 91f0aa4..c062e72 100644
--- a/algorithms/trip_farthest_insertion.hpp
+++ b/include/engine/trip/trip_farthest_insertion.hpp
@@ -1,37 +1,11 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef TRIP_FARTHEST_INSERTION_HPP
#define TRIP_FARTHEST_INSERTION_HPP
-#include "../data_structures/search_engine.hpp"
-#include "../util/dist_table_wrapper.hpp"
+#include "util/typedefs.hpp"
+#include "util/dist_table_wrapper.hpp"
+#include "util/typedefs.hpp"
-#include <osrm/json_container.hpp>
+#include "osrm/json_container.hpp"
#include <boost/assert.hpp>
#include <cstdlib>
@@ -42,6 +16,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace osrm
{
+namespace engine
+{
namespace trip
{
@@ -50,7 +26,7 @@ namespace trip
using NodeIDIter = std::vector<NodeID>::iterator;
std::pair<EdgeWeight, NodeIDIter>
GetShortestRoundTrip(const NodeID new_loc,
- const DistTableWrapper<EdgeWeight> &dist_table,
+ const util::DistTableWrapper<EdgeWeight> &dist_table,
const std::size_t number_of_locations,
std::vector<NodeID> &route)
{
@@ -103,7 +79,7 @@ std::vector<NodeID> FindRoute(const std::size_t &number_of_locations,
const std::size_t &component_size,
const NodeIDIterator &start,
const NodeIDIterator &end,
- const DistTableWrapper<EdgeWeight> &dist_table,
+ const util::DistTableWrapper<EdgeWeight> &dist_table,
const NodeID &start1,
const NodeID &start2)
{
@@ -165,7 +141,7 @@ template <typename NodeIDIterator>
std::vector<NodeID> FarthestInsertionTrip(const NodeIDIterator &start,
const NodeIDIterator &end,
const std::size_t number_of_locations,
- const DistTableWrapper<EdgeWeight> &dist_table)
+ const util::DistTableWrapper<EdgeWeight> &dist_table)
{
//////////////////////////////////////////////////////////////////////////////////////////////////
// START FARTHEST INSERTION HERE
@@ -177,6 +153,13 @@ std::vector<NodeID> FarthestInsertionTrip(const NodeIDIterator &start,
// 5. DONE!
//////////////////////////////////////////////////////////////////////////////////////////////////
+
+ // Guard against division-by-zero in the code path below.
+ BOOST_ASSERT(number_of_locations > 0);
+
+ // Guard against dist_table being empty therefore max_element returning the end iterator.
+ BOOST_ASSERT(dist_table.size() > 0);
+
const auto component_size = std::distance(start, end);
BOOST_ASSERT(component_size >= 0);
@@ -194,12 +177,16 @@ std::vector<NodeID> FarthestInsertionTrip(const NodeIDIterator &start,
}
else
{
- auto max_dist = 0;
+ auto max_dist = std::numeric_limits<EdgeWeight>::min();
+
for (auto x = start; x != end; ++x)
{
for (auto y = start; y != end; ++y)
{
const auto xy_dist = dist_table(*x, *y);
+ // SCC decomposition done correctly?
+ BOOST_ASSERT(xy_dist != INVALID_EDGE_WEIGHT);
+
if (xy_dist > max_dist)
{
max_dist = xy_dist;
@@ -209,14 +196,15 @@ std::vector<NodeID> FarthestInsertionTrip(const NodeIDIterator &start,
}
}
}
+
BOOST_ASSERT(max_from >= 0);
BOOST_ASSERT(max_to >= 0);
BOOST_ASSERT_MSG(static_cast<std::size_t>(max_from) < number_of_locations, "start node");
BOOST_ASSERT_MSG(static_cast<std::size_t>(max_to) < number_of_locations, "start node");
return FindRoute(number_of_locations, component_size, start, end, dist_table, max_from, max_to);
}
-
-} // end namespace trip
-} // end namespace osrm
+}
+}
+}
#endif // TRIP_FARTHEST_INSERTION_HPP
diff --git a/algorithms/trip_nearest_neighbour.hpp b/include/engine/trip/trip_nearest_neighbour.hpp
similarity index 64%
rename from algorithms/trip_nearest_neighbour.hpp
rename to include/engine/trip/trip_nearest_neighbour.hpp
index 0ae1792..df70bc4 100644
--- a/algorithms/trip_nearest_neighbour.hpp
+++ b/include/engine/trip/trip_nearest_neighbour.hpp
@@ -1,38 +1,11 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef TRIP_NEAREST_NEIGHBOUR_HPP
#define TRIP_NEAREST_NEIGHBOUR_HPP
-#include "../data_structures/search_engine.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/dist_table_wrapper.hpp"
+#include "util/typedefs.hpp"
+#include "util/simple_logger.hpp"
+#include "util/dist_table_wrapper.hpp"
-#include <osrm/json_container.hpp>
+#include "osrm/json_container.hpp"
#include <cstdlib>
#include <algorithm>
@@ -42,13 +15,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace osrm
{
+namespace engine
+{
namespace trip
{
+
template <typename NodeIDIterator>
std::vector<NodeID> NearestNeighbourTrip(const NodeIDIterator &start,
const NodeIDIterator &end,
const std::size_t number_of_locations,
- const DistTableWrapper<EdgeWeight> &dist_table)
+ const util::DistTableWrapper<EdgeWeight> &dist_table)
{
//////////////////////////////////////////////////////////////////////////////////////////////////
// START GREEDY NEAREST NEIGHBOUR HERE
@@ -116,7 +92,8 @@ std::vector<NodeID> NearestNeighbourTrip(const NodeIDIterator &start,
}
return route;
}
+}
+}
+}
-} // end namespace trip
-} // end namespace osrm
-#endif // TRIP_NEAREST_NEIGHBOUR_HPP
\ No newline at end of file
+#endif // TRIP_NEAREST_NEIGHBOUR_HPP
diff --git a/include/engine/trip/trip_tabu_search.hpp b/include/engine/trip/trip_tabu_search.hpp
new file mode 100644
index 0000000..24ff745
--- /dev/null
+++ b/include/engine/trip/trip_tabu_search.hpp
@@ -0,0 +1,41 @@
+#ifndef TRIP_BRUTE_FORCE_HPP
+#define TRIP_BRUTE_FORCE_HPP
+
+#include "engine/search_engine.hpp"
+#include "util/simple_logger.hpp"
+
+#include "osrm/json_container.hpp"
+
+#include <cstdlib>
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <limits>
+
+namespace osrm
+{
+namespace engine
+{
+namespace trip
+{
+
+// todo: yet to be implemented
+void TabuSearchTrip(std::vector<unsigned> &location,
+ const PhantomNodeArray &phantom_node_vector,
+ const std::vector<EdgeWeight> &dist_table,
+ InternalRouteResult &min_route,
+ std::vector<int> &min_loc_permutation)
+{
+}
+
+void TabuSearchTrip(const PhantomNodeArray &phantom_node_vector,
+ const std::vector<EdgeWeight> &dist_table,
+ InternalRouteResult &min_route,
+ std::vector<int> &min_loc_permutation)
+{
+}
+}
+}
+}
+
+#endif // TRIP_BRUTE_FORCE_HPP
diff --git a/include/extractor/compressed_edge_container.hpp b/include/extractor/compressed_edge_container.hpp
new file mode 100644
index 0000000..662c18e
--- /dev/null
+++ b/include/extractor/compressed_edge_container.hpp
@@ -0,0 +1,57 @@
+#ifndef GEOMETRY_COMPRESSOR_HPP_
+#define GEOMETRY_COMPRESSOR_HPP_
+
+#include "util/typedefs.hpp"
+
+#include <unordered_map>
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace extractor
+{
+
+class CompressedEdgeContainer
+{
+ public:
+ struct CompressedEdge
+ {
+ public:
+ NodeID node_id; // refers to an internal node-based-node
+ EdgeWeight weight; // the weight of the edge leading to this node
+ };
+ using EdgeBucket = std::vector<CompressedEdge>;
+
+ CompressedEdgeContainer();
+ void CompressEdge(const EdgeID surviving_edge_id,
+ const EdgeID removed_edge_id,
+ const NodeID via_node_id,
+ const NodeID target_node,
+ const EdgeWeight weight1,
+ const EdgeWeight weight2);
+
+ void
+ AddUncompressedEdge(const EdgeID edgei_id, const NodeID target_node, const EdgeWeight weight);
+
+ bool HasEntryForID(const EdgeID edge_id) const;
+ void PrintStatistics() const;
+ void SerializeInternalVector(const std::string &path) const;
+ unsigned GetPositionForID(const EdgeID edge_id) const;
+ const EdgeBucket &GetBucketReference(const EdgeID edge_id) const;
+ NodeID GetFirstEdgeTargetID(const EdgeID edge_id) const;
+ NodeID GetLastEdgeSourceID(const EdgeID edge_id) const;
+
+ private:
+ int free_list_maximum = 0;
+
+ void IncreaseFreeList();
+ std::vector<EdgeBucket> m_compressed_geometries;
+ std::vector<unsigned> m_free_list;
+ std::unordered_map<EdgeID, unsigned> m_edge_id_to_list_index_map;
+};
+}
+}
+
+#endif // GEOMETRY_COMPRESSOR_HPP_
diff --git a/include/extractor/edge_based_edge.hpp b/include/extractor/edge_based_edge.hpp
new file mode 100644
index 0000000..e4e5ef3
--- /dev/null
+++ b/include/extractor/edge_based_edge.hpp
@@ -0,0 +1,80 @@
+#ifndef EDGE_BASED_EDGE_HPP
+#define EDGE_BASED_EDGE_HPP
+
+#include "extractor/travel_mode.hpp"
+#include "util/typedefs.hpp"
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct EdgeBasedEdge
+{
+ public:
+ EdgeBasedEdge();
+
+ template <class EdgeT> explicit EdgeBasedEdge(const EdgeT &other);
+
+ EdgeBasedEdge(const NodeID source,
+ const NodeID target,
+ const NodeID edge_id,
+ const EdgeWeight weight,
+ const bool forward,
+ const bool backward);
+
+ bool operator<(const EdgeBasedEdge &other) const;
+
+ NodeID source;
+ NodeID target;
+ NodeID edge_id;
+ EdgeWeight weight : 30;
+ bool forward : 1;
+ bool backward : 1;
+};
+
+// Impl.
+
+inline EdgeBasedEdge::EdgeBasedEdge()
+ : source(0), target(0), edge_id(0), weight(0), forward(false), backward(false)
+{
+}
+
+template <class EdgeT>
+inline EdgeBasedEdge::EdgeBasedEdge(const EdgeT &other)
+ : source(other.source), target(other.target), edge_id(other.data.via),
+ weight(other.data.distance), forward(other.data.forward), backward(other.data.backward)
+{
+}
+
+inline EdgeBasedEdge::EdgeBasedEdge(const NodeID source,
+ const NodeID target,
+ const NodeID edge_id,
+ const EdgeWeight weight,
+ const bool forward,
+ const bool backward)
+ : source(source), target(target), edge_id(edge_id), weight(weight), forward(forward),
+ backward(backward)
+{
+}
+
+inline bool EdgeBasedEdge::operator<(const EdgeBasedEdge &other) const
+{
+ if (source == other.source)
+ {
+ if (target == other.target)
+ {
+ if (weight == other.weight)
+ {
+ return forward && backward && ((!other.forward) || (!other.backward));
+ }
+ return weight < other.weight;
+ }
+ return target < other.target;
+ }
+ return source < other.source;
+}
+} // ns extractor
+} // ns osrm
+
+#endif /* EDGE_BASED_EDGE_HPP */
diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp
new file mode 100644
index 0000000..1aff390
--- /dev/null
+++ b/include/extractor/edge_based_graph_factory.hpp
@@ -0,0 +1,134 @@
+// This class constructs the edge-expanded routing graph
+
+#ifndef EDGE_BASED_GRAPH_FACTORY_HPP_
+#define EDGE_BASED_GRAPH_FACTORY_HPP_
+
+#include "extractor/edge_based_edge.hpp"
+#include "extractor/profile_properties.hpp"
+#include "extractor/restriction_map.hpp"
+#include "extractor/compressed_edge_container.hpp"
+#include "extractor/edge_based_node.hpp"
+#include "extractor/original_edge_data.hpp"
+#include "extractor/query_node.hpp"
+#include "extractor/guidance/turn_analysis.hpp"
+
+#include "extractor/guidance/turn_instruction.hpp"
+
+#include "util/node_based_graph.hpp"
+#include "util/typedefs.hpp"
+#include "util/deallocating_vector.hpp"
+#include "util/name_table.hpp"
+
+#include <algorithm>
+#include <cstdint>
+#include <cstddef>
+#include <iosfwd>
+#include <memory>
+#include <queue>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+#include <string>
+
+#include <boost/filesystem/fstream.hpp>
+
+struct lua_State;
+
+namespace osrm
+{
+namespace extractor
+{
+
+class EdgeBasedGraphFactory
+{
+ public:
+ EdgeBasedGraphFactory(const EdgeBasedGraphFactory &) = delete;
+ EdgeBasedGraphFactory &operator=(const EdgeBasedGraphFactory &) = delete;
+
+ explicit EdgeBasedGraphFactory(std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph,
+ const CompressedEdgeContainer &compressed_edge_container,
+ const std::unordered_set<NodeID> &barrier_nodes,
+ const std::unordered_set<NodeID> &traffic_lights,
+ std::shared_ptr<const RestrictionMap> restriction_map,
+ const std::vector<QueryNode> &node_info_list,
+ ProfileProperties profile_properties,
+ const util::NameTable &name_table);
+
+ void Run(const std::string &original_edge_data_filename,
+ lua_State *lua_state,
+ const std::string &edge_segment_lookup_filename,
+ const std::string &edge_penalty_filename,
+ const bool generate_edge_lookup);
+
+ // The following get access functions destroy the content in the factory
+ void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges);
+ void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes);
+ void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
+ void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights);
+
+ unsigned GetHighestEdgeID();
+
+ // Basic analysis of a turn (u --(e1)-- v --(e2)-- w)
+ // with known angle.
+ // Handles special cases like u-turns and roundabouts
+ // For basic turns, the turn based on the angle-classification is returned
+ guidance::TurnInstruction AnalyzeTurn(const NodeID u,
+ const EdgeID e1,
+ const NodeID v,
+ const EdgeID e2,
+ const NodeID w,
+ const double angle) const;
+
+ std::int32_t GetTurnPenalty(double angle, lua_State *lua_state) const;
+
+ private:
+ using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
+
+ //! maps index from m_edge_based_node_list to ture/false if the node is an entry point to the
+ //! graph
+ std::vector<bool> m_edge_based_node_is_startpoint;
+
+ //! node weights that indicate the length of the segment (node based) represented by the
+ //! edge-based node
+ std::vector<EdgeWeight> m_edge_based_node_weights;
+
+ //! list of edge based nodes (compressed segments)
+ std::vector<EdgeBasedNode> m_edge_based_node_list;
+ util::DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
+ unsigned m_max_edge_id;
+
+ const std::vector<QueryNode> &m_node_info_list;
+ std::shared_ptr<util::NodeBasedDynamicGraph> m_node_based_graph;
+ std::shared_ptr<RestrictionMap const> m_restriction_map;
+
+ const std::unordered_set<NodeID> &m_barrier_nodes;
+ const std::unordered_set<NodeID> &m_traffic_lights;
+ const CompressedEdgeContainer &m_compressed_edge_container;
+
+ ProfileProperties profile_properties;
+
+ const util::NameTable &name_table;
+
+ void CompressGeometry();
+ unsigned RenumberEdges();
+ void GenerateEdgeExpandedNodes();
+ void GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
+ lua_State *lua_state,
+ const std::string &edge_segment_lookup_filename,
+ const std::string &edge_fixed_penalties_filename,
+ const bool generate_edge_lookup);
+
+ void InsertEdgeBasedNode(const NodeID u, const NodeID v);
+
+ void FlushVectorToStream(std::ofstream &edge_data_file,
+ std::vector<OriginalEdgeData> &original_edge_data_vector) const;
+
+ std::size_t restricted_turns_counter;
+ std::size_t skipped_uturns_counter;
+ std::size_t skipped_barrier_turns_counter;
+};
+} // namespace extractor
+} // namespace osrm
+
+#endif /* EDGE_BASED_GRAPH_FACTORY_HPP_ */
diff --git a/include/extractor/edge_based_node.hpp b/include/extractor/edge_based_node.hpp
new file mode 100644
index 0000000..699e9e7
--- /dev/null
+++ b/include/extractor/edge_based_node.hpp
@@ -0,0 +1,76 @@
+#ifndef EDGE_BASED_NODE_HPP
+#define EDGE_BASED_NODE_HPP
+
+#include "extractor/travel_mode.hpp"
+#include "util/typedefs.hpp"
+
+#include <boost/assert.hpp>
+
+#include "osrm/coordinate.hpp"
+
+#include <limits>
+
+namespace osrm
+{
+namespace extractor
+{
+
+/// This is what util::StaticRTree serialized and stores on disk
+/// It is generated in EdgeBasedGraphFactory.
+struct EdgeBasedNode
+{
+ EdgeBasedNode()
+ : forward_segment_id{SPECIAL_SEGMENTID, false},
+ reverse_segment_id{SPECIAL_SEGMENTID, false}, u(SPECIAL_NODEID),
+ v(SPECIAL_NODEID), name_id(0), forward_packed_geometry_id(SPECIAL_EDGEID),
+ reverse_packed_geometry_id(SPECIAL_EDGEID), component{INVALID_COMPONENTID, false},
+ fwd_segment_position(std::numeric_limits<unsigned short>::max()),
+ forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
+ backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
+ {
+ }
+
+ explicit EdgeBasedNode(const SegmentID forward_segment_id_,
+ const SegmentID reverse_segment_id_,
+ NodeID u,
+ NodeID v,
+ unsigned name_id,
+ unsigned forward_geometry_id_,
+ unsigned reverse_geometry_id_,
+ bool is_tiny_component,
+ unsigned component_id,
+ unsigned short fwd_segment_position,
+ TravelMode forward_travel_mode,
+ TravelMode backward_travel_mode)
+ : forward_segment_id(forward_segment_id_),
+ reverse_segment_id(reverse_segment_id_), u(u), v(v), name_id(name_id),
+ forward_packed_geometry_id(forward_geometry_id_),
+ reverse_packed_geometry_id(reverse_geometry_id_),
+ component{component_id, is_tiny_component}, fwd_segment_position(fwd_segment_position),
+ forward_travel_mode(forward_travel_mode), backward_travel_mode(backward_travel_mode)
+ {
+ BOOST_ASSERT(forward_segment_id.enabled ||
+ reverse_segment_id.enabled);
+ }
+
+ SegmentID forward_segment_id; // needed for edge-expanded graph
+ SegmentID reverse_segment_id; // needed for edge-expanded graph
+ NodeID u; // indices into the coordinates array
+ NodeID v; // indices into the coordinates array
+ unsigned name_id; // id of the edge name
+
+ unsigned forward_packed_geometry_id;
+ unsigned reverse_packed_geometry_id;
+ struct
+ {
+ unsigned id : 31;
+ bool is_tiny : 1;
+ } component;
+ unsigned short fwd_segment_position; // segment id in a compressed geometry
+ TravelMode forward_travel_mode : 4;
+ TravelMode backward_travel_mode : 4;
+};
+}
+}
+
+#endif // EDGE_BASED_NODE_HPP
diff --git a/include/extractor/external_memory_node.hpp b/include/extractor/external_memory_node.hpp
new file mode 100644
index 0000000..d26f7d3
--- /dev/null
+++ b/include/extractor/external_memory_node.hpp
@@ -0,0 +1,56 @@
+#ifndef EXTERNAL_MEMORY_NODE_HPP_
+#define EXTERNAL_MEMORY_NODE_HPP_
+
+#include "extractor/query_node.hpp"
+
+#include "util/typedefs.hpp"
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct ExternalMemoryNode : QueryNode
+{
+ ExternalMemoryNode(const util::FixedLongitude lon_,
+ const util::FixedLatitude lat_,
+ OSMNodeID node_id_,
+ bool barrier_,
+ bool traffic_lights_)
+ : QueryNode(lon_, lat_, node_id_), barrier(barrier_), traffic_lights(traffic_lights_)
+ {
+ }
+
+ ExternalMemoryNode() : barrier(false), traffic_lights(false) {}
+
+ static ExternalMemoryNode min_value()
+ {
+ return ExternalMemoryNode(util::FixedLongitude(0), util::FixedLatitude(0), MIN_OSM_NODEID,
+ false, false);
+ }
+
+ static ExternalMemoryNode max_value()
+ {
+ return ExternalMemoryNode(util::FixedLongitude(std::numeric_limits<int>::max()),
+ util::FixedLatitude(std::numeric_limits<int>::max()),
+ MAX_OSM_NODEID, false, false);
+ }
+
+ bool barrier;
+ bool traffic_lights;
+};
+
+struct ExternalMemoryNodeSTXXLCompare
+{
+ using value_type = ExternalMemoryNode;
+ value_type max_value() { return value_type::max_value(); }
+ value_type min_value() { return value_type::min_value(); }
+ bool operator()(const value_type &left, const value_type &right) const
+ {
+ return left.node_id < right.node_id;
+ }
+};
+}
+}
+
+#endif /* EXTERNAL_MEMORY_NODE_HPP_ */
diff --git a/extractor/extraction_containers.hpp b/include/extractor/extraction_containers.hpp
similarity index 51%
rename from extractor/extraction_containers.hpp
rename to include/extractor/extraction_containers.hpp
index 541ad35..848e457 100644
--- a/extractor/extraction_containers.hpp
+++ b/include/extractor/extraction_containers.hpp
@@ -1,42 +1,20 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef EXTRACTION_CONTAINERS_HPP
#define EXTRACTION_CONTAINERS_HPP
-#include "internal_extractor_edge.hpp"
-#include "first_and_last_segment_of_way.hpp"
-#include "scripting_environment.hpp"
-#include "../data_structures/external_memory_node.hpp"
-#include "../data_structures/restriction.hpp"
+#include "extractor/internal_extractor_edge.hpp"
+#include "extractor/first_and_last_segment_of_way.hpp"
+#include "extractor/scripting_environment.hpp"
+#include "extractor/external_memory_node.hpp"
+#include "extractor/restriction.hpp"
#include <stxxl/vector>
#include <unordered_map>
+namespace osrm
+{
+namespace extractor
+{
+
/**
* Uses external memory containers from stxxl to store all the data that
* is collected by the extractor callbacks.
@@ -56,10 +34,11 @@ class ExtractionContainers
void PrepareRestrictions();
void PrepareEdges(lua_State *segment_state);
- void WriteNodes(std::ofstream& file_out_stream) const;
- void WriteRestrictions(const std::string& restrictions_file_name) const;
- void WriteEdges(std::ofstream& file_out_stream) const;
- void WriteNames(const std::string& names_file_name) const;
+ void WriteNodes(std::ofstream &file_out_stream) const;
+ void WriteRestrictions(const std::string &restrictions_file_name) const;
+ void WriteEdges(std::ofstream &file_out_stream) const;
+ void WriteNames(const std::string &names_file_name) const;
+
public:
using STXXLNodeIDVector = stxxl::vector<OSMNodeID>;
using STXXLNodeVector = stxxl::vector<ExternalMemoryNode>;
@@ -86,5 +65,7 @@ class ExtractionContainers
const std::string &names_file_name,
lua_State *segment_state);
};
+}
+}
#endif /* EXTRACTION_CONTAINERS_HPP */
diff --git a/extractor/extraction_helper_functions.hpp b/include/extractor/extraction_helper_functions.hpp
similarity index 53%
rename from extractor/extraction_helper_functions.hpp
rename to include/extractor/extraction_helper_functions.hpp
index 69ab456..cbd5a64 100644
--- a/extractor/extraction_helper_functions.hpp
+++ b/include/extractor/extraction_helper_functions.hpp
@@ -1,35 +1,8 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef EXTRACTION_HELPER_FUNCTIONS_HPP
#define EXTRACTION_HELPER_FUNCTIONS_HPP
-#include "../util/cast.hpp"
-#include "../util/iso_8601_duration_parser.hpp"
+#include "util/cast.hpp"
+#include "util/iso_8601_duration_parser.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string_regex.hpp>
@@ -39,7 +12,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <limits>
#include <string>
-bool simple_duration_is_valid(const std::string &s)
+namespace osrm
+{
+namespace extractor
+{
+
+inline bool simple_duration_is_valid(const std::string &s)
{
boost::regex simple_format(
"((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",
@@ -54,10 +32,10 @@ bool simple_duration_is_valid(const std::string &s)
return false;
}
-bool iso_8601_duration_is_valid(const std::string &s)
+inline bool iso_8601_duration_is_valid(const std::string &s)
{
- iso_8601_grammar<std::string::const_iterator> iso_parser;
- const bool result = qi::parse(s.begin(), s.end(), iso_parser);
+ util::iso_8601_grammar<std::string::const_iterator> iso_parser;
+ const bool result = boost::spirit::qi::parse(s.begin(), s.end(), iso_parser);
// check if the was an error with the request
if (result && (0 != iso_parser.get_duration()))
@@ -67,12 +45,12 @@ bool iso_8601_duration_is_valid(const std::string &s)
return false;
}
-bool durationIsValid(const std::string &s)
+inline bool durationIsValid(const std::string &s)
{
return simple_duration_is_valid(s) || iso_8601_duration_is_valid(s);
}
-unsigned parseDuration(const std::string &s)
+inline unsigned parseDuration(const std::string &s)
{
if (simple_duration_is_valid(s))
{
@@ -108,13 +86,15 @@ unsigned parseDuration(const std::string &s)
}
else if (iso_8601_duration_is_valid(s))
{
- iso_8601_grammar<std::string::const_iterator> iso_parser;
- qi::parse(s.begin(), s.end(), iso_parser);
+ util::iso_8601_grammar<std::string::const_iterator> iso_parser;
+ boost::spirit::qi::parse(s.begin(), s.end(), iso_parser);
return iso_parser.get_duration();
}
return std::numeric_limits<unsigned>::max();
}
+}
+}
#endif // EXTRACTION_HELPER_FUNCTIONS_HPP
diff --git a/include/extractor/extraction_node.hpp b/include/extractor/extraction_node.hpp
new file mode 100644
index 0000000..e82f298
--- /dev/null
+++ b/include/extractor/extraction_node.hpp
@@ -0,0 +1,19 @@
+#ifndef EXTRACTION_NODE_HPP
+#define EXTRACTION_NODE_HPP
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct ExtractionNode
+{
+ ExtractionNode() : traffic_lights(false), barrier(false) {}
+ void clear() { traffic_lights = barrier = false; }
+ bool traffic_lights;
+ bool barrier;
+};
+}
+}
+
+#endif // EXTRACTION_NODE_HPP
diff --git a/include/extractor/extraction_way.hpp b/include/extractor/extraction_way.hpp
new file mode 100644
index 0000000..f82787d
--- /dev/null
+++ b/include/extractor/extraction_way.hpp
@@ -0,0 +1,58 @@
+#ifndef EXTRACTION_WAY_HPP
+#define EXTRACTION_WAY_HPP
+
+#include "extractor/travel_mode.hpp"
+#include "util/typedefs.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace extractor
+{
+
+/**
+ * This struct is the direct result of the call to ```way_function```
+ * in the lua based profile.
+ *
+ * It is split into multiple edge segments in the ExtractorCallback.
+ */
+struct ExtractionWay
+{
+ ExtractionWay() { clear(); }
+
+ void clear()
+ {
+ forward_speed = -1;
+ backward_speed = -1;
+ duration = -1;
+ roundabout = false;
+ is_startpoint = true;
+ is_access_restricted = false;
+ name.clear();
+ forward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
+ backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
+ }
+
+ // These accessors exists because it's not possible to take the address of a bitfield,
+ // and LUA therefore cannot read/write the mode attributes directly.
+ void set_forward_mode(const TravelMode m) { forward_travel_mode = m; }
+ TravelMode get_forward_mode() const { return forward_travel_mode; }
+ void set_backward_mode(const TravelMode m) { backward_travel_mode = m; }
+ TravelMode get_backward_mode() const { return backward_travel_mode; }
+
+ double forward_speed;
+ double backward_speed;
+ double duration;
+ std::string name;
+ bool roundabout;
+ bool is_access_restricted;
+ bool is_startpoint;
+ TravelMode forward_travel_mode : 4;
+ TravelMode backward_travel_mode : 4;
+};
+}
+}
+
+#endif // EXTRACTION_WAY_HPP
diff --git a/extractor/extractor.hpp b/include/extractor/extractor.hpp
similarity index 65%
rename from extractor/extractor.hpp
rename to include/extractor/extractor.hpp
index c147f19..1b61513 100644
--- a/extractor/extractor.hpp
+++ b/include/extractor/extractor.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,39 +28,56 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef EXTRACTOR_HPP
#define EXTRACTOR_HPP
-#include "extractor_options.hpp"
-#include "edge_based_graph_factory.hpp"
-#include "../algorithms/graph_compressor.hpp"
+#include "extractor/edge_based_edge.hpp"
+#include "extractor/extractor_config.hpp"
+#include "extractor/edge_based_graph_factory.hpp"
+#include "extractor/graph_compressor.hpp"
-class extractor
+#include "util/typedefs.hpp"
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct ProfileProperties;
+
+class Extractor
{
public:
- extractor(ExtractorConfig extractor_config) : config(std::move(extractor_config)) {}
+ Extractor(ExtractorConfig extractor_config) : config(std::move(extractor_config)) {}
int run();
private:
ExtractorConfig config;
- void SetupScriptingEnvironment(lua_State *myLuaState, SpeedProfileProperties &speed_profile);
+
std::pair<std::size_t, std::size_t>
- BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
+ BuildEdgeExpandedGraph(lua_State* lua_state,
+ const ProfileProperties& profile_properties,
+ std::vector<QueryNode> &internal_to_external_node_map,
std::vector<EdgeBasedNode> &node_based_edge_list,
std::vector<bool> &node_is_startpoint,
- DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list);
+ std::vector<EdgeWeight> &edge_based_node_weights,
+ util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list);
+ void WriteProfileProperties(const std::string& output_path, const ProfileProperties& properties) const;
void WriteNodeMapping(const std::vector<QueryNode> &internal_to_external_node_map);
void FindComponents(unsigned max_edge_id,
- const DeallocatingVector<EdgeBasedEdge> &edges,
+ const util::DeallocatingVector<EdgeBasedEdge> &edges,
std::vector<EdgeBasedNode> &nodes) const;
void BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
std::vector<bool> node_is_startpoint,
const std::vector<QueryNode> &internal_to_external_node_map);
std::shared_ptr<RestrictionMap> LoadRestrictionMap();
- std::shared_ptr<NodeBasedDynamicGraph>
+ std::shared_ptr<util::NodeBasedDynamicGraph>
LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
std::unordered_set<NodeID> &traffic_lights,
std::vector<QueryNode> &internal_to_external_node_map);
- void WriteEdgeBasedGraph(std::string const &output_file_filename,
- size_t const max_edge_id,
- DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list);
+ void WriteEdgeBasedGraph(const std::string &output_file_filename,
+ const size_t max_edge_id,
+ util::DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list);
};
+}
+}
+
#endif /* EXTRACTOR_HPP */
diff --git a/extractor/extractor_callbacks.hpp b/include/extractor/extractor_callbacks.hpp
similarity index 51%
rename from extractor/extractor_callbacks.hpp
rename to include/extractor/extractor_callbacks.hpp
index 0026b6f..db4e870 100644
--- a/extractor/extractor_callbacks.hpp
+++ b/include/extractor/extractor_callbacks.hpp
@@ -1,50 +1,28 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef EXTRACTOR_CALLBACKS_HPP
#define EXTRACTOR_CALLBACKS_HPP
-#include "../typedefs.h"
+#include "util/typedefs.hpp"
#include <boost/optional/optional_fwd.hpp>
#include <string>
#include <unordered_map>
-struct ExternalMemoryNode;
-class ExtractionContainers;
-struct InputRestrictionContainer;
-struct ExtractionNode;
-struct ExtractionWay;
namespace osmium
{
class Node;
class Way;
}
+namespace osrm
+{
+namespace extractor
+{
+
+class ExtractionContainers;
+struct InputRestrictionContainer;
+struct ExtractionNode;
+struct ExtractionWay;
+
/**
* This class is uses by the extractor with the results of the
* osmium based parsing and the customization through the lua profile.
@@ -60,10 +38,11 @@ class ExtractorCallbacks
ExtractionContainers &external_memory;
public:
- ExtractorCallbacks() = delete;
- ExtractorCallbacks(const ExtractorCallbacks &) = delete;
explicit ExtractorCallbacks(ExtractionContainers &extraction_containers);
+ ExtractorCallbacks(const ExtractorCallbacks &) = delete;
+ ExtractorCallbacks &operator=(const ExtractorCallbacks &) = delete;
+
// warning: caller needs to take care of synchronization!
void ProcessNode(const osmium::Node ¤t_node, const ExtractionNode &result_node);
@@ -73,5 +52,7 @@ class ExtractorCallbacks
// warning: caller needs to take care of synchronization!
void ProcessWay(const osmium::Way ¤t_way, const ExtractionWay &result_way);
};
+}
+}
#endif /* EXTRACTOR_CALLBACKS_HPP */
diff --git a/extractor/extractor_options.hpp b/include/extractor/extractor_config.hpp
similarity index 56%
rename from extractor/extractor_options.hpp
rename to include/extractor/extractor_config.hpp
index 00d6f84..80196db 100644
--- a/extractor/extractor_options.hpp
+++ b/include/extractor/extractor_config.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,23 +25,55 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef EXTRACTOR_OPTIONS_HPP
-#define EXTRACTOR_OPTIONS_HPP
+#ifndef EXTRACTOR_CONFIG_HPP
+#define EXTRACTOR_CONFIG_HPP
#include <boost/filesystem/path.hpp>
#include <string>
+#include <array>
-enum class return_code : unsigned
+namespace osrm
+{
+namespace extractor
{
- ok,
- fail,
- exit
-};
struct ExtractorConfig
{
ExtractorConfig() noexcept : requested_num_threads(0) {}
+ void UseDefaultOutputNames()
+ {
+ std::string basepath = input_path.string();
+
+ auto pos = std::string::npos;
+ std::array<std::string, 5> known_extensions{
+ {".osm.bz2", ".osm.pbf", ".osm.xml", ".pbf", ".osm"}};
+ for (auto ext : known_extensions)
+ {
+ pos = basepath.find(ext);
+ if (pos != std::string::npos)
+ {
+ basepath.replace(pos, ext.size(), "");
+ break;
+ }
+ }
+
+ output_file_name = basepath + ".osrm";
+ restriction_file_name = basepath + ".osrm.restrictions";
+ names_file_name = basepath + ".osrm.names";
+ timestamp_file_name = basepath + ".osrm.timestamp";
+ geometry_output_path = basepath + ".osrm.geometry";
+ node_output_path = basepath + ".osrm.nodes";
+ edge_output_path = basepath + ".osrm.edges";
+ edge_graph_output_path = basepath + ".osrm.ebg";
+ rtree_nodes_output_path = basepath + ".osrm.ramIndex";
+ rtree_leafs_output_path = basepath + ".osrm.fileIndex";
+ edge_segment_lookup_path = basepath + ".osrm.edge_segment_lookup";
+ edge_penalty_path = basepath + ".osrm.edge_penalties";
+ edge_based_node_weights_output_path = basepath + ".osrm.enw";
+ profile_properties_output_path = basepath + ".osrm.properties";
+ }
+
boost::filesystem::path config_file_path;
boost::filesystem::path input_path;
boost::filesystem::path profile_path;
@@ -53,9 +85,11 @@ struct ExtractorConfig
std::string geometry_output_path;
std::string edge_output_path;
std::string edge_graph_output_path;
+ std::string edge_based_node_weights_output_path;
std::string node_output_path;
std::string rtree_nodes_output_path;
std::string rtree_leafs_output_path;
+ std::string profile_properties_output_path;
unsigned requested_num_threads;
unsigned small_component_size;
@@ -63,16 +97,8 @@ struct ExtractorConfig
bool generate_edge_lookup;
std::string edge_penalty_path;
std::string edge_segment_lookup_path;
-#ifdef DEBUG_GEOMETRY
- std::string debug_turns_path;
-#endif
-};
-
-struct ExtractorOptions
-{
- static return_code ParseArguments(int argc, char *argv[], ExtractorConfig &extractor_config);
-
- static void GenerateOutputFilesNames(ExtractorConfig &extractor_config);
};
+}
+}
-#endif // EXTRACTOR_OPTIONS_HPP
+#endif // EXTRACTOR_CONFIG_HPP
diff --git a/include/extractor/first_and_last_segment_of_way.hpp b/include/extractor/first_and_last_segment_of_way.hpp
new file mode 100644
index 0000000..37d0e40
--- /dev/null
+++ b/include/extractor/first_and_last_segment_of_way.hpp
@@ -0,0 +1,60 @@
+#ifndef FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
+#define FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
+
+#include "extractor/external_memory_node.hpp"
+#include "util/typedefs.hpp"
+
+#include <limits>
+#include <string>
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct FirstAndLastSegmentOfWay
+{
+ OSMWayID way_id;
+ OSMNodeID first_segment_source_id;
+ OSMNodeID first_segment_target_id;
+ OSMNodeID last_segment_source_id;
+ OSMNodeID last_segment_target_id;
+
+ FirstAndLastSegmentOfWay()
+ : way_id(SPECIAL_OSM_WAYID), first_segment_source_id(SPECIAL_OSM_NODEID),
+ first_segment_target_id(SPECIAL_OSM_NODEID), last_segment_source_id(SPECIAL_OSM_NODEID),
+ last_segment_target_id(SPECIAL_OSM_NODEID)
+ {
+ }
+
+ FirstAndLastSegmentOfWay(OSMWayID w, OSMNodeID fs, OSMNodeID ft, OSMNodeID ls, OSMNodeID lt)
+ : way_id(std::move(w)), first_segment_source_id(std::move(fs)),
+ first_segment_target_id(std::move(ft)), last_segment_source_id(std::move(ls)),
+ last_segment_target_id(std::move(lt))
+ {
+ }
+
+ static FirstAndLastSegmentOfWay min_value()
+ {
+ return {MIN_OSM_WAYID, MIN_OSM_NODEID, MIN_OSM_NODEID, MIN_OSM_NODEID, MIN_OSM_NODEID};
+ }
+ static FirstAndLastSegmentOfWay max_value()
+ {
+ return {MAX_OSM_WAYID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID};
+ }
+};
+
+struct FirstAndLastSegmentOfWayStxxlCompare
+{
+ using value_type = FirstAndLastSegmentOfWay;
+ bool operator()(const FirstAndLastSegmentOfWay &a, const FirstAndLastSegmentOfWay &b) const
+ {
+ return a.way_id < b.way_id;
+ }
+ value_type max_value() { return FirstAndLastSegmentOfWay::max_value(); }
+ value_type min_value() { return FirstAndLastSegmentOfWay::min_value(); }
+};
+}
+}
+
+#endif /* FIRST_AND_LAST_SEGMENT_OF_WAY_HPP */
diff --git a/include/extractor/graph_compressor.hpp b/include/extractor/graph_compressor.hpp
new file mode 100644
index 0000000..78f3eaa
--- /dev/null
+++ b/include/extractor/graph_compressor.hpp
@@ -0,0 +1,38 @@
+#ifndef GEOMETRY_COMPRESSOR_HPP
+#define GEOMETRY_COMPRESSOR_HPP
+
+#include "util/typedefs.hpp"
+
+#include "util/node_based_graph.hpp"
+
+#include <memory>
+#include <unordered_set>
+
+namespace osrm
+{
+namespace extractor
+{
+
+class CompressedEdgeContainer;
+class RestrictionMap;
+
+class GraphCompressor
+{
+ using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
+
+ public:
+ void Compress(const std::unordered_set<NodeID> &barrier_nodes,
+ const std::unordered_set<NodeID> &traffic_lights,
+ RestrictionMap &restriction_map,
+ util::NodeBasedDynamicGraph &graph,
+ CompressedEdgeContainer &geometry_compressor);
+
+ private:
+ void PrintStatistics(unsigned original_number_of_nodes,
+ unsigned original_number_of_edges,
+ const util::NodeBasedDynamicGraph &graph) const;
+};
+}
+}
+
+#endif
diff --git a/include/extractor/guidance/classification_data.hpp b/include/extractor/guidance/classification_data.hpp
new file mode 100644
index 0000000..53f54cf
--- /dev/null
+++ b/include/extractor/guidance/classification_data.hpp
@@ -0,0 +1,67 @@
+#ifndef OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
+#define OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
+
+#include <cstdint>
+
+#include <string>
+
+// Forward Declaration to allow usage of external osmium::Way
+namespace osmium
+{
+class Way;
+}
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+enum class FunctionalRoadClass : std::uint8_t
+{
+ UNKNOWN = 0,
+ MOTORWAY,
+ MOTORWAY_LINK,
+ TRUNK,
+ TRUNK_LINK,
+ PRIMARY,
+ PRIMARY_LINK,
+ SECONDARY,
+ SECONDARY_LINK,
+ TERTIARY,
+ TERTIARY_LINK,
+ UNCLASSIFIED,
+ RESIDENTIAL,
+ SERVICE,
+ LIVING_STREET,
+ LOW_PRIORITY_ROAD // a road simply included for connectivity. Should be avoided at all cost
+};
+
+FunctionalRoadClass functionalRoadClassFromTag(std::string const &tag);
+
+inline bool isRampClass(const FunctionalRoadClass road_class)
+{
+ // Primary Roads and down are usually too small to announce their links as ramps
+ return road_class == FunctionalRoadClass::MOTORWAY_LINK ||
+ road_class == FunctionalRoadClass::TRUNK_LINK;
+}
+
+// TODO augment this with all data required for guidance generation
+struct RoadClassificationData
+{
+ FunctionalRoadClass road_class = FunctionalRoadClass::UNKNOWN;
+
+ void augment(const osmium::Way &way);
+};
+
+inline bool operator==(const RoadClassificationData lhs, const RoadClassificationData rhs)
+{
+ return lhs.road_class == rhs.road_class;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif // OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
diff --git a/include/extractor/guidance/discrete_angle.hpp b/include/extractor/guidance/discrete_angle.hpp
new file mode 100644
index 0000000..08509cb
--- /dev/null
+++ b/include/extractor/guidance/discrete_angle.hpp
@@ -0,0 +1,19 @@
+#ifndef OSRM_EXTRACTOR_GUIDANCE_DISCRETE_ANGLE
+#define OSRM_EXTRACTOR_GUIDANCE_DISCRETE_ANGLE
+
+#include <cstdint>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+using DiscreteAngle = std::uint8_t;
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif /* OSRM_EXTRACTOR_GUIDANCE_DISCRETE_ANGLE */
diff --git a/include/extractor/guidance/toolkit.hpp b/include/extractor/guidance/toolkit.hpp
new file mode 100644
index 0000000..45ca897
--- /dev/null
+++ b/include/extractor/guidance/toolkit.hpp
@@ -0,0 +1,404 @@
+#ifndef OSRM_GUIDANCE_TOOLKIT_HPP_
+#define OSRM_GUIDANCE_TOOLKIT_HPP_
+
+#include "util/bearing.hpp"
+#include "util/coordinate.hpp"
+#include "util/coordinate_calculation.hpp"
+
+#include "extractor/compressed_edge_container.hpp"
+#include "extractor/query_node.hpp"
+
+#include "extractor/guidance/discrete_angle.hpp"
+#include "extractor/guidance/classification_data.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+
+#include <algorithm>
+#include <map>
+#include <cmath>
+#include <cstdint>
+#include <string>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+namespace detail
+{
+const constexpr double DESIRED_SEGMENT_LENGTH = 10.0;
+const constexpr bool shiftable_ccw[] = {false, true, true, false, false, true, true, false};
+const constexpr bool shiftable_cw[] = {false, false, true, true, false, false, true, true};
+const constexpr std::uint8_t modifier_bounds[detail::num_direction_modifiers] = {
+ 0, 36, 93, 121, 136, 163, 220, 255};
+const constexpr double discrete_angle_step_size = 360. / 256.;
+
+template <typename IteratorType>
+util::Coordinate
+getCoordinateFromCompressedRange(util::Coordinate current_coordinate,
+ const IteratorType compressed_geometry_begin,
+ const IteratorType compressed_geometry_end,
+ const util::Coordinate final_coordinate,
+ const std::vector<extractor::QueryNode> &query_nodes)
+{
+ const auto extractCoordinateFromNode = [](const extractor::QueryNode &node) -> util::Coordinate
+ {
+ return {node.lon, node.lat};
+ };
+ double distance_to_current_coordinate = 0;
+ double distance_to_next_coordinate = 0;
+
+ // get the length that is missing from the current segment to reach DESIRED_SEGMENT_LENGTH
+ const auto getFactor = [](const double first_distance, const double second_distance)
+ {
+ BOOST_ASSERT(first_distance < detail::DESIRED_SEGMENT_LENGTH);
+ double segment_length = second_distance - first_distance;
+ BOOST_ASSERT(segment_length > 0);
+ BOOST_ASSERT(second_distance >= detail::DESIRED_SEGMENT_LENGTH);
+ double missing_distance = detail::DESIRED_SEGMENT_LENGTH - first_distance;
+ return missing_distance / segment_length;
+ };
+
+ for (auto compressed_geometry_itr = compressed_geometry_begin;
+ compressed_geometry_itr != compressed_geometry_end; ++compressed_geometry_itr)
+ {
+ const auto next_coordinate =
+ extractCoordinateFromNode(query_nodes[compressed_geometry_itr->node_id]);
+ distance_to_next_coordinate =
+ distance_to_current_coordinate +
+ util::coordinate_calculation::haversineDistance(current_coordinate, next_coordinate);
+
+ // reached point where coordinates switch between
+ if (distance_to_next_coordinate >= detail::DESIRED_SEGMENT_LENGTH)
+ return util::coordinate_calculation::interpolateLinear(
+ getFactor(distance_to_current_coordinate, distance_to_next_coordinate),
+ current_coordinate, next_coordinate);
+
+ // prepare for next iteration
+ current_coordinate = next_coordinate;
+ distance_to_current_coordinate = distance_to_next_coordinate;
+ }
+
+ distance_to_next_coordinate =
+ distance_to_current_coordinate +
+ util::coordinate_calculation::haversineDistance(current_coordinate, final_coordinate);
+
+ // reached point where coordinates switch between
+ if (distance_to_next_coordinate >= detail::DESIRED_SEGMENT_LENGTH)
+ return util::coordinate_calculation::interpolateLinear(
+ getFactor(distance_to_current_coordinate, distance_to_next_coordinate),
+ current_coordinate, final_coordinate);
+ else
+ return final_coordinate;
+}
+} // namespace detail
+
+// Finds a (potentially inteprolated) coordinate that is DESIRED_SEGMENT_LENGTH away
+// from the start of an edge
+inline util::Coordinate
+getRepresentativeCoordinate(const NodeID from_node,
+ const NodeID to_node,
+ const EdgeID via_edge_id,
+ const bool traverse_in_reverse,
+ const extractor::CompressedEdgeContainer &compressed_geometries,
+ const std::vector<extractor::QueryNode> &query_nodes)
+{
+ const auto extractCoordinateFromNode = [](const extractor::QueryNode &node) -> util::Coordinate
+ {
+ return {node.lon, node.lat};
+ };
+
+ // Uncompressed roads are simple, return the coordinate at the end
+ if (!compressed_geometries.HasEntryForID(via_edge_id))
+ {
+ return extractCoordinateFromNode(traverse_in_reverse ? query_nodes[from_node]
+ : query_nodes[to_node]);
+ }
+ else
+ {
+ const auto &geometry = compressed_geometries.GetBucketReference(via_edge_id);
+
+ const auto base_node_id = (traverse_in_reverse) ? to_node : from_node;
+ const auto base_coordinate = extractCoordinateFromNode(query_nodes[base_node_id]);
+
+ const auto final_node = (traverse_in_reverse) ? from_node : to_node;
+ const auto final_coordinate = extractCoordinateFromNode(query_nodes[final_node]);
+
+ if (traverse_in_reverse)
+ return detail::getCoordinateFromCompressedRange(
+ base_coordinate, geometry.rbegin(), geometry.rend(), final_coordinate, query_nodes);
+ else
+ return detail::getCoordinateFromCompressedRange(
+ base_coordinate, geometry.begin(), geometry.end(), final_coordinate, query_nodes);
+ }
+}
+
+// shift an instruction around the degree circle in CCW order
+inline DirectionModifier forcedShiftCCW(const DirectionModifier modifier)
+{
+ return static_cast<DirectionModifier>((static_cast<std::uint32_t>(modifier) + 1) %
+ detail::num_direction_modifiers);
+}
+
+inline DirectionModifier shiftCCW(const DirectionModifier modifier)
+{
+ if (detail::shiftable_ccw[static_cast<int>(modifier)])
+ return forcedShiftCCW(modifier);
+ else
+ return modifier;
+}
+
+// shift an instruction around the degree circle in CW order
+inline DirectionModifier forcedShiftCW(const DirectionModifier modifier)
+{
+ return static_cast<DirectionModifier>(
+ (static_cast<std::uint32_t>(modifier) + detail::num_direction_modifiers - 1) %
+ detail::num_direction_modifiers);
+}
+
+inline DirectionModifier shiftCW(const DirectionModifier modifier)
+{
+ if (detail::shiftable_cw[static_cast<int>(modifier)])
+ return forcedShiftCW(modifier);
+ else
+ return modifier;
+}
+
+inline bool isBasic(const TurnType type)
+{
+ return type == TurnType::Turn || type == TurnType::EndOfRoad;
+}
+
+inline bool isUturn(const TurnInstruction instruction)
+{
+ return isBasic(instruction.type) && instruction.direction_modifier == DirectionModifier::UTurn;
+}
+
+inline bool resolve(TurnInstruction &to_resolve, const TurnInstruction neighbor, bool resolve_cw)
+{
+ const auto shifted_turn = resolve_cw ? shiftCW(to_resolve.direction_modifier)
+ : shiftCCW(to_resolve.direction_modifier);
+ if (shifted_turn == neighbor.direction_modifier ||
+ shifted_turn == to_resolve.direction_modifier)
+ return false;
+
+ to_resolve.direction_modifier = shifted_turn;
+ return true;
+}
+
+inline bool resolveTransitive(TurnInstruction &first,
+ TurnInstruction &second,
+ const TurnInstruction third,
+ bool resolve_cw)
+{
+ if (resolve(second, third, resolve_cw))
+ {
+ first.direction_modifier =
+ resolve_cw ? shiftCW(first.direction_modifier) : shiftCCW(first.direction_modifier);
+ return true;
+ }
+ return false;
+}
+
+inline bool isSlightTurn(const TurnInstruction turn)
+{
+ return (isBasic(turn.type) || turn.type == TurnType::NoTurn) &&
+ (turn.direction_modifier == DirectionModifier::Straight ||
+ turn.direction_modifier == DirectionModifier::SlightRight ||
+ turn.direction_modifier == DirectionModifier::SlightLeft);
+}
+
+inline bool isSlightModifier(const DirectionModifier direction_modifier)
+{
+ return (direction_modifier == DirectionModifier::Straight ||
+ direction_modifier == DirectionModifier::SlightRight ||
+ direction_modifier == DirectionModifier::SlightLeft);
+}
+
+inline bool isSharpTurn(const TurnInstruction turn)
+{
+ return isBasic(turn.type) && (turn.direction_modifier == DirectionModifier::SharpLeft ||
+ turn.direction_modifier == DirectionModifier::SharpRight);
+}
+
+inline bool isStraight(const TurnInstruction turn)
+{
+ return (isBasic(turn.type) || turn.type == TurnType::NoTurn) &&
+ turn.direction_modifier == DirectionModifier::Straight;
+}
+
+inline bool isConflict(const TurnInstruction first, const TurnInstruction second)
+{
+ return (first.type == second.type && first.direction_modifier == second.direction_modifier) ||
+ (isStraight(first) && isStraight(second));
+}
+
+inline DiscreteAngle discretizeAngle(const double angle)
+{
+ BOOST_ASSERT(angle >= 0. && angle <= 360.);
+ return DiscreteAngle(static_cast<std::uint8_t>(angle / detail::discrete_angle_step_size));
+}
+
+inline double angleFromDiscreteAngle(const DiscreteAngle angle)
+{
+ return static_cast<double>(angle) * detail::discrete_angle_step_size;
+}
+
+inline double angularDeviation(const double angle, const double from)
+{
+ const double deviation = std::abs(angle - from);
+ return std::min(360 - deviation, deviation);
+}
+
+inline double getAngularPenalty(const double angle, DirectionModifier modifier)
+{
+ // these are not aligned with getTurnDirection but represent an ideal center
+ const double center[] = {0, 45, 90, 135, 180, 225, 270, 315};
+ return angularDeviation(center[static_cast<int>(modifier)], angle);
+}
+
+inline double getTurnConfidence(const double angle, TurnInstruction instruction)
+{
+
+ // special handling of U-Turns and Roundabout
+ if (!isBasic(instruction.type) || instruction.direction_modifier == DirectionModifier::UTurn)
+ return 1.0;
+
+ const double deviations[] = {0, 45, 50, 30, 20, 30, 50, 45};
+ const double difference = getAngularPenalty(angle, instruction.direction_modifier);
+ const double max_deviation = deviations[static_cast<int>(instruction.direction_modifier)];
+ return 1.0 - (difference / max_deviation) * (difference / max_deviation);
+}
+
+// Translates between angles and their human-friendly directional representation
+inline DirectionModifier getTurnDirection(const double angle)
+{
+ // An angle of zero is a u-turn
+ // 180 goes perfectly straight
+ // 0-180 are right turns
+ // 180-360 are left turns
+ if (angle > 0 && angle < 60)
+ return DirectionModifier::SharpRight;
+ if (angle >= 60 && angle < 140)
+ return DirectionModifier::Right;
+ if (angle >= 140 && angle < 170)
+ return DirectionModifier::SlightRight;
+ if (angle >= 165 && angle <= 195)
+ return DirectionModifier::Straight;
+ if (angle > 190 && angle <= 220)
+ return DirectionModifier::SlightLeft;
+ if (angle > 220 && angle <= 300)
+ return DirectionModifier::Left;
+ if (angle > 300 && angle < 360)
+ return DirectionModifier::SharpLeft;
+ return DirectionModifier::UTurn;
+}
+
+// swaps left <-> right modifier types
+inline DirectionModifier mirrorDirectionModifier(const DirectionModifier modifier)
+{
+ const constexpr DirectionModifier results[] = {DirectionModifier::UTurn,
+ DirectionModifier::SharpLeft,
+ DirectionModifier::Left,
+ DirectionModifier::SlightLeft,
+ DirectionModifier::Straight,
+ DirectionModifier::SlightRight,
+ DirectionModifier::Right,
+ DirectionModifier::SharpRight};
+ return results[modifier];
+}
+
+inline bool canBeSuppressed(const TurnType type)
+{
+ if (type == TurnType::Turn)
+ return true;
+ return false;
+}
+
+inline bool isLowPriorityRoadClass(const FunctionalRoadClass road_class)
+{
+ return road_class == FunctionalRoadClass::LOW_PRIORITY_ROAD ||
+ road_class == FunctionalRoadClass::SERVICE;
+}
+
+inline bool isDistinct(const DirectionModifier first, const DirectionModifier second)
+{
+ if ((first + 1) % detail::num_direction_modifiers == second)
+ return false;
+
+ if ((second + 1) % detail::num_direction_modifiers == first)
+ return false;
+
+ return true;
+}
+
+inline bool requiresNameAnnounced(const std::string &from, const std::string &to)
+{
+ // FIXME, handle in profile to begin with?
+ // this uses the encoding of references in the profile, which is very BAD
+ // Input for this function should be a struct separating streetname, suffix (e.g. road,
+ // boulevard, North, West ...), and a list of references
+ std::string from_name;
+ std::string from_ref;
+ std::string to_name;
+ std::string to_ref;
+
+ // Split from the format "{name} ({ref})" -> name, ref
+ auto split = [](const std::string &name, std::string &out_name, std::string &out_ref)
+ {
+ const auto ref_begin = name.find_first_of('(');
+ if (ref_begin != std::string::npos)
+ {
+ out_name = name.substr(0, ref_begin);
+ out_ref = name.substr(ref_begin + 1, name.find_first_of(')') - 1);
+ }
+ else
+ {
+ out_name = name;
+ }
+ };
+
+ split(from, from_name, from_ref);
+ split(to, to_name, to_ref);
+
+ // check similarity of names
+ auto names_are_empty = from_name.empty() && to_name.empty();
+ auto names_are_equal = from_name == to_name;
+ auto name_is_removed = !from_name.empty() && to_name.empty();
+ // references are contained in one another
+ auto refs_are_empty = from_ref.empty() && to_ref.empty();
+ auto ref_is_contained =
+ !from_ref.empty() && !to_ref.empty() &&
+ (from_ref.find(to_ref) != std::string::npos || to_ref.find(from_ref) != std::string::npos);
+ auto ref_is_removed = !from_ref.empty() && to_ref.empty();
+
+ auto obvious_change = ref_is_contained || names_are_equal ||
+ (names_are_empty && refs_are_empty) || name_is_removed || ref_is_removed;
+
+ return !obvious_change;
+}
+
+inline int getPriority( const FunctionalRoadClass road_class )
+{
+ //The road priorities indicate which roads can bee seen as more or less equal.
+ //They are used in Fork-Discovery. Possibly should be moved to profiles post v5?
+ //A fork can happen between road types that are at most 1 priority apart from each other
+ const constexpr int road_priority[] = {10, 0, 10, 2, 10, 4, 10, 6, 10, 8, 10, 11, 10, 12, 10, 14};
+ return road_priority[static_cast<int>(road_class)];
+}
+
+inline bool canBeSeenAsFork(const FunctionalRoadClass first, const FunctionalRoadClass second)
+{
+ // forks require similar road categories
+ // Based on the priorities assigned above, we can set forks only if the road priorities match closely.
+ // Potentially we could include features like number of lanes here and others?
+ // Should also be moved to profiles
+ return std::abs(getPriority(first) - getPriority(second)) <= 1;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif // OSRM_GUIDANCE_TOOLKIT_HPP_
diff --git a/include/extractor/guidance/turn_analysis.hpp b/include/extractor/guidance/turn_analysis.hpp
new file mode 100644
index 0000000..538fabc
--- /dev/null
+++ b/include/extractor/guidance/turn_analysis.hpp
@@ -0,0 +1,202 @@
+#ifndef OSRM_EXTRACTOR_TURN_ANALYSIS
+#define OSRM_EXTRACTOR_TURN_ANALYSIS
+
+#include "extractor/guidance/turn_classification.hpp"
+#include "extractor/guidance/toolkit.hpp"
+#include "extractor/restriction_map.hpp"
+#include "extractor/compressed_edge_container.hpp"
+
+#include "util/name_table.hpp"
+
+#include <cstdint>
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <utility>
+#include <unordered_set>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+// What is exposed to the outside
+struct TurnOperation final
+{
+ EdgeID eid;
+ double angle;
+ TurnInstruction instruction;
+};
+
+// For the turn analysis, we require a full list of all connected roads to determine the outcome.
+// Invalid turns can influence the perceived angles
+//
+// aaa(2)aa
+// a - bbbbb
+// aaa(1)aa
+//
+// will not be perceived as a turn from (1) -> b, and as a U-turn from (1) -> (2).
+// In addition, they can influence whether a turn is obvious or not.
+struct ConnectedRoad final
+{
+ ConnectedRoad(const TurnOperation turn, const bool entry_allowed = false);
+
+ TurnOperation turn;
+ bool entry_allowed; // a turn may be relevant to good instructions, even if we cannot take
+ // the road
+
+ std::string toString() const
+ {
+ std::string result = "[connection] ";
+ result += std::to_string(turn.eid);
+ result += " allows entry: ";
+ result += std::to_string(entry_allowed);
+ result += " angle: ";
+ result += std::to_string(turn.angle);
+ result += " instruction: ";
+ result += std::to_string(static_cast<std::int32_t>(turn.instruction.type)) + " " +
+ std::to_string(static_cast<std::int32_t>(turn.instruction.direction_modifier));
+ return result;
+ }
+};
+
+class TurnAnalysis
+{
+
+ public:
+ TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
+ const std::vector<QueryNode> &node_info_list,
+ const RestrictionMap &restriction_map,
+ const std::unordered_set<NodeID> &barrier_nodes,
+ const CompressedEdgeContainer &compressed_edge_container,
+ const util::NameTable &name_table);
+
+ // the entry into the turn analysis
+ std::vector<TurnOperation> getTurns(const NodeID from_node, const EdgeID via_eid) const;
+
+ private:
+ const util::NodeBasedDynamicGraph &node_based_graph;
+ const std::vector<QueryNode> &node_info_list;
+ const RestrictionMap &restriction_map;
+ const std::unordered_set<NodeID> &barrier_nodes;
+ const CompressedEdgeContainer &compressed_edge_container;
+ const util::NameTable &name_table;
+
+ // Check for restrictions/barriers and generate a list of valid and invalid turns present at
+ // the
+ // node reached
+ // from `from_node` via `via_eid`
+ // The resulting candidates have to be analysed for their actual instructions later on.
+ std::vector<ConnectedRoad> getConnectedRoads(const NodeID from_node,
+ const EdgeID via_eid) const;
+
+ // Merge segregated roads to omit invalid turns in favor of treating segregated roads as
+ // one.
+ // This function combines roads the following way:
+ //
+ // * *
+ // * is converted to *
+ // v ^ +
+ // v ^ +
+ //
+ // The treatment results in a straight turn angle of 180º rather than a turn angle of approx
+ // 160
+ std::vector<ConnectedRoad> mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) const;
+
+ // TODO distinguish roundabouts and rotaries
+ // TODO handle bike/walk cases that allow crossing a roundabout!
+
+ // Processing of roundabouts
+ // Produces instructions to enter/exit a roundabout or to stay on it.
+ // Performs the distinction between roundabout and rotaries.
+ std::vector<ConnectedRoad> handleRoundabouts(const EdgeID via_edge,
+ const bool on_roundabout,
+ const bool can_exit_roundabout,
+ std::vector<ConnectedRoad> intersection) const;
+
+ // Indicates a Junction containing a motoryway
+ bool isMotorwayJunction(const EdgeID via_edge,
+ const std::vector<ConnectedRoad> &intersection) const;
+
+ // Decide whether a turn is a turn or a ramp access
+ TurnType findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
+
+ // Get the Instruction for an obvious turn
+ // Instruction will be a silent instruction
+ TurnInstruction getInstructionForObvious(const std::size_t number_of_candidates,
+ const EdgeID via_edge,
+ const ConnectedRoad &candidate) const;
+
+ // Helper Function that decides between NoTurn or NewName
+ TurnInstruction
+ noTurnOrNewName(const NodeID from, const EdgeID via_edge, const ConnectedRoad &candidate) const;
+
+ // Basic Turn Handling
+
+ // Dead end.
+ std::vector<ConnectedRoad> handleOneWayTurn(std::vector<ConnectedRoad> intersection) const;
+
+ // Mode Changes, new names...
+ std::vector<ConnectedRoad> handleTwoWayTurn(const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection) const;
+
+ // Forks, T intersections and similar
+ std::vector<ConnectedRoad> handleThreeWayTurn(const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection) const;
+
+ // Handling of turns larger then degree three
+ std::vector<ConnectedRoad> handleComplexTurn(const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection) const;
+
+ // Any Junction containing motorways
+ std::vector<ConnectedRoad> handleMotorwayJunction(
+ const EdgeID via_edge, std::vector<ConnectedRoad> intersection) const;
+
+ std::vector<ConnectedRoad> handleFromMotorway(const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection) const;
+
+ std::vector<ConnectedRoad> handleMotorwayRamp(const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection) const;
+
+ // Utility function, setting basic turn types. Prepares for normal turn handling.
+ std::vector<ConnectedRoad> setTurnTypes(const NodeID from,
+ const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection) const;
+
+ // Assignment of specific turn types
+ void assignFork(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
+ void assignFork(const EdgeID via_edge,
+ ConnectedRoad &left,
+ ConnectedRoad ¢er,
+ ConnectedRoad &right) const;
+
+ void
+ handleDistinctConflict(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
+
+ // Type specific fallbacks
+ std::vector<ConnectedRoad>
+ fallbackTurnAssignmentMotorway(std::vector<ConnectedRoad> intersection) const;
+
+ // Classification
+ std::size_t findObviousTurn(const EdgeID via_edge,
+ const std::vector<ConnectedRoad> &intersection) const;
+ std::pair<std::size_t, std::size_t>
+ findFork(const std::vector<ConnectedRoad> &intersection) const;
+
+ std::vector<ConnectedRoad> assignLeftTurns(const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection,
+ const std::size_t starting_at) const;
+ std::vector<ConnectedRoad> assignRightTurns(const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection,
+ const std::size_t up_to) const;
+
+}; // class TurnAnalysis
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif // OSRM_EXTRACTOR_TURN_ANALYSIS
diff --git a/include/extractor/guidance/turn_classification.hpp b/include/extractor/guidance/turn_classification.hpp
new file mode 100644
index 0000000..58f7666
--- /dev/null
+++ b/include/extractor/guidance/turn_classification.hpp
@@ -0,0 +1,123 @@
+#ifndef OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
+#define OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
+
+#include "extractor/guidance/toolkit.hpp"
+
+#include "util/typedefs.hpp"
+#include "util/coordinate.hpp"
+#include "util/node_based_graph.hpp"
+
+#include "extractor/compressed_edge_container.hpp"
+#include "extractor/query_node.hpp"
+
+#include <algorithm>
+#include <cstddef>
+#include <vector>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+struct TurnPossibility
+{
+ TurnPossibility(DiscreteAngle angle, EdgeID edge_id)
+ : angle(std::move(angle)), edge_id(std::move(edge_id))
+ {
+ }
+
+ TurnPossibility() : angle(0), edge_id(SPECIAL_EDGEID) {}
+
+ DiscreteAngle angle;
+ EdgeID edge_id;
+};
+
+struct CompareTurnPossibilities
+{
+ bool operator()(const std::vector<TurnPossibility> &left,
+ const std::vector<TurnPossibility> &right) const
+ {
+ if (left.size() < right.size())
+ return true;
+ if (left.size() > right.size())
+ return false;
+ for (std::size_t i = 0; i < left.size(); ++i)
+ {
+ if ((((int)left[i].angle + 16) % 256) / 32 < (((int)right[i].angle + 16) % 256) / 32)
+ return true;
+ if ((((int)left[i].angle + 16) % 256) / 32 > (((int)right[i].angle + 16) % 256) / 32)
+ return false;
+ }
+ return false;
+ }
+};
+
+inline std::vector<TurnPossibility>
+classifyIntersection(NodeID nid,
+ const util::NodeBasedDynamicGraph &graph,
+ const extractor::CompressedEdgeContainer &compressed_geometries,
+ const std::vector<extractor::QueryNode> &query_nodes)
+{
+
+ std::vector<TurnPossibility> turns;
+
+ if (graph.BeginEdges(nid) == graph.EndEdges(nid))
+ return std::vector<TurnPossibility>();
+
+ const EdgeID base_id = graph.BeginEdges(nid);
+ const auto base_coordinate = getRepresentativeCoordinate(nid, graph.GetTarget(base_id), base_id,
+ graph.GetEdgeData(base_id).reversed,
+ compressed_geometries, query_nodes);
+ const auto node_coordinate = util::Coordinate(query_nodes[nid].lon, query_nodes[nid].lat);
+
+ // generate a list of all turn angles between a base edge, the node and a current edge
+ for (const EdgeID eid : graph.GetAdjacentEdgeRange(nid))
+ {
+ const auto edge_coordinate = getRepresentativeCoordinate(
+ nid, graph.GetTarget(eid), eid, false, compressed_geometries, query_nodes);
+
+ double angle = util::coordinate_calculation::computeAngle(base_coordinate, node_coordinate,
+ edge_coordinate);
+ turns.emplace_back(discretizeAngle(angle), eid);
+ }
+
+ std::sort(turns.begin(), turns.end(),
+ [](const TurnPossibility left, const TurnPossibility right)
+ {
+ return left.angle < right.angle;
+ });
+
+ turns.push_back(turns.front()); // sentinel
+ for (std::size_t turn_nr = 0; turn_nr + 1 < turns.size(); ++turn_nr)
+ {
+ turns[turn_nr].angle = (256 + static_cast<uint32_t>(turns[turn_nr + 1].angle) -
+ static_cast<uint32_t>(turns[turn_nr].angle)) %
+ 256; // calculate the difference to the right
+ }
+ turns.pop_back(); // remove sentinel again
+
+ // find largest:
+ std::size_t best_id = 0;
+ DiscreteAngle largest_turn_angle = turns.front().angle;
+ for (std::size_t current_turn_id = 1; current_turn_id < turns.size(); ++current_turn_id)
+ {
+ if (turns[current_turn_id].angle > largest_turn_angle)
+ {
+ largest_turn_angle = turns[current_turn_id].angle;
+ best_id = current_turn_id;
+ }
+ }
+
+ // rotate all angles so the largest angle comes first
+ std::rotate(turns.begin(), turns.begin() + best_id, turns.end());
+
+ return turns;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif // OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
diff --git a/include/extractor/guidance/turn_instruction.hpp b/include/extractor/guidance/turn_instruction.hpp
new file mode 100644
index 0000000..da3da62
--- /dev/null
+++ b/include/extractor/guidance/turn_instruction.hpp
@@ -0,0 +1,127 @@
+#ifndef OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
+#define OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
+
+#include <cstdint>
+
+#include <boost/assert.hpp>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+namespace detail
+{
+// inclusive bounds for turn modifiers
+const constexpr uint8_t num_direction_modifiers = 8;
+} // detail
+
+// direction modifiers based on angle
+// Would be nice to have
+// enum class DirectionModifier : unsigned char
+enum DirectionModifier
+{
+ UTurn,
+ SharpRight,
+ Right,
+ SlightRight,
+ Straight,
+ SlightLeft,
+ Left,
+ SharpLeft
+};
+
+// enum class TurnType : unsigned char
+enum TurnType // at the moment we can support 32 turn types, without increasing memory consumption
+{
+ Invalid, // no valid turn instruction
+ NoTurn, // end of segment without turn/middle of a segment
+ Suppressed, // location that suppresses a turn
+ NewName, // no turn, but name changes
+ Continue, // remain on a street
+ Turn, // basic turn
+ FirstTurn, // First of x turns
+ SecondTurn, // Second of x turns
+ ThirdTurn, // Third of x turns
+ FourthTurn, // Fourth of x turns
+ Merge, // merge onto a street
+ Ramp, // special turn (highway ramp exits)
+ FirstRamp, // first turn onto a ramp
+ SecondRamp, // second turn onto a ramp
+ ThirdRamp, // third turn onto a ramp
+ FourthRamp, // fourth turn onto a ramp
+ Fork, // fork road splitting up
+ EndOfRoad, // T intersection
+ EnterRoundabout, // Entering a small Roundabout
+ EnterRoundaboutAtExit, // Entering a small Roundabout at a countable exit
+ EnterAndExitRoundabout, // Touching a roundabout
+ ExitRoundabout, // Exiting a small Roundabout
+ EnterRotary, // Enter a rotary
+ EnterRotaryAtExit, // Enter A Rotary at a countable exit
+ EnterAndExitRotary, // Touching a rotary
+ ExitRotary, // Exit a rotary
+ StayOnRoundabout, // Continue on Either a small or a large Roundabout
+ Restriction, // Cross a Barrier, requires barrier penalties instead of full block
+ Notification // Travel Mode Changes`
+};
+
+// turn angle in 1.40625 degree -> 128 == 180 degree
+struct TurnInstruction
+{
+ TurnInstruction(const TurnType type = TurnType::Invalid,
+ const DirectionModifier direction_modifier = DirectionModifier::Straight)
+ : type(type), direction_modifier(direction_modifier)
+ {
+ }
+
+ TurnType type : 5;
+ DirectionModifier direction_modifier : 3;
+
+ static TurnInstruction INVALID()
+ {
+ return TurnInstruction(TurnType::Invalid, DirectionModifier::UTurn);
+ }
+
+ static TurnInstruction NO_TURN()
+ {
+ return TurnInstruction(TurnType::NoTurn, DirectionModifier::UTurn);
+ }
+
+ static TurnInstruction REMAIN_ROUNDABOUT(const DirectionModifier modifier)
+ {
+ return TurnInstruction(TurnType::StayOnRoundabout, modifier);
+ }
+
+ static TurnInstruction ENTER_ROUNDABOUT(const DirectionModifier modifier)
+ {
+ return TurnInstruction(TurnType::EnterRoundabout, modifier);
+ }
+
+ static TurnInstruction EXIT_ROUNDABOUT(const DirectionModifier modifier)
+ {
+ return TurnInstruction(TurnType::ExitRoundabout, modifier);
+ }
+
+ static TurnInstruction SUPPRESSED(const DirectionModifier modifier)
+ {
+ return TurnInstruction{TurnType::Suppressed, modifier};
+ }
+};
+
+inline bool operator!=(const TurnInstruction lhs, const TurnInstruction rhs)
+{
+ return lhs.type != rhs.type || lhs.direction_modifier != rhs.direction_modifier;
+}
+
+inline bool operator==(const TurnInstruction lhs, const TurnInstruction rhs)
+{
+ return lhs.type == rhs.type && lhs.direction_modifier == rhs.direction_modifier;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
+
+#endif // OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
diff --git a/extractor/internal_extractor_edge.hpp b/include/extractor/internal_extractor_edge.hpp
similarity index 60%
rename from extractor/internal_extractor_edge.hpp
rename to include/extractor/internal_extractor_edge.hpp
index 0df6e8c..2ccdb2c 100644
--- a/extractor/internal_extractor_edge.hpp
+++ b/include/extractor/internal_extractor_edge.hpp
@@ -1,46 +1,26 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef INTERNAL_EXTRACTOR_EDGE_HPP
#define INTERNAL_EXTRACTOR_EDGE_HPP
-#include "../typedefs.h"
-#include "../data_structures/travel_mode.hpp"
-#include "../data_structures/import_edge.hpp"
+#include "util/typedefs.hpp"
+#include "extractor/travel_mode.hpp"
+#include "extractor/node_based_edge.hpp"
#include <boost/assert.hpp>
-#include <osrm/coordinate.hpp>
+#include "osrm/coordinate.hpp"
#include <utility>
+#include "extractor/guidance/classification_data.hpp"
+
+namespace osrm
+{
+namespace extractor
+{
struct InternalExtractorEdge
{
// specify the type of the weight data
- enum class WeightType : char {
+ enum class WeightType : char
+ {
INVALID,
SPEED,
EDGE_DURATION,
@@ -50,9 +30,7 @@ struct InternalExtractorEdge
struct WeightData
{
- WeightData() : duration(0.0), type(WeightType::INVALID)
- {
- }
+ WeightData() : duration(0.0), type(WeightType::INVALID) {}
union
{
@@ -63,8 +41,18 @@ struct InternalExtractorEdge
};
explicit InternalExtractorEdge()
- : result(MIN_OSM_NODEID, MIN_OSM_NODEID, 0, 0, false, false, false, false, true,
- TRAVEL_MODE_INACCESSIBLE, false)
+ : result(MIN_OSM_NODEID,
+ MIN_OSM_NODEID,
+ 0,
+ 0,
+ false,
+ false,
+ false,
+ false,
+ true,
+ TRAVEL_MODE_INACCESSIBLE,
+ false,
+ guidance::RoadClassificationData())
{
}
@@ -78,7 +66,8 @@ struct InternalExtractorEdge
bool access_restricted,
bool startpoint,
TravelMode travel_mode,
- bool is_split)
+ bool is_split,
+ guidance::RoadClassificationData road_classification)
: result(OSMNodeID(source),
OSMNodeID(target),
name_id,
@@ -89,7 +78,8 @@ struct InternalExtractorEdge
access_restricted,
startpoint,
travel_mode,
- is_split),
+ is_split,
+ std::move(road_classification)),
weight_data(std::move(weight_data))
{
}
@@ -99,19 +89,20 @@ struct InternalExtractorEdge
// intermediate edge weight
WeightData weight_data;
// coordinate of the source node
- FixedPointCoordinate source_coordinate;
-
+ util::Coordinate source_coordinate;
// necessary static util functions for stxxl's sorting
static InternalExtractorEdge min_osm_value()
{
- return InternalExtractorEdge(MIN_OSM_NODEID, MIN_OSM_NODEID, 0, WeightData(), false, false, false,
- false, true, TRAVEL_MODE_INACCESSIBLE, false);
+ return InternalExtractorEdge(MIN_OSM_NODEID, MIN_OSM_NODEID, 0, WeightData(), false, false,
+ false, false, true, TRAVEL_MODE_INACCESSIBLE, false,
+ guidance::RoadClassificationData());
}
static InternalExtractorEdge max_osm_value()
{
- return InternalExtractorEdge(MAX_OSM_NODEID, MAX_OSM_NODEID, 0, WeightData(), false,
- false, false, false, true, TRAVEL_MODE_INACCESSIBLE, false);
+ return InternalExtractorEdge(MAX_OSM_NODEID, MAX_OSM_NODEID, 0, WeightData(), false, false,
+ false, false, true, TRAVEL_MODE_INACCESSIBLE, false,
+ guidance::RoadClassificationData());
}
static InternalExtractorEdge min_internal_value()
@@ -128,7 +119,6 @@ struct InternalExtractorEdge
v.result.target = std::numeric_limits<NodeID>::max();
return v;
}
-
};
struct CmpEdgeByInternalStartThenInternalTargetID
@@ -136,9 +126,9 @@ struct CmpEdgeByInternalStartThenInternalTargetID
using value_type = InternalExtractorEdge;
bool operator()(const InternalExtractorEdge &lhs, const InternalExtractorEdge &rhs) const
{
- return (lhs.result.source < rhs.result.source) ||
- ((lhs.result.source == rhs.result.source) &&
- (lhs.result.target < rhs.result.target));
+ return (lhs.result.source < rhs.result.source) ||
+ ((lhs.result.source == rhs.result.source) &&
+ (lhs.result.target < rhs.result.target));
}
value_type max_value() { return InternalExtractorEdge::max_internal_value(); }
@@ -168,5 +158,7 @@ struct CmpEdgeByOSMTargetID
value_type max_value() { return InternalExtractorEdge::max_osm_value(); }
value_type min_value() { return InternalExtractorEdge::min_osm_value(); }
};
+}
+}
#endif // INTERNAL_EXTRACTOR_EDGE_HPP
diff --git a/include/extractor/node_based_edge.hpp b/include/extractor/node_based_edge.hpp
new file mode 100644
index 0000000..47090e6
--- /dev/null
+++ b/include/extractor/node_based_edge.hpp
@@ -0,0 +1,143 @@
+#ifndef NODE_BASED_EDGE_HPP
+#define NODE_BASED_EDGE_HPP
+
+#include "extractor/travel_mode.hpp"
+#include "util/typedefs.hpp"
+
+#include "extractor/guidance/classification_data.hpp"
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct NodeBasedEdge
+{
+ NodeBasedEdge();
+
+ NodeBasedEdge(NodeID source,
+ NodeID target,
+ NodeID name_id,
+ EdgeWeight weight,
+ bool forward,
+ bool backward,
+ bool roundabout,
+ bool access_restricted,
+ bool startpoint,
+ TravelMode travel_mode,
+ bool is_split,
+ guidance::RoadClassificationData road_classification);
+
+ bool operator<(const NodeBasedEdge &other) const;
+
+ NodeID source;
+ NodeID target;
+ NodeID name_id;
+ EdgeWeight weight;
+ bool forward : 1;
+ bool backward : 1;
+ bool roundabout : 1;
+ bool access_restricted : 1;
+ bool startpoint : 1;
+ bool is_split : 1;
+ TravelMode travel_mode : 4;
+ guidance::RoadClassificationData road_classification;
+};
+
+struct NodeBasedEdgeWithOSM : NodeBasedEdge
+{
+ NodeBasedEdgeWithOSM(OSMNodeID source,
+ OSMNodeID target,
+ NodeID name_id,
+ EdgeWeight weight,
+ bool forward,
+ bool backward,
+ bool roundabout,
+ bool access_restricted,
+ bool startpoint,
+ TravelMode travel_mode,
+ bool is_split,
+ guidance::RoadClassificationData road_classification);
+
+ OSMNodeID osm_source_id;
+ OSMNodeID osm_target_id;
+};
+
+// Impl.
+
+inline NodeBasedEdge::NodeBasedEdge()
+ : source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), forward(false),
+ backward(false), roundabout(false), access_restricted(false), startpoint(true),
+ is_split(false), travel_mode(false)
+{
+}
+
+inline NodeBasedEdge::NodeBasedEdge(NodeID source,
+ NodeID target,
+ NodeID name_id,
+ EdgeWeight weight,
+ bool forward,
+ bool backward,
+ bool roundabout,
+ bool access_restricted,
+ bool startpoint,
+ TravelMode travel_mode,
+ bool is_split,
+ guidance::RoadClassificationData road_classification)
+ : source(source), target(target), name_id(name_id), weight(weight), forward(forward),
+ backward(backward), roundabout(roundabout), access_restricted(access_restricted),
+ startpoint(startpoint), is_split(is_split), travel_mode(travel_mode),
+ road_classification(std::move(road_classification))
+{
+}
+
+inline bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const
+{
+ if (source == other.source)
+ {
+ if (target == other.target)
+ {
+ if (weight == other.weight)
+ {
+ return forward && backward && ((!other.forward) || (!other.backward));
+ }
+ return weight < other.weight;
+ }
+ return target < other.target;
+ }
+ return source < other.source;
+}
+
+inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(
+ OSMNodeID source,
+ OSMNodeID target,
+ NodeID name_id,
+ EdgeWeight weight,
+ bool forward,
+ bool backward,
+ bool roundabout,
+ bool access_restricted,
+ bool startpoint,
+ TravelMode travel_mode,
+ bool is_split,
+ guidance::RoadClassificationData road_classification)
+ : NodeBasedEdge(SPECIAL_NODEID,
+ SPECIAL_NODEID,
+ name_id,
+ weight,
+ forward,
+ backward,
+ roundabout,
+ access_restricted,
+ startpoint,
+ travel_mode,
+ is_split,
+ std::move(road_classification)),
+ osm_source_id(std::move(source)), osm_target_id(std::move(target))
+{
+}
+
+} // ns extractor
+} // ns osrm
+
+#endif /* NODE_BASED_EDGE_HPP */
diff --git a/include/extractor/original_edge_data.hpp b/include/extractor/original_edge_data.hpp
new file mode 100644
index 0000000..17d234a
--- /dev/null
+++ b/include/extractor/original_edge_data.hpp
@@ -0,0 +1,42 @@
+#ifndef ORIGINAL_EDGE_DATA_HPP
+#define ORIGINAL_EDGE_DATA_HPP
+
+#include "extractor/travel_mode.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+#include "util/typedefs.hpp"
+
+#include <limits>
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct OriginalEdgeData
+{
+ explicit OriginalEdgeData(NodeID via_node,
+ unsigned name_id,
+ guidance::TurnInstruction turn_instruction,
+ TravelMode travel_mode)
+ : via_node(via_node), name_id(name_id), turn_instruction(turn_instruction),
+ travel_mode(travel_mode)
+ {
+ }
+
+ OriginalEdgeData()
+ : via_node(std::numeric_limits<unsigned>::max()),
+ name_id(std::numeric_limits<unsigned>::max()),
+ turn_instruction(guidance::TurnInstruction::INVALID()),
+ travel_mode(TRAVEL_MODE_INACCESSIBLE)
+ {
+ }
+
+ NodeID via_node;
+ unsigned name_id;
+ guidance::TurnInstruction turn_instruction;
+ TravelMode travel_mode;
+};
+}
+}
+
+#endif // ORIGINAL_EDGE_DATA_HPP
diff --git a/include/extractor/profile_properties.hpp b/include/extractor/profile_properties.hpp
new file mode 100644
index 0000000..859034c
--- /dev/null
+++ b/include/extractor/profile_properties.hpp
@@ -0,0 +1,48 @@
+#ifndef PROFILE_PROPERTIES_HPP
+#define PROFILE_PROPERTIES_HPP
+
+#include <boost/numeric/conversion/cast.hpp>
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct ProfileProperties
+{
+ ProfileProperties()
+ : traffic_signal_penalty(0), u_turn_penalty(0), allow_u_turn_at_via(false), use_turn_restrictions(false)
+ {
+ }
+
+ double GetUturnPenalty() const
+ {
+ return u_turn_penalty / 10.;
+ }
+
+ void SetUturnPenalty(const double u_turn_penalty_)
+ {
+ u_turn_penalty = boost::numeric_cast<int>(u_turn_penalty_ * 10.);
+ }
+
+ double GetTrafficSignalPenalty() const
+ {
+ return traffic_signal_penalty / 10.;
+ }
+
+ void SetTrafficSignalPenalty(const double traffic_signal_penalty_)
+ {
+ traffic_signal_penalty = boost::numeric_cast<int>(traffic_signal_penalty_ * 10.);
+ }
+
+ //! penalty to cross a traffic light in deci-seconds
+ int traffic_signal_penalty;
+ //! penalty to do a uturn in deci-seconds
+ int u_turn_penalty;
+ bool allow_u_turn_at_via;
+ bool use_turn_restrictions;
+};
+}
+}
+
+#endif
diff --git a/include/extractor/query_node.hpp b/include/extractor/query_node.hpp
new file mode 100644
index 0000000..93c2d61
--- /dev/null
+++ b/include/extractor/query_node.hpp
@@ -0,0 +1,51 @@
+#ifndef QUERY_NODE_HPP
+#define QUERY_NODE_HPP
+
+#include "util/typedefs.hpp"
+
+#include "util/coordinate.hpp"
+
+#include <limits>
+
+namespace osrm
+{
+namespace extractor
+{
+
+struct QueryNode
+{
+ using key_type = OSMNodeID; // type of NodeID
+ using value_type = int; // type of lat,lons
+
+ explicit QueryNode(const util::FixedLongitude lon_,
+ const util::FixedLatitude lat_,
+ key_type node_id)
+ : lon(lon_), lat(lat_), node_id(std::move(node_id))
+ {
+ }
+ QueryNode()
+ : lon(std::numeric_limits<int>::max()), lat(std::numeric_limits<int>::max()),
+ node_id(SPECIAL_OSM_NODEID)
+ {
+ }
+
+ util::FixedLongitude lon;
+ util::FixedLatitude lat;
+ key_type node_id;
+
+ static QueryNode min_value()
+ {
+ return QueryNode(util::FixedLongitude(-180 * COORDINATE_PRECISION),
+ util::FixedLatitude(-90 * COORDINATE_PRECISION), MIN_OSM_NODEID);
+ }
+
+ static QueryNode max_value()
+ {
+ return QueryNode(util::FixedLongitude(180 * COORDINATE_PRECISION),
+ util::FixedLatitude(90 * COORDINATE_PRECISION), MAX_OSM_NODEID);
+ }
+};
+}
+}
+
+#endif // QUERY_NODE_HPP
diff --git a/data_structures/raster_source.hpp b/include/extractor/raster_source.hpp
similarity index 69%
rename from data_structures/raster_source.hpp
rename to include/extractor/raster_source.hpp
index 86c8596..4cc7e02 100644
--- a/data_structures/raster_source.hpp
+++ b/include/extractor/raster_source.hpp
@@ -1,34 +1,8 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef RASTER_SOURCE_HPP
#define RASTER_SOURCE_HPP
-#include "../util/osrm_exception.hpp"
+#include "util/exception.hpp"
+#include "util/coordinate.hpp"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@@ -40,6 +14,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unordered_map>
#include <iterator>
+namespace osrm
+{
+namespace extractor
+{
+
/**
\brief Small wrapper around raster source queries to optionally provide results
gracefully, depending on source bounds
@@ -64,10 +43,10 @@ class RasterGrid
ydim = _ydim;
_data.reserve(ydim * xdim);
- boost::filesystem::ifstream stream(filepath);
+ boost::filesystem::ifstream stream(filepath, std::ios::binary);
if (!stream)
{
- throw osrm::exception("Unable to open raster file.");
+ throw util::exception("Unable to open raster file.");
}
stream.seekg(0, std::ios_base::end);
@@ -92,13 +71,13 @@ class RasterGrid
}
catch (std::exception const &ex)
{
- throw osrm::exception(
+ throw util::exception(
std::string("Failed to read from raster source with exception: ") + ex.what());
}
if (!r || itr != end)
{
- throw osrm::exception("Failed to parse raster source correctly.");
+ throw util::exception("Failed to parse raster source correctly.");
}
}
@@ -163,13 +142,15 @@ class SourceContainer
std::size_t nrows,
std::size_t ncols);
- RasterDatum getRasterDataFromSource(unsigned int source_id, int lon, int lat);
+ RasterDatum getRasterDataFromSource(unsigned int source_id, double lon, double lat);
- RasterDatum getRasterInterpolateFromSource(unsigned int source_id, int lon, int lat);
+ RasterDatum getRasterInterpolateFromSource(unsigned int source_id, double lon, double lat);
private:
std::vector<RasterSource> LoadedSources;
std::unordered_map<std::string, int> LoadedSourcePaths;
};
+}
+}
#endif /* RASTER_SOURCE_HPP */
diff --git a/data_structures/restriction.hpp b/include/extractor/restriction.hpp
similarity index 69%
rename from data_structures/restriction.hpp
rename to include/extractor/restriction.hpp
index ecab4f9..5916c85 100644
--- a/data_structures/restriction.hpp
+++ b/include/extractor/restriction.hpp
@@ -1,37 +1,15 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef RESTRICTION_HPP
#define RESTRICTION_HPP
-#include "../typedefs.h"
+#include "util/typedefs.hpp"
#include <limits>
+namespace osrm
+{
+namespace extractor
+{
+
struct TurnRestriction
{
union WayOrNode
@@ -79,7 +57,7 @@ struct TurnRestriction
/**
* This is just a wrapper around TurnRestriction used in the extractor.
- *
+ *
* Could be merged with TurnRestriction. For now the type-destiction makes sense
* as the format in which the restriction is presented in the extractor and in the
* preprocessing is different. (see restriction_parser.cpp)
@@ -130,5 +108,7 @@ struct CmpRestrictionContainerByTo
value_type max_value() const { return InputRestrictionContainer::max_value(); }
value_type min_value() const { return InputRestrictionContainer::min_value(); }
};
+}
+}
#endif // RESTRICTION_HPP
diff --git a/data_structures/restriction_map.hpp b/include/extractor/restriction_map.hpp
similarity index 72%
rename from data_structures/restriction_map.hpp
rename to include/extractor/restriction_map.hpp
index dbca356..3e47867 100644
--- a/data_structures/restriction_map.hpp
+++ b/include/extractor/restriction_map.hpp
@@ -1,36 +1,10 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef RESTRICTION_MAP_HPP
#define RESTRICTION_MAP_HPP
-#include "restriction.hpp"
-#include "../util/std_hash.hpp"
-#include "../typedefs.h"
+#include "extractor/edge_based_edge.hpp"
+#include "extractor/restriction.hpp"
+#include "util/std_hash.hpp"
+#include "util/typedefs.hpp"
#include <boost/assert.hpp>
@@ -39,6 +13,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unordered_set>
#include <vector>
+namespace osrm
+{
+namespace extractor
+{
+
struct RestrictionSource
{
NodeID start_node;
@@ -64,26 +43,32 @@ struct RestrictionTarget
return (lhs.target_node == rhs.target_node && lhs.is_only == rhs.is_only);
}
};
+}
+}
namespace std
{
-template <> struct hash<RestrictionSource>
+template <> struct hash<osrm::extractor::RestrictionSource>
{
- size_t operator()(const RestrictionSource &r_source) const
+ size_t operator()(const osrm::extractor::RestrictionSource &r_source) const
{
return hash_val(r_source.start_node, r_source.via_node);
}
};
-template <> struct hash<RestrictionTarget>
+template <> struct hash<osrm::extractor::RestrictionTarget>
{
- size_t operator()(const RestrictionTarget &r_target) const
+ size_t operator()(const osrm::extractor::RestrictionTarget &r_target) const
{
return hash_val(r_target.target_node, r_target.is_only);
}
};
}
+namespace osrm
+{
+namespace extractor
+{
/**
\brief Efficent look up if an edge is the start + via node of a TurnRestriction
EdgeBasedEdgeFactory decides by it if edges are inserted or geometry is compressed
@@ -91,7 +76,7 @@ template <> struct hash<RestrictionTarget>
class RestrictionMap
{
public:
- RestrictionMap() : m_count(0) {};
+ RestrictionMap() : m_count(0){}
RestrictionMap(const std::vector<TurnRestriction> &restriction_list);
// Replace end v with w in each turn restriction containing u as via node
@@ -172,5 +157,7 @@ class RestrictionMap
std::unordered_set<NodeID> m_restriction_start_nodes;
std::unordered_set<NodeID> m_no_turn_via_node_set;
};
+}
+}
#endif // RESTRICTION_MAP_HPP
diff --git a/include/extractor/restriction_parser.hpp b/include/extractor/restriction_parser.hpp
new file mode 100644
index 0000000..d2be8c1
--- /dev/null
+++ b/include/extractor/restriction_parser.hpp
@@ -0,0 +1,58 @@
+#ifndef RESTRICTION_PARSER_HPP
+#define RESTRICTION_PARSER_HPP
+
+#include "extractor/restriction.hpp"
+
+#include <boost/optional/optional.hpp>
+
+#include <string>
+#include <vector>
+
+struct lua_State;
+namespace osmium
+{
+class Relation;
+}
+
+namespace osrm
+{
+namespace extractor
+{
+
+class ProfileProperties;
+
+/**
+ * Parses the relations that represents turn restrictions.
+ *
+ * Currently only restrictions where the via objects is a node are supported.
+ * from via to
+ * ------->(x)-------->
+ *
+ * While this class does not directly invoke any lua code _per relation_ it does
+ * load configuration values from the profile, that are saved in variables.
+ * Namely ```use_turn_restrictions``` and ```get_exceptions```.
+ *
+ * The restriction is represented by the osm id of the from way, the osm id of the
+ * to way and the osm id of the via node. This representation must be post-processed
+ * in the extractor to work with the edge-based data-model of OSRM:
+ * Since the from and to way share the via-node a turn will have the following form:
+ * ...----(a)-----(via)------(b)----...
+ * So it can be represented by the tripe (a, via, b).
+ */
+class RestrictionParser
+{
+ public:
+ RestrictionParser(lua_State *lua_state, const ProfileProperties& properties);
+ boost::optional<InputRestrictionContainer> TryParse(const osmium::Relation &relation) const;
+
+ private:
+ void ReadRestrictionExceptions(lua_State *lua_state);
+ bool ShouldIgnoreRestriction(const std::string &except_tag_string) const;
+
+ std::vector<std::string> restriction_exceptions;
+ bool use_turn_restrictions;
+};
+}
+}
+
+#endif /* RESTRICTION_PARSER_HPP */
diff --git a/include/extractor/scripting_environment.hpp b/include/extractor/scripting_environment.hpp
new file mode 100644
index 0000000..5494c12
--- /dev/null
+++ b/include/extractor/scripting_environment.hpp
@@ -0,0 +1,54 @@
+#ifndef SCRIPTING_ENVIRONMENT_HPP
+#define SCRIPTING_ENVIRONMENT_HPP
+
+#include "extractor/profile_properties.hpp"
+#include "extractor/raster_source.hpp"
+
+#include "util/lua_util.hpp"
+
+#include <string>
+#include <memory>
+#include <mutex>
+#include <tbb/enumerable_thread_specific.h>
+
+struct lua_State;
+
+namespace osrm
+{
+namespace extractor
+{
+
+/**
+ * Creates a lua context and binds osmium way, node and relation objects and
+ * ExtractionWay and ExtractionNode to lua objects.
+ *
+ * Each thread has its own lua state which is implemented with thread specific
+ * storage from TBB.
+ */
+class ScriptingEnvironment
+{
+ public:
+ struct Context
+ {
+ ProfileProperties properties;
+ SourceContainer sources;
+ util::LuaState state;
+ };
+
+ explicit ScriptingEnvironment(const std::string &file_name);
+
+ ScriptingEnvironment(const ScriptingEnvironment &) = delete;
+ ScriptingEnvironment &operator=(const ScriptingEnvironment &) = delete;
+
+ Context &GetContex();
+
+ private:
+ void InitContext(Context &context);
+ std::mutex init_mutex;
+ std::string file_name;
+ tbb::enumerable_thread_specific<std::unique_ptr<Context>> script_contexts;
+};
+}
+}
+
+#endif /* SCRIPTING_ENVIRONMENT_HPP */
diff --git a/algorithms/tarjan_scc.hpp b/include/extractor/tarjan_scc.hpp
similarity index 74%
rename from algorithms/tarjan_scc.hpp
rename to include/extractor/tarjan_scc.hpp
index 5907732..874d3f6 100644
--- a/algorithms/tarjan_scc.hpp
+++ b/include/extractor/tarjan_scc.hpp
@@ -1,45 +1,18 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef TARJAN_SCC_HPP
#define TARJAN_SCC_HPP
-#include "../typedefs.h"
-#include "../data_structures/deallocating_vector.hpp"
-#include "../data_structures/import_edge.hpp"
-#include "../data_structures/query_node.hpp"
-#include "../data_structures/percent.hpp"
+#include "util/typedefs.hpp"
+#include "util/deallocating_vector.hpp"
+#include "extractor/node_based_edge.hpp"
+#include "extractor/query_node.hpp"
+#include "util/percent.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/std_hash.hpp"
-#include "../util/timing_util.hpp"
+#include "util/integer_range.hpp"
+#include "util/simple_logger.hpp"
+#include "util/std_hash.hpp"
+#include "util/timing_util.hpp"
-#include <osrm/coordinate.hpp>
+#include "osrm/coordinate.hpp"
#include <boost/assert.hpp>
#include <cstdint>
@@ -49,6 +22,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stack>
#include <vector>
+namespace osrm
+{
+namespace extractor
+{
+
template <typename GraphT> class TarjanSCC
{
struct TarjanStackFrame
@@ -93,7 +71,7 @@ template <typename GraphT> class TarjanSCC
unsigned component_index = 0, size_of_current_component = 0;
unsigned index = 0;
std::vector<bool> processing_node_before_recursion(max_node_id, true);
- for (const NodeID node : osrm::irange(0u, max_node_id))
+ for (const NodeID node : util::irange(0u, max_node_id))
{
if (SPECIAL_NODEID == components_index[node])
{
@@ -168,8 +146,8 @@ template <typename GraphT> class TarjanSCC
if (size_of_current_component > 1000)
{
- SimpleLogger().Write() << "large component [" << component_index
- << "]=" << size_of_current_component;
+ util::SimpleLogger().Write() << "large component [" << component_index
+ << "]=" << size_of_current_component;
}
++component_index;
@@ -180,7 +158,7 @@ template <typename GraphT> class TarjanSCC
}
TIMER_STOP(SCC_RUN);
- SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN) / 1000. << "s";
+ util::SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN) / 1000. << "s";
size_one_counter = std::count_if(component_size_vector.begin(), component_size_vector.end(),
[](unsigned value)
@@ -200,5 +178,7 @@ template <typename GraphT> class TarjanSCC
unsigned get_component_id(const NodeID node) const { return components_index[node]; }
};
+}
+}
#endif /* TARJAN_SCC_HPP */
diff --git a/data_structures/travel_mode.hpp b/include/extractor/travel_mode.hpp
similarity index 54%
rename from data_structures/travel_mode.hpp
rename to include/extractor/travel_mode.hpp
index 2bbe463..7ec7bec 100644
--- a/data_structures/travel_mode.hpp
+++ b/include/extractor/travel_mode.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,10 +28,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef TRAVEL_MODE_HPP
#define TRAVEL_MODE_HPP
-namespace
+namespace osrm
{
+namespace extractor
+{
+
+// This is a char instead of a typed enum, so that we can
+// pack it into e.g. a "TravelMode mode : 4" packed bitfield
using TravelMode = unsigned char;
-static const TravelMode TRAVEL_MODE_INACCESSIBLE = 0;
-static const TravelMode TRAVEL_MODE_DEFAULT = 1;
}
+}
+
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_INACCESSIBLE = 0;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_DRIVING = 1;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_CYCLING = 2;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_WALKING = 3;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_FERRY = 4;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_TRAIN = 5;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_PUSHING_BIKE = 6;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_MOVABLE_BRIDGE = 7;
+// FIXME only for testbot.lua
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_STEPS_UP = 8;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_STEPS_DOWN = 9;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_RIVER_UP = 10;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_RIVER_DOWN = 11;
+const constexpr osrm::extractor::TravelMode TRAVEL_MODE_ROUTE = 12;
+
#endif /* TRAVEL_MODE_HPP */
diff --git a/data_structures/tribool.hpp b/include/osrm/bearing.hpp
similarity index 88%
copy from data_structures/tribool.hpp
copy to include/osrm/bearing.hpp
index 2d4b610..75ec110 100644
--- a/data_structures/tribool.hpp
+++ b/include/osrm/bearing.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TRIBOOL_HPP
-#define TRIBOOL_HPP
+#ifndef OSRM_BEARING_HPP
+#define OSRM_BEARING_HPP
+
+#include "engine/bearing.hpp"
namespace osrm
{
-enum class tribool : char
-{
- yes,
- no,
- indeterminate
-};
+ using engine::Bearing;
}
-#endif // TRIBOOL_HPP
+
+#endif
diff --git a/include/osrm/coordinate.hpp b/include/osrm/coordinate.hpp
index 6318465..39b684d 100644
--- a/include/osrm/coordinate.hpp
+++ b/include/osrm/coordinate.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,47 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef COORDINATE_HPP_
-#define COORDINATE_HPP_
+#ifndef GLOBAL_COORDINATE_HPP
+#define GLOBAL_COORDINATE_HPP
-#include <iosfwd> //for std::ostream
-#include <string>
-#include <type_traits>
+#include "util/coordinate.hpp"
-namespace
+namespace osrm
{
-constexpr static const float COORDINATE_PRECISION = 1000000.f;
+using util::Coordinate;
}
-struct FixedPointCoordinate
-{
- int lat;
- int lon;
-
- FixedPointCoordinate();
- FixedPointCoordinate(int lat, int lon);
-
- template <class T>
- FixedPointCoordinate(const T &coordinate)
- : lat(coordinate.lat), lon(coordinate.lon)
- {
- static_assert(std::is_same<decltype(lat), decltype(coordinate.lat)>::value,
- "coordinate types incompatible");
- static_assert(std::is_same<decltype(lon), decltype(coordinate.lon)>::value,
- "coordinate types incompatible");
- }
-
- bool is_valid() const;
- bool operator==(const FixedPointCoordinate &other) const;
-
- float bearing(const FixedPointCoordinate &other) const;
- void output(std::ostream &out) const;
-};
-
-inline std::ostream &operator<<(std::ostream &out_stream, FixedPointCoordinate const &coordinate)
-{
- coordinate.output(out_stream);
- return out_stream;
-}
-
-#endif /* COORDINATE_HPP_ */
+#endif
diff --git a/unit_tests/algorithm_tests.cpp b/include/osrm/engine_config.hpp
similarity index 86%
rename from unit_tests/algorithm_tests.cpp
rename to include/osrm/engine_config.hpp
index 0a9f3fd..e48dceb 100644
--- a/unit_tests/algorithm_tests.cpp
+++ b/include/osrm/engine_config.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,10 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define BOOST_TEST_MODULE algorithm tests
+#ifndef GLOBAL_ENGINE_CONFIG_HPP
+#define GLOBAL_ENGINE_CONFIG_HPP
-#include <boost/test/unit_test.hpp>
+#include "engine/engine_config.hpp"
-/*
- * This file will contain an automatically generated main function.
- */
+namespace osrm
+{
+using engine::EngineConfig;
+}
+
+#endif
diff --git a/include/osrm/json_container.hpp b/include/osrm/json_container.hpp
index 63accb8..7010cf4 100644
--- a/include/osrm/json_container.hpp
+++ b/include/osrm/json_container.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,72 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-// based on
-// https://svn.apache.org/repos/asf/mesos/tags/release-0.9.0-incubating-RC0/src/common/json.hpp
-
-#ifndef JSON_CONTAINER_HPP
-#define JSON_CONTAINER_HPP
-
-#include <variant/variant.hpp>
-
-#include <iostream>
-#include <vector>
-#include <string>
-#include <unordered_map>
-
+#ifndef GLOBAL_JSON_CONTAINER_HPP
+#define GLOBAL_JSON_CONTAINER_HPP
+#include "util/json_container.hpp"
namespace osrm
{
-namespace json
-{
-
-struct Object;
-struct Array;
-
-struct String
-{
- String() {}
- String(const char *value) : value(value) {}
- String(std::string value) : value(std::move(value)) {}
- std::string value;
-};
-
-struct Number
-{
- Number() {}
- Number(double value) : value(static_cast<double>(value)) {}
- double value;
-};
-
-struct True
-{
-};
-
-struct False
-{
-};
-
-struct Null
-{
-};
-
-using Value = mapbox::util::variant<String,
- Number,
- mapbox::util::recursive_wrapper<Object>,
- mapbox::util::recursive_wrapper<Array>,
- True,
- False,
- Null>;
-
-struct Object
-{
- std::unordered_map<std::string, Value> values;
-};
-
-struct Array
-{
- std::vector<Value> values;
-};
-
-} // namespace JSON
-} // namespace osrm
-#endif // JSON_CONTAINER_HPP
+namespace json = osrm::util::json;
+}
+#endif
diff --git a/data_structures/tribool.hpp b/include/osrm/match_parameters.hpp
similarity index 86%
copy from data_structures/tribool.hpp
copy to include/osrm/match_parameters.hpp
index 2d4b610..36e7001 100644
--- a/data_structures/tribool.hpp
+++ b/include/osrm/match_parameters.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TRIBOOL_HPP
-#define TRIBOOL_HPP
+#ifndef GLOBAL_MATCH_PARAMETERS_HPP
+#define GLOBAL_MATCH_PARAMETERS_HPP
+
+#include "engine/api/match_parameters.hpp"
namespace osrm
{
-enum class tribool : char
-{
- yes,
- no,
- indeterminate
-};
+using engine::api::MatchParameters;
}
-#endif // TRIBOOL_HPP
+
+#endif
diff --git a/data_structures/tribool.hpp b/include/osrm/nearest_parameters.hpp
similarity index 85%
copy from data_structures/tribool.hpp
copy to include/osrm/nearest_parameters.hpp
index 2d4b610..f19131c 100644
--- a/data_structures/tribool.hpp
+++ b/include/osrm/nearest_parameters.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TRIBOOL_HPP
-#define TRIBOOL_HPP
+#ifndef GLOBAL_NEAREST_PARAMETERS_HPP
+#define GLOBAL_NEAREST_PARAMETERS_HPP
+
+#include "engine/api/nearest_parameters.hpp"
namespace osrm
{
-enum class tribool : char
-{
- yes,
- no,
- indeterminate
-};
+using engine::api::NearestParameters;
}
-#endif // TRIBOOL_HPP
+
+#endif
diff --git a/include/osrm/osrm.hpp b/include/osrm/osrm.hpp
index cbf14d3..1de8610 100644
--- a/include/osrm/osrm.hpp
+++ b/include/osrm/osrm.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,29 +28,111 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef OSRM_HPP
#define OSRM_HPP
-#include <memory>
+#include "osrm/osrm_fwd.hpp"
+#include "osrm/status.hpp"
-struct LibOSRMConfig;
-struct RouteParameters;
+#include <memory>
+#include <string>
namespace osrm
{
-namespace json
-{
-struct Object;
-}
-}
+namespace json = util::json;
+using engine::EngineConfig;
+using engine::api::RouteParameters;
+using engine::api::TableParameters;
+using engine::api::NearestParameters;
+using engine::api::TripParameters;
+using engine::api::MatchParameters;
+using engine::api::TileParameters;
-class OSRM
+/**
+ * Represents a Open Source Routing Machine with access to its services.
+ *
+ * This represents an Open Source Routing Machine (OSRM) instance, with the services:
+ *
+ * - Route: shortest path queries for coordinates
+ * - Table: distance tables for coordinates
+ * - Nearest: nearest street segment for coordinate
+ * - Trip: shortest round trip between coordinates
+ * - Match: snaps noisy coordinate traces to the road network
+ * - Tile: vector tiles with internal graph representation
+ *
+ * All services take service-specific parameters, fill a JSON object, and return a status code.
+ */
+class OSRM final
{
- private:
- class OSRM_impl;
- std::unique_ptr<OSRM_impl> OSRM_pimpl_;
-
public:
- OSRM(LibOSRMConfig &lib_config);
- ~OSRM(); // needed because we need to define it with the implementation of OSRM_impl
- int RunQuery(const RouteParameters &route_parameters, osrm::json::Object &json_result);
+ /**
+ * Constructs an OSRM instance with user-configurable settings.
+ *
+ * \param config The user-provided OSRM configuration.
+ * \see EngineConfig
+ */
+ explicit OSRM(EngineConfig &config);
+
+ ~OSRM();
+
+ // Moveable but not copyable
+ OSRM(OSRM &&) noexcept;
+ OSRM &operator=(OSRM &&) noexcept;
+
+ /**
+ * Shortest path queries for coordinates.
+ *
+ * \param parameters route query specific parameters
+ * \return Status indicating success for the query or failure
+ * \see Status, RouteParameters and json::Object
+ */
+ Status Route(const RouteParameters ¶meters, json::Object &result);
+
+ /**
+ * Distance tables for coordinates.
+ *
+ * \param parameters table query specific parameters
+ * \return Status indicating success for the query or failure
+ * \see Status, TableParameters and json::Object
+ */
+ Status Table(const TableParameters ¶meters, json::Object &result);
+
+ /**
+ * Nearest street segment for coordinate.
+ *
+ * \param parameters nearest query specific parameters
+ * \return Status indicating success for the query or failure
+ * \see Status, NearestParameters and json::Object
+ */
+ Status Nearest(const NearestParameters ¶meters, json::Object &result);
+
+ /**
+ * Trip: shortest round trip between coordinates.
+ *
+ * \param parameters trip query specific parameters
+ * \return Status indicating success for the query or failure
+ * \see Status, TripParameters and json::Object
+ */
+ Status Trip(const TripParameters ¶meters, json::Object &result);
+
+ /**
+ * Match: snaps noisy coordinate traces to the road network
+ *
+ * \param parameters match query specific parameters
+ * \return Status indicating success for the query or failure
+ * \see Status, MatchParameters and json::Object
+ */
+ Status Match(const MatchParameters ¶meters, json::Object &result);
+
+ /**
+ * Tile: vector tiles with internal graph representation
+ *
+ * \param parameters tile query specific parameters
+ * \return Status indicating success for the query or failure
+ * \see Status, TileParameters and json::Object
+ */
+ Status Tile(const TileParameters ¶meters, std::string &result);
+
+ private:
+ std::unique_ptr<engine::Engine> engine_;
};
+}
#endif // OSRM_HPP
diff --git a/util/floating_point.hpp b/include/osrm/osrm_fwd.hpp
similarity index 68%
rename from util/floating_point.hpp
rename to include/osrm/osrm_fwd.hpp
index 13f2d3b..f0f1f17 100644
--- a/util/floating_point.hpp
+++ b/include/osrm/osrm_fwd.hpp
@@ -1,5 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM contributors
+
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -24,21 +25,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FLOATING_POINT_HPP
-#define FLOATING_POINT_HPP
-
-#include <cmath>
+#ifndef OSRM_FWD_HPP
+#define OSRM_FWD_HPP
-#include <limits>
-#include <type_traits>
+// OSRM API forward declarations for usage in interfaces. Exposes forward declarations for:
+// osrm::util::json::Object, osrm::engine::api::XParameters
namespace osrm
{
-template <typename FloatT> bool epsilon_compare(const FloatT number1, const FloatT number2)
+
+namespace util
+{
+namespace json
{
- static_assert(std::is_floating_point<FloatT>::value, "type must be floating point");
- return (std::abs(number1 - number2) < std::numeric_limits<FloatT>::epsilon());
-}
-}
+struct Object;
+} // ns json
+} // ns util
-#endif // FLOATING_POINT_HPP
+namespace engine
+{
+namespace api
+{
+struct RouteParameters;
+struct TableParameters;
+struct NearestParameters;
+struct TripParameters;
+struct MatchParameters;
+struct TileParameters;
+} // ns api
+
+class Engine;
+struct EngineConfig;
+} // ns engine
+} // ns osrm
+
+#endif
diff --git a/include/osrm/route_parameters.hpp b/include/osrm/route_parameters.hpp
index 6d2dda7..6c0508c 100644
--- a/include/osrm/route_parameters.hpp
+++ b/include/osrm/route_parameters.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,92 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ROUTE_PARAMETERS_HPP
-#define ROUTE_PARAMETERS_HPP
+#ifndef GLOBAL_ROUTE_PARAMETERS_HPP
+#define GLOBAL_ROUTE_PARAMETERS_HPP
-#include <osrm/coordinate.hpp>
+#include "engine/api/route_parameters.hpp"
-#include <boost/fusion/container/vector/vector_fwd.hpp>
-#include <boost/spirit/include/qi.hpp>
-
-#include <string>
-#include <vector>
-
-struct RouteParameters
+namespace osrm
{
- RouteParameters();
-
- void setZoomLevel(const short level);
-
- void setNumberOfResults(const short number);
-
- void setAlternateRouteFlag(const bool flag);
-
- void setUTurn(const bool flag);
-
- void setAllUTurns(const bool flag);
-
- void setClassify(const bool classify);
-
- void setMatchingBeta(const double beta);
-
- void setGPSPrecision(const double precision);
-
- void setDeprecatedAPIFlag(const std::string &);
-
- void setChecksum(const unsigned check_sum);
-
- void setInstructionFlag(const bool flag);
-
- void setService(const std::string &service);
-
- void setOutputFormat(const std::string &format);
-
- void setJSONpParameter(const std::string ¶meter);
-
- void addHint(const std::string &hint);
-
- void addTimestamp(const unsigned timestamp);
-
- void addBearing(const boost::fusion::vector<int, boost::optional<int>> &received_bearing, boost::spirit::qi::unused_type unused, bool& pass);
-
- void setLanguage(const std::string &language);
-
- void setGeometryFlag(const bool flag);
-
- void setCompressionFlag(const bool flag);
-
- void addCoordinate(const boost::fusion::vector<double, double> &received_coordinates);
-
- void addDestination(const boost::fusion::vector<double, double> &received_coordinates);
-
- void addSource(const boost::fusion::vector<double, double> &received_coordinates);
-
- void getCoordinatesFromGeometry(const std::string &geometry_string);
-
- short zoom_level;
- bool print_instructions;
- bool alternate_route;
- bool geometry;
- bool compression;
- bool deprecatedAPI;
- bool uturn_default;
- bool classify;
- double matching_beta;
- double gps_precision;
- unsigned check_sum;
- short num_results;
- std::string service;
- std::string output_format;
- std::string jsonp_parameter;
- std::string language;
- std::vector<std::string> hints;
- std::vector<unsigned> timestamps;
- std::vector<std::pair<const int,const boost::optional<int>>> bearings;
- std::vector<bool> uturns;
- std::vector<FixedPointCoordinate> coordinates;
- std::vector<bool> is_destination;
- std::vector<bool> is_source;
-};
+using engine::api::RouteParameters;
+}
-#endif // ROUTE_PARAMETERS_HPP
+#endif
diff --git a/util/fingerprint.cpp b/include/osrm/status.hpp
similarity index 87%
rename from util/fingerprint.cpp
rename to include/osrm/status.hpp
index 8a705b0..8bb1f66 100644
--- a/util/fingerprint.cpp
+++ b/include/osrm/status.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,5 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "util/fingerprint.hpp"
-#include "util/fingerprint_impl.hpp"
+#ifndef OSRM_STATUS_HPP
+#define OSRM_STATUS_HPP
+
+#include "engine/status.hpp"
+
+namespace osrm
+{
+using engine::Status;
+}
+
+#endif
diff --git a/unit_tests/datastructure_tests.cpp b/include/osrm/storage_config.hpp
similarity index 85%
rename from unit_tests/datastructure_tests.cpp
rename to include/osrm/storage_config.hpp
index 850d619..353c75e 100644
--- a/unit_tests/datastructure_tests.cpp
+++ b/include/osrm/storage_config.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,10 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define BOOST_TEST_MODULE datastructure tests
+#ifndef GLOBAL_STORAGE_CONFIG_HPP
+#define GLOBAL_STORAGE_CONFIG_HPP
-#include <boost/test/unit_test.hpp>
+#include "storage/storage_config.hpp"
-/*
- * This file will contain an automatically generated main function.
- */
+namespace osrm
+{
+using storage::StorageConfig;
+}
+
+#endif
diff --git a/include/osrm/strong_typedef.hpp b/include/osrm/strong_typedef.hpp
deleted file mode 100644
index c2364b0..0000000
--- a/include/osrm/strong_typedef.hpp
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef OSRM_STRONG_TYPEDEF_HPP
-#define OSRM_STRONG_TYPEDEF_HPP
-
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include <type_traits>
-#include <functional>
-
-/* Creates strongly typed wrappers around scalar types.
- * Useful for stopping accidental assignment of lats to lons,
- * etc. Also clarifies what this random "int" value is
- * being used for.
- */
-#define OSRM_STRONG_TYPEDEF(From, To) \
- class To final { \
- static_assert(std::is_arithmetic<From>(), ""); \
- From x; \
- \
- public: \
- To() = default; \
- explicit To(const From x_) : x(x_) {} \
- explicit operator From&() { return x; } \
- explicit operator const From&() const { return x; } \
- bool operator <(const To &z_) const { return x < static_cast<const From>(z_) ; } \
- bool operator >(const To &z_) const { return x > static_cast<const From>(z_) ; } \
- bool operator <=(const To &z_) const { return x <= static_cast<const From>(z_) ; } \
- bool operator >=(const To &z_) const { return x >= static_cast<const From>(z_) ; } \
- bool operator ==(const To &z_) const { return x == static_cast<const From>(z_) ; } \
- bool operator !=(const To &z_) const { return x != static_cast<const From>(z_) ; } \
- }; \
- inline From To##_to_##From(To to) { return static_cast<From>(to); } \
- namespace std { \
- template <> \
- struct hash<To> \
- { \
- std::size_t operator()(const To& k) const \
- { \
- return std::hash<From>()(static_cast<const From>(k)); \
- } \
- }; \
- }
-
-#endif // OSRM_STRONG_TYPEDEF_HPP
diff --git a/data_structures/tribool.hpp b/include/osrm/table_parameters.hpp
similarity index 86%
copy from data_structures/tribool.hpp
copy to include/osrm/table_parameters.hpp
index 2d4b610..7bb16eb 100644
--- a/data_structures/tribool.hpp
+++ b/include/osrm/table_parameters.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TRIBOOL_HPP
-#define TRIBOOL_HPP
+#ifndef GLOBAL_TABLE_PARAMETERS_HPP
+#define GLOBAL_TABLE_PARAMETERS_HPP
+
+#include "engine/api/table_parameters.hpp"
namespace osrm
{
-enum class tribool : char
-{
- yes,
- no,
- indeterminate
-};
+using engine::api::TableParameters;
}
-#endif // TRIBOOL_HPP
+
+#endif
diff --git a/data_structures/tribool.hpp b/include/osrm/tile_parameters.hpp
similarity index 86%
copy from data_structures/tribool.hpp
copy to include/osrm/tile_parameters.hpp
index 2d4b610..0672dea 100644
--- a/data_structures/tribool.hpp
+++ b/include/osrm/tile_parameters.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TRIBOOL_HPP
-#define TRIBOOL_HPP
+#ifndef GLOBAL_TILE_PARAMETERS_HPP
+#define GLOBAL_TILE_PARAMETERS_HPP
+
+#include "engine/api/tile_parameters.hpp"
namespace osrm
{
-enum class tribool : char
-{
- yes,
- no,
- indeterminate
-};
+using engine::api::TileParameters;
}
-#endif // TRIBOOL_HPP
+
+#endif
diff --git a/data_structures/tribool.hpp b/include/osrm/trip_parameters.hpp
similarity index 86%
rename from data_structures/tribool.hpp
rename to include/osrm/trip_parameters.hpp
index 2d4b610..15a70c1 100644
--- a/data_structures/tribool.hpp
+++ b/include/osrm/trip_parameters.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TRIBOOL_HPP
-#define TRIBOOL_HPP
+#ifndef GLOBAL_TRIP_PARAMETERS_HPP
+#define GLOBAL_TRIP_PARAMETERS_HPP
+
+#include "engine/api/trip_parameters.hpp"
namespace osrm
{
-enum class tribool : char
-{
- yes,
- no,
- indeterminate
-};
+using engine::api::TripParameters;
}
-#endif // TRIBOOL_HPP
+
+#endif
diff --git a/include/server/api/base_parameters_grammar.hpp b/include/server/api/base_parameters_grammar.hpp
new file mode 100644
index 0000000..2f9a95e
--- /dev/null
+++ b/include/server/api/base_parameters_grammar.hpp
@@ -0,0 +1,108 @@
+#ifndef SERVER_API_BASE_PARAMETERS_GRAMMAR_HPP
+#define SERVER_API_BASE_PARAMETERS_GRAMMAR_HPP
+
+#include "engine/api/base_parameters.hpp"
+
+#include "engine/polyline_compressor.hpp"
+#include "engine/hint.hpp"
+#include "engine/bearing.hpp"
+
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_char_.hpp>
+#include <boost/spirit/include/qi_int.hpp>
+#include <boost/spirit/include/qi_real.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_optional.hpp>
+#include <boost/spirit/include/qi_attr_cast.hpp>
+#include <boost/spirit/include/qi_operator.hpp>
+#include <boost/spirit/include/qi_repeat.hpp>
+#include <boost/spirit/include/qi_as_string.hpp>
+
+#include <string>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace qi = boost::spirit::qi;
+struct BaseParametersGrammar : boost::spirit::qi::grammar<std::string::iterator>
+{
+ using Iterator = std::string::iterator;
+ using RadiusesT = std::vector<boost::optional<double>>;
+
+ BaseParametersGrammar(qi::rule<Iterator> &root_rule_, engine::api::BaseParameters ¶meters_)
+ : BaseParametersGrammar::base_type(root_rule_), base_parameters(parameters_)
+ {
+ const auto add_bearing =
+ [this](boost::optional<boost::fusion::vector2<short, short>> bearing_range)
+ {
+ boost::optional<engine::Bearing> bearing;
+ if (bearing_range)
+ {
+ bearing = engine::Bearing{boost::fusion::at_c<0>(*bearing_range),
+ boost::fusion::at_c<1>(*bearing_range)};
+ }
+ base_parameters.bearings.push_back(std::move(bearing));
+ };
+ const auto set_radiuses = [this](RadiusesT &radiuses)
+ {
+ base_parameters.radiuses = std::move(radiuses);
+ };
+ const auto add_hint = [this](const std::string &hint_string)
+ {
+ if (hint_string.size() > 0)
+ {
+ base_parameters.hints.push_back(engine::Hint::FromBase64(hint_string));
+ }
+ };
+ const auto add_coordinate = [this](const boost::fusion::vector<double, double> &lonLat)
+ {
+ base_parameters.coordinates.emplace_back(util::Coordinate(
+ util::FixedLongitude(boost::fusion::at_c<0>(lonLat) * COORDINATE_PRECISION),
+ util::FixedLatitude(boost::fusion::at_c<1>(lonLat) * COORDINATE_PRECISION)));
+ };
+ const auto polyline_to_coordinates = [this](const std::string &polyline)
+ {
+ base_parameters.coordinates = engine::decodePolyline(polyline);
+ };
+
+ alpha_numeral = +qi::char_("a-zA-Z0-9");
+ polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\%~`^");
+ base64_char = qi::char_("a-zA-Z0-9--_");
+
+ radiuses_rule = qi::lit("radiuses=") >> -qi::double_ % ";";
+ hints_rule =
+ qi::lit("hints=") >>
+ qi::as_string[qi::repeat(engine::ENCODED_HINT_SIZE)[base64_char]][add_hint] % ";";
+ bearings_rule =
+ qi::lit("bearings=") >> (-(qi::short_ >> ',' >> qi::short_))[add_bearing] % ";";
+ polyline_rule = qi::as_string[qi::lit("polyline(") >> +polyline_chars >>
+ qi::lit(")")][polyline_to_coordinates];
+ location_rule = (qi::double_ >> qi::lit(',') >> qi::double_)[add_coordinate];
+ query_rule = (location_rule % ';') | polyline_rule;
+
+ base_rule = bearings_rule | radiuses_rule[set_radiuses] | hints_rule;
+ }
+
+ protected:
+ qi::rule<Iterator> base_rule;
+ qi::rule<Iterator> query_rule;
+
+ private:
+ engine::api::BaseParameters &base_parameters;
+ qi::rule<Iterator> bearings_rule;
+ qi::rule<Iterator> hints_rule;
+ qi::rule<Iterator> polyline_rule, location_rule;
+ qi::rule<Iterator, RadiusesT()> radiuses_rule;
+ qi::rule<Iterator, unsigned char()> base64_char;
+ qi::rule<Iterator, std::string()> alpha_numeral, polyline_chars;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/match_parameter_grammar.hpp b/include/server/api/match_parameter_grammar.hpp
new file mode 100644
index 0000000..7628e87
--- /dev/null
+++ b/include/server/api/match_parameter_grammar.hpp
@@ -0,0 +1,88 @@
+#ifndef MATCH_PARAMETERS_GRAMMAR_HPP
+#define MATCH_PARAMETERS_GRAMMAR_HPP
+
+#include "engine/api/match_parameters.hpp"
+
+#include "server/api/base_parameters_grammar.hpp"
+
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_uint.hpp>
+#include <boost/spirit/include/qi_bool.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_optional.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace qi = boost::spirit::qi;
+
+struct MatchParametersGrammar final : public BaseParametersGrammar
+{
+ using Iterator = std::string::iterator;
+ using StepsT = bool;
+ using TimestampsT = std::vector<unsigned>;
+ using GeometriesT = engine::api::RouteParameters::GeometriesType;
+ using OverviewT = engine::api::RouteParameters::OverviewType;
+
+ MatchParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
+ {
+ const auto set_geojson_type = [this]()
+ {
+ parameters.geometries = engine::api::RouteParameters::GeometriesType::GeoJSON;
+ };
+ const auto set_polyline_type = [this]()
+ {
+ parameters.geometries = engine::api::RouteParameters::GeometriesType::Polyline;
+ };
+
+ const auto set_simplified_type = [this]()
+ {
+ parameters.overview = engine::api::RouteParameters::OverviewType::Simplified;
+ };
+ const auto set_full_type = [this]()
+ {
+ parameters.overview = engine::api::RouteParameters::OverviewType::Full;
+ };
+ const auto set_false_type = [this]()
+ {
+ parameters.overview = engine::api::RouteParameters::OverviewType::False;
+ };
+ const auto set_steps = [this](const StepsT steps)
+ {
+ parameters.steps = steps;
+ };
+ const auto set_timestamps = [this](TimestampsT ×tamps)
+ {
+ parameters.timestamps = std::move(timestamps);
+ };
+
+ steps_rule = qi::lit("steps=") >> qi::bool_;
+ geometries_rule = qi::lit("geometries=geojson")[set_geojson_type] |
+ qi::lit("geometries=polyline")[set_polyline_type];
+ overview_rule = qi::lit("overview=simplified")[set_simplified_type] |
+ qi::lit("overview=full")[set_full_type] |
+ qi::lit("overview=false")[set_false_type];
+ timestamps_rule = qi::lit("timestamps=") >> qi::uint_ % ";";
+ match_rule = steps_rule[set_steps] | geometries_rule | overview_rule |
+ timestamps_rule[set_timestamps];
+ root_rule =
+ query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (match_rule | base_rule) % '&');
+ }
+
+ engine::api::MatchParameters parameters;
+
+ private:
+ qi::rule<Iterator> root_rule, match_rule, geometries_rule, overview_rule;
+ qi::rule<Iterator, TimestampsT()> timestamps_rule;
+ qi::rule<Iterator, StepsT()> steps_rule;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/nearest_parameter_grammar.hpp b/include/server/api/nearest_parameter_grammar.hpp
new file mode 100644
index 0000000..e51ccb5
--- /dev/null
+++ b/include/server/api/nearest_parameter_grammar.hpp
@@ -0,0 +1,48 @@
+#ifndef NEAREST_PARAMETERS_GRAMMAR_HPP
+#define NEAREST_PARAMETERS_GRAMMAR_HPP
+
+#include "engine/api/nearest_parameters.hpp"
+
+#include "server/api/base_parameters_grammar.hpp"
+
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_uint.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_optional.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace qi = boost::spirit::qi;
+
+struct NearestParametersGrammar final : public BaseParametersGrammar
+{
+ using Iterator = std::string::iterator;
+
+ NearestParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
+ {
+ const auto set_number = [this](const unsigned number)
+ {
+ parameters.number_of_results = number;
+ };
+ nearest_rule = (qi::lit("number=") >> qi::uint_)[set_number];
+ root_rule =
+ query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (nearest_rule | base_rule) % '&');
+ }
+
+ engine::api::NearestParameters parameters;
+
+ private:
+ qi::rule<Iterator> root_rule;
+ qi::rule<Iterator> nearest_rule;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/parameters_parser.hpp b/include/server/api/parameters_parser.hpp
new file mode 100644
index 0000000..5af5888
--- /dev/null
+++ b/include/server/api/parameters_parser.hpp
@@ -0,0 +1,49 @@
+#ifndef SERVER_API_ROUTE_PARAMETERS_PARSER_HPP
+#define SERVER_API_ROUTE_PARAMETERS_PARSER_HPP
+
+#include "engine/api/base_parameters.hpp"
+#include "engine/api/tile_parameters.hpp"
+
+#include <boost/optional/optional.hpp>
+
+#include <type_traits>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+// Note: this file provides only the interface for the generic parseParameters function.
+// The actual implementations for each concrete parameter type live in the cpp file.
+
+namespace detail
+{
+template <typename T>
+using is_parameter_t =
+ std::integral_constant<bool,
+ std::is_base_of<engine::api::BaseParameters, T>::value ||
+ std::is_same<engine::api::TileParameters, T>::value>;
+} // ns detail
+
+// Starts parsing and iter and modifies it until iter == end or parsing failed
+template <typename ParameterT,
+ typename std::enable_if<detail::is_parameter_t<ParameterT>::value, int>::type = 0>
+boost::optional<ParameterT> parseParameters(std::string::iterator &iter, std::string::iterator end);
+
+// Copy on purpose because we need mutability
+template <typename ParameterT,
+ typename std::enable_if<detail::is_parameter_t<ParameterT>::value, int>::type = 0>
+boost::optional<ParameterT> parseParameters(std::string options_string)
+{
+ auto first = options_string.begin();
+ const auto last = options_string.end();
+ return parseParameters<ParameterT>(first, last);
+}
+
+} // ns api
+} // ns server
+} // ns osrm
+
+#endif
diff --git a/include/server/api/parsed_url.hpp b/include/server/api/parsed_url.hpp
new file mode 100644
index 0000000..224f4a6
--- /dev/null
+++ b/include/server/api/parsed_url.hpp
@@ -0,0 +1,27 @@
+#ifndef SERVER_API_PARSED_URL_HPP
+#define SERVER_API_PARSED_URL_HPP
+
+#include "util/coordinate.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+struct ParsedURL
+{
+ std::string service;
+ unsigned version;
+ std::string profile;
+ std::string query;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/route_parameters_grammar.hpp b/include/server/api/route_parameters_grammar.hpp
new file mode 100644
index 0000000..d85d435
--- /dev/null
+++ b/include/server/api/route_parameters_grammar.hpp
@@ -0,0 +1,96 @@
+#ifndef ROUTE_PARAMETERS_GRAMMAR_HPP
+#define ROUTE_PARAMETERS_GRAMMAR_HPP
+
+#include "engine/api/route_parameters.hpp"
+
+#include "server/api/base_parameters_grammar.hpp"
+
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_bool.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_optional.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace qi = boost::spirit::qi;
+
+struct RouteParametersGrammar : public BaseParametersGrammar
+{
+ using Iterator = std::string::iterator;
+ using StepsT = bool;
+ using AlternativeT = bool;
+ using GeometriesT = engine::api::RouteParameters::GeometriesType;
+ using OverviewT = engine::api::RouteParameters::OverviewType;
+ using UturnsT = bool;
+
+ RouteParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
+ {
+ const auto set_geojson_type = [this]()
+ {
+ parameters.geometries = engine::api::RouteParameters::GeometriesType::GeoJSON;
+ };
+ const auto set_polyline_type = [this]()
+ {
+ parameters.geometries = engine::api::RouteParameters::GeometriesType::Polyline;
+ };
+
+ const auto set_simplified_type = [this]()
+ {
+ parameters.overview = engine::api::RouteParameters::OverviewType::Simplified;
+ };
+ const auto set_full_type = [this]()
+ {
+ parameters.overview = engine::api::RouteParameters::OverviewType::Full;
+ };
+ const auto set_false_type = [this]()
+ {
+ parameters.overview = engine::api::RouteParameters::OverviewType::False;
+ };
+ const auto set_steps = [this](const StepsT steps)
+ {
+ parameters.steps = steps;
+ };
+ const auto set_alternatives = [this](const AlternativeT alternatives)
+ {
+ parameters.alternatives = alternatives;
+ };
+ const auto set_uturns = [this](UturnsT &uturns)
+ {
+ parameters.uturns = std::move(uturns);
+ };
+
+ alternatives_rule = qi::lit("alternatives=") >> qi::bool_;
+ steps_rule = qi::lit("steps=") >> qi::bool_;
+ geometries_rule = qi::lit("geometries=geojson")[set_geojson_type] |
+ qi::lit("geometries=polyline")[set_polyline_type];
+ overview_rule = qi::lit("overview=simplified")[set_simplified_type] |
+ qi::lit("overview=full")[set_full_type] |
+ qi::lit("overview=false")[set_false_type];
+ uturns_rule = qi::lit("uturns=default") | (qi::lit("uturns=") >> qi::bool_)[set_uturns];
+ route_rule = steps_rule[set_steps] | alternatives_rule[set_alternatives] | geometries_rule |
+ overview_rule | uturns_rule;
+
+ root_rule =
+ query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (route_rule | base_rule) % '&');
+ }
+
+ engine::api::RouteParameters parameters;
+
+ private:
+ qi::rule<Iterator> root_rule;
+ qi::rule<Iterator> route_rule, geometries_rule, overview_rule;
+ qi::rule<Iterator, UturnsT()> uturns_rule;
+ qi::rule<Iterator, StepsT()> steps_rule;
+ qi::rule<Iterator, AlternativeT()> alternatives_rule;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/table_parameter_grammar.hpp b/include/server/api/table_parameter_grammar.hpp
new file mode 100644
index 0000000..d5acb04
--- /dev/null
+++ b/include/server/api/table_parameter_grammar.hpp
@@ -0,0 +1,61 @@
+#ifndef TABLE_PARAMETERS_GRAMMAR_HPP
+#define TABLE_PARAMETERS_GRAMMAR_HPP
+
+#include "engine/api/table_parameters.hpp"
+
+#include "server/api/base_parameters_grammar.hpp"
+
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_uint.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_optional.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace qi = boost::spirit::qi;
+
+struct TableParametersGrammar final : public BaseParametersGrammar
+{
+ using Iterator = std::string::iterator;
+ using SourcesT = std::vector<std::size_t>;
+ using DestinationsT = std::vector<std::size_t>;
+
+ TableParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
+ {
+ const auto set_destiantions = [this](DestinationsT &dests)
+ {
+ parameters.destinations = std::move(dests);
+ };
+ const auto set_sources = [this](SourcesT &sources)
+ {
+ parameters.sources = std::move(sources);
+ };
+ destinations_rule = (qi::lit("destinations=") >> (qi::ulong_ % ";")[set_destiantions]) |
+ qi::lit("destinations=all");
+ sources_rule =
+ (qi::lit("sources=") >> (qi::ulong_ % ";")[set_sources]) | qi::lit("sources=all");
+ table_rule = destinations_rule | sources_rule;
+
+ root_rule =
+ query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (table_rule | base_rule) % '&');
+ }
+
+ engine::api::TableParameters parameters;
+
+ private:
+ qi::rule<Iterator> root_rule;
+ qi::rule<Iterator> table_rule;
+ qi::rule<Iterator> sources_rule;
+ qi::rule<Iterator> destinations_rule;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/tile_parameter_grammar.hpp b/include/server/api/tile_parameter_grammar.hpp
new file mode 100644
index 0000000..2212b81
--- /dev/null
+++ b/include/server/api/tile_parameter_grammar.hpp
@@ -0,0 +1,59 @@
+#ifndef SERVER_API_TILE_PARAMETERS_GRAMMAR_HPP
+#define SERVER_API_TILE_PARAMETERS_GRAMMAR_HPP
+
+#include "engine/api/tile_parameters.hpp"
+
+#include "engine/polyline_compressor.hpp"
+#include "engine/hint.hpp"
+
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_uint.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_operator.hpp>
+
+#include <string>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace qi = boost::spirit::qi;
+struct TileParametersGrammar final : boost::spirit::qi::grammar<std::string::iterator>
+{
+ using Iterator = std::string::iterator;
+
+ TileParametersGrammar() : TileParametersGrammar::base_type(root_rule)
+ {
+ const auto set_x = [this](const unsigned x_)
+ {
+ parameters.x = x_;
+ };
+ const auto set_y = [this](const unsigned y_)
+ {
+ parameters.y = y_;
+ };
+ const auto set_z = [this](const unsigned z_)
+ {
+ parameters.z = z_;
+ };
+
+ query_rule = qi::lit("tile(") >> qi::uint_[set_x] >> qi::lit(",") >> qi::uint_[set_y] >>
+ qi::lit(",") >> qi::uint_[set_z] >> qi::lit(")");
+
+ root_rule = query_rule >> qi::lit(".mvt");
+ }
+ engine::api::TileParameters parameters;
+
+ private:
+ qi::rule<Iterator> root_rule;
+ qi::rule<Iterator> query_rule;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/trip_parameter_grammar.hpp b/include/server/api/trip_parameter_grammar.hpp
new file mode 100644
index 0000000..3165d99
--- /dev/null
+++ b/include/server/api/trip_parameter_grammar.hpp
@@ -0,0 +1,81 @@
+#ifndef TRIP_PARAMETERS_GRAMMAR_HPP
+#define TRIP_PARAMETERS_GRAMMAR_HPP
+
+#include "engine/api/trip_parameters.hpp"
+
+#include "server/api/base_parameters_grammar.hpp"
+
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_uint.hpp>
+#include <boost/spirit/include/qi_bool.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_optional.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace qi = boost::spirit::qi;
+
+struct TripParametersGrammar final : public BaseParametersGrammar
+{
+ using Iterator = std::string::iterator;
+ using StepsT = bool;
+ using GeometriesT = engine::api::RouteParameters::GeometriesType;
+ using OverviewT = engine::api::RouteParameters::OverviewType;
+
+ TripParametersGrammar() : BaseParametersGrammar(root_rule, parameters)
+ {
+ const auto set_geojson_type = [this]()
+ {
+ parameters.geometries = engine::api::RouteParameters::GeometriesType::GeoJSON;
+ };
+ const auto set_polyline_type = [this]()
+ {
+ parameters.geometries = engine::api::RouteParameters::GeometriesType::Polyline;
+ };
+
+ const auto set_simplified_type = [this]()
+ {
+ parameters.overview = engine::api::RouteParameters::OverviewType::Simplified;
+ };
+ const auto set_full_type = [this]()
+ {
+ parameters.overview = engine::api::RouteParameters::OverviewType::Full;
+ };
+ const auto set_false_type = [this]()
+ {
+ parameters.overview = engine::api::RouteParameters::OverviewType::False;
+ };
+ const auto set_steps = [this](const StepsT steps)
+ {
+ parameters.steps = steps;
+ };
+
+ steps_rule = qi::lit("steps=") >> qi::bool_;
+ geometries_rule = qi::lit("geometries=geojson")[set_geojson_type] |
+ qi::lit("geometries=polyline")[set_polyline_type];
+ overview_rule = qi::lit("overview=simplified")[set_simplified_type] |
+ qi::lit("overview=full")[set_full_type] |
+ qi::lit("overview=false")[set_false_type];
+ trip_rule = steps_rule[set_steps] | geometries_rule | overview_rule;
+
+ root_rule =
+ query_rule >> -qi::lit(".json") >> -(qi::lit("?") >> (trip_rule | base_rule) % '&');
+ }
+
+ engine::api::TripParameters parameters;
+
+ private:
+ qi::rule<Iterator> root_rule, trip_rule, geometries_rule, overview_rule;
+ qi::rule<Iterator, StepsT()> steps_rule;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/api/url_parser.hpp b/include/server/api/url_parser.hpp
new file mode 100644
index 0000000..0bac20f
--- /dev/null
+++ b/include/server/api/url_parser.hpp
@@ -0,0 +1,29 @@
+#ifndef SERVER_URL_PARSER_HPP
+#define SERVER_URL_PARSER_HPP
+
+#include "server/api/parsed_url.hpp"
+
+#include <boost/optional.hpp>
+
+#include <string>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+// Starts parsing and iter and modifies it until iter == end or parsing failed
+boost::optional<ParsedURL> parseURL(std::string::iterator &iter, std::string::iterator end);
+// copy on purpose because we need mutability
+inline boost::optional<ParsedURL> parseURL(std::string url_string)
+{
+ auto iter = url_string.begin();
+ return parseURL(iter, url_string.end());
+}
+}
+}
+}
+
+#endif
diff --git a/include/server/connection.hpp b/include/server/connection.hpp
new file mode 100644
index 0000000..0882159
--- /dev/null
+++ b/include/server/connection.hpp
@@ -0,0 +1,72 @@
+#ifndef CONNECTION_HPP
+#define CONNECTION_HPP
+
+#include "server/http/compression_type.hpp"
+#include "server/http/reply.hpp"
+#include "server/http/request.hpp"
+#include "server/request_parser.hpp"
+
+#include <boost/array.hpp>
+#include <boost/asio.hpp>
+#include <boost/config.hpp>
+#include <boost/version.hpp>
+
+#include <memory>
+#include <vector>
+
+// workaround for incomplete std::shared_ptr compatibility in old boost versions
+#if BOOST_VERSION < 105300 || defined BOOST_NO_CXX11_SMART_PTR
+
+namespace boost
+{
+template <class T> const T *get_pointer(std::shared_ptr<T> const &p) { return p.get(); }
+
+template <class T> T *get_pointer(std::shared_ptr<T> &p) { return p.get(); }
+} // namespace boost
+
+#endif
+
+namespace osrm
+{
+namespace server
+{
+
+class RequestHandler;
+
+/// Represents a single connection from a client.
+class Connection : public std::enable_shared_from_this<Connection>
+{
+ public:
+ explicit Connection(boost::asio::io_service &io_service, RequestHandler &handler);
+ Connection(const Connection &) = delete;
+ Connection &operator=(const Connection &) = delete;
+
+ boost::asio::ip::tcp::socket &socket();
+
+ /// Start the first asynchronous operation for the connection.
+ void start();
+
+ private:
+ void handle_read(const boost::system::error_code &e, std::size_t bytes_transferred);
+
+ /// Handle completion of a write operation.
+ void handle_write(const boost::system::error_code &e);
+
+ std::vector<char> compress_buffers(const std::vector<char> &uncompressed_data,
+ const http::compression_type compression_type);
+
+ boost::asio::io_service::strand strand;
+ boost::asio::ip::tcp::socket TCP_socket;
+ RequestHandler &request_handler;
+ RequestParser request_parser;
+ boost::array<char, 8192> incoming_data_buffer;
+ http::request current_request;
+ http::reply current_reply;
+ std::vector<char> compressed_output;
+ // Header compression_header;
+ std::vector<boost::asio::const_buffer> output_buffer;
+};
+}
+}
+
+#endif // CONNECTION_HPP
diff --git a/include/server/http/compression_type.hpp b/include/server/http/compression_type.hpp
new file mode 100644
index 0000000..7ff929c
--- /dev/null
+++ b/include/server/http/compression_type.hpp
@@ -0,0 +1,21 @@
+#ifndef COMPRESSION_TYPE_HPP
+#define COMPRESSION_TYPE_HPP
+
+namespace osrm
+{
+namespace server
+{
+namespace http
+{
+
+enum compression_type
+{
+ no_compression,
+ gzip_rfc1952,
+ deflate_rfc1951
+};
+}
+}
+}
+
+#endif // COMPRESSION_TYPE_HPP
diff --git a/include/server/http/header.hpp b/include/server/http/header.hpp
new file mode 100644
index 0000000..33cc4bb
--- /dev/null
+++ b/include/server/http/header.hpp
@@ -0,0 +1,34 @@
+#ifndef HEADER_HPP
+#define HEADER_HPP
+
+#include <string>
+#include <algorithm>
+
+namespace osrm
+{
+namespace server
+{
+namespace http
+{
+
+struct header
+{
+ // explicitly use default copy c'tor as adding move c'tor
+ header &operator=(const header &other) = default;
+ header(std::string name, std::string value) : name(std::move(name)), value(std::move(value)) {}
+ header(header &&other) : name(std::move(other.name)), value(std::move(other.value)) {}
+
+ void clear()
+ {
+ name.clear();
+ value.clear();
+ }
+
+ std::string name;
+ std::string value;
+};
+}
+}
+}
+
+#endif // HEADER_HPP
diff --git a/include/server/http/reply.hpp b/include/server/http/reply.hpp
new file mode 100644
index 0000000..8474a5c
--- /dev/null
+++ b/include/server/http/reply.hpp
@@ -0,0 +1,45 @@
+#ifndef REPLY_HPP
+#define REPLY_HPP
+
+#include "server/http/header.hpp"
+
+#include <boost/asio.hpp>
+
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace http
+{
+
+class reply
+{
+ public:
+ enum status_type
+ {
+ ok = 200,
+ bad_request = 400,
+ internal_server_error = 500
+ } status;
+
+ std::vector<header> headers;
+ std::vector<boost::asio::const_buffer> to_buffers();
+ std::vector<boost::asio::const_buffer> headers_to_buffers();
+ std::vector<char> content;
+ static reply stock_reply(const status_type status);
+ void set_size(const std::size_t size);
+ void set_uncompressed_size();
+
+ reply();
+
+ private:
+ std::string status_to_string(reply::status_type status);
+ boost::asio::const_buffer status_to_buffer(reply::status_type status);
+};
+}
+}
+}
+
+#endif // REPLY_HPP
diff --git a/include/server/http/request.hpp b/include/server/http/request.hpp
new file mode 100644
index 0000000..1b86253
--- /dev/null
+++ b/include/server/http/request.hpp
@@ -0,0 +1,26 @@
+#ifndef REQUEST_HPP
+#define REQUEST_HPP
+
+#include <boost/asio.hpp>
+
+#include <string>
+
+namespace osrm
+{
+namespace server
+{
+namespace http
+{
+
+struct request
+{
+ std::string uri;
+ std::string referrer;
+ std::string agent;
+ boost::asio::ip::address endpoint;
+};
+}
+}
+}
+
+#endif // REQUEST_HPP
diff --git a/include/server/request_handler.hpp b/include/server/request_handler.hpp
new file mode 100644
index 0000000..d76ba6d
--- /dev/null
+++ b/include/server/request_handler.hpp
@@ -0,0 +1,37 @@
+#ifndef REQUEST_HANDLER_HPP
+#define REQUEST_HANDLER_HPP
+
+#include "server/service_handler.hpp"
+
+#include <string>
+
+namespace osrm
+{
+namespace server
+{
+
+namespace http
+{
+class reply;
+struct request;
+}
+
+class RequestHandler
+{
+
+ public:
+ RequestHandler() = default;
+ RequestHandler(const RequestHandler &) = delete;
+ RequestHandler &operator=(const RequestHandler &) = delete;
+
+ void RegisterServiceHandler(std::unique_ptr<ServiceHandler> service_handler);
+
+ void HandleRequest(const http::request ¤t_request, http::reply ¤t_reply);
+
+ private:
+ std::unique_ptr<ServiceHandler> service_handler;
+};
+}
+}
+
+#endif // REQUEST_HANDLER_HPP
diff --git a/include/server/request_parser.hpp b/include/server/request_parser.hpp
new file mode 100644
index 0000000..3ac4c17
--- /dev/null
+++ b/include/server/request_parser.hpp
@@ -0,0 +1,76 @@
+#ifndef REQUEST_PARSER_HPP
+#define REQUEST_PARSER_HPP
+
+#include "server/http/compression_type.hpp"
+#include "server/http/header.hpp"
+
+#include <tuple>
+
+namespace osrm
+{
+namespace server
+{
+
+namespace http
+{
+struct request;
+}
+
+class RequestParser
+{
+ public:
+ RequestParser();
+
+ enum class RequestStatus : char
+ {
+ valid,
+ invalid,
+ indeterminate
+ };
+
+ std::tuple<RequestStatus, http::compression_type>
+ parse(http::request ¤t_request, char *begin, char *end);
+
+ private:
+ RequestStatus consume(http::request ¤t_request, const char input);
+
+ bool is_char(const int character) const;
+
+ bool is_CTL(const int character) const;
+
+ bool is_special(const int character) const;
+
+ bool is_digit(const int character) const;
+
+ enum class internal_state : unsigned char
+ {
+ method_start,
+ method,
+ uri_start,
+ uri,
+ http_version_h,
+ http_version_t_1,
+ http_version_t_2,
+ http_version_p,
+ http_version_slash,
+ http_version_major_start,
+ http_version_major,
+ http_version_minor_start,
+ http_version_minor,
+ expecting_newline_1,
+ header_line_start,
+ header_lws,
+ header_name,
+ space_before_header_value,
+ header_value,
+ expecting_newline_2,
+ expecting_newline_3
+ } state;
+
+ http::header current_header;
+ http::compression_type selected_compression;
+};
+}
+}
+
+#endif // REQUEST_PARSER_HPP
diff --git a/server/server.hpp b/include/server/server.hpp
similarity index 57%
rename from server/server.hpp
rename to include/server/server.hpp
index 80fae97..8813074 100644
--- a/server/server.hpp
+++ b/include/server/server.hpp
@@ -1,38 +1,12 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef SERVER_HPP
#define SERVER_HPP
-#include "connection.hpp"
-#include "request_handler.hpp"
+#include "server/connection.hpp"
+#include "server/request_handler.hpp"
+#include "server/service_handler.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/simple_logger.hpp"
+#include "util/integer_range.hpp"
+#include "util/simple_logger.hpp"
#include <boost/asio.hpp>
#include <boost/bind.hpp>
@@ -45,6 +19,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <vector>
#include <string>
+namespace osrm
+{
+namespace server
+{
+
class Server
{
public:
@@ -52,7 +31,8 @@ class Server
static std::shared_ptr<Server>
CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads)
{
- SimpleLogger().Write() << "http 1.1 compression handled by zlib version " << zlibVersion();
+ util::SimpleLogger().Write() << "http 1.1 compression handled by zlib version "
+ << zlibVersion();
const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
return std::make_shared<Server>(ip_address, ip_port, real_num_threads);
@@ -60,7 +40,7 @@ class Server
explicit Server(const std::string &address, const int port, const unsigned thread_pool_size)
: thread_pool_size(thread_pool_size), acceptor(io_service),
- new_connection(std::make_shared<http::Connection>(io_service, request_handler))
+ new_connection(std::make_shared<Connection>(io_service, request_handler))
{
const auto port_string = std::to_string(port);
@@ -72,6 +52,9 @@ class Server
acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
acceptor.bind(endpoint);
acceptor.listen();
+
+ util::SimpleLogger().Write() << "Listening on: " << acceptor.local_endpoint();
+
acceptor.async_accept(
new_connection->socket(),
boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
@@ -94,7 +77,10 @@ class Server
void Stop() { io_service.stop(); }
- RequestHandler &GetRequestHandlerPtr() { return request_handler; }
+ void RegisterServiceHandler(std::unique_ptr<ServiceHandler> service_handler_)
+ {
+ request_handler.RegisterServiceHandler(std::move(service_handler_));
+ }
private:
void HandleAccept(const boost::system::error_code &e)
@@ -102,7 +88,7 @@ class Server
if (!e)
{
new_connection->start();
- new_connection = std::make_shared<http::Connection>(io_service, request_handler);
+ new_connection = std::make_shared<Connection>(io_service, request_handler);
acceptor.async_accept(
new_connection->socket(),
boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
@@ -112,8 +98,10 @@ class Server
unsigned thread_pool_size;
boost::asio::io_service io_service;
boost::asio::ip::tcp::acceptor acceptor;
- std::shared_ptr<http::Connection> new_connection;
+ std::shared_ptr<Connection> new_connection;
RequestHandler request_handler;
};
+}
+}
#endif // SERVER_HPP
diff --git a/include/server/service/base_service.hpp b/include/server/service/base_service.hpp
new file mode 100644
index 0000000..36c82db
--- /dev/null
+++ b/include/server/service/base_service.hpp
@@ -0,0 +1,39 @@
+#ifndef SERVER_SERVICE_BASE_SERVICE_HPP
+#define SERVER_SERVICE_BASE_SERVICE_HPP
+
+#include "engine/status.hpp"
+#include "util/coordinate.hpp"
+#include "osrm/osrm.hpp"
+
+#include <variant/variant.hpp>
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+class BaseService
+{
+ public:
+ using ResultT = mapbox::util::variant<util::json::Object, std::string>;
+
+ BaseService(OSRM &routing_machine) : routing_machine(routing_machine) {}
+ virtual ~BaseService() = default;
+
+ virtual engine::Status RunQuery(std::string &query, ResultT &result) = 0;
+
+ virtual unsigned GetVersion() = 0;
+
+ protected:
+ OSRM &routing_machine;
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/service/match_service.hpp b/include/server/service/match_service.hpp
new file mode 100644
index 0000000..23212c1
--- /dev/null
+++ b/include/server/service/match_service.hpp
@@ -0,0 +1,33 @@
+#ifndef SERVER_SERVICE_MATCH_SERVICE_HPP
+#define SERVER_SERVICE_MATCH_SERVICE_HPP
+
+#include "server/service/base_service.hpp"
+
+#include "engine/status.hpp"
+#include "util/coordinate.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+class MatchService final : public BaseService
+{
+ public:
+ MatchService(OSRM &routing_machine) : BaseService(routing_machine) {}
+
+ engine::Status RunQuery(std::string &query, ResultT &result) final override;
+
+ unsigned GetVersion() final override { return 1; }
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/service/nearest_service.hpp b/include/server/service/nearest_service.hpp
new file mode 100644
index 0000000..222003c
--- /dev/null
+++ b/include/server/service/nearest_service.hpp
@@ -0,0 +1,33 @@
+#ifndef SERVER_SERVICE_NEAREST_SERVICE_HPP
+#define SERVER_SERVICE_NEAREST_SERVICE_HPP
+
+#include "server/service/base_service.hpp"
+
+#include "engine/status.hpp"
+#include "util/coordinate.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+class NearestService final : public BaseService
+{
+ public:
+ NearestService(OSRM &routing_machine) : BaseService(routing_machine) {}
+
+ engine::Status RunQuery(std::string &query, ResultT &result) final override;
+
+ unsigned GetVersion() final override { return 1; }
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/service/route_service.hpp b/include/server/service/route_service.hpp
new file mode 100644
index 0000000..1115585
--- /dev/null
+++ b/include/server/service/route_service.hpp
@@ -0,0 +1,33 @@
+#ifndef SERVER_SERVICE_ROUTE_SERVICE_HPP
+#define SERVER_SERVICE_ROUTE_SERVICE_HPP
+
+#include "server/service/base_service.hpp"
+
+#include "engine/status.hpp"
+#include "util/coordinate.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+class RouteService final : public BaseService
+{
+ public:
+ RouteService(OSRM &routing_machine) : BaseService(routing_machine) {}
+
+ engine::Status RunQuery(std::string &query, ResultT &result) final override;
+
+ unsigned GetVersion() final override { return 1; }
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/service/table_service.hpp b/include/server/service/table_service.hpp
new file mode 100644
index 0000000..61b9d84
--- /dev/null
+++ b/include/server/service/table_service.hpp
@@ -0,0 +1,33 @@
+#ifndef SERVER_SERVICE_TABLE_SERVICE_HPP
+#define SERVER_SERVICE_TABLE_SERVICE_HPP
+
+#include "server/service/base_service.hpp"
+
+#include "engine/status.hpp"
+#include "util/coordinate.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+class TableService final : public BaseService
+{
+ public:
+ TableService(OSRM &routing_machine) : BaseService(routing_machine) {}
+
+ engine::Status RunQuery(std::string &query, ResultT &result) final override;
+
+ unsigned GetVersion() final override { return 1; }
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/service/tile_service.hpp b/include/server/service/tile_service.hpp
new file mode 100644
index 0000000..05365d4
--- /dev/null
+++ b/include/server/service/tile_service.hpp
@@ -0,0 +1,33 @@
+#ifndef SERVER_SERVICE_TILE_SERVICE_HPP
+#define SERVER_SERVICE_TILE_SERVICE_HPP
+
+#include "server/service/base_service.hpp"
+
+#include "engine/status.hpp"
+#include "util/coordinate.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+class TileService final : public BaseService
+{
+ public:
+ TileService(OSRM &routing_machine) : BaseService(routing_machine) {}
+
+ engine::Status RunQuery(std::string &query, ResultT &result) final override;
+
+ unsigned GetVersion() final override { return 1; }
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/service/trip_service.hpp b/include/server/service/trip_service.hpp
new file mode 100644
index 0000000..7daeba6
--- /dev/null
+++ b/include/server/service/trip_service.hpp
@@ -0,0 +1,33 @@
+#ifndef SERVER_SERVICE_TRIP_SERVICE_HPP
+#define SERVER_SERVICE_TRIP_SERVICE_HPP
+
+#include "server/service/base_service.hpp"
+
+#include "engine/status.hpp"
+#include "util/coordinate.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+class TripService final : public BaseService
+{
+ public:
+ TripService(OSRM &routing_machine) : BaseService(routing_machine) {}
+
+ engine::Status RunQuery(std::string &query, ResultT &result) final override;
+
+ unsigned GetVersion() final override { return 1; }
+};
+}
+}
+}
+
+#endif
diff --git a/include/server/service/utils.hpp b/include/server/service/utils.hpp
new file mode 100644
index 0000000..e4fd7df
--- /dev/null
+++ b/include/server/service/utils.hpp
@@ -0,0 +1,29 @@
+#include <boost/format.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+const constexpr char PARAMETER_SIZE_MISMATCH_MSG[] =
+ "Number of elements in %1% size %2% does not match coordinate size %3%";
+
+template <typename ParamT>
+bool constrainParamSize(const char *msg_template,
+ const char *name,
+ const ParamT ¶m,
+ const std::size_t target_size,
+ std::string &help)
+{
+ if (param.size() > 0 && param.size() != target_size)
+ {
+ help = (boost::format(msg_template) % name % param.size() % target_size).str();
+ return true;
+ }
+ return false;
+}
+}
+}
+}
diff --git a/include/server/service_handler.hpp b/include/server/service_handler.hpp
new file mode 100644
index 0000000..cb9b037
--- /dev/null
+++ b/include/server/service_handler.hpp
@@ -0,0 +1,41 @@
+#ifndef SERVER_SERVICE_HANLDER_HPP
+#define SERVER_SERVICE_HANLDER_HPP
+
+#include "server/service/base_service.hpp"
+
+#include "osrm/osrm.hpp"
+
+#include <unordered_map>
+
+namespace osrm
+{
+namespace util
+{
+namespace json
+{
+struct Object;
+}
+}
+namespace server
+{
+namespace api
+{
+struct ParsedURL;
+}
+
+class ServiceHandler
+{
+ public:
+ ServiceHandler(osrm::EngineConfig &config);
+ using ResultT = service::BaseService::ResultT;
+
+ engine::Status RunQuery(api::ParsedURL parsed_url, ResultT &result);
+
+ private:
+ std::unordered_map<std::string, std::unique_ptr<service::BaseService>> service_map;
+ OSRM routing_machine;
+};
+}
+}
+
+#endif
diff --git a/include/storage/shared_barriers.hpp b/include/storage/shared_barriers.hpp
new file mode 100644
index 0000000..48d305c
--- /dev/null
+++ b/include/storage/shared_barriers.hpp
@@ -0,0 +1,39 @@
+#ifndef SHARED_BARRIERS_HPP
+#define SHARED_BARRIERS_HPP
+
+#include <boost/interprocess/sync/named_mutex.hpp>
+#include <boost/interprocess/sync/named_condition.hpp>
+
+namespace osrm
+{
+namespace storage
+{
+struct SharedBarriers
+{
+
+ SharedBarriers()
+ : pending_update_mutex(boost::interprocess::open_or_create, "pending_update"),
+ update_mutex(boost::interprocess::open_or_create, "update"),
+ query_mutex(boost::interprocess::open_or_create, "query"),
+ no_running_queries_condition(boost::interprocess::open_or_create, "no_running_queries"),
+ update_ongoing(false), number_of_queries(0)
+ {
+ }
+
+ // Mutex to protect access to the boolean variable
+ boost::interprocess::named_mutex pending_update_mutex;
+ boost::interprocess::named_mutex update_mutex;
+ boost::interprocess::named_mutex query_mutex;
+
+ // Condition that no update is running
+ boost::interprocess::named_condition no_running_queries_condition;
+
+ // Is there an ongoing update?
+ bool update_ongoing;
+ // Is there any query?
+ int number_of_queries;
+};
+}
+}
+
+#endif // SHARED_BARRIERS_HPP
diff --git a/include/storage/shared_datatype.hpp b/include/storage/shared_datatype.hpp
new file mode 100644
index 0000000..ec1033a
--- /dev/null
+++ b/include/storage/shared_datatype.hpp
@@ -0,0 +1,136 @@
+#ifndef SHARED_DATA_TYPE_HPP
+#define SHARED_DATA_TYPE_HPP
+
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+
+#include <cstdint>
+
+#include <array>
+
+namespace osrm
+{
+namespace storage
+{
+
+// Added at the start and end of each block as sanity check
+const constexpr char CANARY[] = "OSRM";
+
+struct SharedDataLayout
+{
+ enum BlockID
+ {
+ NAME_OFFSETS = 0,
+ NAME_BLOCKS,
+ NAME_CHAR_LIST,
+ NAME_ID_LIST,
+ VIA_NODE_LIST,
+ GRAPH_NODE_LIST,
+ GRAPH_EDGE_LIST,
+ COORDINATE_LIST,
+ TURN_INSTRUCTION,
+ TRAVEL_MODE,
+ R_SEARCH_TREE,
+ GEOMETRIES_INDEX,
+ GEOMETRIES_LIST,
+ HSGR_CHECKSUM,
+ TIMESTAMP,
+ FILE_INDEX_PATH,
+ CORE_MARKER,
+ DATASOURCES_LIST,
+ DATASOURCE_NAME_DATA,
+ DATASOURCE_NAME_OFFSETS,
+ DATASOURCE_NAME_LENGTHS,
+ PROPERTIES,
+ NUM_BLOCKS
+ };
+
+ std::array<uint64_t, NUM_BLOCKS> num_entries;
+ std::array<uint64_t, NUM_BLOCKS> entry_size;
+
+ SharedDataLayout() : num_entries(), entry_size() {}
+
+ template <typename T> inline void SetBlockSize(BlockID bid, uint64_t entries)
+ {
+ num_entries[bid] = entries;
+ entry_size[bid] = sizeof(T);
+ }
+
+ inline uint64_t GetBlockSize(BlockID bid) const
+ {
+ // special bit encoding
+ if (bid == CORE_MARKER)
+ {
+ return (num_entries[bid] / 32 + 1) * entry_size[bid];
+ }
+
+ return num_entries[bid] * entry_size[bid];
+ }
+
+ inline uint64_t GetSizeOfLayout() const
+ {
+ return GetBlockOffset(NUM_BLOCKS) + NUM_BLOCKS * 2 * sizeof(CANARY);
+ }
+
+ inline uint64_t GetBlockOffset(BlockID bid) const
+ {
+ uint64_t result = sizeof(CANARY);
+ for (auto i = 0; i < bid; i++)
+ {
+ result += GetBlockSize((BlockID)i) + 2 * sizeof(CANARY);
+ }
+ return result;
+ }
+
+ template <typename T, bool WRITE_CANARY = false>
+ inline T *GetBlockPtr(char *shared_memory, BlockID bid)
+ {
+ T *ptr = (T *)(shared_memory + GetBlockOffset(bid));
+ if (WRITE_CANARY)
+ {
+ char *start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
+ char *end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
+ std::copy(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
+ std::copy(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
+ }
+ else
+ {
+ char *start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
+ char *end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
+ bool start_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
+ bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
+ if (!start_canary_alive)
+ {
+ throw util::exception("Start canary of block corrupted.");
+ }
+ if (!end_canary_alive)
+ {
+ throw util::exception("End canary of block corrupted.");
+ }
+ }
+
+ return ptr;
+ }
+};
+
+enum SharedDataType
+{
+ CURRENT_REGIONS,
+ LAYOUT_1,
+ DATA_1,
+ LAYOUT_2,
+ DATA_2,
+ LAYOUT_NONE,
+ DATA_NONE
+};
+
+struct SharedDataTimestamp
+{
+ SharedDataType layout;
+ SharedDataType data;
+ unsigned timestamp;
+};
+}
+}
+
+#endif /* SHARED_DATA_TYPE_HPP */
diff --git a/data_structures/shared_memory_factory.hpp b/include/storage/shared_memory.hpp
similarity index 68%
rename from data_structures/shared_memory_factory.hpp
rename to include/storage/shared_memory.hpp
index 833b4aa..47238cf 100644
--- a/data_structures/shared_memory_factory.hpp
+++ b/include/storage/shared_memory.hpp
@@ -1,35 +1,8 @@
-/*
+#ifndef SHARED_MEMORY_HPP
+#define SHARED_MEMORY_HPP
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef SHARED_MEMORY_FACTORY_HPP
-#define SHARED_MEMORY_FACTORY_HPP
-
-#include "../util/osrm_exception.hpp"
-#include "../util/simple_logger.hpp"
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@@ -51,6 +24,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <algorithm>
#include <exception>
+namespace osrm
+{
+namespace storage
+{
+
struct OSRMLockFile
{
boost::filesystem::path operator()()
@@ -80,15 +58,18 @@ class SharedMemory
}
shm_remove() : m_shmid(INT_MIN), m_initialized(false) {}
+
shm_remove(const shm_remove &) = delete;
+ shm_remove &operator=(const shm_remove &) = delete;
+
~shm_remove()
{
if (m_initialized)
{
- SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
+ util::SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
if (!boost::interprocess::xsi_shared_memory::remove(m_shmid))
{
- SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
+ util::SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
}
}
}
@@ -97,7 +78,6 @@ class SharedMemory
public:
void *Ptr() const { return region.get_address(); }
- SharedMemory() = delete;
SharedMemory(const SharedMemory &) = delete;
SharedMemory &operator=(const SharedMemory &) = delete;
@@ -131,14 +111,15 @@ class SharedMemory
{
if (ENOMEM == errno)
{
- SimpleLogger().Write(logWARNING) << "could not lock shared memory to RAM";
+ util::SimpleLogger().Write(logWARNING) << "could not lock shared memory to RAM";
}
}
#endif
region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
remover.SetID(shm.get_shmid());
- SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size << " bytes";
+ util::SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size
+ << " bytes";
}
}
@@ -185,7 +166,7 @@ class SharedMemory
bool ret = false;
try
{
- SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
+ util::SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
boost::interprocess::xsi_shared_memory xsi(boost::interprocess::open_only, key);
ret = boost::interprocess::xsi_shared_memory::remove(xsi.get_shmid());
}
@@ -214,8 +195,6 @@ class SharedMemory
class shm_remove
{
private:
- shm_remove(const shm_remove &) = delete;
- shm_remove &operator=(const shm_remove &) = delete;
char *m_shmid;
bool m_initialized;
@@ -228,14 +207,17 @@ class SharedMemory
shm_remove() : m_shmid("undefined"), m_initialized(false) {}
+ shm_remove(const shm_remove &) = delete;
+ shm_remove &operator=(const shm_remove &) = delete;
+
~shm_remove()
{
if (m_initialized)
{
- SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
+ util::SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
if (!boost::interprocess::shared_memory_object::remove(m_shmid))
{
- SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
+ util::SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
}
}
}
@@ -272,7 +254,8 @@ class SharedMemory
region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
remover.SetID(key);
- SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size << " bytes";
+ util::SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size
+ << " bytes";
}
}
@@ -322,7 +305,7 @@ class SharedMemory
bool ret = false;
try
{
- SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
+ util::SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
ret = boost::interprocess::shared_memory_object::remove(key);
}
catch (const boost::interprocess::interprocess_exception &e)
@@ -342,45 +325,36 @@ class SharedMemory
};
#endif
-template <class LockFileT = OSRMLockFile> class SharedMemoryFactory_tmpl
+template <typename IdentifierT, typename LockFileT = OSRMLockFile>
+SharedMemory *makeSharedMemory(const IdentifierT &id,
+ const uint64_t size = 0,
+ bool read_write = false,
+ bool remove_prev = true)
{
- public:
- template <typename IdentifierT>
- static SharedMemory *Get(const IdentifierT &id,
- const uint64_t size = 0,
- bool read_write = false,
- bool remove_prev = true)
+ try
{
- try
+ LockFileT lock_file;
+ if (!boost::filesystem::exists(lock_file()))
{
- LockFileT lock_file;
- if (!boost::filesystem::exists(lock_file()))
+ if (0 == size)
{
- if (0 == size)
- {
- throw osrm::exception("lock file does not exist, exiting");
- }
- else
- {
- boost::filesystem::ofstream ofs(lock_file());
- ofs.close();
- }
+ throw util::exception("lock file does not exist, exiting");
+ }
+ else
+ {
+ boost::filesystem::ofstream ofs(lock_file());
}
- return new SharedMemory(lock_file(), id, size, read_write, remove_prev);
- }
- catch (const boost::interprocess::interprocess_exception &e)
- {
- SimpleLogger().Write(logWARNING) << "caught exception: " << e.what() << ", code "
- << e.get_error_code();
- throw osrm::exception(e.what());
}
+ return new SharedMemory(lock_file(), id, size, read_write, remove_prev);
}
+ catch (const boost::interprocess::interprocess_exception &e)
+ {
+ util::SimpleLogger().Write(logWARNING) << "caught exception: " << e.what() << ", code "
+ << e.get_error_code();
+ throw util::exception(e.what());
+ }
+}
+}
+}
- SharedMemoryFactory_tmpl() = delete;
- SharedMemoryFactory_tmpl(const SharedMemoryFactory_tmpl &) = delete;
- SharedMemoryFactory_tmpl &operator=(const SharedMemoryFactory_tmpl &) = delete;
-};
-
-using SharedMemoryFactory = SharedMemoryFactory_tmpl<>;
-
-#endif // SHARED_MEMORY_FACTORY_HPP
+#endif // SHARED_MEMORY_HPP
diff --git a/include/storage/storage.hpp b/include/storage/storage.hpp
new file mode 100644
index 0000000..31278aa
--- /dev/null
+++ b/include/storage/storage.hpp
@@ -0,0 +1,26 @@
+#ifndef STORAGE_HPP
+#define STORAGE_HPP
+
+#include "storage/storage_config.hpp"
+
+#include <boost/filesystem/path.hpp>
+
+#include <string>
+
+namespace osrm
+{
+namespace storage
+{
+class Storage
+{
+ public:
+ Storage(StorageConfig config);
+ int Run();
+
+ private:
+ StorageConfig config;
+};
+}
+}
+
+#endif
diff --git a/include/storage/storage_config.hpp b/include/storage/storage_config.hpp
new file mode 100644
index 0000000..e5e0e88
--- /dev/null
+++ b/include/storage/storage_config.hpp
@@ -0,0 +1,44 @@
+#ifndef STORAGE_CONFIG_HPP
+#define STORAGE_CONFIG_HPP
+
+#include <boost/filesystem/path.hpp>
+
+namespace osrm
+{
+namespace storage
+{
+
+/**
+ * Configures OSRM's file storage paths.
+ *
+ * \see OSRM, EngineConfig
+ */
+struct StorageConfig final
+{
+ StorageConfig() = default;
+
+ /**
+ * Constructs a storage configuration setting paths based on a base path.
+ *
+ * \param base The base path (e.g. france.pbf.osrm) to derive auxiliary file suffixes from.
+ */
+ StorageConfig(const boost::filesystem::path &base);
+ bool IsValid() const;
+
+ boost::filesystem::path ram_index_path;
+ boost::filesystem::path file_index_path;
+ boost::filesystem::path hsgr_data_path;
+ boost::filesystem::path nodes_data_path;
+ boost::filesystem::path edges_data_path;
+ boost::filesystem::path core_data_path;
+ boost::filesystem::path geometries_path;
+ boost::filesystem::path timestamp_path;
+ boost::filesystem::path datasource_names_path;
+ boost::filesystem::path datasource_indexes_path;
+ boost::filesystem::path names_data_path;
+ boost::filesystem::path properties_path;
+};
+}
+}
+
+#endif
diff --git a/include/util/assert.hpp b/include/util/assert.hpp
new file mode 100644
index 0000000..d9bfb95
--- /dev/null
+++ b/include/util/assert.hpp
@@ -0,0 +1,20 @@
+#ifndef OSRM_ASSERT_HPP
+#define OSRM_ASSERT_HPP
+
+#include <boost/assert.hpp>
+
+#include <stdexcept>
+
+namespace osrm
+{
+namespace util
+{
+// Assertion type to be thrown for stack unwinding
+struct assertionError final : std::logic_error
+{
+ assertionError(const char *msg) : std::logic_error{msg} {}
+};
+}
+}
+
+#endif
diff --git a/util/bearing.hpp b/include/util/bearing.hpp
similarity index 62%
rename from util/bearing.hpp
rename to include/util/bearing.hpp
index 5f3036a..f1ba624 100644
--- a/util/bearing.hpp
+++ b/include/util/bearing.hpp
@@ -1,36 +1,14 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef BEARING_HPP
#define BEARING_HPP
#include <boost/assert.hpp>
#include <string>
+namespace osrm
+{
+namespace util
+{
+
namespace bearing
{
inline std::string get(const double heading)
@@ -112,5 +90,7 @@ inline bool CheckInBounds(const int A, const int B, const int range)
}
}
}
+}
+}
#endif // BEARING_HPP
diff --git a/data_structures/binary_heap.hpp b/include/util/binary_heap.hpp
similarity index 83%
rename from data_structures/binary_heap.hpp
rename to include/util/binary_heap.hpp
index 85703f4..f3c01f6 100644
--- a/data_structures/binary_heap.hpp
+++ b/include/util/binary_heap.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef BINARY_HEAP_H
#define BINARY_HEAP_H
@@ -37,6 +10,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unordered_map>
#include <vector>
+namespace osrm
+{
+namespace util
+{
+
template <typename NodeID, typename Key> class ArrayStorage
{
public:
@@ -189,9 +167,10 @@ class BinaryHeap
return inserted_nodes[heap[1].index].node;
}
- Weight MinKey() const {
- BOOST_ASSERT(heap.size() > 1);
- return heap[1].weight;
+ Weight MinKey() const
+ {
+ BOOST_ASSERT(heap.size() > 1);
+ return heap[1].weight;
}
NodeID DeleteMin()
@@ -311,5 +290,7 @@ class BinaryHeap
#endif
}
};
+}
+}
#endif // BINARY_HEAP_H
diff --git a/include/util/cast.hpp b/include/util/cast.hpp
new file mode 100644
index 0000000..e78f630
--- /dev/null
+++ b/include/util/cast.hpp
@@ -0,0 +1,49 @@
+#ifndef CAST_HPP
+#define CAST_HPP
+
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <type_traits>
+
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/trim.hpp>
+
+namespace osrm
+{
+namespace util
+{
+
+namespace cast
+{
+template <typename Enumeration>
+inline auto enum_to_underlying(Enumeration const value) ->
+ typename std::underlying_type<Enumeration>::type
+{
+ return static_cast<typename std::underlying_type<Enumeration>::type>(value);
+}
+
+template <typename T, int Precision = 6> inline std::string to_string_with_precision(const T x)
+{
+ static_assert(std::is_arithmetic<T>::value, "integral or floating point type required");
+
+ std::ostringstream out;
+ out << std::fixed << std::setprecision(Precision) << x;
+ auto rv = out.str();
+
+ // Javascript has no separation of float / int, digits without a '.' are integral typed
+ // X.Y.0 -> X.Y
+ // X.0 -> X
+ boost::trim_right_if(rv, boost::is_any_of("0"));
+ boost::trim_right_if(rv, boost::is_any_of("."));
+ // Note:
+ // - assumes the locale to use '.' as digit separator
+ // - this is not identical to: trim_right_if(rv, is_any_of('0 .'))
+
+ return rv;
+}
+}
+}
+}
+
+#endif // CAST_HPP
diff --git a/include/util/container.hpp b/include/util/container.hpp
new file mode 100644
index 0000000..bd85e9c
--- /dev/null
+++ b/include/util/container.hpp
@@ -0,0 +1,20 @@
+#ifndef CONTAINER_HPP
+#define CONTAINER_HPP
+
+namespace osrm
+{
+namespace util
+{
+
+template <class Container> void append_to_container(Container &&) {}
+
+template <class Container, typename T, typename... Args>
+void append_to_container(Container &&container, T value, Args &&... args)
+{
+ container.emplace_back(value);
+ append_to_container(std::forward<Container>(container), std::forward<Args>(args)...);
+}
+}
+}
+
+#endif
diff --git a/include/util/coordinate.hpp b/include/util/coordinate.hpp
new file mode 100644
index 0000000..e249bb2
--- /dev/null
+++ b/include/util/coordinate.hpp
@@ -0,0 +1,187 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef COORDINATE_HPP_
+#define COORDINATE_HPP_
+
+#include "util/strong_typedef.hpp"
+
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <iosfwd> //for std::ostream
+#include <string>
+#include <type_traits>
+#include <cstddef>
+
+namespace osrm
+{
+
+constexpr const double COORDINATE_PRECISION = 1e6;
+
+namespace util
+{
+
+OSRM_STRONG_TYPEDEF(int32_t, FixedLatitude)
+OSRM_STRONG_TYPEDEF(int32_t, FixedLongitude)
+OSRM_STRONG_TYPEDEF(double, FloatLatitude)
+OSRM_STRONG_TYPEDEF(double, FloatLongitude)
+
+/**
+ * Converts a typed latitude from floating to fixed representation.
+ *
+ * \param floating typed latitude in floating representation.
+ * \return typed latitude in fixed representation
+ * \see Coordinate, toFloating
+ */
+inline FixedLatitude toFixed(const FloatLatitude floating)
+{
+ const auto latitude = static_cast<double>(floating);
+ const auto fixed = boost::numeric_cast<std::int32_t>(latitude * COORDINATE_PRECISION);
+ return FixedLatitude(fixed);
+}
+
+/**
+ * Converts a typed longitude from floating to fixed representation.
+ *
+ * \param floating typed longitude in floating representation.
+ * \return typed latitude in fixed representation
+ * \see Coordinate, toFloating
+ */
+inline FixedLongitude toFixed(const FloatLongitude floating)
+{
+ const auto longitude = static_cast<double>(floating);
+ const auto fixed = boost::numeric_cast<std::int32_t>(longitude * COORDINATE_PRECISION);
+ return FixedLongitude(fixed);
+}
+
+/**
+ * Converts a typed latitude from fixed to floating representation.
+ *
+ * \param fixed typed latitude in fixed representation.
+ * \return typed latitude in floating representation
+ * \see Coordinate, toFixed
+ */
+inline FloatLatitude toFloating(const FixedLatitude fixed)
+{
+ const auto latitude = static_cast<std::int32_t>(fixed);
+ const auto floating = boost::numeric_cast<double>(latitude / COORDINATE_PRECISION);
+ return FloatLatitude(floating);
+}
+
+/**
+ * Converts a typed longitude from fixed to floating representation.
+ *
+ * \param fixed typed longitude in fixed representation.
+ * \return typed longitude in floating representation
+ * \see Coordinate, toFixed
+ */
+inline FloatLongitude toFloating(const FixedLongitude fixed)
+{
+ const auto longitude = static_cast<std::int32_t>(fixed);
+ const auto floating = boost::numeric_cast<double>(longitude / COORDINATE_PRECISION);
+ return FloatLongitude(floating);
+}
+
+// fwd. decl.
+struct FloatCoordinate;
+
+/**
+ * Represents a coordinate based on longitude and latitude in fixed representation.
+ *
+ * To prevent accidental longitude and latitude flips, we provide typed longitude and latitude
+ * wrappers. You can cast these wrappers back to their underlying representation or convert them
+ * from one representation to the other.
+ *
+ * The two representation we provide are:
+ * - Fixed point
+ * - Floating point
+ *
+ * \see FloatCoordinate, toFixed, toFloating
+ */
+struct Coordinate
+{
+ FixedLongitude lon;
+ FixedLatitude lat;
+
+ Coordinate();
+ Coordinate(const FloatCoordinate &other);
+ Coordinate(const FixedLongitude lon_, const FixedLatitude lat_);
+ Coordinate(const FloatLongitude lon_, const FloatLatitude lat_);
+
+ template <class T> Coordinate(const T &coordinate) : lon(coordinate.lon), lat(coordinate.lat)
+ {
+ static_assert(!std::is_same<T, Coordinate>::value,
+ "This constructor should not be used for Coordinates");
+ static_assert(std::is_same<decltype(lon), decltype(coordinate.lon)>::value,
+ "coordinate types incompatible");
+ static_assert(std::is_same<decltype(lat), decltype(coordinate.lat)>::value,
+ "coordinate types incompatible");
+ }
+
+ bool IsValid() const;
+ friend bool operator==(const Coordinate lhs, const Coordinate rhs);
+ friend bool operator!=(const Coordinate lhs, const Coordinate rhs);
+ friend std::ostream &operator<<(std::ostream &out, const Coordinate coordinate);
+};
+
+/**
+ * Represents a coordinate based on longitude and latitude in floating representation.
+ *
+ * To prevent accidental longitude and latitude flips, we provide typed longitude and latitude
+ * wrappers. You can cast these wrappers back to their underlying representation or convert them
+ * from one representation to the other.
+ *
+ * The two representation we provide are:
+ * - Fixed point
+ * - Floating point
+ *
+ * \see Coordinate, toFixed, toFloating
+ */
+struct FloatCoordinate
+{
+ FloatLongitude lon;
+ FloatLatitude lat;
+
+ FloatCoordinate();
+ FloatCoordinate(const FixedLongitude lon_, const FixedLatitude lat_);
+ FloatCoordinate(const FloatLongitude lon_, const FloatLatitude lat_);
+ FloatCoordinate(const Coordinate other);
+
+ bool IsValid() const;
+ friend bool operator==(const FloatCoordinate lhs, const FloatCoordinate rhs);
+ friend bool operator!=(const FloatCoordinate lhs, const FloatCoordinate rhs);
+ friend std::ostream &operator<<(std::ostream &out, const FloatCoordinate coordinate);
+};
+
+bool operator==(const Coordinate lhs, const Coordinate rhs);
+bool operator==(const FloatCoordinate lhs, const FloatCoordinate rhs);
+std::ostream &operator<<(std::ostream &out, const Coordinate coordinate);
+std::ostream &operator<<(std::ostream &out, const FloatCoordinate coordinate);
+}
+}
+
+#endif /* COORDINATE_HPP_ */
diff --git a/include/util/coordinate_calculation.hpp b/include/util/coordinate_calculation.hpp
new file mode 100644
index 0000000..806b538
--- /dev/null
+++ b/include/util/coordinate_calculation.hpp
@@ -0,0 +1,92 @@
+#ifndef COORDINATE_CALCULATION
+#define COORDINATE_CALCULATION
+
+#include "util/coordinate.hpp"
+
+#include <boost/math/constants/constants.hpp>
+
+#include <utility>
+
+namespace osrm
+{
+namespace util
+{
+namespace coordinate_calculation
+{
+
+const constexpr long double DEGREE_TO_RAD = 0.017453292519943295769236907684886;
+const constexpr long double RAD_TO_DEGREE = 1. / DEGREE_TO_RAD;
+// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
+// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
+const constexpr long double EARTH_RADIUS = 6372797.560856;
+// radius used by WGS84
+const constexpr double EARTH_RADIUS_WGS84 = 6378137.0;
+
+namespace detail
+{
+// earth circumference devided by 2
+const constexpr double MAXEXTENT = EARTH_RADIUS_WGS84 * boost::math::constants::pi<double>();
+// ^ math functions are not constexpr since they have side-effects (setting errno) :(
+const double MAX_LATITUDE = RAD_TO_DEGREE * (2.0 * std::atan(std::exp(180.0 * DEGREE_TO_RAD)) -
+ boost::math::constants::half_pi<double>());
+const constexpr double MAX_LONGITUDE = 180.0;
+}
+
+//! Takes the squared euclidean distance of the input coordinates. Does not return meters!
+double squaredEuclideanDistance(const FloatCoordinate &lhs, const FloatCoordinate &rhs);
+
+double haversineDistance(const Coordinate first_coordinate, const Coordinate second_coordinate);
+
+double greatCircleDistance(const Coordinate first_coordinate, const Coordinate second_coordinate);
+
+std::pair<double, FloatCoordinate>
+projectPointOnSegment(const FloatCoordinate &projected_xy_source,
+ const FloatCoordinate &projected_xy_target,
+ const FloatCoordinate &projected_xy_coordinate);
+
+double perpendicularDistance(const Coordinate segment_source,
+ const Coordinate segment_target,
+ const Coordinate query_location);
+
+double perpendicularDistance(const Coordinate segment_source,
+ const Coordinate segment_target,
+ const Coordinate query_location,
+ Coordinate &nearest_location,
+ double &ratio);
+
+Coordinate centroid(const Coordinate lhs, const Coordinate rhs);
+
+double bearing(const Coordinate first_coordinate, const Coordinate second_coordinate);
+
+// Get angle of line segment (A,C)->(C,B)
+double computeAngle(const Coordinate first, const Coordinate second, const Coordinate third);
+
+// factor in [0,1]. Returns point along the straight line between from and to. 0 returns from, 1
+// returns to
+Coordinate interpolateLinear(double factor, const Coordinate from, const Coordinate to);
+
+namespace mercator
+{
+// This is the global default tile size for all Mapbox Vector Tiles
+const constexpr double TILE_SIZE = 256.0;
+// Converts projected mercator degrees to PX
+const constexpr double DEGREE_TO_PX = detail::MAXEXTENT / 180.0;
+
+double degreeToPixel(FloatLatitude lat, unsigned zoom);
+double degreeToPixel(FloatLongitude lon, unsigned zoom);
+FloatLatitude yToLat(const double value);
+double latToY(const FloatLatitude latitude);
+
+FloatCoordinate fromWGS84(const FloatCoordinate &wgs84_coordinate);
+FloatCoordinate toWGS84(const FloatCoordinate &mercator_coordinate);
+
+void xyzToMercator(
+ const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy);
+void xyzToWGS84(
+ const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy);
+} // ns mercator
+} // ns coordinate_calculation
+} // ns util
+} // ns osrm
+
+#endif // COORDINATE_CALCULATION
diff --git a/data_structures/deallocating_vector.hpp b/include/util/deallocating_vector.hpp
similarity index 85%
rename from data_structures/deallocating_vector.hpp
rename to include/util/deallocating_vector.hpp
index 72cb081..c8883b2 100644
--- a/data_structures/deallocating_vector.hpp
+++ b/include/util/deallocating_vector.hpp
@@ -1,34 +1,7 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef DEALLOCATING_VECTOR_HPP
#define DEALLOCATING_VECTOR_HPP
-#include "../util/integer_range.hpp"
+#include "util/integer_range.hpp"
#include <boost/iterator/iterator_facade.hpp>
@@ -36,6 +9,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <utility>
#include <vector>
+namespace osrm
+{
+namespace util
+{
+
template <typename ElementT> struct ConstDeallocatingVectorIteratorState
{
ConstDeallocatingVectorIteratorState()
@@ -47,14 +25,15 @@ template <typename ElementT> struct ConstDeallocatingVectorIteratorState
{
}
explicit ConstDeallocatingVectorIteratorState(const std::size_t idx,
- const std::vector<ElementT *> *input_list)
+ const std::vector<ElementT *> *input_list)
: index(idx), bucket_list(input_list)
{
}
std::size_t index;
const std::vector<ElementT *> *bucket_list;
- ConstDeallocatingVectorIteratorState &operator=(const ConstDeallocatingVectorIteratorState &other)
+ ConstDeallocatingVectorIteratorState &
+ operator=(const ConstDeallocatingVectorIteratorState &other)
{
index = other.index;
bucket_list = other.bucket_list;
@@ -237,11 +216,10 @@ class DeallocatingVectorRemoveIterator
}
};
-template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK>
-class DeallocatingVector;
+template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK> class DeallocatingVector;
-template<typename T, std::size_t S>
-void swap(DeallocatingVector<T, S>& lhs, DeallocatingVector<T, S>& rhs);
+template <typename T, std::size_t S>
+void swap(DeallocatingVector<T, S> &lhs, DeallocatingVector<T, S> &rhs);
template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK = 8388608 / sizeof(ElementT)>
class DeallocatingVector
@@ -263,7 +241,8 @@ class DeallocatingVector
~DeallocatingVector() { clear(); }
- friend void swap<>(DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK>& lhs, DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK>& rhs);
+ friend void swap<>(DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK> &lhs,
+ DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK> &rhs);
void swap(DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK> &other)
{
@@ -327,8 +306,7 @@ class DeallocatingVector
else
{ // down-size
const std::size_t number_of_necessary_buckets = 1 + (new_size / ELEMENTS_PER_BLOCK);
- for (const auto bucket_index :
- osrm::irange(number_of_necessary_buckets, bucket_list.size()))
+ for (const auto bucket_index : irange(number_of_necessary_buckets, bucket_list.size()))
{
if (nullptr != bucket_list[bucket_index])
{
@@ -394,10 +372,12 @@ class DeallocatingVector
}
};
-template<typename T, std::size_t S>
-void swap(DeallocatingVector<T, S>& lhs, DeallocatingVector<T, S>& rhs)
+template <typename T, std::size_t S>
+void swap(DeallocatingVector<T, S> &lhs, DeallocatingVector<T, S> &rhs)
{
lhs.swap(rhs);
}
+}
+}
#endif /* DEALLOCATING_VECTOR_HPP */
diff --git a/util/dist_table_wrapper.hpp b/include/util/dist_table_wrapper.hpp
similarity index 58%
rename from util/dist_table_wrapper.hpp
rename to include/util/dist_table_wrapper.hpp
index 15550fa..714bcef 100644
--- a/util/dist_table_wrapper.hpp
+++ b/include/util/dist_table_wrapper.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef DIST_TABLE_WRAPPER_H
#define DIST_TABLE_WRAPPER_H
@@ -33,6 +6,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/assert.hpp>
#include <cstddef>
+namespace osrm
+{
+namespace util
+{
+
// This Wrapper provides an easier access to a distance table that is given as an linear vector
template <typename T> class DistTableWrapper
@@ -47,7 +25,7 @@ template <typename T> class DistTableWrapper
BOOST_ASSERT_MSG(table.size() == 0, "table is empty");
BOOST_ASSERT_MSG(number_of_nodes_ * number_of_nodes_ <= table_.size(),
"number_of_nodes_ is invalid");
- };
+ }
std::size_t GetNumberOfNodes() const { return number_of_nodes_; }
@@ -84,5 +62,7 @@ template <typename T> class DistTableWrapper
std::vector<T> table_;
const std::size_t number_of_nodes_;
};
+}
+}
#endif // DIST_TABLE_WRAPPER_H
diff --git a/data_structures/dynamic_graph.hpp b/include/util/dynamic_graph.hpp
similarity index 80%
rename from data_structures/dynamic_graph.hpp
rename to include/util/dynamic_graph.hpp
index 4f63c02..7df32a9 100644
--- a/data_structures/dynamic_graph.hpp
+++ b/include/util/dynamic_graph.hpp
@@ -1,36 +1,9 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef DYNAMICGRAPH_HPP
#define DYNAMICGRAPH_HPP
-#include "deallocating_vector.hpp"
-#include "../util/integer_range.hpp"
-#include "../typedefs.h"
+#include "util/deallocating_vector.hpp"
+#include "util/integer_range.hpp"
+#include "util/typedefs.hpp"
#include <boost/assert.hpp>
@@ -42,13 +15,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <tuple>
#include <vector>
+namespace osrm
+{
+namespace util
+{
+
template <typename EdgeDataT> class DynamicGraph
{
public:
using EdgeData = EdgeDataT;
using NodeIterator = unsigned;
using EdgeIterator = unsigned;
- using EdgeRange = osrm::range<EdgeIterator>;
+ using EdgeRange = range<EdgeIterator>;
class InputEdge
{
@@ -91,14 +69,15 @@ template <typename EdgeDataT> class DynamicGraph
template <class ContainerT> DynamicGraph(const NodeIterator nodes, const ContainerT &graph)
{
// we need to cast here because DeallocatingVector does not have a valid const iterator
- BOOST_ASSERT(std::is_sorted(const_cast<ContainerT&>(graph).begin(), const_cast<ContainerT&>(graph).end()));
+ BOOST_ASSERT(std::is_sorted(const_cast<ContainerT &>(graph).begin(),
+ const_cast<ContainerT &>(graph).end()));
number_of_nodes = nodes;
number_of_edges = static_cast<EdgeIterator>(graph.size());
node_array.resize(number_of_nodes + 1);
EdgeIterator edge = 0;
EdgeIterator position = 0;
- for (const auto node : osrm::irange(0u, number_of_nodes))
+ for (const auto node : irange(0u, number_of_nodes))
{
EdgeIterator last_edge = edge;
while (edge < number_of_edges && graph[edge].source == node)
@@ -113,10 +92,10 @@ template <typename EdgeDataT> class DynamicGraph
edge_list.reserve(static_cast<std::size_t>(edge_list.size() * 1.1));
edge_list.resize(position);
edge = 0;
- for (const auto node : osrm::irange(0u, number_of_nodes))
+ for (const auto node : irange(0u, number_of_nodes))
{
- for (const auto i : osrm::irange(node_array[node].first_edge,
- node_array[node].first_edge + node_array[node].edges))
+ for (const auto i : irange(node_array[node].first_edge,
+ node_array[node].first_edge + node_array[node].edges))
{
edge_list[i].target = graph[edge].target;
BOOST_ASSERT(edge_list[i].target < number_of_nodes);
@@ -137,7 +116,7 @@ template <typename EdgeDataT> class DynamicGraph
unsigned GetDirectedOutDegree(const NodeIterator n) const
{
unsigned degree = 0;
- for (const auto edge : osrm::irange(BeginEdges(n), EndEdges(n)))
+ for (const auto edge : irange(BeginEdges(n), EndEdges(n)))
{
if (!GetEdgeData(edge).reversed)
{
@@ -167,7 +146,7 @@ template <typename EdgeDataT> class DynamicGraph
EdgeRange GetAdjacentEdgeRange(const NodeIterator node) const
{
- return osrm::irange(BeginEdges(node), EndEdges(node));
+ return irange(BeginEdges(node), EndEdges(node));
}
NodeIterator InsertNode()
@@ -201,12 +180,12 @@ template <typename EdgeDataT> class DynamicGraph
edge_list.reserve(requiredCapacity * 1.1);
}
edge_list.resize(edge_list.size() + newSize);
- for (const auto i : osrm::irange(0u, node.edges))
+ for (const auto i : irange(0u, node.edges))
{
edge_list[newFirstEdge + i] = edge_list[node.first_edge + i];
makeDummy(node.first_edge + i);
}
- for (const auto i : osrm::irange(node.edges + 1, newSize))
+ for (const auto i : irange(node.edges + 1, newSize))
{
makeDummy(newFirstEdge + i);
}
@@ -261,7 +240,7 @@ template <typename EdgeDataT> class DynamicGraph
// searches for a specific edge
EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
{
- for (const auto i : osrm::irange(BeginEdges(from), EndEdges(from)))
+ for (const auto i : irange(BeginEdges(from), EndEdges(from)))
{
if (to == edge_list[i].target)
{
@@ -341,5 +320,7 @@ template <typename EdgeDataT> class DynamicGraph
std::vector<Node> node_array;
DeallocatingVector<Edge> edge_list;
};
+}
+}
#endif // DYNAMICGRAPH_HPP
diff --git a/include/util/exception.hpp b/include/util/exception.hpp
new file mode 100644
index 0000000..41efb0b
--- /dev/null
+++ b/include/util/exception.hpp
@@ -0,0 +1,30 @@
+#ifndef OSRM_EXCEPTION_HPP
+#define OSRM_EXCEPTION_HPP
+
+#include <exception>
+#include <string>
+#include <utility>
+
+namespace osrm
+{
+namespace util
+{
+
+class exception final : public std::exception
+{
+ public:
+ explicit exception(const char *message) : message(message) {}
+ explicit exception(std::string message) : message(std::move(message)) {}
+ const char *what() const noexcept override { return message.c_str(); }
+
+ private:
+ // This function exists to 'anchor' the class, and stop the compiler from
+ // copying vtable and RTTI info into every object file that includes
+ // this header. (Caught by -Wweak-vtables under Clang.)
+ virtual void anchor() const;
+ const std::string message;
+};
+}
+}
+
+#endif /* OSRM_EXCEPTION_HPP */
diff --git a/include/util/fingerprint.hpp b/include/util/fingerprint.hpp
new file mode 100644
index 0000000..e8238c0
--- /dev/null
+++ b/include/util/fingerprint.hpp
@@ -0,0 +1,39 @@
+#ifndef FINGERPRINT_H
+#define FINGERPRINT_H
+
+#include <boost/uuid/uuid.hpp>
+#include <type_traits>
+
+namespace osrm
+{
+namespace util
+{
+
+// implements a singleton, i.e. there is one and only one conviguration object
+class FingerPrint
+{
+ public:
+ static FingerPrint GetValid();
+ const boost::uuids::uuid &GetFingerPrint() const;
+ bool IsMagicNumberOK(const FingerPrint &other) const;
+ bool TestGraphUtil(const FingerPrint &other) const;
+ bool TestContractor(const FingerPrint &other) const;
+ bool TestRTree(const FingerPrint &other) const;
+ bool TestQueryObjects(const FingerPrint &other) const;
+
+ private:
+ unsigned magic_number;
+ char md5_prepare[33];
+ char md5_tree[33];
+ char md5_graph[33];
+ char md5_objects[33];
+
+ // initialize to {6ba7b810-9dad-11d1-80b4-00c04fd430c8}
+ boost::uuids::uuid named_uuid;
+};
+
+static_assert(std::is_trivial<FingerPrint>::value, "FingerPrint needs to be trivial.");
+}
+}
+
+#endif /* FingerPrint_H */
diff --git a/util/fingerprint_impl.hpp.in b/include/util/fingerprint_impl.hpp.in
similarity index 58%
rename from util/fingerprint_impl.hpp.in
rename to include/util/fingerprint_impl.hpp.in
index 88e8436..7b31d6d 100644
--- a/util/fingerprint_impl.hpp.in
+++ b/include/util/fingerprint_impl.hpp.in
@@ -1,31 +1,4 @@
-/*
-
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "util/osrm_exception.hpp"
+#include "util/exception.hpp"
#include <boost/uuid/name_generator.hpp>
#include <boost/uuid/uuid_generators.hpp>
@@ -40,6 +13,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#cmakedefine MD5GRAPH "${MD5GRAPH}"
#cmakedefine MD5OBJECTS "${MD5OBJECTS}"
+namespace osrm
+{
+namespace util
+{
+
FingerPrint FingerPrint::GetValid()
{
FingerPrint fingerprint;
@@ -79,16 +57,16 @@ bool FingerPrint::TestGraphUtil(const FingerPrint &other) const
{
if (!IsMagicNumberOK(other))
{
- throw osrm::exception("hsgr input file misses magic number. Check or reprocess the file");
+ throw exception("hsgr input file misses magic number. Check or reprocess the file");
}
return std::equal(md5_graph, md5_graph + 32, other.md5_graph);
}
-bool FingerPrint::TestPrepare(const FingerPrint &other) const
+bool FingerPrint::TestContractor(const FingerPrint &other) const
{
if (!IsMagicNumberOK(other))
{
- throw osrm::exception("osrm input file misses magic number. Check or reprocess the file");
+ throw exception("osrm input file misses magic number. Check or reprocess the file");
}
return std::equal(md5_prepare, md5_prepare + 32, other.md5_prepare);
}
@@ -97,7 +75,7 @@ bool FingerPrint::TestRTree(const FingerPrint &other) const
{
if (!IsMagicNumberOK(other))
{
- throw osrm::exception("r-tree input file misses magic number. Check or reprocess the file");
+ throw exception("r-tree input file misses magic number. Check or reprocess the file");
}
return std::equal(md5_tree, md5_tree + 32, other.md5_tree);
}
@@ -106,7 +84,10 @@ bool FingerPrint::TestQueryObjects(const FingerPrint &other) const
{
if (!IsMagicNumberOK(other))
{
- throw osrm::exception("missing magic number. Check or reprocess the file");
+ throw exception("missing magic number. Check or reprocess the file");
}
return std::equal(md5_objects, md5_objects + 32, other.md5_objects);
}
+
+}
+}
diff --git a/include/util/for_each_pair.hpp b/include/util/for_each_pair.hpp
new file mode 100644
index 0000000..86fc75e
--- /dev/null
+++ b/include/util/for_each_pair.hpp
@@ -0,0 +1,45 @@
+#ifndef FOR_EACH_PAIR_HPP
+#define FOR_EACH_PAIR_HPP
+
+#include <numeric>
+#include <iterator>
+
+namespace osrm
+{
+namespace util
+{
+
+// TODO: check why this is not an option here:
+// std::adjacent_find(begin, end, [=](const auto& l, const auto& r){ return function(), false; });
+template <typename ForwardIterator, typename Function>
+Function for_each_pair(ForwardIterator begin, ForwardIterator end, Function function)
+{
+ if (begin == end)
+ {
+ return function;
+ }
+
+ auto next = begin;
+ next = std::next(next);
+
+ while (next != end)
+ {
+ function(*begin, *next);
+ begin = std::next(begin);
+ next = std::next(next);
+ }
+ return function;
+}
+
+template <class ContainerT, typename Function>
+Function for_each_pair(ContainerT &container, Function function)
+{
+ using std::begin;
+ using std::end;
+ return for_each_pair(begin(container), end(container), function);
+}
+
+} // namespace util
+} // namespace osrm
+
+#endif /* FOR_EACH_PAIR_HPP */
diff --git a/util/graph_loader.hpp b/include/util/graph_loader.hpp
similarity index 71%
rename from util/graph_loader.hpp
rename to include/util/graph_loader.hpp
index 6ddd0eb..b611e04 100644
--- a/util/graph_loader.hpp
+++ b/include/util/graph_loader.hpp
@@ -1,41 +1,14 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef GRAPH_LOADER_HPP
#define GRAPH_LOADER_HPP
-#include "fingerprint.hpp"
-#include "osrm_exception.hpp"
-#include "simple_logger.hpp"
-#include "../data_structures/external_memory_node.hpp"
-#include "../data_structures/import_edge.hpp"
-#include "../data_structures/query_node.hpp"
-#include "../data_structures/restriction.hpp"
-#include "../typedefs.h"
+#include "util/fingerprint.hpp"
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+#include "extractor/external_memory_node.hpp"
+#include "extractor/node_based_edge.hpp"
+#include "extractor/query_node.hpp"
+#include "extractor/restriction.hpp"
+#include "util/typedefs.hpp"
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
@@ -49,19 +22,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <ios>
#include <vector>
+namespace osrm
+{
+namespace util
+{
+
/**
* Reads the .restrictions file and loads it to a vector.
* The since the restrictions reference nodes using their external node id,
* we need to renumber it to the new internal id.
*/
unsigned loadRestrictionsFromFile(std::istream &input_stream,
- std::vector<TurnRestriction> &restriction_list)
+ std::vector<extractor::TurnRestriction> &restriction_list)
{
const FingerPrint fingerprint_valid = FingerPrint::GetValid();
FingerPrint fingerprint_loaded;
unsigned number_of_usable_restrictions = 0;
input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
- if (!fingerprint_loaded.TestPrepare(fingerprint_valid))
+ if (!fingerprint_loaded.TestContractor(fingerprint_valid))
{
SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n"
"Reprocess to get rid of this warning.";
@@ -72,7 +50,7 @@ unsigned loadRestrictionsFromFile(std::istream &input_stream,
if (number_of_usable_restrictions > 0)
{
input_stream.read((char *)restriction_list.data(),
- number_of_usable_restrictions * sizeof(TurnRestriction));
+ number_of_usable_restrictions * sizeof(extractor::TurnRestriction));
}
return number_of_usable_restrictions;
@@ -87,13 +65,13 @@ unsigned loadRestrictionsFromFile(std::istream &input_stream,
NodeID loadNodesFromFile(std::istream &input_stream,
std::vector<NodeID> &barrier_node_list,
std::vector<NodeID> &traffic_light_node_list,
- std::vector<QueryNode> &node_array)
+ std::vector<extractor::QueryNode> &node_array)
{
const FingerPrint fingerprint_valid = FingerPrint::GetValid();
FingerPrint fingerprint_loaded;
input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
- if (!fingerprint_loaded.TestPrepare(fingerprint_valid))
+ if (!fingerprint_loaded.TestContractor(fingerprint_valid))
{
SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n"
"Reprocess to get rid of this warning.";
@@ -103,11 +81,12 @@ NodeID loadNodesFromFile(std::istream &input_stream,
input_stream.read(reinterpret_cast<char *>(&n), sizeof(NodeID));
SimpleLogger().Write() << "Importing n = " << n << " nodes ";
- ExternalMemoryNode current_node;
+ extractor::ExternalMemoryNode current_node;
for (NodeID i = 0; i < n; ++i)
{
- input_stream.read(reinterpret_cast<char *>(¤t_node), sizeof(ExternalMemoryNode));
- node_array.emplace_back(current_node.lat, current_node.lon, current_node.node_id);
+ input_stream.read(reinterpret_cast<char *>(¤t_node),
+ sizeof(extractor::ExternalMemoryNode));
+ node_array.emplace_back(current_node.lon, current_node.lat, current_node.node_id);
if (current_node.barrier)
{
barrier_node_list.emplace_back(i);
@@ -128,21 +107,22 @@ NodeID loadNodesFromFile(std::istream &input_stream,
/**
* Reads a .osrm file and produces the edges.
*/
-NodeID loadEdgesFromFile(std::istream &input_stream, std::vector<NodeBasedEdge> &edge_list)
+NodeID loadEdgesFromFile(std::istream &input_stream,
+ std::vector<extractor::NodeBasedEdge> &edge_list)
{
EdgeID m;
input_stream.read(reinterpret_cast<char *>(&m), sizeof(unsigned));
edge_list.resize(m);
SimpleLogger().Write() << " and " << m << " edges ";
- input_stream.read((char *)edge_list.data(), m * sizeof(NodeBasedEdge));
+ input_stream.read((char *)edge_list.data(), m * sizeof(extractor::NodeBasedEdge));
BOOST_ASSERT(edge_list.size() > 0);
#ifndef NDEBUG
SimpleLogger().Write() << "Validating loaded edges...";
tbb::parallel_sort(edge_list.begin(), edge_list.end(),
- [](const NodeBasedEdge &lhs, const NodeBasedEdge &rhs)
+ [](const extractor::NodeBasedEdge &lhs, const extractor::NodeBasedEdge &rhs)
{
return (lhs.source < rhs.source) ||
(lhs.source == rhs.source && lhs.target < rhs.target);
@@ -175,11 +155,11 @@ unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
{
if (!boost::filesystem::exists(hsgr_file))
{
- throw osrm::exception("hsgr file does not exist");
+ throw exception("hsgr file does not exist");
}
if (0 == boost::filesystem::file_size(hsgr_file))
{
- throw osrm::exception("hsgr file is empty");
+ throw exception("hsgr file is empty");
}
boost::filesystem::ifstream hsgr_input_stream(hsgr_file, std::ios::binary);
@@ -214,9 +194,10 @@ unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
hsgr_input_stream.read(reinterpret_cast<char *>(&edge_list[0]),
number_of_edges * sizeof(EdgeT));
}
- hsgr_input_stream.close();
return number_of_nodes;
}
+}
+}
#endif // GRAPH_LOADER_HPP
diff --git a/util/graph_utils.hpp b/include/util/graph_utils.hpp
similarity index 84%
rename from util/graph_utils.hpp
rename to include/util/graph_utils.hpp
index 9af8dbc..c2165c5 100644
--- a/util/graph_utils.hpp
+++ b/include/util/graph_utils.hpp
@@ -1,26 +1,31 @@
#ifndef GRAPH_UTILS_HPP
#define GRAPH_UTILS_HPP
-#include "../typedefs.h"
+#include "util/typedefs.hpp"
#include <boost/assert.hpp>
#include <vector>
+namespace osrm
+{
+namespace util
+{
+
/// This function checks if the graph (consisting of directed edges) is undirected
-template<typename GraphT>
-bool isUndirectedGraph(const GraphT& graph)
+template <typename GraphT> bool isUndirectedGraph(const GraphT &graph)
{
for (auto source = 0u; source < graph.GetNumberOfNodes(); ++source)
{
for (auto edge = graph.BeginEdges(source); edge < graph.EndEdges(source); ++edge)
{
- const auto& data = graph.GetEdgeData(edge);
+ const auto &data = graph.GetEdgeData(edge);
auto target = graph.GetTarget(edge);
BOOST_ASSERT(target != SPECIAL_NODEID);
bool found_reverse = false;
- for (auto rev_edge = graph.BeginEdges(target); rev_edge < graph.EndEdges(target); ++rev_edge)
+ for (auto rev_edge = graph.BeginEdges(target); rev_edge < graph.EndEdges(target);
+ ++rev_edge)
{
auto rev_target = graph.GetTarget(rev_edge);
BOOST_ASSERT(rev_target != SPECIAL_NODEID);
@@ -44,7 +49,6 @@ bool isUndirectedGraph(const GraphT& graph)
return true;
}
-
/// Since DynamicGraph assumes directed edges we have to make sure we transformed
/// the compressed edge format into single directed edges. We do this to make sure
/// every node also knows its incoming edges, not only its outgoing edges and use the reversed=true
@@ -60,13 +64,14 @@ bool isUndirectedGraph(const GraphT& graph)
/// (a <-- b gets reducted to b --> a)
/// 2. a --> b will be transformed to a --> b and b <-- a
/// 3. a <-> b will be transformed to a --> b and b --> a
-template<typename OutputEdgeT, typename InputEdgeT, typename FunctorT>
-std::vector<OutputEdgeT> directedEdgesFromCompressed(const std::vector<InputEdgeT>& input_edge_list, FunctorT copy_data)
+template <typename OutputEdgeT, typename InputEdgeT, typename FunctorT>
+std::vector<OutputEdgeT> directedEdgesFromCompressed(const std::vector<InputEdgeT> &input_edge_list,
+ FunctorT copy_data)
{
std::vector<OutputEdgeT> output_edge_list;
OutputEdgeT edge;
- for (const auto& input_edge : input_edge_list)
+ for (const auto &input_edge : input_edge_list)
{
// edges that are not forward get converted by flipping the end points
BOOST_ASSERT(input_edge.forward);
@@ -91,4 +96,7 @@ std::vector<OutputEdgeT> directedEdgesFromCompressed(const std::vector<InputEdge
return output_edge_list;
}
+}
+}
+
#endif
diff --git a/include/util/hilbert_value.hpp b/include/util/hilbert_value.hpp
new file mode 100644
index 0000000..2acb6b4
--- /dev/null
+++ b/include/util/hilbert_value.hpp
@@ -0,0 +1,18 @@
+#ifndef HILBERT_VALUE_HPP
+#define HILBERT_VALUE_HPP
+
+#include "osrm/coordinate.hpp"
+
+#include <cstdint>
+
+namespace osrm
+{
+namespace util
+{
+
+// Computes a 64 bit value that corresponds to the hilbert space filling curve
+std::uint64_t hilbertCode(const Coordinate coordinate);
+}
+}
+
+#endif /* HILBERT_VALUE_HPP */
diff --git a/include/util/integer_range.hpp b/include/util/integer_range.hpp
new file mode 100644
index 0000000..29d428f
--- /dev/null
+++ b/include/util/integer_range.hpp
@@ -0,0 +1,58 @@
+#ifndef INTEGER_RANGE_HPP
+#define INTEGER_RANGE_HPP
+
+#include <boost/assert.hpp>
+
+#include <type_traits>
+
+#include <cstdint>
+
+namespace osrm
+{
+namespace util
+{
+
+// Warning: do not try to replace this with Boost's irange, as it is broken on Boost 1.55:
+// auto r = boost::irange<unsigned int>(0, 15);
+// std::cout << r.size() << std::endl;
+// results in -4294967281. Latest Boost versions fix this, but we still support older ones.
+
+template <typename Integer> class range
+{
+ private:
+ const Integer last;
+ Integer iter;
+
+ public:
+ range(Integer start, Integer end) noexcept : last(end), iter(start)
+ {
+ BOOST_ASSERT_MSG(start <= end, "backwards counting ranges not suppoted");
+ static_assert(std::is_integral<Integer>::value, "range type must be integral");
+ }
+
+ // Iterable functions
+ const range &begin() const noexcept { return *this; }
+ const range &end() const noexcept { return *this; }
+ Integer front() const noexcept { return iter; }
+ Integer back() const noexcept { return last - 1; }
+ std::size_t size() const noexcept { return static_cast<std::size_t>(last - iter); }
+
+ // Iterator functions
+ bool operator!=(const range &) const noexcept { return iter < last; }
+ void operator++() noexcept { ++iter; }
+ Integer operator*() const noexcept { return iter; }
+};
+
+// convenience function to construct an integer range with type deduction
+template <typename Integer>
+range<Integer>
+irange(const Integer first,
+ const Integer last,
+ typename std::enable_if<std::is_integral<Integer>::value>::type * = 0) noexcept
+{
+ return range<Integer>(first, last);
+}
+}
+}
+
+#endif // INTEGER_RANGE_HPP
diff --git a/include/util/io.hpp b/include/util/io.hpp
new file mode 100644
index 0000000..70ab64a
--- /dev/null
+++ b/include/util/io.hpp
@@ -0,0 +1,127 @@
+#ifndef OSRM_INCLUDE_UTIL_IO_HPP_
+#define OSRM_INCLUDE_UTIL_IO_HPP_
+
+#include "util/simple_logger.hpp"
+
+#include <boost/filesystem.hpp>
+
+#include <cstddef>
+#include <cstdint>
+
+#include <fstream>
+#include <bitset>
+#include <vector>
+
+#include "util/fingerprint.hpp"
+
+namespace osrm
+{
+namespace util
+{
+
+inline bool writeFingerprint(std::ostream &stream)
+{
+ const auto fingerprint = FingerPrint::GetValid();
+ stream.write(reinterpret_cast<const char *>(&fingerprint), sizeof(fingerprint));
+ return static_cast<bool>(stream);
+}
+
+inline bool readAndCheckFingerprint(std::istream &stream)
+{
+ FingerPrint fingerprint;
+ const auto valid = FingerPrint::GetValid();
+ stream.read(reinterpret_cast<char *>(&fingerprint), sizeof(fingerprint));
+ // compare the compilation state stored in the fingerprint
+ return static_cast<bool>(stream) && valid.IsMagicNumberOK(fingerprint) &&
+ valid.TestContractor(fingerprint) && valid.TestGraphUtil(fingerprint) &&
+ valid.TestRTree(fingerprint) && valid.TestQueryObjects(fingerprint);
+}
+
+template <typename simple_type>
+bool serializeVector(const std::string &filename, const std::vector<simple_type> &data)
+{
+ std::ofstream stream(filename, std::ios::binary);
+
+ writeFingerprint(stream);
+
+ std::uint64_t count = data.size();
+ stream.write(reinterpret_cast<const char *>(&count), sizeof(count));
+ if (!data.empty())
+ stream.write(reinterpret_cast<const char *>(&data[0]), sizeof(simple_type) * count);
+ return static_cast<bool>(stream);
+}
+
+template <typename simple_type>
+bool deserializeVector(const std::string &filename, std::vector<simple_type> &data)
+{
+ std::ifstream stream(filename, std::ios::binary);
+
+ if (!readAndCheckFingerprint(stream))
+ return false;
+
+ std::uint64_t count = 0;
+ stream.read(reinterpret_cast<char *>(&count), sizeof(count));
+ data.resize(count);
+ if (count)
+ stream.read(reinterpret_cast<char *>(&data[0]), sizeof(simple_type) * count);
+ return static_cast<bool>(stream);
+}
+
+inline bool serializeFlags(const boost::filesystem::path &path, const std::vector<bool> &flags)
+{
+ // TODO this should be replaced with a FILE-based write using error checking
+ std::ofstream flag_stream(path.string(), std::ios::binary);
+
+ writeFingerprint(flag_stream);
+
+ std::uint32_t number_of_bits = flags.size();
+ flag_stream.write(reinterpret_cast<const char *>(&number_of_bits), sizeof(number_of_bits));
+ // putting bits in ints
+ std::uint32_t chunk = 0;
+ std::size_t chunk_count = 0;
+ for (std::size_t bit_nr = 0; bit_nr < number_of_bits;)
+ {
+ std::bitset<32> chunk_bitset;
+ for (std::size_t chunk_bit = 0; chunk_bit < 32 && bit_nr < number_of_bits;
+ ++chunk_bit, ++bit_nr)
+ chunk_bitset[chunk_bit] = flags[bit_nr];
+
+ chunk = chunk_bitset.to_ulong();
+ ++chunk_count;
+ flag_stream.write(reinterpret_cast<const char *>(&chunk), sizeof(chunk));
+ }
+ SimpleLogger().Write() << "Wrote " << number_of_bits << " bits in " << chunk_count
+ << " chunks (Flags).";
+ return static_cast<bool>(flag_stream);
+}
+
+inline bool deserializeFlags(const boost::filesystem::path &path, std::vector<bool> &flags)
+{
+ SimpleLogger().Write() << "Reading flags from " << path;
+ std::ifstream flag_stream(path.string(), std::ios::binary);
+
+ if (!readAndCheckFingerprint(flag_stream))
+ return false;
+
+ std::uint32_t number_of_bits;
+ flag_stream.read(reinterpret_cast<char *>(&number_of_bits), sizeof(number_of_bits));
+ flags.resize(number_of_bits);
+ // putting bits in ints
+ std::uint32_t chunks = (number_of_bits + 31) / 32;
+ std::size_t bit_position = 0;
+ std::uint32_t chunk;
+ for (std::size_t chunk_id = 0; chunk_id < chunks; ++chunk_id)
+ {
+ flag_stream.read(reinterpret_cast<char *>(&chunk), sizeof(chunk));
+ std::bitset<32> chunk_bits(chunk);
+ for (std::size_t bit = 0; bit < 32 && bit_position < number_of_bits; ++bit, ++bit_position)
+ flags[bit_position] = chunk_bits[bit];
+ }
+ SimpleLogger().Write() << "Read " << number_of_bits << " bits in " << chunks
+ << " Chunks from disk.";
+ return static_cast<bool>(flag_stream);
+}
+} // namespace util
+} // namespace osrm
+
+#endif // OSRM_INCLUDE_UTIL_IO_HPP_
diff --git a/util/iso_8601_duration_parser.hpp b/include/util/iso_8601_duration_parser.hpp
similarity index 61%
rename from util/iso_8601_duration_parser.hpp
rename to include/util/iso_8601_duration_parser.hpp
index 3e558ce..91f9d2d 100644
--- a/util/iso_8601_duration_parser.hpp
+++ b/include/util/iso_8601_duration_parser.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef ISO_8601_DURATION_PARSER_HPP
#define ISO_8601_DURATION_PARSER_HPP
@@ -32,6 +5,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_action.hpp>
+namespace osrm
+{
+namespace util
+{
+
namespace qi = boost::spirit::qi;
template <typename Iterator> struct iso_8601_grammar : qi::grammar<Iterator>
@@ -98,5 +76,7 @@ template <typename Iterator> struct iso_8601_grammar : qi::grammar<Iterator>
return temp;
}
};
+}
+}
#endif // ISO_8601_DURATION_PARSER_HPP
diff --git a/include/osrm/json_container.hpp b/include/util/json_container.hpp
similarity index 59%
copy from include/osrm/json_container.hpp
copy to include/util/json_container.hpp
index 63accb8..9a383bb 100644
--- a/include/osrm/json_container.hpp
+++ b/include/util/json_container.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM contributors
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -33,46 +33,92 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <variant/variant.hpp>
-#include <iostream>
#include <vector>
#include <string>
+#include <utility>
#include <unordered_map>
namespace osrm
{
+
+namespace util
+{
+
+/**
+ * JSON types representing OSRM responses.
+ *
+ * The json::Value type represents the basic sum-type, implemented as a variant.
+ *
+ * There are two ways for destructuring such types:
+ * - Either provide a visitor and use the apply_visitor function or
+ * - use the get function and explicitely specify the type
+ *
+ * See the following documentations on variants:
+ * - https://github.com/mapbox/variant
+ * - http://www.boost.org/doc/libs/1_55_0/doc/html/variant.html
+ *
+ * And take a look at the example we provide.
+ *
+ * \see OSRM
+ */
namespace json
{
+// fwd. decls.
struct Object;
struct Array;
+/**
+ * Typed string wrapper.
+ *
+ * Unwrap the type via its value member attribute.
+ */
struct String
{
- String() {}
- String(const char *value) : value(value) {}
- String(std::string value) : value(std::move(value)) {}
+ String() = default;
+ String(const char *value_) : value{value_} {}
+ String(std::string value_) : value{std::move(value_)} {}
std::string value;
};
+/**
+ * Typed floating point number.
+ *
+ * Unwrap the type via its value member attribute.
+ */
struct Number
{
- Number() {}
- Number(double value) : value(static_cast<double>(value)) {}
+ Number() = default;
+ Number(double value_) : value{value_} {}
double value;
};
+/**
+ * Typed True.
+ */
struct True
{
};
+/**
+ * Typed False.
+ */
struct False
{
};
+/**
+ * Typed Null.
+ */
struct Null
{
};
+/**
+ * Typed Value sum-type implemented as a variant able to represent tree-like JSON structures.
+ *
+ * Dispatch on its type by either by using apply_visitor or its get function.
+ */
using Value = mapbox::util::variant<String,
Number,
mapbox::util::recursive_wrapper<Object>,
@@ -81,16 +127,28 @@ using Value = mapbox::util::variant<String,
False,
Null>;
+/**
+ * Typed Object.
+ *
+ * Unwrap the key-value pairs holding type via its values member attribute.
+ */
struct Object
{
std::unordered_map<std::string, Value> values;
};
+/**
+ * Typed Array.
+ *
+ * Unwrap the Value holding type via its values member attribute.
+ */
struct Array
{
std::vector<Value> values;
};
-} // namespace JSON
+} // namespace json
+} // namespace util
} // namespace osrm
+
#endif // JSON_CONTAINER_HPP
diff --git a/include/util/json_deep_compare.hpp b/include/util/json_deep_compare.hpp
new file mode 100644
index 0000000..32b0bde
--- /dev/null
+++ b/include/util/json_deep_compare.hpp
@@ -0,0 +1,158 @@
+#ifndef UTIL_JSON_DEEP_COMPARE_HPP
+#define UTIL_JSON_DEEP_COMPARE_HPP
+
+#include "util/json_container.hpp"
+#include "util/integer_range.hpp"
+
+#include <boost/assert.hpp>
+
+#include <algorithm>
+#include <functional>
+#include <set>
+
+namespace osrm
+{
+namespace util
+{
+namespace json
+{
+
+struct Comparator : mapbox::util::static_visitor<bool>
+{
+ Comparator(std::string &reason_, const std::string &lhs_path_, const std::string &rhs_path_)
+ : reason(reason_), lhs_path(lhs_path_), rhs_path(rhs_path_)
+ {
+ }
+
+ bool operator()(const String &lhs, const String &rhs) const {
+ bool is_same = lhs.value == rhs.value;
+ if (!is_same)
+ {
+ reason = lhs_path + " (= \"" + lhs.value + "\") != " + rhs_path + " (= \"" + rhs.value + "\")";
+ }
+ return is_same;
+ }
+
+ bool operator()(const Number &lhs, const Number &rhs) const {
+ bool is_same = lhs.value == rhs.value;
+ if (!is_same)
+ {
+ reason = lhs_path + " (= " + std::to_string(lhs.value) + ") != " + rhs_path + " (= " + std::to_string(rhs.value) + ")";
+ }
+ return is_same;
+ }
+
+ bool operator()(const Object &lhs, const Object &rhs) const
+ {
+ std::set<std::string> lhs_keys;
+ for (const auto &key_value : lhs.values)
+ {
+ lhs_keys.insert(key_value.first);
+ }
+
+ std::set<std::string> rhs_keys;
+ for (const auto &key_value : rhs.values)
+ {
+ rhs_keys.insert(key_value.first);
+ }
+
+ for (const auto &key : lhs_keys)
+ {
+ if (rhs_keys.find(key) == rhs_keys.end())
+ {
+ reason = rhs_path + " doesn't have key \"" + key + "\"";
+ return false;
+ }
+ }
+
+ for (const auto &key : rhs_keys)
+ {
+ if (lhs_keys.find(key) == lhs_keys.end())
+ {
+ reason = lhs_path + " doesn't have key \"" + key + "\"";
+ return false;
+ }
+ }
+
+ for (const auto &key : lhs_keys)
+ {
+ BOOST_ASSERT(rhs.values.find(key) != rhs.values.end());
+ BOOST_ASSERT(lhs.values.find(key) != lhs.values.end());
+
+ const auto &rhs_child = rhs.values.find(key)->second;
+ const auto &lhs_child = lhs.values.find(key)->second;
+ auto is_same = mapbox::util::apply_visitor(
+ Comparator(reason, lhs_path + "." + key, rhs_path + "." + key), lhs_child,
+ rhs_child);
+ if (!is_same)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool operator()(const Array &lhs, const Array &rhs) const
+ {
+ if (lhs.values.size() != rhs.values.size())
+ {
+ reason = lhs_path + ".length " + std::to_string(lhs.values.size()) + " != " + rhs_path +
+ ".length " + std::to_string(rhs.values.size());
+ return false;
+ }
+
+ for (auto i = 0UL; i < lhs.values.size(); ++i)
+ {
+ auto is_same = mapbox::util::apply_visitor(
+ Comparator(reason, lhs_path + "[" + std::to_string(i) + "]",
+ rhs_path + "[" + std::to_string(i) + "]"),
+ lhs.values[i], rhs.values[i]);
+ if (!is_same)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool operator()(const True &, const True &) const { return true; }
+ bool operator()(const False &, const False &) const { return true; }
+ bool operator()(const Null &, const Null &) const { return true; }
+
+ bool operator()(const False &, const True &) const
+ {
+ reason = lhs_path + " is false but " + rhs_path + " is true";
+ return false;
+ }
+ bool operator()(const True &, const False &) const
+ {
+ reason = lhs_path + " is true but " + rhs_path + " is false";
+ return false;
+ }
+
+ template <typename T1,
+ typename T2,
+ typename = typename std::enable_if<!std::is_same<T1, T2>::value>::type>
+ bool operator()(const T1 &, const T2 &)
+ {
+ reason = lhs_path + " and " + rhs_path + " have different types";
+ return false;
+ }
+
+ private:
+ std::string &reason;
+ const std::string &lhs_path;
+ const std::string &rhs_path;
+};
+
+inline bool compare(const Value &reference, const Value &result, std::string &reason)
+{
+ return mapbox::util::apply_visitor(Comparator(reason, "reference", "result"), reference,
+ result);
+}
+}
+}
+}
+
+#endif
diff --git a/include/util/json_logger.hpp b/include/util/json_logger.hpp
new file mode 100644
index 0000000..aa72b54
--- /dev/null
+++ b/include/util/json_logger.hpp
@@ -0,0 +1,62 @@
+#ifndef JSON_LOGGER_HPP
+#define JSON_LOGGER_HPP
+
+#include "osrm/json_container.hpp"
+
+#include <boost/thread/tss.hpp>
+
+#include <string>
+#include <unordered_map>
+
+namespace osrm
+{
+namespace util
+{
+namespace json
+{
+
+// Used to append additional debugging information to the JSON response in a
+// thread safe manner.
+class Logger
+{
+ using MapT = std::unordered_map<std::string, Value>;
+
+ public:
+ static Logger *get()
+ {
+ static Logger logger;
+
+ bool return_logger = true;
+#ifdef NDEBUG
+ return_logger = false;
+#endif
+#ifdef ENABLE_JSON_LOGGING
+ return_logger = true;
+#endif
+
+ if (return_logger)
+ {
+ return &logger;
+ }
+
+ return nullptr;
+ }
+
+ void initialize(const std::string &name)
+ {
+ if (!map.get())
+ {
+ map.reset(new MapT());
+ }
+ (*map)[name] = Object();
+ }
+
+ void render(const std::string &name, Object &obj) const { obj.values["debug"] = map->at(name); }
+
+ boost::thread_specific_ptr<MapT> map;
+};
+}
+}
+}
+
+#endif /* JSON_LOGGER_HPP */
diff --git a/util/json_renderer.hpp b/include/util/json_renderer.hpp
similarity index 72%
rename from util/json_renderer.hpp
rename to include/util/json_renderer.hpp
index 09d7bb2..a1ac7a0 100644
--- a/util/json_renderer.hpp
+++ b/include/util/json_renderer.hpp
@@ -1,47 +1,27 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
// based on
// https://svn.apache.org/repos/asf/mesos/tags/release-0.9.0-incubating-RC0/src/common/json.hpp
#ifndef JSON_RENDERER_HPP
#define JSON_RENDERER_HPP
-#include "cast.hpp"
-#include "string_util.hpp"
+#include "util/cast.hpp"
+#include "util/string_util.hpp"
+
+#include "osrm/json_container.hpp"
-#include <osrm/json_container.hpp>
+#include <ostream>
+#include <vector>
+#include <iterator>
+#include <string>
namespace osrm
{
+namespace util
+{
namespace json
{
-struct Renderer : mapbox::util::static_visitor<>
+struct Renderer
{
explicit Renderer(std::ostream &_out) : out(_out) {}
@@ -97,7 +77,7 @@ struct Renderer : mapbox::util::static_visitor<>
std::ostream &out;
};
-struct ArrayRenderer : mapbox::util::static_visitor<>
+struct ArrayRenderer
{
explicit ArrayRenderer(std::vector<char> &_out) : out(_out) {}
@@ -183,5 +163,7 @@ inline void render(std::vector<char> &out, const Object &object)
}
} // namespace json
+} // namespace util
} // namespace osrm
+
#endif // JSON_RENDERER_HPP
diff --git a/include/util/json_util.hpp b/include/util/json_util.hpp
new file mode 100644
index 0000000..32a1bd7
--- /dev/null
+++ b/include/util/json_util.hpp
@@ -0,0 +1,58 @@
+#ifndef JSON_UTIL_HPP
+#define JSON_UTIL_HPP
+
+#include "osrm/json_container.hpp"
+#include "util/container.hpp"
+
+#include <cmath>
+#include <limits>
+
+namespace osrm
+{
+namespace util
+{
+namespace json
+{
+// Make sure we don't have inf and NaN values
+template <typename T> T clamp_float(T d)
+{
+ if (std::isnan(d) || std::numeric_limits<T>::infinity() == d)
+ {
+ return std::numeric_limits<T>::max();
+ }
+ if (-std::numeric_limits<T>::infinity() == d)
+ {
+ return std::numeric_limits<T>::lowest();
+ }
+
+ return d;
+}
+
+template <typename... Args> Array make_array(Args... args)
+{
+ Array a;
+ // TODO: check why a.values.emplace_back(args...); is not an option here
+ append_to_container(a.values, args...);
+ return a;
+}
+
+// Easy acces to object hierachies
+inline Value &get(Value &value) { return value; }
+
+template <typename... Keys> Value &get(Value &value, const char *key, Keys... keys)
+{
+ using recursive_object_t = mapbox::util::recursive_wrapper<Object>;
+ return get(value.get<recursive_object_t>().get().values[key], keys...);
+}
+
+template <typename... Keys> Value &get(Value &value, unsigned key, Keys... keys)
+{
+ using recursive_array_t = mapbox::util::recursive_wrapper<Array>;
+ return get(value.get<recursive_array_t>().get().values[key], keys...);
+}
+
+} // namespace json
+} // namespace util
+} // namespace osrm
+
+#endif // JSON_UTIL_HPP
diff --git a/include/util/lua_util.hpp b/include/util/lua_util.hpp
new file mode 100644
index 0000000..4d4fe17
--- /dev/null
+++ b/include/util/lua_util.hpp
@@ -0,0 +1,54 @@
+#ifndef LUA_UTIL_HPP
+#define LUA_UTIL_HPP
+
+extern "C" {
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+}
+
+#include <boost/filesystem/convenience.hpp>
+#include <luabind/luabind.hpp>
+
+#include <iostream>
+#include <string>
+
+namespace osrm
+{
+namespace util
+{
+
+struct LuaState
+{
+ LuaState() : handle{::luaL_newstate(), &::lua_close} { luaL_openlibs(*this); }
+
+ operator lua_State *() { return handle.get(); }
+ operator lua_State const *() const { return handle.get(); }
+
+ using handle_type = std::unique_ptr<lua_State, decltype(&::lua_close)>;
+ handle_type handle;
+};
+
+// Check if the lua function <name> is defined
+inline bool luaFunctionExists(lua_State *lua_state, const char *name)
+{
+ luabind::object globals_table = luabind::globals(lua_state);
+ luabind::object lua_function = globals_table[name];
+ return lua_function && (luabind::type(lua_function) == LUA_TFUNCTION);
+}
+
+// Add the folder contain the script to the lua load path, so script can easily require() other lua
+// scripts inside that folder, or subfolders.
+// See http://lua-users.org/wiki/PackagePath for details on the package.path syntax.
+inline void luaAddScriptFolderToLoadPath(lua_State *lua_state, const char *file_name)
+{
+ boost::filesystem::path profile_path = boost::filesystem::canonical(file_name);
+ std::string folder = profile_path.parent_path().string();
+ // TODO: This code is most probably not Windows safe since it uses UNIX'ish path delimiters
+ const std::string lua_code = "package.path = \"" + folder + "/?.lua;\" .. package.path";
+ luaL_dostring(lua_state, lua_code.c_str());
+}
+}
+}
+
+#endif // LUA_UTIL_HPP
diff --git a/util/make_unique.hpp b/include/util/make_unique.hpp
similarity index 51%
rename from util/make_unique.hpp
rename to include/util/make_unique.hpp
index 83e2301..74d4e3d 100644
--- a/util/make_unique.hpp
+++ b/include/util/make_unique.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef MAKE_UNIQUE_H_
#define MAKE_UNIQUE_H_
@@ -34,6 +7,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace osrm
{
+namespace util
+{
+
// Implement make_unique according to N3656. Taken from libcxx's implementation
/// \brief Constructs a `new T()` with the given args and returns a
@@ -70,4 +46,6 @@ make_unique(size_t n)
template <class T, class... Args>
typename std::enable_if<std::extent<T>::value != 0>::type make_unique(Args &&...) = delete;
}
+}
+
#endif // MAKE_UNIQUE_H_
diff --git a/include/util/matrix_graph_wrapper.hpp b/include/util/matrix_graph_wrapper.hpp
new file mode 100644
index 0000000..3b4ee5c
--- /dev/null
+++ b/include/util/matrix_graph_wrapper.hpp
@@ -0,0 +1,51 @@
+#ifndef MATRIX_GRAPH_WRAPPER_H
+#define MATRIX_GRAPH_WRAPPER_H
+
+#include <vector>
+#include <cstddef>
+#include <iterator>
+
+#include "util/typedefs.hpp"
+
+namespace osrm
+{
+namespace util
+{
+
+// This Wrapper provides all methods that are needed for extractor::TarjanSCC, when the graph is
+// given in a
+// matrix representation (e.g. as output from a distance table call)
+
+template <typename T> class MatrixGraphWrapper
+{
+ public:
+ MatrixGraphWrapper(std::vector<T> table, const std::size_t number_of_nodes)
+ : table_(std::move(table)), number_of_nodes_(number_of_nodes){}
+
+ std::size_t GetNumberOfNodes() const { return number_of_nodes_; }
+
+ std::vector<T> GetAdjacentEdgeRange(const NodeID node) const
+ {
+
+ std::vector<T> edges;
+ // find all valid adjacent edges and move to vector `edges`
+ for (std::size_t i = 0; i < number_of_nodes_; ++i)
+ {
+ if (*(std::begin(table_) + node * number_of_nodes_ + i) != INVALID_EDGE_WEIGHT)
+ {
+ edges.push_back(i);
+ }
+ }
+ return edges;
+ }
+
+ EdgeWeight GetTarget(const EdgeWeight edge) const { return edge; }
+
+ private:
+ const std::vector<T> table_;
+ const std::size_t number_of_nodes_;
+};
+}
+}
+
+#endif // MATRIX_GRAPH_WRAPPER_H
diff --git a/include/util/name_table.hpp b/include/util/name_table.hpp
new file mode 100644
index 0000000..2f1887a
--- /dev/null
+++ b/include/util/name_table.hpp
@@ -0,0 +1,31 @@
+#ifndef OSRM_UTIL_NAME_TABLE_HPP
+#define OSRM_UTIL_NAME_TABLE_HPP
+
+#include "util/shared_memory_vector_wrapper.hpp"
+#include "util/range_table.hpp"
+
+#include <string>
+
+namespace osrm
+{
+namespace util
+{
+
+// While this could, theoretically, hold any names in the fitting format,
+// the NameTable allows access to a part of the Datafacade to allow
+// processing based on name indices.
+class NameTable
+{
+ private:
+ // FIXME should this use shared memory
+ RangeTable<16, false> m_name_table;
+ ShM<char, false>::vector m_names_char_list;
+
+ public:
+ NameTable(const std::string &filename);
+ std::string GetNameForID(const unsigned name_id) const;
+};
+} // namespace util
+} // namespace osrm
+
+#endif // OSRM_UTIL_NAME_TABLE_HPP
diff --git a/include/util/node_based_graph.hpp b/include/util/node_based_graph.hpp
new file mode 100644
index 0000000..463fbb1
--- /dev/null
+++ b/include/util/node_based_graph.hpp
@@ -0,0 +1,95 @@
+#ifndef NODE_BASED_GRAPH_HPP
+#define NODE_BASED_GRAPH_HPP
+
+#include "util/dynamic_graph.hpp"
+#include "extractor/node_based_edge.hpp"
+#include "util/graph_utils.hpp"
+#include "extractor/guidance/classification_data.hpp"
+
+#include <tbb/parallel_sort.h>
+
+#include <memory>
+
+namespace osrm
+{
+namespace util
+{
+
+struct NodeBasedEdgeData
+{
+ NodeBasedEdgeData()
+ : distance(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID),
+ name_id(std::numeric_limits<unsigned>::max()), access_restricted(false), reversed(false),
+ roundabout(false), travel_mode(TRAVEL_MODE_INACCESSIBLE)
+ {
+ }
+
+ NodeBasedEdgeData(int distance,
+ unsigned edge_id,
+ unsigned name_id,
+ bool access_restricted,
+ bool reversed,
+ bool roundabout,
+ bool startpoint,
+ extractor::TravelMode travel_mode)
+ : distance(distance), edge_id(edge_id), name_id(name_id),
+ access_restricted(access_restricted), reversed(reversed), roundabout(roundabout),
+ startpoint(startpoint), travel_mode(travel_mode)
+ {
+ }
+
+ int distance;
+ unsigned edge_id;
+ unsigned name_id;
+ bool access_restricted : 1;
+ bool reversed : 1;
+ bool roundabout : 1;
+ bool startpoint : 1;
+ extractor::TravelMode travel_mode : 4;
+ extractor::guidance::RoadClassificationData road_classification;
+
+ bool IsCompatibleTo(const NodeBasedEdgeData &other) const
+ {
+ return (name_id == other.name_id) && (reversed == other.reversed) &&
+ (roundabout == other.roundabout) && (startpoint == other.startpoint) &&
+ (access_restricted == other.access_restricted) &&
+ (travel_mode == other.travel_mode) &&
+ (road_classification == other.road_classification);
+ }
+};
+
+using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
+
+/// Factory method to create NodeBasedDynamicGraph from NodeBasedEdges
+/// Since DynamicGraph expects directed edges, we need to insert
+/// two edges for undirected edges.
+inline std::shared_ptr<NodeBasedDynamicGraph>
+NodeBasedDynamicGraphFromEdges(std::size_t number_of_nodes,
+ const std::vector<extractor::NodeBasedEdge> &input_edge_list)
+{
+ auto edges_list = directedEdgesFromCompressed<NodeBasedDynamicGraph::InputEdge>(
+ input_edge_list, [](NodeBasedDynamicGraph::InputEdge &output_edge,
+ const extractor::NodeBasedEdge &input_edge)
+ {
+ output_edge.data.distance = static_cast<int>(input_edge.weight);
+ BOOST_ASSERT(output_edge.data.distance > 0);
+
+ output_edge.data.roundabout = input_edge.roundabout;
+ output_edge.data.name_id = input_edge.name_id;
+ output_edge.data.access_restricted = input_edge.access_restricted;
+ output_edge.data.travel_mode = input_edge.travel_mode;
+ output_edge.data.startpoint = input_edge.startpoint;
+ output_edge.data.road_classification = input_edge.road_classification;
+ });
+
+ tbb::parallel_sort(edges_list.begin(), edges_list.end());
+
+ auto graph = std::make_shared<NodeBasedDynamicGraph>(
+ static_cast<NodeBasedDynamicGraph::NodeIterator>(number_of_nodes), edges_list);
+
+ return graph;
+}
+}
+}
+
+#endif // NODE_BASED_GRAPH_HPP
diff --git a/data_structures/percent.hpp b/include/util/percent.hpp
similarity index 57%
rename from data_structures/percent.hpp
rename to include/util/percent.hpp
index 392417e..d34a77d 100644
--- a/data_structures/percent.hpp
+++ b/include/util/percent.hpp
@@ -1,36 +1,14 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef PERCENT_HPP
#define PERCENT_HPP
#include <iostream>
#include <atomic>
+namespace osrm
+{
+namespace util
+{
+
class Percent
{
public:
@@ -97,5 +75,7 @@ class Percent
}
}
};
+}
+}
#endif // PERCENT_HPP
diff --git a/data_structures/range_table.hpp b/include/util/range_table.hpp
similarity index 81%
rename from data_structures/range_table.hpp
rename to include/util/range_table.hpp
index e750c90..f012349 100644
--- a/data_structures/range_table.hpp
+++ b/include/util/range_table.hpp
@@ -1,39 +1,17 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef RANGE_TABLE_HPP
#define RANGE_TABLE_HPP
-#include "../util/integer_range.hpp"
-#include "shared_memory_factory.hpp"
-#include "shared_memory_vector_wrapper.hpp"
+#include "util/integer_range.hpp"
+#include "util/shared_memory_vector_wrapper.hpp"
#include <fstream>
#include <array>
+#include <utility>
+
+namespace osrm
+{
+namespace util
+{
/*
* These pre-declarations are needed because parsing C++ is hard
* and otherwise the compiler gets confused.
@@ -62,7 +40,7 @@ template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY> class RangeTable
using BlockT = std::array<unsigned char, BLOCK_SIZE>;
using BlockContainerT = typename ShM<BlockT, USE_SHARED_MEMORY>::vector;
using OffsetContainerT = typename ShM<unsigned, USE_SHARED_MEMORY>::vector;
- using RangeT = osrm::range<unsigned>;
+ using RangeT = range<unsigned>;
friend std::ostream &operator<<<>(std::ostream &out, const RangeTable &table);
friend std::istream &operator>><>(std::istream &in, RangeTable &table);
@@ -75,13 +53,13 @@ template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY> class RangeTable
const unsigned sum_lengths)
: sum_lengths(sum_lengths)
{
- block_offsets.swap(external_offsets);
- diff_blocks.swap(external_blocks);
+ using std::swap;
+ swap(block_offsets, external_offsets);
+ swap(diff_blocks, external_blocks);
}
// construct table from length vector
- template<typename VectorT>
- explicit RangeTable(const VectorT &lengths)
+ template <typename VectorT> explicit RangeTable(const VectorT &lengths)
{
const unsigned number_of_blocks = [&lengths]()
{
@@ -194,7 +172,7 @@ template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY> class RangeTable
BOOST_ASSERT(begin_idx < sum_lengths && end_idx <= sum_lengths);
BOOST_ASSERT(begin_idx <= end_idx);
- return osrm::irange(begin_idx, end_idx);
+ return irange(begin_idx, end_idx);
}
private:
@@ -256,5 +234,7 @@ std::istream &operator>>(std::istream &in, RangeTable<BLOCK_SIZE, USE_SHARED_MEM
in.read((char *)table.diff_blocks.data(), BLOCK_SIZE * number_of_blocks);
return in;
}
+}
+}
#endif // RANGE_TABLE_HPP
diff --git a/include/util/rectangle.hpp b/include/util/rectangle.hpp
new file mode 100644
index 0000000..fd0f871
--- /dev/null
+++ b/include/util/rectangle.hpp
@@ -0,0 +1,182 @@
+#ifndef RECTANGLE_HPP
+#define RECTANGLE_HPP
+
+#include "util/coordinate_calculation.hpp"
+
+#include <boost/assert.hpp>
+
+#include "osrm/coordinate.hpp"
+
+#include <iomanip>
+#include <algorithm>
+#include <utility>
+#include <limits>
+
+#include <cstdint>
+
+namespace osrm
+{
+namespace util
+{
+
+// TODO: Make template type, add tests
+struct RectangleInt2D
+{
+ RectangleInt2D()
+ : min_lon(std::numeric_limits<std::int32_t>::max()),
+ max_lon(std::numeric_limits<std::int32_t>::min()),
+ min_lat(std::numeric_limits<std::int32_t>::max()),
+ max_lat(std::numeric_limits<std::int32_t>::min())
+ {
+ }
+
+ RectangleInt2D(FixedLongitude min_lon_,
+ FixedLongitude max_lon_,
+ FixedLatitude min_lat_,
+ FixedLatitude max_lat_)
+ : min_lon(min_lon_), max_lon(max_lon_), min_lat(min_lat_), max_lat(max_lat_)
+ {
+ }
+
+ RectangleInt2D(FloatLongitude min_lon_,
+ FloatLongitude max_lon_,
+ FloatLatitude min_lat_,
+ FloatLatitude max_lat_)
+ : min_lon(toFixed(min_lon_)), max_lon(toFixed(max_lon_)), min_lat(toFixed(min_lat_)),
+ max_lat(toFixed(max_lat_))
+ {
+ }
+
+ FixedLongitude min_lon, max_lon;
+ FixedLatitude min_lat, max_lat;
+
+ void MergeBoundingBoxes(const RectangleInt2D &other)
+ {
+ min_lon = std::min(min_lon, other.min_lon);
+ max_lon = std::max(max_lon, other.max_lon);
+ min_lat = std::min(min_lat, other.min_lat);
+ max_lat = std::max(max_lat, other.max_lat);
+ BOOST_ASSERT(min_lon != FixedLongitude(std::numeric_limits<std::int32_t>::min()));
+ BOOST_ASSERT(min_lat != FixedLatitude(std::numeric_limits<std::int32_t>::min()));
+ BOOST_ASSERT(max_lon != FixedLongitude(std::numeric_limits<std::int32_t>::min()));
+ BOOST_ASSERT(max_lat != FixedLatitude(std::numeric_limits<std::int32_t>::min()));
+ }
+
+ Coordinate Centroid() const
+ {
+ Coordinate centroid;
+ // The coordinates of the midpoints are given by:
+ // x = (x1 + x2) /2 and y = (y1 + y2) /2.
+ centroid.lon = (min_lon + max_lon) / FixedLongitude(2);
+ centroid.lat = (min_lat + max_lat) / FixedLatitude(2);
+ return centroid;
+ }
+
+ bool Intersects(const RectangleInt2D &other) const
+ {
+ // Standard box intersection test - check if boxes *don't* overlap,
+ // and return the negative of that
+ return !(max_lon < other.min_lon || min_lon > other.max_lon || max_lat < other.min_lat ||
+ min_lat > other.max_lat);
+ }
+
+ // This code assumes that we are operating in euclidean space!
+ // That means if you just put unprojected lat/lon in here you will
+ // get invalid results.
+ double GetMinSquaredDist(const Coordinate location) const
+ {
+ const bool is_contained = Contains(location);
+ if (is_contained)
+ {
+ return 0.0f;
+ }
+
+ enum Direction
+ {
+ INVALID = 0,
+ NORTH = 1,
+ SOUTH = 2,
+ EAST = 4,
+ NORTH_EAST = 5,
+ SOUTH_EAST = 6,
+ WEST = 8,
+ NORTH_WEST = 9,
+ SOUTH_WEST = 10
+ };
+
+ Direction d = INVALID;
+ if (location.lat > max_lat)
+ d = (Direction)(d | NORTH);
+ else if (location.lat < min_lat)
+ d = (Direction)(d | SOUTH);
+ if (location.lon > max_lon)
+ d = (Direction)(d | EAST);
+ else if (location.lon < min_lon)
+ d = (Direction)(d | WEST);
+
+ BOOST_ASSERT(d != INVALID);
+
+ double min_dist = std::numeric_limits<double>::max();
+ switch (d)
+ {
+ case NORTH:
+ min_dist = coordinate_calculation::squaredEuclideanDistance(
+ location, Coordinate(location.lon, max_lat));
+ break;
+ case SOUTH:
+ min_dist = coordinate_calculation::squaredEuclideanDistance(
+ location, Coordinate(location.lon, min_lat));
+ break;
+ case WEST:
+ min_dist = coordinate_calculation::squaredEuclideanDistance(
+ location, Coordinate(min_lon, location.lat));
+ break;
+ case EAST:
+ min_dist = coordinate_calculation::squaredEuclideanDistance(
+ location, Coordinate(max_lon, location.lat));
+ break;
+ case NORTH_EAST:
+ min_dist =
+ coordinate_calculation::squaredEuclideanDistance(location, Coordinate(max_lon, max_lat));
+ break;
+ case NORTH_WEST:
+ min_dist =
+ coordinate_calculation::squaredEuclideanDistance(location, Coordinate(min_lon, max_lat));
+ break;
+ case SOUTH_EAST:
+ min_dist =
+ coordinate_calculation::squaredEuclideanDistance(location, Coordinate(max_lon, min_lat));
+ break;
+ case SOUTH_WEST:
+ min_dist =
+ coordinate_calculation::squaredEuclideanDistance(location, Coordinate(min_lon, min_lat));
+ break;
+ default:
+ break;
+ }
+
+ BOOST_ASSERT(min_dist < std::numeric_limits<double>::max());
+
+ return min_dist;
+ }
+
+ bool Contains(const Coordinate location) const
+ {
+ const bool lons_contained = (location.lon >= min_lon) && (location.lon <= max_lon);
+ const bool lats_contained = (location.lat >= min_lat) && (location.lat <= max_lat);
+ return lons_contained && lats_contained;
+ }
+
+ friend std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect);
+};
+inline std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect)
+{
+ out << std::setprecision(12) << "(" << toFloating(rect.min_lon) << ","
+ << toFloating(rect.max_lon) << "," << toFloating(rect.min_lat) << ","
+ << toFloating(rect.max_lat) << ")";
+ return out;
+}
+}
+}
+
+#endif
diff --git a/data_structures/shared_memory_vector_wrapper.hpp b/include/util/shared_memory_vector_wrapper.hpp
similarity index 61%
rename from data_structures/shared_memory_vector_wrapper.hpp
rename to include/util/shared_memory_vector_wrapper.hpp
index dc51cff..74f4a8e 100644
--- a/data_structures/shared_memory_vector_wrapper.hpp
+++ b/include/util/shared_memory_vector_wrapper.hpp
@@ -1,39 +1,20 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef SHARED_MEMORY_VECTOR_WRAPPER_HPP
#define SHARED_MEMORY_VECTOR_WRAPPER_HPP
#include <boost/assert.hpp>
+#include <cstddef>
+
#include <algorithm>
#include <iterator>
#include <type_traits>
#include <vector>
+#include <utility>
+
+namespace osrm
+{
+namespace util
+{
template <typename DataT> class ShMemIterator : public std::iterator<std::input_iterator_tag, DataT>
{
@@ -74,13 +55,6 @@ template <typename DataT> class SharedMemoryWrapper
SharedMemoryWrapper(DataT *ptr, std::size_t size) : m_ptr(ptr), m_size(size) {}
- void swap(SharedMemoryWrapper<DataT> &other)
- {
- // BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
- std::swap(m_size, other.m_size);
- std::swap(m_ptr, other.m_ptr);
- }
-
DataT &at(const std::size_t index) { return m_ptr[index]; }
const DataT &at(const std::size_t index) const { return m_ptr[index]; }
@@ -104,6 +78,9 @@ template <typename DataT> class SharedMemoryWrapper
BOOST_ASSERT_MSG(index < m_size, "invalid size");
return m_ptr[index];
}
+
+ template <typename T>
+ friend void swap(SharedMemoryWrapper<T> &, SharedMemoryWrapper<T> &) noexcept;
};
template <> class SharedMemoryWrapper<bool>
@@ -117,18 +94,11 @@ template <> class SharedMemoryWrapper<bool>
SharedMemoryWrapper(unsigned *ptr, std::size_t size) : m_ptr(ptr), m_size(size) {}
- void swap(SharedMemoryWrapper<bool> &other)
- {
- // BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
- std::swap(m_size, other.m_size);
- std::swap(m_ptr, other.m_ptr);
- }
-
bool at(const std::size_t index) const
{
const std::size_t bucket = index / 32;
const unsigned offset = static_cast<unsigned>(index % 32);
- return m_ptr[bucket] & (1 << offset);
+ return m_ptr[bucket] & (1u << offset);
}
std::size_t size() const { return m_size; }
@@ -140,15 +110,28 @@ template <> class SharedMemoryWrapper<bool>
BOOST_ASSERT_MSG(index < m_size, "invalid size");
const unsigned bucket = index / 32;
const unsigned offset = index % 32;
- return m_ptr[bucket] & (1 << offset);
+ return m_ptr[bucket] & (1u << offset);
}
+
+ template <typename T>
+ friend void swap(SharedMemoryWrapper<T> &, SharedMemoryWrapper<T> &) noexcept;
};
+// Both SharedMemoryWrapper<T> and the SharedMemoryWrapper<bool> specializations share this impl.
+template <typename DataT>
+void swap(SharedMemoryWrapper<DataT> &lhs, SharedMemoryWrapper<DataT> &rhs) noexcept
+{
+ std::swap(lhs.m_ptr, rhs.m_ptr);
+ std::swap(lhs.m_size, rhs.m_size);
+}
+
template <typename DataT, bool UseSharedMemory> struct ShM
{
using vector = typename std::conditional<UseSharedMemory,
SharedMemoryWrapper<DataT>,
std::vector<DataT>>::type;
};
+}
+}
#endif // SHARED_MEMORY_VECTOR_WRAPPER_HPP
diff --git a/include/util/simple_logger.hpp b/include/util/simple_logger.hpp
new file mode 100644
index 0000000..f71f0ff
--- /dev/null
+++ b/include/util/simple_logger.hpp
@@ -0,0 +1,55 @@
+#ifndef SIMPLE_LOGGER_HPP
+#define SIMPLE_LOGGER_HPP
+
+#include <atomic>
+#include <mutex>
+#include <sstream>
+
+enum LogLevel
+{
+ logINFO,
+ logWARNING,
+ logDEBUG
+};
+
+namespace osrm
+{
+namespace util
+{
+
+class LogPolicy
+{
+ public:
+ void Unmute();
+
+ void Mute();
+
+ bool IsMute() const;
+
+ static LogPolicy &GetInstance();
+
+ LogPolicy(const LogPolicy &) = delete;
+ LogPolicy &operator=(const LogPolicy &) = delete;
+
+ private:
+ LogPolicy() : m_is_mute(true) {}
+ std::atomic<bool> m_is_mute;
+};
+
+class SimpleLogger
+{
+ public:
+ SimpleLogger();
+
+ virtual ~SimpleLogger();
+ std::mutex &get_mutex();
+ std::ostringstream &Write(LogLevel l = logINFO) noexcept;
+
+ private:
+ std::ostringstream os;
+ LogLevel level;
+};
+}
+}
+
+#endif /* SIMPLE_LOGGER_HPP */
diff --git a/data_structures/static_graph.hpp b/include/util/static_graph.hpp
similarity index 70%
rename from data_structures/static_graph.hpp
rename to include/util/static_graph.hpp
index 3b8f927..a4fa2d7 100644
--- a/data_structures/static_graph.hpp
+++ b/include/util/static_graph.hpp
@@ -1,37 +1,10 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef STATIC_GRAPH_HPP
#define STATIC_GRAPH_HPP
-#include "percent.hpp"
-#include "shared_memory_vector_wrapper.hpp"
-#include "../util/integer_range.hpp"
-#include "../typedefs.h"
+#include "util/percent.hpp"
+#include "util/shared_memory_vector_wrapper.hpp"
+#include "util/integer_range.hpp"
+#include "util/typedefs.hpp"
#include <boost/assert.hpp>
@@ -40,13 +13,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <utility>
#include <vector>
+namespace osrm
+{
+namespace util
+{
+
template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
{
public:
using NodeIterator = NodeID;
using EdgeIterator = NodeID;
using EdgeData = EdgeDataT;
- using EdgeRange = osrm::range<EdgeIterator>;
+ using EdgeRange = range<EdgeIterator>;
class InputEdge
{
@@ -84,20 +62,20 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
EdgeRange GetAdjacentEdgeRange(const NodeID node) const
{
- return osrm::irange(BeginEdges(node), EndEdges(node));
+ return irange(BeginEdges(node), EndEdges(node));
}
- template<typename ContainerT>
- StaticGraph(const int nodes, const ContainerT &graph)
+ template <typename ContainerT> StaticGraph(const int nodes, const ContainerT &graph)
{
- BOOST_ASSERT(std::is_sorted(const_cast<ContainerT&>(graph).begin(), const_cast<ContainerT&>(graph).end()));
+ BOOST_ASSERT(std::is_sorted(const_cast<ContainerT &>(graph).begin(),
+ const_cast<ContainerT &>(graph).end()));
number_of_nodes = nodes;
number_of_edges = static_cast<EdgeIterator>(graph.size());
node_array.resize(number_of_nodes + 1);
EdgeIterator edge = 0;
EdgeIterator position = 0;
- for (const auto node : osrm::irange(0u, number_of_nodes + 1))
+ for (const auto node : irange(0u, number_of_nodes + 1))
{
EdgeIterator last_edge = edge;
while (edge < number_of_edges && graph[edge].source == node)
@@ -109,10 +87,10 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
}
edge_array.resize(position); //(edge)
edge = 0;
- for (const auto node : osrm::irange(0u, number_of_nodes))
+ for (const auto node : irange(0u, number_of_nodes))
{
EdgeIterator e = node_array[node + 1].first_edge;
- for (const auto i : osrm::irange(node_array[node].first_edge, e))
+ for (const auto i : irange(node_array[node].first_edge, e))
{
edge_array[i].target = graph[edge].target;
edge_array[i].data = graph[edge].data;
@@ -127,8 +105,9 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
number_of_nodes = static_cast<decltype(number_of_nodes)>(nodes.size() - 1);
number_of_edges = static_cast<decltype(number_of_edges)>(edges.size());
- node_array.swap(nodes);
- edge_array.swap(edges);
+ using std::swap;
+ swap(node_array, nodes);
+ swap(edge_array, edges);
}
unsigned GetNumberOfNodes() const { return number_of_nodes; }
@@ -159,7 +138,7 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
// searches for a specific edge
EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
{
- for (const auto i : osrm::irange(BeginEdges(from), EndEdges(from)))
+ for (const auto i : irange(BeginEdges(from), EndEdges(from)))
{
if (to == edge_array[i].target)
{
@@ -215,5 +194,7 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
typename ShM<NodeArrayEntry, UseSharedMemory>::vector node_array;
typename ShM<EdgeArrayEntry, UseSharedMemory>::vector edge_array;
};
+}
+}
#endif // STATIC_GRAPH_HPP
diff --git a/data_structures/static_rtree.hpp b/include/util/static_rtree.hpp
similarity index 53%
rename from data_structures/static_rtree.hpp
rename to include/util/static_rtree.hpp
index 6bc3678..6924d94 100644
--- a/data_structures/static_rtree.hpp
+++ b/include/util/static_rtree.hpp
@@ -1,46 +1,17 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef STATIC_RTREE_HPP
#define STATIC_RTREE_HPP
-#include "deallocating_vector.hpp"
-#include "hilbert_value.hpp"
-#include "rectangle.hpp"
-#include "shared_memory_factory.hpp"
-#include "shared_memory_vector_wrapper.hpp"
+#include "util/deallocating_vector.hpp"
+#include "util/hilbert_value.hpp"
+#include "util/rectangle.hpp"
+#include "util/shared_memory_vector_wrapper.hpp"
-#include "../util/bearing.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/mercator.hpp"
-#include "../util/osrm_exception.hpp"
-#include "../typedefs.h"
+#include "util/bearing.hpp"
+#include "util/integer_range.hpp"
+#include "util/exception.hpp"
+#include "util/typedefs.hpp"
-#include <osrm/coordinate.hpp>
+#include "osrm/coordinate.hpp"
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
@@ -59,12 +30,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
#include <vector>
+namespace osrm
+{
+namespace util
+{
+
// Static RTree for serving nearest neighbour queries
+// All coordinates are pojected first to Web Mercator before the bounding boxes
+// are computed, this means the internal distance metric doesn not represent meters!
template <class EdgeDataT,
- class CoordinateListT = std::vector<FixedPointCoordinate>,
+ class CoordinateListT = std::vector<Coordinate>,
bool UseSharedMemory = false,
- uint32_t BRANCHING_FACTOR = 64,
- uint32_t LEAF_NODE_SIZE = 1024>
+ std::uint32_t BRANCHING_FACTOR = 64,
+ std::uint32_t LEAF_NODE_SIZE = 1024>
class StaticRTree
{
public:
@@ -72,21 +50,33 @@ class StaticRTree
using EdgeData = EdgeDataT;
using CoordinateList = CoordinateListT;
- static constexpr std::size_t MAX_CHECKED_ELEMENTS = 4 * LEAF_NODE_SIZE;
+ struct CandidateSegment
+ {
+ Coordinate fixed_projected_coordinate;
+ EdgeDataT data;
+ };
struct TreeNode
{
TreeNode() : child_count(0), child_is_on_disk(false) {}
Rectangle minimum_bounding_rectangle;
- uint32_t child_count : 31;
+ std::uint32_t child_count : 31;
bool child_is_on_disk : 1;
- uint32_t children[BRANCHING_FACTOR];
+ std::uint32_t children[BRANCHING_FACTOR];
+ };
+
+ struct LeafNode
+ {
+ LeafNode() : object_count(0), objects() {}
+ uint32_t object_count;
+ std::array<EdgeDataT, LEAF_NODE_SIZE> objects;
};
private:
struct WrappedInputElement
{
- explicit WrappedInputElement(const uint64_t _hilbert_value, const uint32_t _array_index)
+ explicit WrappedInputElement(const uint64_t _hilbert_value,
+ const std::uint32_t _array_index)
: m_hilbert_value(_hilbert_value), m_array_index(_array_index)
{
}
@@ -94,7 +84,7 @@ class StaticRTree
WrappedInputElement() : m_hilbert_value(0), m_array_index(UINT_MAX) {}
uint64_t m_hilbert_value;
- uint32_t m_array_index;
+ std::uint32_t m_array_index;
inline bool operator<(const WrappedInputElement &other) const
{
@@ -102,23 +92,16 @@ class StaticRTree
}
};
- struct LeafNode
- {
- LeafNode() : object_count(0), objects() {}
- uint32_t object_count;
- std::array<EdgeDataT, LEAF_NODE_SIZE> objects;
- };
-
- using QueryNodeType = mapbox::util::variant<TreeNode, EdgeDataT>;
+ using QueryNodeType = mapbox::util::variant<TreeNode, CandidateSegment>;
struct QueryCandidate
{
inline bool operator<(const QueryCandidate &other) const
{
// Attn: this is reversed order. std::pq is a max pq!
- return other.min_dist < min_dist;
+ return other.squared_min_dist < squared_min_dist;
}
- float min_dist;
+ double squared_min_dist;
QueryNodeType node;
};
@@ -129,8 +112,8 @@ class StaticRTree
boost::filesystem::ifstream leaves_stream;
public:
- StaticRTree() = delete;
StaticRTree(const StaticRTree &) = delete;
+ StaticRTree &operator=(const StaticRTree &) = delete;
template <typename CoordinateT>
// Construct a packed Hilbert-R-Tree with Kamel-Faloutsos algorithm [1]
@@ -142,12 +125,10 @@ class StaticRTree
{
std::vector<WrappedInputElement> input_wrapper_vector(m_element_count);
- HilbertCode get_hilbert_number;
-
// generate auxiliary vector of hilbert-values
tbb::parallel_for(
tbb::blocked_range<uint64_t>(0, m_element_count),
- [&input_data_vector, &input_wrapper_vector, &get_hilbert_number,
+ [&input_data_vector, &input_wrapper_vector,
&coordinate_list](const tbb::blocked_range<uint64_t> &range)
{
for (uint64_t element_counter = range.begin(), end = range.end();
@@ -159,16 +140,16 @@ class StaticRTree
EdgeDataT const ¤t_element = input_data_vector[element_counter];
// Get Hilbert-Value for centroid in mercartor projection
- FixedPointCoordinate current_centroid = EdgeDataT::Centroid(
- FixedPointCoordinate(coordinate_list.at(current_element.u).lat,
- coordinate_list.at(current_element.u).lon),
- FixedPointCoordinate(coordinate_list.at(current_element.v).lat,
- coordinate_list.at(current_element.v).lon));
- current_centroid.lat =
+ BOOST_ASSERT(current_element.u < coordinate_list.size());
+ BOOST_ASSERT(current_element.v < coordinate_list.size());
+
+ Coordinate current_centroid = coordinate_calculation::centroid(
+ coordinate_list[current_element.u], coordinate_list[current_element.v]);
+ current_centroid.lat = FixedLatitude(
COORDINATE_PRECISION *
- mercator::lat2y(current_centroid.lat / COORDINATE_PRECISION);
+ coordinate_calculation::mercator::latToY(toFloating(current_centroid.lat)));
- current_wrapper.m_hilbert_value = get_hilbert_number(current_centroid);
+ current_wrapper.m_hilbert_value = hilbertCode(current_centroid);
}
});
@@ -187,12 +168,12 @@ class StaticRTree
LeafNode current_leaf;
TreeNode current_node;
- for (uint32_t current_element_index = 0; LEAF_NODE_SIZE > current_element_index;
+ for (std::uint32_t current_element_index = 0; LEAF_NODE_SIZE > current_element_index;
++current_element_index)
{
if (m_element_count > (processed_objects_count + current_element_index))
{
- uint32_t index_of_next_object =
+ std::uint32_t index_of_next_object =
input_wrapper_vector[processed_objects_count + current_element_index]
.m_array_index;
current_leaf.objects[current_element_index] =
@@ -213,19 +194,16 @@ class StaticRTree
processed_objects_count += current_leaf.object_count;
}
- // close leaf file
- leaf_node_file.close();
-
- uint32_t processing_level = 0;
+ std::uint32_t processing_level = 0;
while (1 < tree_nodes_in_level.size())
{
std::vector<TreeNode> tree_nodes_in_next_level;
- uint32_t processed_tree_nodes_in_level = 0;
+ std::uint32_t processed_tree_nodes_in_level = 0;
while (processed_tree_nodes_in_level < tree_nodes_in_level.size())
{
TreeNode parent_node;
// pack BRANCHING_FACTOR elements into tree_nodes each
- for (uint32_t current_child_node_index = 0;
+ for (std::uint32_t current_child_node_index = 0;
BRANCHING_FACTOR > current_child_node_index; ++current_child_node_index)
{
if (processed_tree_nodes_in_level < tree_nodes_in_level.size())
@@ -255,17 +233,18 @@ class StaticRTree
// reverse and renumber tree to have root at index 0
std::reverse(m_search_tree.begin(), m_search_tree.end());
- uint32_t search_tree_size = m_search_tree.size();
- tbb::parallel_for(tbb::blocked_range<uint32_t>(0, search_tree_size),
- [this, &search_tree_size](const tbb::blocked_range<uint32_t> &range)
+ std::uint32_t search_tree_size = m_search_tree.size();
+ tbb::parallel_for(tbb::blocked_range<std::uint32_t>(0, search_tree_size),
+ [this, &search_tree_size](const tbb::blocked_range<std::uint32_t> &range)
{
- for (uint32_t i = range.begin(), end = range.end(); i != end; ++i)
+ for (std::uint32_t i = range.begin(), end = range.end(); i != end;
+ ++i)
{
TreeNode ¤t_tree_node = this->m_search_tree[i];
- for (uint32_t j = 0; j < current_tree_node.child_count; ++j)
+ for (std::uint32_t j = 0; j < current_tree_node.child_count; ++j)
{
- const uint32_t old_id = current_tree_node.children[j];
- const uint32_t new_id = search_tree_size - old_id - 1;
+ const std::uint32_t old_id = current_tree_node.children[j];
+ const std::uint32_t new_id = search_tree_size - old_id - 1;
current_tree_node.children[j] = new_id;
}
}
@@ -274,12 +253,10 @@ class StaticRTree
// open tree file
boost::filesystem::ofstream tree_node_file(tree_node_filename, std::ios::binary);
- uint32_t size_of_tree = m_search_tree.size();
+ std::uint32_t size_of_tree = m_search_tree.size();
BOOST_ASSERT_MSG(0 < size_of_tree, "tree empty");
- tree_node_file.write((char *)&size_of_tree, sizeof(uint32_t));
+ tree_node_file.write((char *)&size_of_tree, sizeof(std::uint32_t));
tree_node_file.write((char *)&m_search_tree[0], sizeof(TreeNode) * size_of_tree);
- // close tree node file.
- tree_node_file.close();
}
explicit StaticRTree(const boost::filesystem::path &node_file,
@@ -292,31 +269,31 @@ class StaticRTree
if (!boost::filesystem::exists(node_file))
{
- throw osrm::exception("ram index file does not exist");
+ throw exception("ram index file does not exist");
}
if (0 == boost::filesystem::file_size(node_file))
{
- throw osrm::exception("ram index file is empty");
+ throw exception("ram index file is empty");
}
boost::filesystem::ifstream tree_node_file(node_file, std::ios::binary);
- uint32_t tree_size = 0;
- tree_node_file.read((char *)&tree_size, sizeof(uint32_t));
+ std::uint32_t tree_size = 0;
+ tree_node_file.read((char *)&tree_size, sizeof(std::uint32_t));
m_search_tree.resize(tree_size);
if (tree_size > 0)
{
tree_node_file.read((char *)&m_search_tree[0], sizeof(TreeNode) * tree_size);
}
- tree_node_file.close();
+
// open leaf node file and store thread specific pointer
if (!boost::filesystem::exists(leaf_file))
{
- throw osrm::exception("mem index file does not exist");
+ throw exception("mem index file does not exist");
}
if (0 == boost::filesystem::file_size(leaf_file))
{
- throw osrm::exception("mem index file is empty");
+ throw exception("mem index file is empty");
}
leaves_stream.open(leaf_file, std::ios::binary);
@@ -333,27 +310,94 @@ class StaticRTree
// open leaf node file and store thread specific pointer
if (!boost::filesystem::exists(leaf_file))
{
- throw osrm::exception("mem index file does not exist");
+ throw exception("mem index file does not exist");
}
if (0 == boost::filesystem::file_size(leaf_file))
{
- throw osrm::exception("mem index file is empty");
+ throw exception("mem index file is empty");
}
leaves_stream.open(leaf_file, std::ios::binary);
leaves_stream.read((char *)&m_element_count, sizeof(uint64_t));
}
+ /* Returns all features inside the bounding box.
+ Rectangle needs to be projected!*/
+ std::vector<EdgeDataT> SearchInBox(const Rectangle &search_rectangle)
+ {
+ const Rectangle projected_rectangle{
+ search_rectangle.min_lon, search_rectangle.max_lon,
+ toFixed(FloatLatitude{coordinate_calculation::mercator::latToY(
+ toFloating(FixedLatitude(search_rectangle.min_lat)))}),
+ toFixed(FloatLatitude{coordinate_calculation::mercator::latToY(
+ toFloating(FixedLatitude(search_rectangle.max_lat)))})};
+ std::vector<EdgeDataT> results;
+
+ std::queue<TreeNode> traversal_queue;
+
+ traversal_queue.push(m_search_tree[0]);
+
+ while (!traversal_queue.empty())
+ {
+ auto const current_tree_node = traversal_queue.front();
+ traversal_queue.pop();
+
+ if (current_tree_node.child_is_on_disk)
+ {
+ LeafNode current_leaf_node;
+ LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
+
+ for (const auto i : irange(0u, current_leaf_node.object_count))
+ {
+ const auto ¤t_edge = current_leaf_node.objects[i];
+
+ // we don't need to project the coordinates here,
+ // because we use the unprojected rectangle to test against
+ const Rectangle bbox{std::min((*m_coordinate_list)[current_edge.u].lon,
+ (*m_coordinate_list)[current_edge.v].lon),
+ std::max((*m_coordinate_list)[current_edge.u].lon,
+ (*m_coordinate_list)[current_edge.v].lon),
+ std::min((*m_coordinate_list)[current_edge.u].lat,
+ (*m_coordinate_list)[current_edge.v].lat),
+ std::max((*m_coordinate_list)[current_edge.u].lat,
+ (*m_coordinate_list)[current_edge.v].lat)};
+
+ // use the _unprojected_ input rectangle here
+ if (bbox.Intersects(search_rectangle))
+ {
+ results.push_back(current_edge);
+ }
+ }
+ }
+ else
+ {
+ // If it's a tree node, look at all children and add them
+ // to the search queue if their bounding boxes intersect
+ for (std::uint32_t i = 0; i < current_tree_node.child_count; ++i)
+ {
+ const std::int32_t child_id = current_tree_node.children[i];
+ const auto &child_tree_node = m_search_tree[child_id];
+ const auto &child_rectangle = child_tree_node.minimum_bounding_rectangle;
+
+ if (child_rectangle.Intersects(projected_rectangle))
+ {
+ traversal_queue.push(m_search_tree[child_id]);
+ }
+ }
+ }
+ }
+ return results;
+ }
+
// Override filter and terminator for the desired behaviour.
- std::vector<EdgeDataT> Nearest(const FixedPointCoordinate &input_coordinate,
- const std::size_t max_results)
+ std::vector<EdgeDataT> Nearest(const Coordinate input_coordinate, const std::size_t max_results)
{
return Nearest(input_coordinate,
- [](const EdgeDataT &)
+ [](const CandidateSegment &)
{
return std::make_pair(true, true);
},
- [max_results](const std::size_t num_results, const float)
+ [max_results](const std::size_t num_results, const CandidateSegment &)
{
return num_results >= max_results;
});
@@ -361,28 +405,20 @@ class StaticRTree
// Override filter and terminator for the desired behaviour.
template <typename FilterT, typename TerminationT>
- std::vector<EdgeDataT> Nearest(const FixedPointCoordinate &input_coordinate,
- const FilterT filter,
- const TerminationT terminate)
+ std::vector<EdgeDataT>
+ Nearest(const Coordinate input_coordinate, const FilterT filter, const TerminationT terminate)
{
std::vector<EdgeDataT> results;
- std::pair<double, double> projected_coordinate = {
- mercator::lat2y(input_coordinate.lat / COORDINATE_PRECISION),
- input_coordinate.lon / COORDINATE_PRECISION};
+ auto projected_coordinate = coordinate_calculation::mercator::fromWGS84(input_coordinate);
+ Coordinate fixed_projected_coordinate{projected_coordinate};
// initialize queue with root element
std::priority_queue<QueryCandidate> traversal_queue;
- traversal_queue.push(QueryCandidate {0.f, m_search_tree[0]});
+ traversal_queue.push(QueryCandidate{0.f, m_search_tree[0]});
while (!traversal_queue.empty())
{
- const QueryCandidate current_query_node = traversal_queue.top();
- if (terminate(results.size(), current_query_node.min_dist))
- {
- traversal_queue = std::priority_queue<QueryCandidate>{};
- break;
- }
-
+ QueryCandidate current_query_node = traversal_queue.top();
traversal_queue.pop();
if (current_query_node.node.template is<TreeNode>())
@@ -391,37 +427,34 @@ class StaticRTree
current_query_node.node.template get<TreeNode>();
if (current_tree_node.child_is_on_disk)
{
- ExploreLeafNode(current_tree_node.children[0], input_coordinate,
- projected_coordinate, traversal_queue);
+ ExploreLeafNode(current_tree_node.children[0], projected_coordinate,
+ traversal_queue);
}
else
{
- ExploreTreeNode(current_tree_node, input_coordinate, traversal_queue);
+ ExploreTreeNode(current_tree_node, fixed_projected_coordinate, traversal_queue);
}
}
else
{
// inspecting an actual road segment
- const auto ¤t_segment = current_query_node.node.template get<EdgeDataT>();
-
+ auto ¤t_candidate = current_query_node.node.template get<CandidateSegment>();
+ if (terminate(results.size(), current_candidate))
+ {
+ traversal_queue = std::priority_queue<QueryCandidate>{};
+ break;
+ }
- auto use_segment = filter(current_segment);
+ auto use_segment = filter(current_candidate);
if (!use_segment.first && !use_segment.second)
{
continue;
}
+ current_candidate.data.forward_segment_id.enabled &= use_segment.first;
+ current_candidate.data.reverse_segment_id.enabled &= use_segment.second;
// store phantom node in result vector
- results.push_back(std::move(current_segment));
-
- if (!use_segment.first)
- {
- results.back().forward_edge_based_node_id = SPECIAL_NODEID;
- }
- else if (!use_segment.second)
- {
- results.back().reverse_edge_based_node_id = SPECIAL_NODEID;
- }
+ results.push_back(std::move(current_candidate.data));
}
}
@@ -431,44 +464,55 @@ class StaticRTree
private:
template <typename QueueT>
void ExploreLeafNode(const std::uint32_t leaf_id,
- const FixedPointCoordinate &input_coordinate,
- const std::pair<double, double> &projected_coordinate,
+ const FloatCoordinate &projected_input_coordinate,
QueueT &traversal_queue)
{
LeafNode current_leaf_node;
LoadLeafFromDisk(leaf_id, current_leaf_node);
// current object represents a block on disk
- for (const auto i : osrm::irange(0u, current_leaf_node.object_count))
+ for (const auto i : irange(0u, current_leaf_node.object_count))
{
auto ¤t_edge = current_leaf_node.objects[i];
- const float current_perpendicular_distance =
- coordinate_calculation::perpendicular_distance_from_projected_coordinate(
- m_coordinate_list->at(current_edge.u), m_coordinate_list->at(current_edge.v),
- input_coordinate, projected_coordinate);
+ auto projected_u =
+ coordinate_calculation::mercator::fromWGS84((*m_coordinate_list)[current_edge.u]);
+ auto projected_v =
+ coordinate_calculation::mercator::fromWGS84((*m_coordinate_list)[current_edge.v]);
+
+ FloatCoordinate projected_nearest;
+ std::tie(std::ignore, projected_nearest) =
+ coordinate_calculation::projectPointOnSegment(projected_u, projected_v,
+ projected_input_coordinate);
+
+ auto squared_distance = coordinate_calculation::squaredEuclideanDistance(
+ projected_input_coordinate, projected_nearest);
// distance must be non-negative
- BOOST_ASSERT(0.f <= current_perpendicular_distance);
+ BOOST_ASSERT(0. <= squared_distance);
- traversal_queue.push(QueryCandidate {current_perpendicular_distance, std::move(current_edge)});
+ traversal_queue.push(
+ QueryCandidate{squared_distance, CandidateSegment{Coordinate{projected_nearest},
+ std::move(current_edge)}});
}
}
template <class QueueT>
void ExploreTreeNode(const TreeNode &parent,
- const FixedPointCoordinate &input_coordinate,
+ const Coordinate fixed_projected_input_coordinate,
QueueT &traversal_queue)
{
- for (uint32_t i = 0; i < parent.child_count; ++i)
+ for (std::uint32_t i = 0; i < parent.child_count; ++i)
{
- const int32_t child_id = parent.children[i];
+ const std::int32_t child_id = parent.children[i];
const auto &child_tree_node = m_search_tree[child_id];
const auto &child_rectangle = child_tree_node.minimum_bounding_rectangle;
- const float lower_bound_to_element = child_rectangle.GetMinDist(input_coordinate);
- traversal_queue.push(QueryCandidate {lower_bound_to_element, m_search_tree[child_id]});
+ const auto squared_lower_bound_to_element =
+ child_rectangle.GetMinSquaredDist(fixed_projected_input_coordinate);
+ traversal_queue.push(
+ QueryCandidate{squared_lower_bound_to_element, m_search_tree[child_id]});
}
}
- inline void LoadLeafFromDisk(const uint32_t leaf_id, LeafNode &result_node)
+ inline void LoadLeafFromDisk(const std::uint32_t leaf_id, LeafNode &result_node)
{
if (!leaves_stream.is_open())
{
@@ -476,7 +520,7 @@ class StaticRTree
}
if (!leaves_stream.good())
{
- throw osrm::exception("Could not read from leaf file.");
+ throw exception("Could not read from leaf file.");
}
const uint64_t seek_pos = sizeof(uint64_t) + leaf_id * sizeof(LeafNode);
leaves_stream.seekg(seek_pos);
@@ -488,29 +532,42 @@ class StaticRTree
template <typename CoordinateT>
void InitializeMBRectangle(Rectangle &rectangle,
const std::array<EdgeDataT, LEAF_NODE_SIZE> &objects,
- const uint32_t element_count,
+ const std::uint32_t element_count,
const std::vector<CoordinateT> &coordinate_list)
{
- for (uint32_t i = 0; i < element_count; ++i)
+ for (std::uint32_t i = 0; i < element_count; ++i)
{
+ BOOST_ASSERT(objects[i].u < coordinate_list.size());
+ BOOST_ASSERT(objects[i].v < coordinate_list.size());
+
+ Coordinate projected_u{coordinate_calculation::mercator::fromWGS84(
+ Coordinate{coordinate_list[objects[i].u]})};
+ Coordinate projected_v{coordinate_calculation::mercator::fromWGS84(
+ Coordinate{coordinate_list[objects[i].v]})};
+
+ BOOST_ASSERT(toFloating(projected_u.lon) <= FloatLongitude(180.));
+ BOOST_ASSERT(toFloating(projected_u.lon) >= FloatLongitude(-180.));
+ BOOST_ASSERT(toFloating(projected_u.lat) <= FloatLatitude(180.));
+ BOOST_ASSERT(toFloating(projected_u.lat) >= FloatLatitude(-180.));
+ BOOST_ASSERT(toFloating(projected_v.lon) <= FloatLongitude(180.));
+ BOOST_ASSERT(toFloating(projected_v.lon) >= FloatLongitude(-180.));
+ BOOST_ASSERT(toFloating(projected_v.lat) <= FloatLatitude(180.));
+ BOOST_ASSERT(toFloating(projected_v.lat) >= FloatLatitude(-180.));
+
rectangle.min_lon =
- std::min(rectangle.min_lon, std::min(coordinate_list.at(objects[i].u).lon,
- coordinate_list.at(objects[i].v).lon));
+ std::min(rectangle.min_lon, std::min(projected_u.lon, projected_v.lon));
rectangle.max_lon =
- std::max(rectangle.max_lon, std::max(coordinate_list.at(objects[i].u).lon,
- coordinate_list.at(objects[i].v).lon));
+ std::max(rectangle.max_lon, std::max(projected_u.lon, projected_v.lon));
rectangle.min_lat =
- std::min(rectangle.min_lat, std::min(coordinate_list.at(objects[i].u).lat,
- coordinate_list.at(objects[i].v).lat));
+ std::min(rectangle.min_lat, std::min(projected_u.lat, projected_v.lat));
rectangle.max_lat =
- std::max(rectangle.max_lat, std::max(coordinate_list.at(objects[i].u).lat,
- coordinate_list.at(objects[i].v).lat));
+ std::max(rectangle.max_lat, std::max(projected_u.lat, projected_v.lat));
}
- BOOST_ASSERT(rectangle.min_lat != std::numeric_limits<int>::min());
- BOOST_ASSERT(rectangle.min_lon != std::numeric_limits<int>::min());
- BOOST_ASSERT(rectangle.max_lat != std::numeric_limits<int>::min());
- BOOST_ASSERT(rectangle.max_lon != std::numeric_limits<int>::min());
+ BOOST_ASSERT(rectangle.min_lon != FixedLongitude(std::numeric_limits<int>::min()));
+ BOOST_ASSERT(rectangle.min_lat != FixedLatitude(std::numeric_limits<int>::min()));
+ BOOST_ASSERT(rectangle.max_lon != FixedLongitude(std::numeric_limits<int>::min()));
+ BOOST_ASSERT(rectangle.max_lat != FixedLatitude(std::numeric_limits<int>::min()));
}
};
@@ -518,4 +575,7 @@ class StaticRTree
//[2] "Nearest Neighbor Queries", N. Roussopulos et al; 1995; DOI: 10.1145/223784.223794
//[3] "Distance Browsing in Spatial Databases"; G. Hjaltason, H. Samet; 1999; ACM Trans. DB Sys
// Vol.24 No.2, pp.265-318
+}
+}
+
#endif // STATIC_RTREE_HPP
diff --git a/include/util/std_hash.hpp b/include/util/std_hash.hpp
new file mode 100644
index 0000000..b456ab1
--- /dev/null
+++ b/include/util/std_hash.hpp
@@ -0,0 +1,41 @@
+#ifndef STD_HASH_HPP
+#define STD_HASH_HPP
+
+#include <functional>
+
+// this is largely inspired by boost's hash combine as can be found in
+// "The C++ Standard Library" 2nd Edition. Nicolai M. Josuttis. 2012.
+
+template <typename T> void hash_combine(std::size_t &seed, const T &val)
+{
+ seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+}
+
+template <typename T> void hash_val(std::size_t &seed, const T &val) { hash_combine(seed, val); }
+
+template <typename T, typename... Types>
+void hash_val(std::size_t &seed, const T &val, const Types &... args)
+{
+ hash_combine(seed, val);
+ hash_val(seed, args...);
+}
+
+template <typename... Types> std::size_t hash_val(const Types &... args)
+{
+ std::size_t seed = 0;
+ hash_val(seed, args...);
+ return seed;
+}
+
+namespace std
+{
+template <typename T1, typename T2> struct hash<std::pair<T1, T2>>
+{
+ size_t operator()(const std::pair<T1, T2> &pair) const
+ {
+ return hash_val(pair.first, pair.second);
+ }
+};
+}
+
+#endif // STD_HASH_HPP
diff --git a/util/string_util.hpp b/include/util/string_util.hpp
similarity index 68%
rename from util/string_util.hpp
rename to include/util/string_util.hpp
index 8075e65..41c5f09 100644
--- a/util/string_util.hpp
+++ b/include/util/string_util.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef STRING_UTIL_HPP
#define STRING_UTIL_HPP
@@ -34,10 +7,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
#include <vector>
+namespace osrm
+{
+namespace util
+{
+
// precision: position after decimal point
// length: maximum number of digits including comma and decimals
// work with negative values to prevent overflowing when taking -value
-template <int length, int precision> static inline char *printInt(char *buffer, int value)
+template <int length, int precision> char *printInt(char *buffer, int value)
{
static_assert(length > 0, "length must be positive");
static_assert(precision > 0, "precision must be positive");
@@ -148,5 +126,7 @@ inline std::size_t URIDecode(const std::string &input, std::string &output)
}
inline std::size_t URIDecodeInPlace(std::string &URI) { return URIDecode(URI, URI); }
+}
+}
#endif // STRING_UTIL_HPP
diff --git a/include/util/strong_typedef.hpp b/include/util/strong_typedef.hpp
new file mode 100644
index 0000000..eabcaa3
--- /dev/null
+++ b/include/util/strong_typedef.hpp
@@ -0,0 +1,84 @@
+/*
+
+Copyright (c) 2016, Project OSRM contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef STRONG_TYPEDEF_HPP
+#define STRONG_TYPEDEF_HPP
+
+#include <iostream>
+#include <type_traits>
+#include <functional>
+
+namespace osrm
+{
+
+/* Creates strongly typed wrappers around scalar types.
+ * Useful for stopping accidental assignment of lats to lons,
+ * etc. Also clarifies what this random "int" value is
+ * being used for.
+ */
+#define OSRM_STRONG_TYPEDEF(From, To) \
+ class To final \
+ { \
+ static_assert(std::is_arithmetic<From>(), ""); \
+ From x; \
+ friend std::ostream &operator<<(std::ostream &stream, const To &inst); \
+ \
+ public: \
+ To() = default; \
+ explicit To(const From x_) : x(x_) {} \
+ explicit operator From &() { return x; } \
+ explicit operator From() const { return x; } \
+ To operator+(const To rhs_) const { return To(x + static_cast<const From>(rhs_)); } \
+ To operator-(const To rhs_) const { return To(x - static_cast<const From>(rhs_)); } \
+ To operator*(const To rhs_) const { return To(x * static_cast<const From>(rhs_)); } \
+ To operator/(const To rhs_) const { return To(x / static_cast<const From>(rhs_)); } \
+ bool operator<(const To z_) const { return x < static_cast<const From>(z_); } \
+ bool operator>(const To z_) const { return x > static_cast<const From>(z_); } \
+ bool operator<=(const To z_) const { return x <= static_cast<const From>(z_); } \
+ bool operator>=(const To z_) const { return x >= static_cast<const From>(z_); } \
+ bool operator==(const To z_) const { return x == static_cast<const From>(z_); } \
+ bool operator!=(const To z_) const { return x != static_cast<const From>(z_); } \
+ }; \
+ inline std::ostream &operator<<(std::ostream &stream, const To &inst) \
+ { \
+ return stream << inst.x; \
+ }
+
+#define OSRM_STRONG_TYPEDEF_HASHABLE(From, To) \
+ namespace std \
+ { \
+ template <> struct hash<To> \
+ { \
+ std::size_t operator()(const To &k) const \
+ { \
+ return std::hash<From>()(static_cast<const From>(k)); \
+ } \
+ }; \
+ }
+}
+
+#endif // OSRM_STRONG_TYPEDEF_HPP
diff --git a/util/timing_util.hpp b/include/util/timing_util.hpp
similarity index 68%
rename from util/timing_util.hpp
rename to include/util/timing_util.hpp
index c0c59c8..537f0dc 100644
--- a/util/timing_util.hpp
+++ b/include/util/timing_util.hpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef TIMING_UTIL_HPP
#define TIMING_UTIL_HPP
@@ -34,6 +7,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <mutex>
#include <unordered_map>
+namespace osrm
+{
+namespace util
+{
+
struct GlobalTimer
{
GlobalTimer() : time(0) {}
@@ -86,5 +64,7 @@ class GlobalTimerFactory
std::chrono::duration_cast<std::chrono::microseconds>(_X##_stop - _X##_start).count())
#define TIMER_MIN(_X) \
std::chrono::duration_cast<std::chrono::minutes>(_X##_stop - _X##_start).count()
+}
+}
#endif // TIMING_UTIL_HPP
diff --git a/util/trigonometry_table.hpp b/include/util/trigonometry_table.hpp
similarity index 95%
rename from util/trigonometry_table.hpp
rename to include/util/trigonometry_table.hpp
index 234a94e..fe1d316 100644
--- a/util/trigonometry_table.hpp
+++ b/include/util/trigonometry_table.hpp
@@ -1,38 +1,18 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#ifndef TRIGONOMETRY_TABLE_HPP
#define TRIGONOMETRY_TABLE_HPP
-#include "../typedefs.h"
+#include "util/typedefs.hpp"
#include <cmath>
#include <limits>
+#include <boost/math/constants/constants.hpp>
+
+namespace osrm
+{
+namespace util
+{
+
constexpr unsigned short atan_table[4096] = {
0x0000, 0x0014, 0x0028, 0x003d, 0x0051, 0x0065, 0x007a, 0x008e, 0x00a3, 0x00b7, 0x00cb, 0x00e0,
0x00f4, 0x0108, 0x011d, 0x0131, 0x0146, 0x015a, 0x016e, 0x0183, 0x0197, 0x01ab, 0x01c0, 0x01d4,
@@ -378,19 +358,27 @@ constexpr unsigned short atan_table[4096] = {
0xffe0, 0xffea, 0xfff4, 0xffff};
// max value is pi/4
-constexpr double SCALING_FACTOR = 4. / M_PI * 0xFFFF;
+#ifdef _MSC_VER //TODO: remove as soon as boost allows C++14 features with Visual Studio
+const constexpr double SCALING_FACTOR = 4. / M_PI * 0xFFFF;
+#else
+const constexpr double SCALING_FACTOR = 4. / boost::math::constants::pi<double>() * 0xFFFF;
+#endif
+
inline double atan2_lookup(double y, double x)
{
+
+ using namespace boost::math::constants;
+
if (std::abs(x) < std::numeric_limits<double>::epsilon())
{
if (y >= 0.)
{
- return M_PI / 2.;
+ return half_pi<double>();
}
else
{
- return -M_PI / 2.;
+ return -half_pi<double>();
}
}
@@ -421,28 +409,30 @@ inline double atan2_lookup(double y, double x)
case 0:
break;
case 1:
- angle = M_PI - angle;
+ angle = pi<double>() - angle;
break;
case 2:
angle = -angle;
break;
case 3:
- angle = -M_PI + angle;
+ angle = -pi<double>() + angle;
break;
case 4:
- angle = M_PI / 2.0 - angle;
+ angle = half_pi<double>() - angle;
break;
case 5:
- angle = M_PI / 2.0 + angle;
+ angle = half_pi<double>() + angle;
break;
case 6:
- angle = -M_PI / 2.0 + angle;
+ angle = -half_pi<double>() + angle;
break;
case 7:
- angle = -M_PI / 2.0 - angle;
+ angle = -half_pi<double>() - angle;
break;
}
return angle;
}
+}
+}
#endif // TRIGONOMETRY_TABLE_HPP
diff --git a/typedefs.h b/include/util/typedefs.hpp
similarity index 80%
rename from typedefs.h
rename to include/util/typedefs.hpp
index dc77f39..b3404bc 100644
--- a/typedefs.h
+++ b/include/util/typedefs.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,21 +28,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef TYPEDEFS_H
#define TYPEDEFS_H
+#include "util/strong_typedef.hpp"
+
+#include <boost/assert.hpp>
+
#include <limits>
-#include <osrm/strong_typedef.hpp>
#include <cstddef>
-// Necessary workaround for Windows as VS doesn't implement C99
-#ifdef _MSC_VER
-#define WIN32_LEAN_AND_MEAN
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-#endif
-
// OpenStreetMap node ids are higher than 2^32
OSRM_STRONG_TYPEDEF(uint64_t, OSMNodeID)
+OSRM_STRONG_TYPEDEF_HASHABLE(uint64_t, OSMNodeID)
+
OSRM_STRONG_TYPEDEF(uint32_t, OSMWayID)
+OSRM_STRONG_TYPEDEF_HASHABLE(uint32_t, OSMWayID)
static const OSMNodeID SPECIAL_OSM_NODEID = OSMNodeID(std::numeric_limits<std::uint64_t>::max());
static const OSMWayID SPECIAL_OSM_WAYID = OSMWayID(std::numeric_limits<std::uint32_t>::max());
@@ -60,9 +58,26 @@ using EdgeID = unsigned int;
using EdgeWeight = int;
static const NodeID SPECIAL_NODEID = std::numeric_limits<unsigned>::max();
+static const NodeID SPECIAL_SEGMENTID = std::numeric_limits<int>::max();
static const EdgeID SPECIAL_EDGEID = std::numeric_limits<unsigned>::max();
static const unsigned INVALID_NAMEID = std::numeric_limits<unsigned>::max();
static const unsigned INVALID_COMPONENTID = 0;
static const EdgeWeight INVALID_EDGE_WEIGHT = std::numeric_limits<int>::max();
+struct SegmentID
+{
+ SegmentID(const NodeID id_, const bool enabled_) : id{id_}, enabled{enabled_}
+ {
+ BOOST_ASSERT(!enabled || id != SPECIAL_SEGMENTID);
+ }
+
+ NodeID id : 31;
+ bool enabled : 1;
+};
+
+// bit-fields are broken on Windows
+#ifndef _MSC_VER
+static_assert(sizeof(SegmentID) == 4, "SegmentID needs to be 4 bytes big");
+#endif
+
#endif /* TYPEDEFS_H */
diff --git a/include/util/version.hpp.in b/include/util/version.hpp.in
new file mode 100644
index 0000000..cb97dca
--- /dev/null
+++ b/include/util/version.hpp.in
@@ -0,0 +1,10 @@
+#ifndef VERSION_HPP
+#define VERSION_HPP
+
+#define OSRM_VERSION_MAJOR "@OSRM_VERSION_MAJOR@"
+#define OSRM_VERSION_MINOR "@OSRM_VERSION_MINOR@"
+#define OSRM_VERSION_PATCH "@OSRM_VERSION_PATCH@"
+
+#define OSRM_VERSION "v" OSRM_VERSION_MAJOR "." OSRM_VERSION_MINOR "." OSRM_VERSION_PATCH
+
+#endif // VERSION_HPP
diff --git a/include/util/viewport.hpp b/include/util/viewport.hpp
new file mode 100644
index 0000000..fd0ac73
--- /dev/null
+++ b/include/util/viewport.hpp
@@ -0,0 +1,51 @@
+#ifndef UTIL_VIEWPORT_HPP
+#define UTIL_VIEWPORT_HPP
+
+#include "util/coordinate.hpp"
+#include "util/coordinate_calculation.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cmath>
+#include <tuple>
+
+// Port of https://github.com/mapbox/geo-viewport
+
+namespace osrm
+{
+namespace util
+{
+namespace viewport
+{
+
+namespace detail
+{
+static constexpr unsigned MAX_ZOOM = 18;
+static constexpr unsigned MIN_ZOOM = 1;
+// this is an upper bound to current display sizes
+static constexpr double VIEWPORT_WIDTH = 8 * coordinate_calculation::mercator::TILE_SIZE;
+static constexpr double VIEWPORT_HEIGHT = 5 * coordinate_calculation::mercator::TILE_SIZE;
+static double INV_LOG_2 = 1. / std::log(2);
+}
+
+unsigned getFittedZoom(util::Coordinate south_west, util::Coordinate north_east)
+{
+ const auto min_x = coordinate_calculation::mercator::degreeToPixel(toFloating(south_west.lon), detail::MAX_ZOOM);
+ const auto max_y = coordinate_calculation::mercator::degreeToPixel(toFloating(south_west.lat), detail::MAX_ZOOM);
+ const auto max_x = coordinate_calculation::mercator::degreeToPixel(toFloating(north_east.lon), detail::MAX_ZOOM);
+ const auto min_y = coordinate_calculation::mercator::degreeToPixel(toFloating(north_east.lat), detail::MAX_ZOOM);
+ const double width_ratio = (max_x - min_x) / detail::VIEWPORT_WIDTH;
+ const double height_ratio = (max_y - min_y) / detail::VIEWPORT_HEIGHT;
+ const auto zoom = detail::MAX_ZOOM - std::max(std::log(width_ratio), std::log(height_ratio)) * detail::INV_LOG_2;
+
+ if (std::isfinite(zoom))
+ return std::max<unsigned>(detail::MIN_ZOOM, zoom);
+ else
+ return detail::MIN_ZOOM;
+}
+
+}
+}
+}
+
+#endif
diff --git a/include/util/xor_fast_hash.hpp b/include/util/xor_fast_hash.hpp
new file mode 100644
index 0000000..6ad79d6
--- /dev/null
+++ b/include/util/xor_fast_hash.hpp
@@ -0,0 +1,71 @@
+#ifndef XOR_FAST_HASH_HPP
+#define XOR_FAST_HASH_HPP
+
+#include <boost/assert.hpp>
+
+#include <array>
+#include <algorithm>
+#include <iterator>
+#include <numeric>
+#include <random>
+#include <vector>
+
+#include <cstdint>
+
+namespace osrm
+{
+namespace util
+{
+
+/*
+ This is an implementation of Tabulation hashing, which has suprising properties like
+ universality.
+ The space requirement is 2*2^16 = 256 kb of memory, which fits into L2 cache.
+ Evaluation boils down to 10 or less assembly instruction on any recent X86 CPU:
+
+ 1: movq table2(%rip), %rdx
+ 2: movl %edi, %eax
+ 3: movzwl %di, %edi
+ 4: shrl $16, %eax
+ 5: movzwl %ax, %eax
+ 6: movzbl (%rdx,%rax), %eax
+ 7: movq table1(%rip), %rdx
+ 8: xorb (%rdx,%rdi), %al
+ 9: movzbl %al, %eax
+ 10: ret
+
+*/
+template <std::size_t MaxNumElements = (1u << 16u)> class XORFastHash
+{
+ static_assert(MaxNumElements <= (1u << 16u), "only 65536 elements indexable with uint16_t");
+
+ std::array<std::uint16_t, MaxNumElements> table1;
+ std::array<std::uint16_t, MaxNumElements> table2;
+
+ public:
+ XORFastHash()
+ {
+ std::mt19937 generator; // impl. defined but deterministic default seed
+
+ std::iota(begin(table1), end(table1), 0u);
+ std::shuffle(begin(table1), end(table1), generator);
+
+ std::iota(begin(table2), end(table2), 0u);
+ std::shuffle(begin(table2), end(table2), generator);
+ }
+
+ inline std::uint16_t operator()(const std::uint32_t originalValue) const
+ {
+ std::uint16_t lsb = originalValue & 0xffffu;
+ std::uint16_t msb = originalValue >> 16u;
+
+ BOOST_ASSERT(lsb < table1.size());
+ BOOST_ASSERT(msb < table2.size());
+
+ return table1[lsb] ^ table2[msb];
+ }
+};
+}
+}
+
+#endif // XOR_FAST_HASH_HPP
diff --git a/include/util/xor_fast_hash_storage.hpp b/include/util/xor_fast_hash_storage.hpp
new file mode 100644
index 0000000..6d2d76b
--- /dev/null
+++ b/include/util/xor_fast_hash_storage.hpp
@@ -0,0 +1,84 @@
+#ifndef XOR_FAST_HASH_STORAGE_HPP
+#define XOR_FAST_HASH_STORAGE_HPP
+
+#include "util/xor_fast_hash.hpp"
+
+#include <limits>
+#include <vector>
+
+namespace osrm
+{
+namespace util
+{
+
+template <typename NodeID, typename Key, std::size_t MaxNumElements = (1u << 16u)>
+class XORFastHashStorage
+{
+ public:
+ struct HashCell
+ {
+ unsigned time;
+ NodeID id;
+ Key key;
+ HashCell()
+ : time(std::numeric_limits<unsigned>::max()), id(std::numeric_limits<unsigned>::max()),
+ key(std::numeric_limits<unsigned>::max())
+ {
+ }
+
+ HashCell(const HashCell &other) : time(other.key), id(other.id), key(other.time) {}
+ operator Key() const { return key; }
+ void operator=(const Key key_to_insert) { key = key_to_insert; }
+ };
+
+ explicit XORFastHashStorage(size_t) : positions(MaxNumElements), current_timestamp{0u} {}
+
+ HashCell &operator[](const NodeID node)
+ {
+ std::uint16_t position = fast_hasher(node);
+ while ((positions[position].time == current_timestamp) && (positions[position].id != node))
+ {
+ ++position %= MaxNumElements;
+ }
+
+ positions[position].time = current_timestamp;
+ positions[position].id = node;
+
+ BOOST_ASSERT(position < positions.size());
+
+ return positions[position];
+ }
+
+ // peek into table, get key for node, think of it as a read-only operator[]
+ Key peek_index(const NodeID node) const
+ {
+ std::uint16_t position = fast_hasher(node);
+ while ((positions[position].time == current_timestamp) && (positions[position].id != node))
+ {
+ ++position %= MaxNumElements;
+ }
+
+ BOOST_ASSERT(position < positions.size());
+
+ return positions[position].key;
+ }
+
+ void Clear()
+ {
+ ++current_timestamp;
+ if (std::numeric_limits<unsigned>::max() == current_timestamp)
+ {
+ positions.clear();
+ positions.resize(MaxNumElements);
+ }
+ }
+
+ private:
+ std::vector<HashCell> positions;
+ XORFastHash<MaxNumElements> fast_hasher;
+ unsigned current_timestamp;
+};
+}
+}
+
+#endif // XOR_FAST_HASH_STORAGE_HPP
diff --git a/library/osrm_impl.cpp b/library/osrm_impl.cpp
deleted file mode 100644
index 069ef95..0000000
--- a/library/osrm_impl.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-namespace boost
-{
-namespace interprocess
-{
-class named_mutex;
-}
-}
-
-#include "osrm_impl.hpp"
-
-#include "../plugins/distance_table.hpp"
-#include "../plugins/hello_world.hpp"
-#include "../plugins/nearest.hpp"
-#include "../plugins/timestamp.hpp"
-#include "../plugins/trip.hpp"
-#include "../plugins/viaroute.hpp"
-#include "../plugins/match.hpp"
-#include "../server/data_structures/datafacade_base.hpp"
-#include "../server/data_structures/internal_datafacade.hpp"
-#include "../server/data_structures/shared_barriers.hpp"
-#include "../server/data_structures/shared_datafacade.hpp"
-#include "../util/make_unique.hpp"
-#include "../util/routed_options.hpp"
-#include "../util/simple_logger.hpp"
-
-#include <boost/assert.hpp>
-#include <boost/interprocess/sync/named_condition.hpp>
-#include <boost/interprocess/sync/scoped_lock.hpp>
-
-#include <osrm/route_parameters.hpp>
-#include <osrm/libosrm_config.hpp>
-#include <osrm/osrm.hpp>
-
-#include <algorithm>
-#include <fstream>
-#include <utility>
-#include <vector>
-
-OSRM::OSRM_impl::OSRM_impl(LibOSRMConfig& lib_config)
-{
- if (lib_config.use_shared_memory)
- {
- barrier = osrm::make_unique<SharedBarriers>();
- query_data_facade = new SharedDataFacade<QueryEdge::EdgeData>();
- }
- else
- {
- // populate base path
- populate_base_path(lib_config.server_paths);
- query_data_facade = new InternalDataFacade<QueryEdge::EdgeData>(lib_config.server_paths);
- }
-
- // The following plugins handle all requests.
- RegisterPlugin(new DistanceTablePlugin<BaseDataFacade<QueryEdge::EdgeData>>(
- query_data_facade, lib_config.max_locations_distance_table));
- RegisterPlugin(new HelloWorldPlugin());
- RegisterPlugin(new NearestPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
- RegisterPlugin(new MapMatchingPlugin<BaseDataFacade<QueryEdge::EdgeData>>(
- query_data_facade, lib_config.max_locations_map_matching));
- RegisterPlugin(new TimestampPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
- RegisterPlugin(new ViaRoutePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade,
- lib_config.max_locations_viaroute));
- RegisterPlugin(new RoundTripPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade,
- lib_config.max_locations_trip));
-}
-
-void OSRM::OSRM_impl::RegisterPlugin(BasePlugin *raw_plugin_ptr)
-{
- std::unique_ptr<BasePlugin> plugin_ptr(raw_plugin_ptr);
- SimpleLogger().Write() << "loaded plugin: " << plugin_ptr->GetDescriptor();
- plugin_map[plugin_ptr->GetDescriptor()] = std::move(plugin_ptr);
-}
-
-int OSRM::OSRM_impl::RunQuery(const RouteParameters &route_parameters, osrm::json::Object &json_result)
-{
- const auto &plugin_iterator = plugin_map.find(route_parameters.service);
-
- if (plugin_map.end() == plugin_iterator)
- {
- json_result.values["status_message"] = "Service not found";
- return 400;
- }
-
- increase_concurrent_query_count();
- BasePlugin::Status return_code;
- if (barrier) {
- // Get a shared data lock so that other threads won't update
- // things while the query is running
- boost::shared_lock<boost::shared_mutex> data_lock{
- (static_cast<SharedDataFacade<QueryEdge::EdgeData> *>(query_data_facade))->data_mutex};
- return_code = plugin_iterator->second->HandleRequest(route_parameters, json_result);
- } else {
- return_code = plugin_iterator->second->HandleRequest(route_parameters, json_result);
- }
- decrease_concurrent_query_count();
- return static_cast<int>(return_code);
-}
-
-// decrease number of concurrent queries
-void OSRM::OSRM_impl::decrease_concurrent_query_count()
-{
- if (!barrier)
- {
- return;
- }
- // lock query
- boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
- barrier->query_mutex);
-
- // decrement query count
- --(barrier->number_of_queries);
- BOOST_ASSERT_MSG(0 <= barrier->number_of_queries, "invalid number of queries");
-
- // notify all processes that were waiting for this condition
- if (0 == barrier->number_of_queries)
- {
- barrier->no_running_queries_condition.notify_all();
- }
-}
-
-// increase number of concurrent queries
-void OSRM::OSRM_impl::increase_concurrent_query_count()
-{
- if (!barrier)
- {
- return;
- }
-
- // lock update pending
- boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
- barrier->pending_update_mutex);
-
- // lock query
- boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
- barrier->query_mutex);
-
- // unlock update pending
- pending_lock.unlock();
-
- // increment query count
- ++(barrier->number_of_queries);
-
- (static_cast<SharedDataFacade<QueryEdge::EdgeData> *>(query_data_facade))
- ->CheckAndReloadFacade();
-}
-
-// proxy code for compilation firewall
-OSRM::OSRM(LibOSRMConfig &lib_config) : OSRM_pimpl_(osrm::make_unique<OSRM_impl>(lib_config)) {}
-
-// needed because unique_ptr needs the size of OSRM_impl for delete
-OSRM::~OSRM() {}
-
-int OSRM::RunQuery(const RouteParameters &route_parameters, osrm::json::Object &json_result)
-{
- return OSRM_pimpl_->RunQuery(route_parameters, json_result);
-}
diff --git a/library/osrm_impl.hpp b/library/osrm_impl.hpp
deleted file mode 100644
index c223449..0000000
--- a/library/osrm_impl.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef OSRM_IMPL_HPP
-#define OSRM_IMPL_HPP
-
-class BasePlugin;
-struct RouteParameters;
-
-#include "../data_structures/query_edge.hpp"
-
-#include <osrm/json_container.hpp>
-#include <osrm/libosrm_config.hpp>
-#include <osrm/osrm.hpp>
-
-#include <memory>
-#include <unordered_map>
-#include <string>
-
-struct SharedBarriers;
-template <class EdgeDataT> class BaseDataFacade;
-
-class OSRM::OSRM_impl final
-{
- private:
- using PluginMap = std::unordered_map<std::string, std::unique_ptr<BasePlugin>>;
-
- public:
- OSRM_impl(LibOSRMConfig &lib_config);
- OSRM_impl(const OSRM_impl &) = delete;
- int RunQuery(const RouteParameters &route_parameters, osrm::json::Object &json_result);
-
- private:
- void RegisterPlugin(BasePlugin *plugin);
- PluginMap plugin_map;
- // will only be initialized if shared memory is used
- std::unique_ptr<SharedBarriers> barrier;
- // base class pointer to the objects
- BaseDataFacade<QueryEdge::EdgeData> *query_data_facade;
-
- // decrease number of concurrent queries
- void decrease_concurrent_query_count();
- // increase number of concurrent queries
- void increase_concurrent_query_count();
-};
-
-#endif // OSRM_IMPL_HPP
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..46c0bb7
--- /dev/null
+++ b/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "osrm-backend-test-suite",
+ "version": "0.0.0",
+ "private": true,
+ "description": "The Open Source Routing Machine is a high performance routing engine written in C++11 designed to run on OpenStreetMap data.",
+ "dependencies": {
+ "cucumber": "^0.9.4",
+ "d3-queue": "^2.0.3",
+ "node-timeout": "0.0.4",
+ "request": "^2.69.0",
+ "xmlbuilder": "^4.2.1",
+ "chalk": "^1.1.3"
+ },
+ "bin": {
+ "cucumber": "./node_modules/cucumber/bin/cucumber.js"
+ },
+ "scripts": {
+ "lint": "eslint -c ./.eslintrc features/step_definitions/ features/support/",
+ "test": "npm run lint && ./node_modules/cucumber/bin/cucumber.js features/ -p verify",
+ "clean-test": "rm -rf test/cache",
+ "cucumber": "./node_modules/cucumber/bin/cucumber.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/Project-OSRM/osrm-backend.git"
+ },
+ "author": "",
+ "license": "ISC",
+ "bugs": {
+ "url": "https://github.com/Project-OSRM/osrm-backend/issues"
+ },
+ "homepage": "https://github.com/Project-OSRM/osrm-backend",
+ "engines": {
+ "node": ">=4.0.0"
+ },
+ "devDependencies": {
+ "eslint": "^2.4.0"
+ }
+}
diff --git a/plugins/distance_table.hpp b/plugins/distance_table.hpp
deleted file mode 100644
index c4ed250..0000000
--- a/plugins/distance_table.hpp
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef DISTANCE_TABLE_HPP
-#define DISTANCE_TABLE_HPP
-
-#include "plugin_base.hpp"
-
-#include "../algorithms/object_encoder.hpp"
-#include "../data_structures/query_edge.hpp"
-#include "../data_structures/search_engine.hpp"
-#include "../descriptors/descriptor_base.hpp"
-#include "../util/json_renderer.hpp"
-#include "../util/make_unique.hpp"
-#include "../util/string_util.hpp"
-#include "../util/timing_util.hpp"
-
-#include <osrm/json_container.hpp>
-
-#include <cstdlib>
-
-#include <algorithm>
-#include <memory>
-#include <unordered_map>
-#include <string>
-#include <vector>
-
-template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
-{
- private:
- std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
- int max_locations_distance_table;
-
- public:
- explicit DistanceTablePlugin(DataFacadeT *facade, const int max_locations_distance_table)
- : max_locations_distance_table(max_locations_distance_table), descriptor_string("table"),
- facade(facade)
- {
- search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
- }
-
- virtual ~DistanceTablePlugin() {}
-
- const std::string GetDescriptor() const override final { return descriptor_string; }
-
- Status HandleRequest(const RouteParameters &route_parameters,
- osrm::json::Object &json_result) override final
- {
- if (!check_all_coordinates(route_parameters.coordinates))
- {
- json_result.values["status_message"] = "Coordinates are invalid";
- return Status::Error;
- }
-
- const auto &input_bearings = route_parameters.bearings;
- if (input_bearings.size() > 0 &&
- route_parameters.coordinates.size() != input_bearings.size())
- {
- json_result.values["status_message"] =
- "Number of bearings does not match number of coordinates";
- return Status::Error;
- }
-
- auto number_of_sources =
- std::count_if(route_parameters.is_source.begin(), route_parameters.is_source.end(),
- [](const bool is_source)
- {
- return is_source;
- });
- auto number_of_destination =
- std::count_if(route_parameters.is_destination.begin(),
- route_parameters.is_destination.end(), [](const bool is_destination)
- {
- return is_destination;
- });
-
- if (max_locations_distance_table > 0 &&
- (number_of_sources * number_of_destination >
- max_locations_distance_table * max_locations_distance_table))
- {
- json_result.values["status_message"] =
- "Number of entries " + std::to_string(number_of_sources * number_of_destination) +
- " is higher than current maximum (" +
- std::to_string(max_locations_distance_table * max_locations_distance_table) + ")";
- return Status::Error;
- }
-
- const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
-
- std::vector<PhantomNodePair> phantom_node_source_vector(number_of_sources);
- std::vector<PhantomNodePair> phantom_node_target_vector(number_of_destination);
- auto phantom_node_source_out_iter = phantom_node_source_vector.begin();
- auto phantom_node_target_out_iter = phantom_node_target_vector.begin();
- for (const auto i : osrm::irange<std::size_t>(0u, route_parameters.coordinates.size()))
- {
- if (checksum_OK && i < route_parameters.hints.size() &&
- !route_parameters.hints[i].empty())
- {
- PhantomNode current_phantom_node;
- ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
- if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
- {
- if (route_parameters.is_source[i])
- {
- *phantom_node_source_out_iter =
- std::make_pair(current_phantom_node, current_phantom_node);
- if (route_parameters.is_destination[i])
- {
- *phantom_node_target_out_iter = *phantom_node_source_out_iter;
- phantom_node_target_out_iter++;
- }
- phantom_node_source_out_iter++;
- }
- else
- {
- BOOST_ASSERT(route_parameters.is_destination[i] &&
- !route_parameters.is_source[i]);
- *phantom_node_target_out_iter =
- std::make_pair(current_phantom_node, current_phantom_node);
- phantom_node_target_out_iter++;
- }
- continue;
- }
- }
- const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
- const int range = input_bearings.size() > 0
- ? (input_bearings[i].second ? *input_bearings[i].second : 10)
- : 180;
- if (route_parameters.is_source[i])
- {
- *phantom_node_source_out_iter =
- facade->NearestPhantomNodeWithAlternativeFromBigComponent(
- route_parameters.coordinates[i], bearing, range);
- // we didn't found a fitting node, return error
- if (!phantom_node_source_out_iter->first.is_valid(facade->GetNumberOfNodes()))
- {
- json_result.values["status_message"] =
- std::string("Could not find a matching segment for coordinate ") + std::to_string(i);
- return Status::NoSegment;
- }
-
- if (route_parameters.is_destination[i])
- {
- *phantom_node_target_out_iter = *phantom_node_source_out_iter;
- phantom_node_target_out_iter++;
- }
- phantom_node_source_out_iter++;
- }
- else
- {
- BOOST_ASSERT(route_parameters.is_destination[i] && !route_parameters.is_source[i]);
-
- *phantom_node_target_out_iter =
- facade->NearestPhantomNodeWithAlternativeFromBigComponent(
- route_parameters.coordinates[i], bearing, range);
- // we didn't found a fitting node, return error
- if (!phantom_node_target_out_iter->first.is_valid(facade->GetNumberOfNodes()))
- {
- json_result.values["status_message"] =
- std::string("Could not find a matching segment for coordinate ") + std::to_string(i);
- return Status::NoSegment;
- }
- phantom_node_target_out_iter++;
- }
- }
-
- BOOST_ASSERT((phantom_node_source_out_iter - phantom_node_source_vector.begin()) ==
- number_of_sources);
- BOOST_ASSERT((phantom_node_target_out_iter - phantom_node_target_vector.begin()) ==
- number_of_destination);
-
- // FIXME we should clear phantom_node_source_vector and phantom_node_target_vector after
- // this
- auto snapped_source_phantoms = snapPhantomNodes(phantom_node_source_vector);
- auto snapped_target_phantoms = snapPhantomNodes(phantom_node_target_vector);
-
- auto result_table =
- search_engine_ptr->distance_table(snapped_source_phantoms, snapped_target_phantoms);
-
- if (!result_table)
- {
- json_result.values["status_message"] = "No distance table found";
- return Status::EmptyResult;
- }
-
- osrm::json::Array matrix_json_array;
- for (const auto row : osrm::irange<std::size_t>(0, number_of_sources))
- {
- osrm::json::Array json_row;
- auto row_begin_iterator = result_table->begin() + (row * number_of_destination);
- auto row_end_iterator = result_table->begin() + ((row + 1) * number_of_destination);
- json_row.values.insert(json_row.values.end(), row_begin_iterator, row_end_iterator);
- matrix_json_array.values.push_back(json_row);
- }
- json_result.values["distance_table"] = matrix_json_array;
-
- osrm::json::Array target_coord_json_array;
- for (const auto &phantom : snapped_target_phantoms)
- {
- osrm::json::Array json_coord;
- json_coord.values.push_back(phantom.location.lat / COORDINATE_PRECISION);
- json_coord.values.push_back(phantom.location.lon / COORDINATE_PRECISION);
- target_coord_json_array.values.push_back(json_coord);
- }
- json_result.values["destination_coordinates"] = target_coord_json_array;
- osrm::json::Array source_coord_json_array;
- for (const auto &phantom : snapped_source_phantoms)
- {
- osrm::json::Array json_coord;
- json_coord.values.push_back(phantom.location.lat / COORDINATE_PRECISION);
- json_coord.values.push_back(phantom.location.lon / COORDINATE_PRECISION);
- source_coord_json_array.values.push_back(json_coord);
- }
- json_result.values["source_coordinates"] = source_coord_json_array;
- return Status::Ok;
- }
-
- private:
- std::string descriptor_string;
- DataFacadeT *facade;
-};
-
-#endif // DISTANCE_TABLE_HPP
diff --git a/plugins/hello_world.hpp b/plugins/hello_world.hpp
deleted file mode 100644
index 512fb07..0000000
--- a/plugins/hello_world.hpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef HELLO_WORLD_HPP
-#define HELLO_WORLD_HPP
-
-#include "plugin_base.hpp"
-
-#include "../util/json_renderer.hpp"
-
-#include <osrm/json_container.hpp>
-
-#include <string>
-
-class HelloWorldPlugin final : public BasePlugin
-{
- private:
- std::string temp_string;
-
- public:
- HelloWorldPlugin() : descriptor_string("hello") {}
- virtual ~HelloWorldPlugin() {}
- const std::string GetDescriptor() const override final { return descriptor_string; }
-
- Status HandleRequest(const RouteParameters &routeParameters,
- osrm::json::Object &json_result) override final
- {
- std::string temp_string;
- json_result.values["title"] = "Hello World";
-
- temp_string = std::to_string(routeParameters.zoom_level);
- json_result.values["zoom_level"] = temp_string;
-
- temp_string = std::to_string(routeParameters.check_sum);
- json_result.values["check_sum"] = temp_string;
- json_result.values["instructions"] = (routeParameters.print_instructions ? "yes" : "no");
- json_result.values["geometry"] = (routeParameters.geometry ? "yes" : "no");
- json_result.values["compression"] = (routeParameters.compression ? "yes" : "no");
- json_result.values["output_format"] =
- (!routeParameters.output_format.empty() ? "yes" : "no");
-
- json_result.values["jsonp_parameter"] =
- (!routeParameters.jsonp_parameter.empty() ? "yes" : "no");
- json_result.values["language"] = (!routeParameters.language.empty() ? "yes" : "no");
-
- temp_string = std::to_string(routeParameters.coordinates.size());
- json_result.values["location_count"] = temp_string;
-
- osrm::json::Array json_locations;
- unsigned counter = 0;
- for (const FixedPointCoordinate &coordinate : routeParameters.coordinates)
- {
- osrm::json::Object json_location;
- osrm::json::Array json_coordinates;
-
- json_coordinates.values.push_back(
- static_cast<double>(coordinate.lat / COORDINATE_PRECISION));
- json_coordinates.values.push_back(
- static_cast<double>(coordinate.lon / COORDINATE_PRECISION));
- json_location.values[std::to_string(counter)] = json_coordinates;
- json_locations.values.push_back(json_location);
- ++counter;
- }
- json_result.values["locations"] = json_locations;
- json_result.values["hint_count"] = routeParameters.hints.size();
-
- osrm::json::Array json_hints;
- counter = 0;
- for (const std::string ¤t_hint : routeParameters.hints)
- {
- json_hints.values.push_back(current_hint);
- ++counter;
- }
- json_result.values["hints"] = json_hints;
- return Status::Ok;
- }
-
- private:
- std::string descriptor_string;
-};
-
-#endif // HELLO_WORLD_HPP
diff --git a/plugins/match.hpp b/plugins/match.hpp
deleted file mode 100644
index e213d19..0000000
--- a/plugins/match.hpp
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef MATCH_HPP
-#define MATCH_HPP
-
-#include "plugin_base.hpp"
-
-#include "../algorithms/bayes_classifier.hpp"
-#include "../algorithms/object_encoder.hpp"
-#include "../data_structures/search_engine.hpp"
-#include "../descriptors/descriptor_base.hpp"
-#include "../descriptors/json_descriptor.hpp"
-#include "../routing_algorithms/map_matching.hpp"
-#include "../util/compute_angle.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/json_logger.hpp"
-#include "../util/json_util.hpp"
-#include "../util/string_util.hpp"
-
-#include <cstdlib>
-
-#include <algorithm>
-#include <memory>
-#include <string>
-#include <vector>
-
-template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
-{
- std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
-
- using ClassifierT = BayesClassifier<LaplaceDistribution, LaplaceDistribution, double>;
- using TraceClassification = ClassifierT::ClassificationT;
-
- public:
- MapMatchingPlugin(DataFacadeT *facade, const int max_locations_map_matching)
- : descriptor_string("match"), facade(facade),
- max_locations_map_matching(max_locations_map_matching),
- // the values where derived from fitting a laplace distribution
- // to the values of manually classified traces
- classifier(LaplaceDistribution(0.005986, 0.016646),
- LaplaceDistribution(0.054385, 0.458432),
- 0.696774) // valid apriori probability
- {
- search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
- }
-
- virtual ~MapMatchingPlugin() {}
-
- const std::string GetDescriptor() const final override { return descriptor_string; }
-
- TraceClassification
- classify(const float trace_length, const float matched_length, const int removed_points) const
- {
- (void)removed_points; // unused
-
- const double distance_feature = -std::log(trace_length) + std::log(matched_length);
-
- // matched to the same point
- if (!std::isfinite(distance_feature))
- {
- return std::make_pair(ClassifierT::ClassLabel::NEGATIVE, 1.0);
- }
-
- const auto label_with_confidence = classifier.classify(distance_feature);
-
- return label_with_confidence;
- }
-
- osrm::matching::CandidateLists getCandidates(
- const std::vector<FixedPointCoordinate> &input_coords,
- const std::vector<std::pair<const int, const boost::optional<int>>> &input_bearings,
- const double gps_precision,
- std::vector<double> &sub_trace_lengths)
- {
- osrm::matching::CandidateLists candidates_lists;
-
- // assuming the gps_precision is the standart-diviation of normal distribution that models
- // GPS noise (in this model) this should give us the correct candidate with >0.95
- double query_radius = 3 * gps_precision;
- double last_distance =
- coordinate_calculation::haversine_distance(input_coords[0], input_coords[1]);
-
- sub_trace_lengths.resize(input_coords.size());
- sub_trace_lengths[0] = 0;
- for (const auto current_coordinate : osrm::irange<std::size_t>(0, input_coords.size()))
- {
- bool allow_uturn = false;
- if (0 < current_coordinate)
- {
- last_distance = coordinate_calculation::haversine_distance(
- input_coords[current_coordinate - 1], input_coords[current_coordinate]);
-
- sub_trace_lengths[current_coordinate] +=
- sub_trace_lengths[current_coordinate - 1] + last_distance;
- }
-
- if (input_coords.size() - 1 > current_coordinate && 0 < current_coordinate)
- {
- double turn_angle = ComputeAngle::OfThreeFixedPointCoordinates(
- input_coords[current_coordinate - 1], input_coords[current_coordinate],
- input_coords[current_coordinate + 1]);
-
- // sharp turns indicate a possible uturn
- if (turn_angle <= 90.0 || turn_angle >= 270.0)
- {
- allow_uturn = true;
- }
- }
-
- // Use bearing values if supplied, otherwise fallback to 0,180 defaults
- auto bearing = input_bearings.size() > 0 ? input_bearings[current_coordinate].first : 0;
- auto range = input_bearings.size() > 0
- ? (input_bearings[current_coordinate].second
- ? *input_bearings[current_coordinate].second
- : 10)
- : 180;
- auto candidates = facade->NearestPhantomNodesInRange(input_coords[current_coordinate],
- query_radius, bearing, range);
-
- if (candidates.size() == 0)
- {
- break;
- }
-
- // sort by foward id, then by reverse id and then by distance
- std::sort(
- candidates.begin(), candidates.end(),
- [](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
- {
- return lhs.phantom_node.forward_node_id < rhs.phantom_node.forward_node_id ||
- (lhs.phantom_node.forward_node_id == rhs.phantom_node.forward_node_id &&
- (lhs.phantom_node.reverse_node_id < rhs.phantom_node.reverse_node_id ||
- (lhs.phantom_node.reverse_node_id ==
- rhs.phantom_node.reverse_node_id &&
- lhs.distance < rhs.distance)));
- });
-
- auto new_end = std::unique(
- candidates.begin(), candidates.end(),
- [](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
- {
- return lhs.phantom_node.forward_node_id == rhs.phantom_node.forward_node_id &&
- lhs.phantom_node.reverse_node_id == rhs.phantom_node.reverse_node_id;
- });
- candidates.resize(new_end - candidates.begin());
-
- if (!allow_uturn)
- {
- const auto compact_size = candidates.size();
- for (const auto i : osrm::irange<std::size_t>(0, compact_size))
- {
- // Split edge if it is bidirectional and append reverse direction to end of list
- if (candidates[i].phantom_node.forward_node_id != SPECIAL_NODEID &&
- candidates[i].phantom_node.reverse_node_id != SPECIAL_NODEID)
- {
- PhantomNode reverse_node(candidates[i].phantom_node);
- reverse_node.forward_node_id = SPECIAL_NODEID;
- candidates.push_back(
- PhantomNodeWithDistance{reverse_node, candidates[i].distance});
-
- candidates[i].phantom_node.reverse_node_id = SPECIAL_NODEID;
- }
- }
- }
-
- // sort by distance to make pruning effective
- std::sort(candidates.begin(), candidates.end(),
- [](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
- {
- return lhs.distance < rhs.distance;
- });
-
- candidates_lists.push_back(std::move(candidates));
- }
-
- return candidates_lists;
- }
-
- osrm::json::Object submatchingToJSON(const osrm::matching::SubMatching &sub,
- const RouteParameters &route_parameters,
- const InternalRouteResult &raw_route)
- {
- osrm::json::Object subtrace;
-
- if (route_parameters.classify)
- {
- subtrace.values["confidence"] = sub.confidence;
- }
-
- JSONDescriptor<DataFacadeT> json_descriptor(facade);
- json_descriptor.SetConfig(route_parameters);
-
- subtrace.values["hint_data"] = json_descriptor.BuildHintData(raw_route);
-
- if (route_parameters.geometry || route_parameters.print_instructions)
- {
- DescriptionFactory factory;
- FixedPointCoordinate current_coordinate;
- factory.SetStartSegment(raw_route.segment_end_coordinates.front().source_phantom,
- raw_route.source_traversed_in_reverse.front());
- for (const auto i :
- osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size()))
- {
- for (const PathData &path_data : raw_route.unpacked_path_segments[i])
- {
- current_coordinate = facade->GetCoordinateOfNode(path_data.node);
- factory.AppendSegment(current_coordinate, path_data);
- }
- factory.SetEndSegment(raw_route.segment_end_coordinates[i].target_phantom,
- raw_route.target_traversed_in_reverse[i],
- raw_route.is_via_leg(i));
- }
-
- factory.Run(route_parameters.zoom_level);
-
- // we need because we don't run path simplification
- for (auto &segment : factory.path_description)
- {
- segment.necessary = true;
- }
-
- if (route_parameters.geometry)
- {
- subtrace.values["geometry"] =
- factory.AppendGeometryString(route_parameters.compression);
- }
-
- if (route_parameters.print_instructions)
- {
- std::vector<typename JSONDescriptor<DataFacadeT>::Segment> temp_segments;
- subtrace.values["instructions"] =
- json_descriptor.BuildTextualDescription(factory, temp_segments);
- }
-
- factory.BuildRouteSummary(factory.get_entire_length(), raw_route.shortest_path_length);
- osrm::json::Object json_route_summary;
- json_route_summary.values["total_distance"] = factory.summary.distance;
- json_route_summary.values["total_time"] = factory.summary.duration;
- subtrace.values["route_summary"] = json_route_summary;
- }
-
- subtrace.values["indices"] = osrm::json::make_array(sub.indices);
-
- osrm::json::Array points;
- for (const auto &node : sub.nodes)
- {
- points.values.emplace_back(
- osrm::json::make_array(node.location.lat / COORDINATE_PRECISION,
- node.location.lon / COORDINATE_PRECISION));
- }
- subtrace.values["matched_points"] = points;
-
- osrm::json::Array names;
- for (const auto &node : sub.nodes)
- {
- names.values.emplace_back(facade->get_name_for_id(node.name_id));
- }
- subtrace.values["matched_names"] = names;
-
- return subtrace;
- }
-
- Status HandleRequest(const RouteParameters &route_parameters,
- osrm::json::Object &json_result) final override
- {
- // enforce maximum number of locations for performance reasons
- if (max_locations_map_matching > 0 &&
- static_cast<int>(route_parameters.coordinates.size()) > max_locations_map_matching)
- {
- json_result.values["status_message"] = "Too many coodindates";
- return Status::Error;
- }
-
- // check number of parameters
- if (!check_all_coordinates(route_parameters.coordinates))
- {
- json_result.values["status_message"] = "Invalid coordinates";
- return Status::Error;
- }
-
- std::vector<double> sub_trace_lengths;
- const auto &input_coords = route_parameters.coordinates;
- const auto &input_timestamps = route_parameters.timestamps;
- const auto &input_bearings = route_parameters.bearings;
- if (input_timestamps.size() > 0 && input_coords.size() != input_timestamps.size())
- {
- json_result.values["status_message"] =
- "Number of timestamps does not match number of coordinates";
- return Status::Error;
- }
-
- if (input_bearings.size() > 0 && input_coords.size() != input_bearings.size())
- {
- json_result.values["status_message"] =
- "Number of bearings does not match number of coordinates";
- return Status::Error;
- }
-
- // enforce maximum number of locations for performance reasons
- if (static_cast<int>(input_coords.size()) < 2)
- {
- json_result.values["status_message"] = "At least two coordinates needed";
- return Status::Error;
- }
-
- const auto candidates_lists = getCandidates(
- input_coords, input_bearings, route_parameters.gps_precision, sub_trace_lengths);
- if (candidates_lists.size() != input_coords.size())
- {
- BOOST_ASSERT(candidates_lists.size() < input_coords.size());
- json_result.values["status_message"] =
- std::string("Could not find a matching segment for coordinate ") +
- std::to_string(candidates_lists.size());
- return Status::NoSegment;
- }
-
- // setup logging if enabled
- if (osrm::json::Logger::get())
- osrm::json::Logger::get()->initialize("matching");
-
- // call the actual map matching
- osrm::matching::SubMatchingList sub_matchings;
- search_engine_ptr->map_matching(candidates_lists, input_coords, input_timestamps,
- route_parameters.matching_beta,
- route_parameters.gps_precision, sub_matchings);
-
- osrm::json::Array matchings;
- for (auto &sub : sub_matchings)
- {
- // classify result
- if (route_parameters.classify)
- {
- double trace_length =
- sub_trace_lengths[sub.indices.back()] - sub_trace_lengths[sub.indices.front()];
- TraceClassification classification =
- classify(trace_length, sub.length,
- (sub.indices.back() - sub.indices.front() + 1) - sub.nodes.size());
- if (classification.first == ClassifierT::ClassLabel::POSITIVE)
- {
- sub.confidence = classification.second;
- }
- else
- {
- sub.confidence = 1 - classification.second;
- }
- }
-
- BOOST_ASSERT(sub.nodes.size() > 1);
-
- // FIXME we only run this to obtain the geometry
- // The clean way would be to get this directly from the map matching plugin
- InternalRouteResult raw_route;
- PhantomNodes current_phantom_node_pair;
- for (unsigned i = 0; i < sub.nodes.size() - 1; ++i)
- {
- current_phantom_node_pair.source_phantom = sub.nodes[i];
- current_phantom_node_pair.target_phantom = sub.nodes[i + 1];
- BOOST_ASSERT(current_phantom_node_pair.source_phantom.is_valid());
- BOOST_ASSERT(current_phantom_node_pair.target_phantom.is_valid());
- raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
- }
- search_engine_ptr->shortest_path(
- raw_route.segment_end_coordinates,
- std::vector<bool>(raw_route.segment_end_coordinates.size() + 1, true), raw_route);
-
- BOOST_ASSERT(raw_route.shortest_path_length != INVALID_EDGE_WEIGHT);
-
- matchings.values.emplace_back(submatchingToJSON(sub, route_parameters, raw_route));
- }
-
- if (osrm::json::Logger::get())
- osrm::json::Logger::get()->render("matching", json_result);
- json_result.values["matchings"] = matchings;
-
- if (sub_matchings.empty())
- {
- json_result.values["status_message"] = "Cannot find matchings";
- return Status::EmptyResult;
- }
-
- json_result.values["status_message"] = "Found matchings";
- return Status::Ok;
- }
-
- private:
- std::string descriptor_string;
- DataFacadeT *facade;
- int max_locations_map_matching;
- ClassifierT classifier;
-};
-
-#endif // MATCH_HPP
diff --git a/plugins/nearest.hpp b/plugins/nearest.hpp
deleted file mode 100644
index 2459819..0000000
--- a/plugins/nearest.hpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef NEAREST_HPP
-#define NEAREST_HPP
-
-#include "plugin_base.hpp"
-
-#include "../data_structures/phantom_node.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/json_renderer.hpp"
-
-#include <osrm/json_container.hpp>
-
-#include <string>
-
-/*
- * This Plugin locates the nearest point on a street in the road network for a given coordinate.
- */
-
-template <class DataFacadeT> class NearestPlugin final : public BasePlugin
-{
- public:
- explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest") {}
-
- const std::string GetDescriptor() const override final { return descriptor_string; }
-
- Status HandleRequest(const RouteParameters &route_parameters,
- osrm::json::Object &json_result) override final
- {
- // check number of parameters
- if (route_parameters.coordinates.empty() ||
- !route_parameters.coordinates.front().is_valid())
- {
- return Status::Error;
- }
-
- const auto &input_bearings = route_parameters.bearings;
- if (input_bearings.size() > 0 &&
- route_parameters.coordinates.size() != input_bearings.size())
- {
- json_result.values["status_message"] =
- "Number of bearings does not match number of coordinates";
- return Status::Error;
- }
-
- auto number_of_results = static_cast<std::size_t>(route_parameters.num_results);
- const int bearing = input_bearings.size() > 0 ? input_bearings.front().first : 0;
- const int range =
- input_bearings.size() > 0
- ? (input_bearings.front().second ? *input_bearings.front().second : 10)
- : 180;
- auto phantom_node_vector = facade->NearestPhantomNodes(route_parameters.coordinates.front(),
- number_of_results, bearing, range);
-
- if (phantom_node_vector.empty())
- {
- json_result.values["status_message"] =
- std::string("Could not find a matching segments for coordinate");
- return Status::NoSegment;
- }
- else
- {
- json_result.values["status_message"] = "Found nearest edge";
- if (number_of_results > 1)
- {
- osrm::json::Array results;
-
- auto vector_length = phantom_node_vector.size();
- for (const auto i :
- osrm::irange<std::size_t>(0, std::min(number_of_results, vector_length)))
- {
- const auto &node = phantom_node_vector[i].phantom_node;
- osrm::json::Array json_coordinate;
- osrm::json::Object result;
- json_coordinate.values.push_back(node.location.lat / COORDINATE_PRECISION);
- json_coordinate.values.push_back(node.location.lon / COORDINATE_PRECISION);
- result.values["mapped coordinate"] = json_coordinate;
- result.values["name"] = facade->get_name_for_id(node.name_id);
- results.values.push_back(result);
- }
- json_result.values["results"] = results;
- }
- else
- {
- osrm::json::Array json_coordinate;
- json_coordinate.values.push_back(
- phantom_node_vector.front().phantom_node.location.lat / COORDINATE_PRECISION);
- json_coordinate.values.push_back(
- phantom_node_vector.front().phantom_node.location.lon / COORDINATE_PRECISION);
- json_result.values["mapped_coordinate"] = json_coordinate;
- json_result.values["name"] =
- facade->get_name_for_id(phantom_node_vector.front().phantom_node.name_id);
- }
- }
- return Status::Ok;
- }
-
- private:
- DataFacadeT *facade;
- std::string descriptor_string;
-};
-
-#endif /* NEAREST_HPP */
diff --git a/plugins/plugin_base.hpp b/plugins/plugin_base.hpp
deleted file mode 100644
index a05785a..0000000
--- a/plugins/plugin_base.hpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef BASE_PLUGIN_HPP
-#define BASE_PLUGIN_HPP
-
-#include "../data_structures/phantom_node.hpp"
-
-#include <osrm/coordinate.hpp>
-#include <osrm/json_container.hpp>
-#include <osrm/route_parameters.hpp>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-class BasePlugin
-{
- public:
- enum class Status : int
- {
- Ok = 200,
- EmptyResult = 207,
- NoSegment = 208,
- Error = 400
- };
-
- BasePlugin() {}
- // Maybe someone can explain the pure virtual destructor thing to me (dennis)
- virtual ~BasePlugin() {}
- virtual const std::string GetDescriptor() const = 0;
- virtual Status HandleRequest(const RouteParameters &, osrm::json::Object &) = 0;
- virtual bool check_all_coordinates(const std::vector<FixedPointCoordinate> &coordinates,
- const unsigned min = 2) const final
- {
- if (min > coordinates.size() || std::any_of(std::begin(coordinates), std::end(coordinates),
- [](const FixedPointCoordinate &coordinate)
- {
- return !coordinate.is_valid();
- }))
- {
- return false;
- }
- return true;
- }
-
- // Decides whether to use the phantom node from a big or small component if both are found.
- // Returns true if all phantom nodes are in the same component after snapping.
- std::vector<PhantomNode> snapPhantomNodes(
- const std::vector<std::pair<PhantomNode, PhantomNode>> &phantom_node_pair_list) const
- {
- const auto check_component_id_is_tiny =
- [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
- {
- return phantom_pair.first.component.is_tiny;
- };
-
- // are all phantoms from a tiny cc?
- const auto check_all_in_same_component =
- [](const std::vector<std::pair<PhantomNode, PhantomNode>> &nodes)
- {
- const auto component_id = nodes.front().first.component.id;
-
- return std::all_of(std::begin(nodes), std::end(nodes),
- [component_id](const PhantomNodePair &phantom_pair)
- {
- return component_id == phantom_pair.first.component.id;
- });
- };
-
- const auto fallback_to_big_component =
- [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
- {
- if (phantom_pair.first.component.is_tiny && phantom_pair.second.is_valid() &&
- !phantom_pair.second.component.is_tiny)
- {
- return phantom_pair.second;
- }
- return phantom_pair.first;
- };
-
- const auto use_closed_phantom = [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
- {
- return phantom_pair.first;
- };
-
- const bool every_phantom_is_in_tiny_cc =
- std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
- check_component_id_is_tiny);
- auto all_in_same_component = check_all_in_same_component(phantom_node_pair_list);
-
- std::vector<PhantomNode> snapped_phantoms;
- snapped_phantoms.reserve(phantom_node_pair_list.size());
-
- // The only case we don't snap to the big component if all phantoms are in the same small
- // component
- if (every_phantom_is_in_tiny_cc && all_in_same_component)
- {
- std::transform(phantom_node_pair_list.begin(), phantom_node_pair_list.end(),
- std::back_inserter(snapped_phantoms), use_closed_phantom);
- }
- else
- {
- std::transform(phantom_node_pair_list.begin(), phantom_node_pair_list.end(),
- std::back_inserter(snapped_phantoms), fallback_to_big_component);
- }
-
- return snapped_phantoms;
- }
-};
-
-#endif /* BASE_PLUGIN_HPP */
diff --git a/plugins/timestamp.hpp b/plugins/timestamp.hpp
deleted file mode 100644
index 899ef46..0000000
--- a/plugins/timestamp.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef TIMESTAMP_PLUGIN_H
-#define TIMESTAMP_PLUGIN_H
-
-#include "plugin_base.hpp"
-
-#include "../util/json_renderer.hpp"
-
-#include <osrm/json_container.hpp>
-
-#include <string>
-
-template <class DataFacadeT> class TimestampPlugin final : public BasePlugin
-{
- public:
- explicit TimestampPlugin(const DataFacadeT *facade)
- : facade(facade), descriptor_string("timestamp")
- {
- }
- const std::string GetDescriptor() const override final { return descriptor_string; }
- Status HandleRequest(const RouteParameters &route_parameters,
- osrm::json::Object &json_result) override final
- {
- (void)route_parameters; // unused
-
- const std::string timestamp = facade->GetTimestamp();
- json_result.values["timestamp"] = timestamp;
- return Status::Ok;
- }
-
- private:
- const DataFacadeT *facade;
- std::string descriptor_string;
-};
-
-#endif /* TIMESTAMP_PLUGIN_H */
diff --git a/plugins/trip.hpp b/plugins/trip.hpp
deleted file mode 100644
index b1ba55b..0000000
--- a/plugins/trip.hpp
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef TRIP_HPP
-#define TRIP_HPP
-
-#include "plugin_base.hpp"
-
-#include "../algorithms/object_encoder.hpp"
-#include "../algorithms/tarjan_scc.hpp"
-#include "../algorithms/trip_nearest_neighbour.hpp"
-#include "../algorithms/trip_farthest_insertion.hpp"
-#include "../algorithms/trip_brute_force.hpp"
-#include "../data_structures/search_engine.hpp"
-#include "../data_structures/matrix_graph_wrapper.hpp" // wrapper to use tarjan
- // scc on dist table
-#include "../descriptors/descriptor_base.hpp" // to make json output
-#include "../descriptors/json_descriptor.hpp" // to make json output
-#include "../util/make_unique.hpp"
-#include "../util/timing_util.hpp" // to time runtime
-//#include "../util/simple_logger.hpp" // for logging output
-#include "../util/dist_table_wrapper.hpp" // to access the dist
- // table more easily
-
-#include <osrm/json_container.hpp>
-#include <boost/assert.hpp>
-
-#include <cstdlib>
-#include <algorithm>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-#include <iterator>
-
-template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
-{
- private:
- std::string descriptor_string;
- DataFacadeT *facade;
- std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
- int max_locations_trip;
-
- public:
- explicit RoundTripPlugin(DataFacadeT *facade, int max_locations_trip)
- : descriptor_string("trip"), facade(facade), max_locations_trip(max_locations_trip)
- {
- search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
- }
-
- const std::string GetDescriptor() const override final { return descriptor_string; }
-
- std::vector<PhantomNode> GetPhantomNodes(const RouteParameters &route_parameters)
- {
- const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
- const auto &input_bearings = route_parameters.bearings;
-
- std::vector<PhantomNode> phantom_node_list;
- phantom_node_list.reserve(route_parameters.coordinates.size());
-
- // find phantom nodes for all input coords
- for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
- {
- // if client hints are helpful, encode hints
- if (checksum_OK && i < route_parameters.hints.size() &&
- !route_parameters.hints[i].empty())
- {
- PhantomNode current_phantom_node;
- ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
- if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
- {
- phantom_node_list.push_back(std::move(current_phantom_node));
- continue;
- }
- }
- const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
- const int range = input_bearings.size() > 0
- ? (input_bearings[i].second ? *input_bearings[i].second : 10)
- : 180;
- auto results = facade->NearestPhantomNodes(route_parameters.coordinates[i], 1, bearing, range);
- if (results.empty())
- {
- break;
- }
- phantom_node_list.push_back(std::move(results.front().phantom_node));
- BOOST_ASSERT(phantom_node_list.back().is_valid(facade->GetNumberOfNodes()));
- }
-
- return phantom_node_list;
- }
-
- // Object to hold all strongly connected components (scc) of a graph
- // to access all graphs with component ID i, get the iterators by:
- // auto start = std::begin(scc_component.component) + scc_component.range[i];
- // auto end = std::begin(scc_component.component) + scc_component.range[i+1];
- struct SCC_Component
- {
- // in_component: all NodeIDs sorted by component ID
- // in_range: index where a new component starts
- //
- // example: NodeID 0, 1, 2, 4, 5 are in component 0
- // NodeID 3, 6, 7, 8 are in component 1
- // => in_component = [0, 1, 2, 4, 5, 3, 6, 7, 8]
- // => in_range = [0, 5]
- SCC_Component(std::vector<NodeID> in_component_nodes, std::vector<size_t> in_range)
- : component(std::move(in_component_nodes)), range(std::move(in_range))
- {
- BOOST_ASSERT_MSG(component.size() > 0, "there's no scc component");
- BOOST_ASSERT_MSG(*std::max_element(range.begin(), range.end()) == component.size(),
- "scc component ranges are out of bound");
- BOOST_ASSERT_MSG(*std::min_element(range.begin(), range.end()) == 0,
- "invalid scc component range");
- BOOST_ASSERT_MSG(std::is_sorted(std::begin(range), std::end(range)),
- "invalid component ranges");
- };
-
- std::size_t GetNumberOfComponents() const
- {
- BOOST_ASSERT_MSG(range.size() > 0, "there's no range");
- return range.size() - 1;
- }
-
- const std::vector<NodeID> component;
- std::vector<std::size_t> range;
- };
-
- // takes the number of locations and its distance matrix,
- // identifies and splits the graph in its strongly connected components (scc)
- // and returns an SCC_Component
- SCC_Component SplitUnaccessibleLocations(const std::size_t number_of_locations,
- const DistTableWrapper<EdgeWeight> &result_table)
- {
-
- if (std::find(std::begin(result_table), std::end(result_table), INVALID_EDGE_WEIGHT) ==
- std::end(result_table))
- {
- // whole graph is one scc
- std::vector<NodeID> location_ids(number_of_locations);
- std::iota(std::begin(location_ids), std::end(location_ids), 0);
- std::vector<size_t> range = {0, location_ids.size()};
- return SCC_Component(std::move(location_ids), std::move(range));
- }
-
- // Run TarjanSCC
- auto wrapper = std::make_shared<MatrixGraphWrapper<EdgeWeight>>(result_table.GetTable(),
- number_of_locations);
- auto scc = TarjanSCC<MatrixGraphWrapper<EdgeWeight>>(wrapper);
- scc.run();
-
- const auto number_of_components = scc.get_number_of_components();
-
- std::vector<std::size_t> range_insertion;
- std::vector<std::size_t> range;
- range_insertion.reserve(number_of_components);
- range.reserve(number_of_components);
-
- std::vector<NodeID> components(number_of_locations, 0);
-
- std::size_t prefix = 0;
- for (std::size_t j = 0; j < number_of_components; ++j)
- {
- range_insertion.push_back(prefix);
- range.push_back(prefix);
- prefix += scc.get_component_size(j);
- }
- // senitel
- range.push_back(components.size());
-
- for (std::size_t i = 0; i < number_of_locations; ++i)
- {
- components[range_insertion[scc.get_component_id(i)]] = i;
- ++range_insertion[scc.get_component_id(i)];
- }
-
- return SCC_Component(std::move(components), std::move(range));
- }
-
- void SetLocPermutationOutput(const std::vector<NodeID> &permutation,
- osrm::json::Object &json_result)
- {
- osrm::json::Array json_permutation;
- json_permutation.values.insert(std::end(json_permutation.values), std::begin(permutation),
- std::end(permutation));
- json_result.values["permutation"] = json_permutation;
- }
-
- InternalRouteResult ComputeRoute(const std::vector<PhantomNode> &phantom_node_list,
- const RouteParameters &route_parameters,
- const std::vector<NodeID> &trip)
- {
- InternalRouteResult min_route;
- // given he final trip, compute total distance and return the route and location permutation
- PhantomNodes viapoint;
- const auto start = std::begin(trip);
- const auto end = std::end(trip);
- // computes a roundtrip from the nodes in trip
- for (auto it = start; it != end; ++it)
- {
- const auto from_node = *it;
- // if from_node is the last node, compute the route from the last to the first location
- const auto to_node = std::next(it) != end ? *std::next(it) : *start;
-
- viapoint = PhantomNodes{phantom_node_list[from_node], phantom_node_list[to_node]};
- min_route.segment_end_coordinates.emplace_back(viapoint);
- }
- BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size());
-
- std::vector<bool> uturns(trip.size() + 1);
- BOOST_ASSERT(route_parameters.uturns.size() > 0);
- std::transform(trip.begin(), trip.end(), uturns.begin(),
- [&route_parameters](const NodeID idx)
- {
- return route_parameters.uturns[idx];
- });
- BOOST_ASSERT(uturns.size() > 0);
- uturns.back() = route_parameters.uturns[trip.front()];
-
- search_engine_ptr->shortest_path(min_route.segment_end_coordinates, uturns, min_route);
-
- BOOST_ASSERT_MSG(min_route.shortest_path_length < INVALID_EDGE_WEIGHT, "unroutable route");
- return min_route;
- }
-
- Status HandleRequest(const RouteParameters &route_parameters,
- osrm::json::Object &json_result) override final
- {
- if (max_locations_trip > 0 &&
- (static_cast<int>(route_parameters.coordinates.size()) > max_locations_trip))
- {
- json_result.values["status_message"] =
- "Number of entries " + std::to_string(route_parameters.coordinates.size()) +
- " is higher than current maximum (" + std::to_string(max_locations_trip) + ")";
- return Status::Error;
- }
-
- // check if all inputs are coordinates
- if (!check_all_coordinates(route_parameters.coordinates))
- {
- json_result.values["status_message"] = "Invalid coordinates";
- return Status::Error;
- }
-
- const auto &input_bearings = route_parameters.bearings;
- if (input_bearings.size() > 0 &&
- route_parameters.coordinates.size() != input_bearings.size())
- {
- json_result.values["status_message"] =
- "Number of bearings does not match number of coordinates";
- return Status::Error;
- }
-
- // get phantom nodes
- auto phantom_node_list = GetPhantomNodes(route_parameters);
- if (phantom_node_list.size() != route_parameters.coordinates.size())
- {
- BOOST_ASSERT(phantom_node_list.size() < route_parameters.coordinates.size());
- json_result.values["status_message"] =
- std::string("Could not find a matching segment for coordinate ") +
- std::to_string(phantom_node_list.size());
- return Status::NoSegment;
- }
-
- const auto number_of_locations = phantom_node_list.size();
-
- // compute the distance table of all phantom nodes
- const auto result_table = DistTableWrapper<EdgeWeight>(
- *search_engine_ptr->distance_table(phantom_node_list, phantom_node_list),
- number_of_locations);
-
- if (result_table.size() == 0)
- {
- return Status::Error;
- }
-
- const constexpr std::size_t BF_MAX_FEASABLE = 10;
- BOOST_ASSERT_MSG(result_table.size() == number_of_locations * number_of_locations,
- "Distance Table has wrong size");
-
- // get scc components
- SCC_Component scc = SplitUnaccessibleLocations(number_of_locations, result_table);
-
- using NodeIDIterator = typename std::vector<NodeID>::const_iterator;
-
- std::vector<std::vector<NodeID>> route_result;
- route_result.reserve(scc.GetNumberOfComponents());
- TIMER_START(TRIP_TIMER);
- // run Trip computation for every SCC
- for (std::size_t k = 0; k < scc.GetNumberOfComponents(); ++k)
- {
- const auto component_size = scc.range[k + 1] - scc.range[k];
-
- BOOST_ASSERT_MSG(component_size > 0, "invalid component size");
-
- std::vector<NodeID> scc_route;
- NodeIDIterator start = std::begin(scc.component) + scc.range[k];
- NodeIDIterator end = std::begin(scc.component) + scc.range[k + 1];
-
- if (component_size > 1)
- {
-
- if (component_size < BF_MAX_FEASABLE)
- {
- scc_route =
- osrm::trip::BruteForceTrip(start, end, number_of_locations, result_table);
- }
- else
- {
- scc_route = osrm::trip::FarthestInsertionTrip(start, end, number_of_locations,
- result_table);
- }
-
- // use this output if debugging of route is needed:
- // SimpleLogger().Write() << "Route #" << k << ": " << [&scc_route]()
- // {
- // std::string s = "";
- // for (auto x : scc_route)
- // {
- // s += std::to_string(x) + " ";
- // }
- // return s;
- // }();
-
- }
- else
- {
- scc_route = std::vector<NodeID>(start, end);
- }
-
- route_result.push_back(std::move(scc_route));
- }
-
- // compute all round trip routes
- std::vector<InternalRouteResult> comp_route;
- comp_route.reserve(route_result.size());
- for (auto &elem : route_result)
- {
- comp_route.push_back(ComputeRoute(phantom_node_list, route_parameters, elem));
- }
-
- TIMER_STOP(TRIP_TIMER);
-
- // prepare JSON output
- // create a json object for every trip
- osrm::json::Array trip;
- for (std::size_t i = 0; i < route_result.size(); ++i)
- {
- std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor =
- osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
- descriptor->SetConfig(route_parameters);
-
- osrm::json::Object scc_trip;
-
- // set permutation output
- SetLocPermutationOutput(route_result[i], scc_trip);
- // set viaroute output
- descriptor->Run(comp_route[i], scc_trip);
-
- trip.values.push_back(std::move(scc_trip));
- }
-
-
- if (trip.values.empty())
- {
- json_result.values["status_message"] = "Cannot find trips";
- return Status::EmptyResult;
- }
-
- json_result.values["trips"] = std::move(trip);
- json_result.values["status_message"] = "Found trips";
- return Status::Ok;
- }
-};
-
-#endif // TRIP_HPP
diff --git a/plugins/viaroute.hpp b/plugins/viaroute.hpp
deleted file mode 100644
index 21e8714..0000000
--- a/plugins/viaroute.hpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef VIA_ROUTE_HPP
-#define VIA_ROUTE_HPP
-
-#include "plugin_base.hpp"
-
-#include "../algorithms/object_encoder.hpp"
-#include "../data_structures/search_engine.hpp"
-#include "../descriptors/descriptor_base.hpp"
-#include "../descriptors/gpx_descriptor.hpp"
-#include "../descriptors/json_descriptor.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/json_renderer.hpp"
-#include "../util/make_unique.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/timing_util.hpp"
-
-#include <osrm/json_container.hpp>
-
-#include <cstdlib>
-
-#include <algorithm>
-#include <memory>
-#include <string>
-#include <vector>
-
-template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
-{
- private:
- DescriptorTable descriptor_table;
- std::string descriptor_string;
- std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
- DataFacadeT *facade;
- int max_locations_viaroute;
-
- public:
- explicit ViaRoutePlugin(DataFacadeT *facade, int max_locations_viaroute)
- : descriptor_string("viaroute"), facade(facade),
- max_locations_viaroute(max_locations_viaroute)
- {
- search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
-
- descriptor_table.emplace("json", 0);
- descriptor_table.emplace("gpx", 1);
- // descriptor_table.emplace("geojson", 2);
- }
-
- virtual ~ViaRoutePlugin() {}
-
- const std::string GetDescriptor() const override final { return descriptor_string; }
-
- Status HandleRequest(const RouteParameters &route_parameters,
- osrm::json::Object &json_result) override final
- {
- if (max_locations_viaroute > 0 &&
- (static_cast<int>(route_parameters.coordinates.size()) > max_locations_viaroute))
- {
- json_result.values["status_message"] =
- "Number of entries " + std::to_string(route_parameters.coordinates.size()) +
- " is higher than current maximum (" + std::to_string(max_locations_viaroute) + ")";
- return Status::Error;
- }
-
- if (!check_all_coordinates(route_parameters.coordinates))
- {
- json_result.values["status_message"] = "Invalid coordinates";
- return Status::Error;
- }
-
- const auto &input_bearings = route_parameters.bearings;
- if (input_bearings.size() > 0 &&
- route_parameters.coordinates.size() != input_bearings.size())
- {
- json_result.values["status_message"] =
- "Number of bearings does not match number of coordinate";
- return Status::Error;
- }
-
- std::vector<PhantomNodePair> phantom_node_pair_list(route_parameters.coordinates.size());
- const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
-
- for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
- {
- if (checksum_OK && i < route_parameters.hints.size() &&
- !route_parameters.hints[i].empty())
- {
- ObjectEncoder::DecodeFromBase64(route_parameters.hints[i],
- phantom_node_pair_list[i].first);
- if (phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
- {
- continue;
- }
- }
- const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
- const int range = input_bearings.size() > 0
- ? (input_bearings[i].second ? *input_bearings[i].second : 10)
- : 180;
- phantom_node_pair_list[i] = facade->NearestPhantomNodeWithAlternativeFromBigComponent(
- route_parameters.coordinates[i], bearing, range);
- // we didn't found a fitting node, return error
- if (!phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
- {
- json_result.values["status_message"] =
- std::string("Could not find a matching segment for coordinate ") +
- std::to_string(i);
- return Status::NoSegment;
- }
- BOOST_ASSERT(phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()));
- BOOST_ASSERT(phantom_node_pair_list[i].second.is_valid(facade->GetNumberOfNodes()));
- }
-
- auto snapped_phantoms = snapPhantomNodes(phantom_node_pair_list);
-
- InternalRouteResult raw_route;
- auto build_phantom_pairs = [&raw_route](const PhantomNode &first_node,
- const PhantomNode &second_node)
- {
- raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node});
- };
- osrm::for_each_pair(snapped_phantoms, build_phantom_pairs);
-
- if (1 == raw_route.segment_end_coordinates.size())
- {
- if (route_parameters.alternate_route)
- {
- search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
- raw_route);
- }
- else
- {
- search_engine_ptr->direct_shortest_path(raw_route.segment_end_coordinates,
- route_parameters.uturns, raw_route);
- }
- }
- else
- {
- search_engine_ptr->shortest_path(raw_route.segment_end_coordinates,
- route_parameters.uturns, raw_route);
- }
-
- // we can only know this after the fact, different SCC ids still
- // allow for connection in one direction.
- if (raw_route.shortest_path_length == INVALID_EDGE_WEIGHT)
- {
- auto first_component_id = snapped_phantoms.front().component.id;
- auto not_in_same_component =
- std::any_of(snapped_phantoms.begin(), snapped_phantoms.end(),
- [first_component_id](const PhantomNode &node)
- {
- return node.component.id != first_component_id;
- });
-
- if (not_in_same_component)
- {
- json_result.values["status_message"] = "Impossible route between points";
- return Status::EmptyResult;
- }
- else
- {
- json_result.values["status_message"] = "No route found between points";
- return Status::Error;
- }
- }
- else
- {
- std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
- switch (descriptor_table.get_id(route_parameters.output_format))
- {
- case 1:
- descriptor = osrm::make_unique<GPXDescriptor<DataFacadeT>>(facade);
- break;
- // case 2:
- // descriptor = osrm::make_unique<GEOJSONDescriptor<DataFacadeT>>();
- // break;
- default:
- descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
- break;
- }
-
- descriptor->SetConfig(route_parameters);
- descriptor->Run(raw_route, json_result);
- json_result.values["status_message"] = "Found route between points";
- }
-
- return Status::Ok;
- }
-};
-
-#endif // VIA_ROUTE_HPP
diff --git a/prepare.cpp b/prepare.cpp
deleted file mode 100644
index aaf9376..0000000
--- a/prepare.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "contractor/processing_chain.hpp"
-#include "contractor/contractor_options.hpp"
-#include "util/simple_logger.hpp"
-
-#include <boost/program_options/errors.hpp>
-
-#include <tbb/task_scheduler_init.h>
-
-#include <cstdlib>
-#include <exception>
-#include <ostream>
-#include <new>
-
-int main(int argc, char *argv[]) try
-{
- LogPolicy::GetInstance().Unmute();
- ContractorConfig contractor_config;
-
- const return_code result = ContractorOptions::ParseArguments(argc, argv, contractor_config);
-
- if (return_code::fail == result)
- {
- return EXIT_FAILURE;
- }
-
- if (return_code::exit == result)
- {
- return EXIT_SUCCESS;
- }
-
- ContractorOptions::GenerateOutputFilesNames(contractor_config);
-
- if (1 > contractor_config.requested_num_threads)
- {
- SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
- return EXIT_FAILURE;
- }
-
- const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
-
- if (recommended_num_threads != contractor_config.requested_num_threads)
- {
- SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
- << recommended_num_threads
- << "! This setting may have performance side-effects.";
- }
-
- if (!boost::filesystem::is_regular_file(contractor_config.osrm_input_path))
- {
- SimpleLogger().Write(logWARNING)
- << "Input file " << contractor_config.osrm_input_path.string() << " not found!";
- return EXIT_FAILURE;
- }
-
- if (!boost::filesystem::is_regular_file(contractor_config.profile_path))
- {
- SimpleLogger().Write(logWARNING) << "Profile " << contractor_config.profile_path.string()
- << " not found!";
- return EXIT_FAILURE;
- }
-
- SimpleLogger().Write() << "Input file: "
- << contractor_config.osrm_input_path.filename().string();
- SimpleLogger().Write() << "Profile: " << contractor_config.profile_path.filename().string();
- SimpleLogger().Write() << "Threads: " << contractor_config.requested_num_threads;
-
- tbb::task_scheduler_init init(contractor_config.requested_num_threads);
-
- return Prepare(contractor_config).Run();
-}
-catch (const std::bad_alloc &e)
-{
- SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
- SimpleLogger().Write(logWARNING)
- << "Please provide more memory or consider using a larger swapfile";
- return EXIT_FAILURE;
-}
-catch (const std::exception &e)
-{
- SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
- return EXIT_FAILURE;
-}
diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua
index 1ebbffd..5575747 100644
--- a/profiles/bicycle.lua
+++ b/profiles/bicycle.lua
@@ -91,9 +91,10 @@ surface_speeds = {
}
-- these need to be global because they are accesed externaly
-traffic_signal_penalty = 2
-use_turn_restrictions = false
-u_turn_penalty = 20
+properties.traffic_signal_penalty = 2
+properties.use_turn_restrictions = false
+properties.u_turn_penalty = 20
+properties.allow_u_turn_at_via = true
local obey_oneway = true
local ignore_areas = true
@@ -105,13 +106,6 @@ local safety_penalty = 1.0
local use_public_transport = true
local fallback_names = true
---modes
-local mode_normal = 1
-local mode_pushing = 2
-local mode_ferry = 3
-local mode_train = 4
-local mode_movable_bridge = 5
-
local function parse_maxspeed(source)
if not source then
return 0
@@ -191,6 +185,9 @@ function way_function (way, result)
return
end
+ result.forward_mode = mode.cycling
+ result.backward_mode = mode.cycling
+
-- other tags
local name = way:get_value_by_key("name")
local ref = way:get_value_by_key("ref")
@@ -237,14 +234,14 @@ function way_function (way, result)
if duration and durationIsValid(duration) then
result.duration = math.max( parseDuration(duration), 1 )
end
- result.forward_mode = mode_movable_bridge
- result.backward_mode = mode_movable_bridge
+ result.forward_mode = mode.movable_bridge
+ result.backward_mode = mode.movable_bridge
result.forward_speed = bridge_speed
result.backward_speed = bridge_speed
elseif route_speeds[route] then
-- ferries (doesn't cover routes tagged using relations)
- result.forward_mode = mode_ferry
- result.backward_mode = mode_ferry
+ result.forward_mode = mode.ferry
+ result.backward_mode = mode.ferry
result.ignore_in_grid = true
if duration and durationIsValid(duration) then
result.duration = math.max( 1, parseDuration(duration) )
@@ -262,8 +259,8 @@ function way_function (way, result)
result.forward_speed = platform_speeds[public_transport]
result.backward_speed = platform_speeds[public_transport]
elseif use_public_transport and railway and railway_speeds[railway] then
- result.forward_mode = mode_train
- result.backward_mode = mode_train
+ result.forward_mode = mode.train
+ result.backward_mode = mode.train
-- railways
if access and access_tag_whitelist[access] then
result.forward_speed = railway_speeds[railway]
@@ -293,27 +290,27 @@ function way_function (way, result)
-- pedestrian-only ways and areas
result.forward_speed = pedestrian_speeds[highway]
result.backward_speed = pedestrian_speeds[highway]
- result.forward_mode = mode_pushing
- result.backward_mode = mode_pushing
+ result.forward_mode = mode.pushing_bike
+ result.backward_mode = mode.pushing_bike
elseif man_made and man_made_speeds[man_made] then
-- man made structures
result.forward_speed = man_made_speeds[man_made]
result.backward_speed = man_made_speeds[man_made]
- result.forward_mode = mode_pushing
- result.backward_mode = mode_pushing
+ result.forward_mode = mode.pushing_bike
+ result.backward_mode = mode.pushing_bike
elseif foot == 'yes' then
result.forward_speed = walking_speed
result.backward_speed = walking_speed
- result.forward_mode = mode_pushing
- result.backward_mode = mode_pushing
+ result.forward_mode = mode.pushing_bike
+ result.backward_mode = mode.pushing_bike
elseif foot_forward == 'yes' then
result.forward_speed = walking_speed
- result.forward_mode = mode_pushing
- result.backward_mode = 0
+ result.forward_mode = mode.pushing_bike
+ result.backward_mode = mode.inaccessible
elseif foot_backward == 'yes' then
result.forward_speed = walking_speed
- result.forward_mode = 0
- result.backward_mode = mode_pushing
+ result.forward_mode = mode.inaccessible
+ result.backward_mode = mode.pushing_bike
end
end
end
@@ -325,48 +322,48 @@ function way_function (way, result)
end
if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then
- result.backward_mode = 0
+ result.backward_mode = mode.inaccessible
elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then
-- prevent implied oneway
elseif onewayClass == "-1" then
- result.forward_mode = 0
+ result.forward_mode = mode.inaccessible
elseif oneway == "no" or oneway == "0" or oneway == "false" then
-- prevent implied oneway
elseif cycleway and string.find(cycleway, "opposite") == 1 then
if impliedOneway then
- result.forward_mode = 0
- result.backward_mode = mode_normal
+ result.forward_mode = mode.inaccessible
+ result.backward_mode = mode.cycling
result.backward_speed = bicycle_speeds["cycleway"]
end
elseif cycleway_left and cycleway_tags[cycleway_left] and cycleway_right and cycleway_tags[cycleway_right] then
-- prevent implied
elseif cycleway_left and cycleway_tags[cycleway_left] then
if impliedOneway then
- result.forward_mode = 0
- result.backward_mode = mode_normal
+ result.forward_mode = mode.inaccessible
+ result.backward_mode = mode.cycling
result.backward_speed = bicycle_speeds["cycleway"]
end
elseif cycleway_right and cycleway_tags[cycleway_right] then
if impliedOneway then
- result.forward_mode = mode_normal
+ result.forward_mode = mode.cycling
result.backward_speed = bicycle_speeds["cycleway"]
- result.backward_mode = 0
+ result.backward_mode = mode.inaccessible
end
elseif oneway == "-1" then
- result.forward_mode = 0
+ result.forward_mode = mode.inaccessible
elseif oneway == "yes" or oneway == "1" or oneway == "true" or impliedOneway then
- result.backward_mode = 0
+ result.backward_mode = mode.inaccessible
end
-- pushing bikes
if bicycle_speeds[highway] or pedestrian_speeds[highway] then
if foot ~= "no" and junction ~= "roundabout" then
- if result.backward_mode == 0 then
+ if result.backward_mode == mode.inaccessible then
result.backward_speed = walking_speed
- result.backward_mode = mode_pushing
- elseif result.forward_mode == 0 then
+ result.backward_mode = mode.pushing_bike
+ elseif result.forward_mode == mode.inaccessible then
result.forward_speed = walking_speed
- result.forward_mode = mode_pushing
+ result.forward_mode = mode.pushing_bike
end
end
end
@@ -382,8 +379,8 @@ function way_function (way, result)
-- dismount
if bicycle == "dismount" then
- result.forward_mode = mode_pushing
- result.backward_mode = mode_pushing
+ result.forward_mode = mode.pushing_bike
+ result.backward_mode = mode.pushing_bike
result.forward_speed = walking_speed
result.backward_speed = walking_speed
end
diff --git a/profiles/car.lua b/profiles/car.lua
index 959558f..8b1e7f2 100644
--- a/profiles/car.lua
+++ b/profiles/car.lua
@@ -128,18 +128,20 @@ maxspeed_table = {
["uk:motorway"] = (70*1609)/1000
}
--- these need to be global because they are accesed externaly
-u_turn_penalty = 20
-traffic_signal_penalty = 2
-use_turn_restrictions = true
+-- set profile properties
+properties.u_turn_penalty = 20
+properties.traffic_signal_penalty = 2
+properties.use_turn_restrictions = true
-local turn_penalty = 10
+local side_road_speed_multiplier = 0.8
+
+local turn_penalty = 10
-- Note: this biases right-side driving. Should be
-- inverted for left-driving countries.
-local turn_bias = 1.2
+local turn_bias = 1.2
-local obey_oneway = true
-local ignore_areas = true
+local obey_oneway = true
+local ignore_areas = true
local abs = math.abs
local min = math.min
@@ -147,11 +149,6 @@ local max = math.max
local speed_reduction = 0.8
---modes
-local mode_normal = 1
-local mode_ferry = 2
-local mode_movable_bridge = 3
-
function get_exceptions(vector)
for i,v in ipairs(restriction_exception_tags) do
vector:Add(v)
@@ -246,6 +243,9 @@ function way_function (way, result)
return
end
+ result.forward_mode = mode.driving
+ result.backward_mode = mode.driving
+
-- handling ferries and piers
local route_speed = speed_profile[route]
if (route_speed and route_speed > 0) then
@@ -254,8 +254,8 @@ function way_function (way, result)
if duration and durationIsValid(duration) then
result.duration = max( parseDuration(duration), 1 )
end
- result.forward_mode = mode_ferry
- result.backward_mode = mode_ferry
+ result.forward_mode = mode.ferry
+ result.backward_mode = mode.ferry
result.forward_speed = route_speed
result.backward_speed = route_speed
end
@@ -269,8 +269,8 @@ function way_function (way, result)
if duration and durationIsValid(duration) then
result.duration = max( parseDuration(duration), 1 )
end
- result.forward_mode = mode_movable_bridge
- result.backward_mode = mode_movable_bridge
+ result.forward_mode = mode.movable_bridge
+ result.backward_mode = mode.movable_bridge
result.forward_speed = bridge_speed
result.backward_speed = bridge_speed
end
@@ -311,6 +311,14 @@ function way_function (way, result)
return
end
+ -- reduce speed on special side roads
+ local sideway = way:get_value_by_key("side_road")
+ if "yes" == sideway or
+ "rotary" == sideway then
+ result.forward_speed = result.forward_speed * side_road_speed_multiplier
+ result.backward_speed = result.backward_speed * side_road_speed_multiplier
+ end
+
-- reduce speed on bad surfaces
local surface = way:get_value_by_key("surface")
local tracktype = way:get_value_by_key("tracktype")
@@ -368,14 +376,14 @@ function way_function (way, result)
-- Set direction according to tags on way
if obey_oneway then
if oneway == "-1" then
- result.forward_mode = 0
+ result.forward_mode = mode.inaccessible
elseif oneway == "yes" or
oneway == "1" or
oneway == "true" or
junction == "roundabout" or
(highway == "motorway_link" and oneway ~="no") or
(highway == "motorway" and oneway ~= "no") then
- result.backward_mode = 0
+ result.backward_mode = mode.inaccessible
end
end
@@ -383,7 +391,7 @@ function way_function (way, result)
local maxspeed_forward = parse_maxspeed(way:get_value_by_key("maxspeed:forward"))
local maxspeed_backward = parse_maxspeed(way:get_value_by_key("maxspeed:backward"))
if maxspeed_forward and maxspeed_forward > 0 then
- if 0 ~= result.forward_mode and 0 ~= result.backward_mode then
+ if mode.inaccessible ~= result.forward_mode and mode.inaccessible ~= result.backward_mode then
result.backward_speed = result.forward_speed
end
result.forward_speed = maxspeed_forward
@@ -398,15 +406,15 @@ function way_function (way, result)
local advisory_backward = parse_maxspeed(way:get_value_by_key("maxspeed:advisory:backward"))
-- apply bi-directional advisory speed first
if advisory_speed and advisory_speed > 0 then
- if 0 ~= result.forward_mode then
+ if mode.inaccessible ~= result.forward_mode then
result.forward_speed = advisory_speed
end
- if 0 ~= result.backward_mode then
+ if mode.inaccessible ~= result.backward_mode then
result.backward_speed = advisory_speed
end
end
if advisory_forward and advisory_forward > 0 then
- if 0 ~= result.forward_mode and 0 ~= result.backward_mode then
+ if mode.inaccessible ~= result.forward_mode and mode.inaccessible ~= result.backward_mode then
result.backward_speed = result.forward_speed
end
result.forward_speed = advisory_forward
@@ -429,7 +437,7 @@ function way_function (way, result)
end
end
- local is_bidirectional = result.forward_mode ~= 0 and result.backward_mode ~= 0
+ local is_bidirectional = result.forward_mode ~= mode.inaccessible and result.backward_mode ~= mode.inaccessible
-- scale speeds to get better avg driving times
if result.forward_speed > 0 then
@@ -451,7 +459,7 @@ function way_function (way, result)
end
-- only allow this road as start point if it not a ferry
- result.is_startpoint = result.forward_mode == mode_normal or result.backward_mode == mode_normal
+ result.is_startpoint = result.forward_mode == mode.driving or result.backward_mode == mode.driving
end
function turn_function (angle)
diff --git a/profiles/foot.lua b/profiles/foot.lua
index 61751e3..af1f76e 100644
--- a/profiles/foot.lua
+++ b/profiles/foot.lua
@@ -64,14 +64,12 @@ leisure_speeds = {
["track"] = walking_speed
}
-traffic_signal_penalty = 2
-u_turn_penalty = 2
-use_turn_restrictions = false
-local fallback_names = true
+properties.traffic_signal_penalty = 2
+properties.u_turn_penalty = 2
+properties.use_turn_restrictions = false
+properties.allow_u_turn_at_via = true
---modes
-local mode_normal = 1
-local mode_ferry = 2
+local fallback_names = true
function get_exceptions(vector)
for i,v in ipairs(restriction_exception_tags) do
@@ -138,6 +136,9 @@ function way_function (way, result)
return
end
+ result.forward_mode = mode.walking
+ result.backward_mode = mode.walking
+
local name = way:get_value_by_key("name")
local ref = way:get_value_by_key("ref")
local junction = way:get_value_by_key("junction")
@@ -175,8 +176,8 @@ function way_function (way, result)
result.forward_speed = route_speeds[route]
result.backward_speed = route_speeds[route]
end
- result.forward_mode = mode_ferry
- result.backward_mode = mode_ferry
+ result.forward_mode = mode.ferry
+ result.backward_mode = mode.ferry
elseif railway and platform_speeds[railway] then
-- railway platforms (old tagging scheme)
result.forward_speed = platform_speeds[railway]
@@ -205,11 +206,11 @@ function way_function (way, result)
-- oneway
if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then
- result.backward_mode = 0
+ result.backward_mode = mode.inaccessible
elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then
-- nothing to do
elseif onewayClass == "-1" then
- result.forward_mode = 0
+ result.forward_mode = mode.inaccessible
end
-- surfaces
diff --git a/profiles/rasterbot.lua b/profiles/rasterbot.lua
index 847384d..03ff8f2 100644
--- a/profiles/rasterbot.lua
+++ b/profiles/rasterbot.lua
@@ -13,6 +13,9 @@ function way_function (way, result)
result.name = name
end
+ result.forward_mode = mode.cycling
+ result.backward_mode = mode.cycling
+
result.forward_speed = 15
result.backward_speed = 15
end
@@ -32,15 +35,15 @@ end
function segment_function (source, target, distance, weight)
local sourceData = sources:query(raster_source, source.lon, source.lat)
local targetData = sources:query(raster_source, target.lon, target.lat)
- print ("evaluating segment: " .. sourceData.datum .. " " .. targetData.datum)
+ io.write("evaluating segment: " .. sourceData.datum .. " " .. targetData.datum .. "\n")
local invalid = sourceData.invalid_data()
if sourceData.datum ~= invalid and targetData.datum ~= invalid then
local slope = math.abs(sourceData.datum - targetData.datum) / distance
- print (" slope: " .. slope)
- print (" was speed: " .. weight.speed)
+ io.write(" slope: " .. slope .. "\n")
+ io.write(" was speed: " .. weight.speed .. "\n")
weight.speed = weight.speed * (1 - (slope * 5))
- print (" new speed: " .. weight.speed)
+ io.write(" new speed: " .. weight.speed .. "\n")
end
end
diff --git a/profiles/rasterbot-interp.lua b/profiles/rasterbotinterp.lua
similarity index 77%
rename from profiles/rasterbot-interp.lua
rename to profiles/rasterbotinterp.lua
index 42c98b6..8266b07 100644
--- a/profiles/rasterbot-interp.lua
+++ b/profiles/rasterbotinterp.lua
@@ -13,6 +13,9 @@ function way_function (way, result)
result.name = name
end
+ result.forward_mode = mode.cycling
+ result.backward_mode = mode.cycling
+
result.forward_speed = 15
result.backward_speed = 15
end
@@ -32,15 +35,15 @@ end
function segment_function (source, target, distance, weight)
local sourceData = sources:interpolate(raster_source, source.lon, source.lat)
local targetData = sources:interpolate(raster_source, target.lon, target.lat)
- print ("evaluating segment: " .. sourceData.datum .. " " .. targetData.datum)
+ io.write("evaluating segment: " .. sourceData.datum .. " " .. targetData.datum .. "\n")
local invalid = sourceData.invalid_data()
if sourceData.datum ~= invalid and targetData.datum ~= invalid then
local slope = math.abs(sourceData.datum - targetData.datum) / distance
- print (" slope: " .. slope)
- print (" was speed: " .. weight.speed)
+ io.write(" slope: " .. slope .. "\n")
+ io.write(" was speed: " .. weight.speed .. "\n")
weight.speed = weight.speed * (1 - (slope * 5))
- print (" new speed: " .. weight.speed)
+ io.write(" new speed: " .. weight.speed .. "\n")
end
end
diff --git a/profiles/testbot.lua b/profiles/testbot.lua
index 6b10d04..aecffae 100644
--- a/profiles/testbot.lua
+++ b/profiles/testbot.lua
@@ -6,14 +6,6 @@
-- Secondary road: 18km/h = 18000m/3600s = 100m/20s
-- Tertiary road: 12km/h = 12000m/3600s = 100m/30s
--- modes:
--- 1: normal
--- 2: route
--- 3: river downstream
--- 4: river upstream
--- 5: steps down
--- 6: steps up
-
speed_profile = {
["primary"] = 36,
["secondary"] = 18,
@@ -24,13 +16,10 @@ speed_profile = {
-- these settings are read directly by osrm
-take_minimum_of_speeds = true
-obey_oneway = true
-obey_barriers = true
-use_turn_restrictions = true
-ignore_areas = true -- future feature
-traffic_signal_penalty = 7 -- seconds
-u_turn_penalty = 20
+properties.allow_u_turn_at_via = false
+properties.use_turn_restrictions = true
+properties.traffic_signal_penalty = 7 -- seconds
+properties.u_turn_penalty = 20
function limit_speed(speed, limits)
-- don't use ipairs(), since it stops at the first nil value
@@ -68,24 +57,26 @@ function way_function (way, result)
if name then
result.name = name
end
+ result.forward_mode = mode.driving
+ result.backward_mode = mode.driving
if duration and durationIsValid(duration) then
result.duration = math.max( 1, parseDuration(duration) )
- result.forward_mode = 2
- result.backward_mode = 2
+ result.forward_mode = mode.route
+ result.backward_mode = mode.route
else
local speed_forw = speed_profile[highway] or speed_profile['default']
local speed_back = speed_forw
if highway == "river" then
local temp_speed = speed_forw
- result.forward_mode = 3
- result.backward_mode = 4
+ result.forward_mode = mode.river_down
+ result.backward_mode = mode.river_up
speed_forw = temp_speed*1.5
speed_back = temp_speed/1.5
elseif highway == "steps" then
- result.forward_mode = 5
- result.backward_mode = 6
+ result.forward_mode = mode.steps_down
+ result.backward_mode = mode.steps_up
end
if maxspeed_forward ~= nil and maxspeed_forward > 0 then
@@ -111,9 +102,9 @@ function way_function (way, result)
if oneway == "no" or oneway == "0" or oneway == "false" then
-- nothing to do
elseif oneway == "-1" then
- result.forward_mode = 0
+ result.forward_mode = mode.inaccessible
elseif oneway == "yes" or oneway == "1" or oneway == "true" or junction == "roundabout" then
- result.backward_mode = 0
+ result.backward_mode = mode.inaccessible
end
if junction == 'roundabout' then
diff --git a/routed.cpp b/routed.cpp
deleted file mode 100644
index b4404c1..0000000
--- a/routed.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "server/server.hpp"
-#include "util/version.hpp"
-#include "util/routed_options.hpp"
-#include "util/simple_logger.hpp"
-
-#include <osrm/osrm.hpp>
-#include <osrm/libosrm_config.hpp>
-
-#ifdef __linux__
-#include <sys/mman.h>
-#endif
-
-#include <cstdlib>
-
-#include <signal.h>
-
-#include <chrono>
-#include <future>
-#include <iostream>
-#include <thread>
-#include <new>
-
-#ifdef _WIN32
-boost::function0<void> console_ctrl_function;
-
-BOOL WINAPI console_ctrl_handler(DWORD ctrl_type)
-{
- switch (ctrl_type)
- {
- case CTRL_C_EVENT:
- case CTRL_BREAK_EVENT:
- case CTRL_CLOSE_EVENT:
- case CTRL_SHUTDOWN_EVENT:
- console_ctrl_function();
- return TRUE;
- default:
- return FALSE;
- }
-}
-#endif
-
-int main(int argc, const char *argv[]) try
-{
- LogPolicy::GetInstance().Unmute();
-
- bool trial_run = false;
- std::string ip_address;
- int ip_port, requested_thread_num;
-
- LibOSRMConfig lib_config;
- const unsigned init_result = GenerateServerProgramOptions(
- argc, argv, lib_config.server_paths, ip_address, ip_port, requested_thread_num,
- lib_config.use_shared_memory, trial_run, lib_config.max_locations_trip, lib_config.max_locations_viaroute,
- lib_config.max_locations_distance_table,
- lib_config.max_locations_map_matching);
- if (init_result == INIT_OK_DO_NOT_START_ENGINE)
- {
- return EXIT_SUCCESS;
- }
- if (init_result == INIT_FAILED)
- {
- return EXIT_FAILURE;
- }
-
-#ifdef __linux__
- struct MemoryLocker final
- {
- explicit MemoryLocker(bool shouldLock_) : shouldLock(shouldLock_)
- {
- if (shouldLock && -1 == mlockall(MCL_CURRENT | MCL_FUTURE))
- {
- couldLock = false;
- SimpleLogger().Write(logWARNING) << "memory could not be locked to RAM";
- }
- }
- ~MemoryLocker()
- {
- if (shouldLock && couldLock)
- (void)munlockall();
- }
- bool shouldLock = false, couldLock = true;
- } memoryLocker(lib_config.use_shared_memory);
-#endif
- SimpleLogger().Write() << "starting up engines, " << OSRM_VERSION;
-
- if (lib_config.use_shared_memory)
- {
- SimpleLogger().Write(logDEBUG) << "Loading from shared memory";
- }
-
- SimpleLogger().Write(logDEBUG) << "Threads:\t" << requested_thread_num;
- SimpleLogger().Write(logDEBUG) << "IP address:\t" << ip_address;
- SimpleLogger().Write(logDEBUG) << "IP port:\t" << ip_port;
-
-#ifndef _WIN32
- int sig = 0;
- sigset_t new_mask;
- sigset_t old_mask;
- sigfillset(&new_mask);
- pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask);
-#endif
-
- OSRM osrm_lib(lib_config);
- auto routing_server = Server::CreateServer(ip_address, ip_port, requested_thread_num);
-
- routing_server->GetRequestHandlerPtr().RegisterRoutingMachine(&osrm_lib);
-
- if (trial_run)
- {
- SimpleLogger().Write() << "trial run, quitting after successful initialization";
- }
- else
- {
- std::packaged_task<int()> server_task([&]() -> int
- {
- routing_server->Run();
- return 0;
- });
- auto future = server_task.get_future();
- std::thread server_thread(std::move(server_task));
-
-#ifndef _WIN32
- sigset_t wait_mask;
- pthread_sigmask(SIG_SETMASK, &old_mask, nullptr);
- sigemptyset(&wait_mask);
- sigaddset(&wait_mask, SIGINT);
- sigaddset(&wait_mask, SIGQUIT);
- sigaddset(&wait_mask, SIGTERM);
- pthread_sigmask(SIG_BLOCK, &wait_mask, nullptr);
- SimpleLogger().Write() << "running and waiting for requests";
- sigwait(&wait_mask, &sig);
-#else
- // Set console control handler to allow server to be stopped.
- console_ctrl_function = std::bind(&Server::Stop, routing_server);
- SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
- SimpleLogger().Write() << "running and waiting for requests";
- routing_server->Run();
-#endif
- SimpleLogger().Write() << "initiating shutdown";
- routing_server->Stop();
- SimpleLogger().Write() << "stopping threads";
-
- auto status = future.wait_for(std::chrono::seconds(2));
-
- if (status == std::future_status::ready)
- {
- server_thread.join();
- }
- else
- {
- SimpleLogger().Write(logWARNING) << "Didn't exit within 2 seconds. Hard abort!";
- server_task.reset(); // just kill it
- }
- }
-
- SimpleLogger().Write() << "freeing objects";
- routing_server.reset();
- SimpleLogger().Write() << "shutdown completed";
-}
-catch (const std::bad_alloc &e)
-{
- SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
- SimpleLogger().Write(logWARNING)
- << "Please provide more memory or consider using a larger swapfile";
- return EXIT_FAILURE;
-}
-catch (const std::exception &e)
-{
- SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
- return EXIT_FAILURE;
-}
diff --git a/routing_algorithms/routing_base.hpp b/routing_algorithms/routing_base.hpp
deleted file mode 100644
index ecbc07e..0000000
--- a/routing_algorithms/routing_base.hpp
+++ /dev/null
@@ -1,687 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef ROUTING_BASE_HPP
-#define ROUTING_BASE_HPP
-
-#include "../algorithms/coordinate_calculation.hpp"
-#include "../data_structures/internal_route_result.hpp"
-#include "../data_structures/search_engine_data.hpp"
-#include "../data_structures/turn_instructions.hpp"
-
-#include <boost/assert.hpp>
-
-#include <stack>
-
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_1;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_1;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_2;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_2;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_3;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_3;
-
-template <class DataFacadeT, class Derived> class BasicRoutingInterface
-{
- private:
- using EdgeData = typename DataFacadeT::EdgeData;
-
- protected:
- DataFacadeT *facade;
-
- public:
- BasicRoutingInterface() = delete;
- BasicRoutingInterface(const BasicRoutingInterface &) = delete;
- explicit BasicRoutingInterface(DataFacadeT *facade) : facade(facade) {}
- ~BasicRoutingInterface() {}
-
- // min_edge_offset is needed in case we use multiple
- // nodes as start/target nodes with different (even negative) offsets.
- // In that case the termination criterion is not correct
- // anymore.
- //
- // Example:
- // forward heap: a(-100), b(0),
- // reverse heap: c(0), d(100)
- //
- // a --- d
- // \ /
- // / \
- // b --- c
- //
- // This is equivalent to running a bi-directional Dijkstra on the following graph:
- //
- // a --- d
- // / \ / \
- // y x z
- // \ / \ /
- // b --- c
- //
- // The graph is constructed by inserting nodes y and z that are connected to the initial nodes
- // using edges (y, a) with weight -100, (y, b) with weight 0 and,
- // (d, z) with weight 100, (c, z) with weight 0 corresponding.
- // Since we are dealing with a graph that contains _negative_ edges,
- // we need to add an offset to the termination criterion.
- void RoutingStep(SearchEngineData::QueryHeap &forward_heap,
- SearchEngineData::QueryHeap &reverse_heap,
- NodeID &middle_node_id,
- int &upper_bound,
- int min_edge_offset,
- const bool forward_direction,
- const bool stalling = true) const
- {
- const NodeID node = forward_heap.DeleteMin();
- const int distance = forward_heap.GetKey(node);
-
- if (reverse_heap.WasInserted(node))
- {
- const int new_distance = reverse_heap.GetKey(node) + distance;
- if (new_distance < upper_bound)
- {
- if (new_distance >= 0)
- {
- middle_node_id = node;
- upper_bound = new_distance;
- }
- }
- }
-
- // make sure we don't terminate too early if we initialize the distance
- // for the nodes in the forward heap with the forward/reverse offset
- BOOST_ASSERT(min_edge_offset <= 0);
- if (distance + min_edge_offset > upper_bound)
- {
- forward_heap.DeleteAll();
- return;
- }
-
- // Stalling
- if (stalling)
- {
- for (const auto edge : facade->GetAdjacentEdgeRange(node))
- {
- const EdgeData &data = facade->GetEdgeData(edge);
- const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
- if (reverse_flag)
- {
- const NodeID to = facade->GetTarget(edge);
- const int edge_weight = data.distance;
-
- BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
-
- if (forward_heap.WasInserted(to))
- {
- if (forward_heap.GetKey(to) + edge_weight < distance)
- {
- return;
- }
- }
- }
- }
- }
-
- for (const auto edge : facade->GetAdjacentEdgeRange(node))
- {
- const EdgeData &data = facade->GetEdgeData(edge);
- bool forward_directionFlag = (forward_direction ? data.forward : data.backward);
- if (forward_directionFlag)
- {
-
- const NodeID to = facade->GetTarget(edge);
- const int edge_weight = data.distance;
-
- BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
- const int to_distance = distance + edge_weight;
-
- // New Node discovered -> Add to Heap + Node Info Storage
- if (!forward_heap.WasInserted(to))
- {
- forward_heap.Insert(to, to_distance, node);
- }
- // Found a shorter Path -> Update distance
- else if (to_distance < forward_heap.GetKey(to))
- {
- // new parent
- forward_heap.GetData(to).parent = node;
- forward_heap.DecreaseKey(to, to_distance);
- }
- }
- }
- }
-
- template <typename RandomIter>
- void UnpackPath(RandomIter packed_path_begin,
- RandomIter packed_path_end,
- const PhantomNodes &phantom_node_pair,
- std::vector<PathData> &unpacked_path) const
- {
- const bool start_traversed_in_reverse =
- (*packed_path_begin != phantom_node_pair.source_phantom.forward_node_id);
- const bool target_traversed_in_reverse =
- (*std::prev(packed_path_end) != phantom_node_pair.target_phantom.forward_node_id);
-
- BOOST_ASSERT(std::distance(packed_path_begin, packed_path_end) > 0);
- std::stack<std::pair<NodeID, NodeID>> recursion_stack;
-
- // We have to push the path in reverse order onto the stack because it's LIFO.
- for (auto current = std::prev(packed_path_end); current != packed_path_begin;
- current = std::prev(current))
- {
- recursion_stack.emplace(*std::prev(current), *current);
- }
-
- std::pair<NodeID, NodeID> edge;
- while (!recursion_stack.empty())
- {
- // edge.first edge.second
- // *------------------>*
- // edge_id
- edge = recursion_stack.top();
- recursion_stack.pop();
-
- // facade->FindEdge does not suffice here in case of shortcuts.
- // The above explanation unclear? Think!
- EdgeID smaller_edge_id = SPECIAL_EDGEID;
- int edge_weight = std::numeric_limits<EdgeWeight>::max();
- for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
- {
- const int weight = facade->GetEdgeData(edge_id).distance;
- if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
- facade->GetEdgeData(edge_id).forward)
- {
- smaller_edge_id = edge_id;
- edge_weight = weight;
- }
- }
-
- // edge.first edge.second
- // *<------------------*
- // edge_id
- if (SPECIAL_EDGEID == smaller_edge_id)
- {
- for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
- {
- const int weight = facade->GetEdgeData(edge_id).distance;
- if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
- facade->GetEdgeData(edge_id).backward)
- {
- smaller_edge_id = edge_id;
- edge_weight = weight;
- }
- }
- }
- BOOST_ASSERT_MSG(edge_weight != INVALID_EDGE_WEIGHT, "edge id invalid");
-
- const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
- if (ed.shortcut)
- { // unpack
- const NodeID middle_node_id = ed.id;
- // again, we need to this in reversed order
- recursion_stack.emplace(middle_node_id, edge.second);
- recursion_stack.emplace(edge.first, middle_node_id);
- }
- else
- {
- BOOST_ASSERT_MSG(!ed.shortcut, "original edge flagged as shortcut");
- unsigned name_index = facade->GetNameIndexFromEdgeID(ed.id);
- const TurnInstruction turn_instruction = facade->GetTurnInstructionForEdgeID(ed.id);
- const TravelMode travel_mode = facade->GetTravelModeForEdgeID(ed.id);
-
- if (!facade->EdgeIsCompressed(ed.id))
- {
- BOOST_ASSERT(!facade->EdgeIsCompressed(ed.id));
- unpacked_path.emplace_back(facade->GetGeometryIndexForEdgeID(ed.id), name_index,
- turn_instruction, ed.distance, travel_mode);
- }
- else
- {
- std::vector<unsigned> id_vector;
- facade->GetUncompressedGeometry(facade->GetGeometryIndexForEdgeID(ed.id),
- id_vector);
-
- const std::size_t start_index =
- (unpacked_path.empty()
- ? ((start_traversed_in_reverse)
- ? id_vector.size() -
- phantom_node_pair.source_phantom.fwd_segment_position - 1
- : phantom_node_pair.source_phantom.fwd_segment_position)
- : 0);
- const std::size_t end_index = id_vector.size();
-
- BOOST_ASSERT(start_index >= 0);
- BOOST_ASSERT(start_index <= end_index);
- for (std::size_t i = start_index; i < end_index; ++i)
- {
- unpacked_path.emplace_back(id_vector[i], name_index,
- TurnInstruction::NoTurn, 0, travel_mode);
- }
- unpacked_path.back().turn_instruction = turn_instruction;
- unpacked_path.back().segment_duration = ed.distance;
- }
- }
- }
- if (SPECIAL_EDGEID != phantom_node_pair.target_phantom.packed_geometry_id)
- {
- std::vector<unsigned> id_vector;
- facade->GetUncompressedGeometry(phantom_node_pair.target_phantom.packed_geometry_id,
- id_vector);
- const bool is_local_path = (phantom_node_pair.source_phantom.packed_geometry_id ==
- phantom_node_pair.target_phantom.packed_geometry_id) &&
- unpacked_path.empty();
-
- std::size_t start_index = 0;
- if (is_local_path)
- {
- start_index = phantom_node_pair.source_phantom.fwd_segment_position;
- if (target_traversed_in_reverse)
- {
- start_index =
- id_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position;
- }
- }
-
- std::size_t end_index = phantom_node_pair.target_phantom.fwd_segment_position;
- if (target_traversed_in_reverse)
- {
- std::reverse(id_vector.begin(), id_vector.end());
- end_index =
- id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position;
- }
-
- if (start_index > end_index)
- {
- start_index = std::min(start_index, id_vector.size() - 1);
- }
-
- for (std::size_t i = start_index; i != end_index; (start_index < end_index ? ++i : --i))
- {
- BOOST_ASSERT(i < id_vector.size());
- BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode > 0);
- unpacked_path.emplace_back(PathData{
- id_vector[i], phantom_node_pair.target_phantom.name_id, TurnInstruction::NoTurn,
- 0, phantom_node_pair.target_phantom.forward_travel_mode});
- }
- }
-
- // there is no equivalent to a node-based node in an edge-expanded graph.
- // two equivalent routes may start (or end) at different node-based edges
- // as they are added with the offset how much "distance" on the edge
- // has already been traversed. Depending on offset one needs to remove
- // the last node.
- if (unpacked_path.size() > 1)
- {
- const std::size_t last_index = unpacked_path.size() - 1;
- const std::size_t second_to_last_index = last_index - 1;
-
- // looks like a trivially true check but tests for underflow
- BOOST_ASSERT(last_index > second_to_last_index);
-
- if (unpacked_path[last_index].node == unpacked_path[second_to_last_index].node)
- {
- unpacked_path.pop_back();
- }
- BOOST_ASSERT(!unpacked_path.empty());
- }
- }
-
- void UnpackEdge(const NodeID s, const NodeID t, std::vector<NodeID> &unpacked_path) const
- {
- std::stack<std::pair<NodeID, NodeID>> recursion_stack;
- recursion_stack.emplace(s, t);
-
- std::pair<NodeID, NodeID> edge;
- while (!recursion_stack.empty())
- {
- edge = recursion_stack.top();
- recursion_stack.pop();
-
- EdgeID smaller_edge_id = SPECIAL_EDGEID;
- int edge_weight = std::numeric_limits<EdgeWeight>::max();
- for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
- {
- const int weight = facade->GetEdgeData(edge_id).distance;
- if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
- facade->GetEdgeData(edge_id).forward)
- {
- smaller_edge_id = edge_id;
- edge_weight = weight;
- }
- }
-
- if (SPECIAL_EDGEID == smaller_edge_id)
- {
- for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
- {
- const int weight = facade->GetEdgeData(edge_id).distance;
- if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
- facade->GetEdgeData(edge_id).backward)
- {
- smaller_edge_id = edge_id;
- edge_weight = weight;
- }
- }
- }
- BOOST_ASSERT_MSG(edge_weight != std::numeric_limits<EdgeWeight>::max(),
- "edge weight invalid");
-
- const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
- if (ed.shortcut)
- { // unpack
- const NodeID middle_node_id = ed.id;
- // again, we need to this in reversed order
- recursion_stack.emplace(middle_node_id, edge.second);
- recursion_stack.emplace(edge.first, middle_node_id);
- }
- else
- {
- BOOST_ASSERT_MSG(!ed.shortcut, "edge must be shortcut");
- unpacked_path.emplace_back(edge.first);
- }
- }
- unpacked_path.emplace_back(t);
- }
-
- void RetrievePackedPathFromHeap(const SearchEngineData::QueryHeap &forward_heap,
- const SearchEngineData::QueryHeap &reverse_heap,
- const NodeID middle_node_id,
- std::vector<NodeID> &packed_path) const
- {
- RetrievePackedPathFromSingleHeap(forward_heap, middle_node_id, packed_path);
- std::reverse(packed_path.begin(), packed_path.end());
- packed_path.emplace_back(middle_node_id);
- RetrievePackedPathFromSingleHeap(reverse_heap, middle_node_id, packed_path);
- }
-
- void RetrievePackedPathFromSingleHeap(const SearchEngineData::QueryHeap &search_heap,
- const NodeID middle_node_id,
- std::vector<NodeID> &packed_path) const
- {
- NodeID current_node_id = middle_node_id;
- while (current_node_id != search_heap.GetData(current_node_id).parent)
- {
- current_node_id = search_heap.GetData(current_node_id).parent;
- packed_path.emplace_back(current_node_id);
- }
- }
-
- // assumes that heaps are already setup correctly.
- void Search(SearchEngineData::QueryHeap &forward_heap,
- SearchEngineData::QueryHeap &reverse_heap,
- int &distance,
- std::vector<NodeID> &packed_leg) const
- {
- NodeID middle = SPECIAL_NODEID;
-
- // get offset to account for offsets on phantom nodes on compressed edges
- const auto min_edge_offset = std::min(0, forward_heap.MinKey());
- BOOST_ASSERT(min_edge_offset <= 0);
- // we only every insert negative offsets for nodes in the forward heap
- BOOST_ASSERT(reverse_heap.MinKey() >= 0);
-
- // run two-Target Dijkstra routing step.
- while (0 < (forward_heap.Size() + reverse_heap.Size()))
- {
- if (!forward_heap.Empty())
- {
- RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, true);
- }
- if (!reverse_heap.Empty())
- {
- RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset, false);
- }
- }
-
- // No path found for both target nodes?
- if (INVALID_EDGE_WEIGHT == distance || SPECIAL_NODEID == middle)
- {
- return;
- }
-
- // Was a paths over one of the forward/reverse nodes not found?
- BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance),
- "no path found");
-
- RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
- }
-
- // assumes that heaps are already setup correctly.
- void SearchWithCore(SearchEngineData::QueryHeap &forward_heap,
- SearchEngineData::QueryHeap &reverse_heap,
- SearchEngineData::QueryHeap &forward_core_heap,
- SearchEngineData::QueryHeap &reverse_core_heap,
- int &distance,
- std::vector<NodeID> &packed_leg) const
- {
- NodeID middle = SPECIAL_NODEID;
-
- std::vector<std::pair<NodeID, EdgeWeight>> forward_entry_points;
- std::vector<std::pair<NodeID, EdgeWeight>> reverse_entry_points;
-
- // get offset to account for offsets on phantom nodes on compressed edges
- const auto min_edge_offset = std::min(0, forward_heap.MinKey());
- // we only every insert negative offsets for nodes in the forward heap
- BOOST_ASSERT(reverse_heap.MinKey() >= 0);
-
- // run two-Target Dijkstra routing step.
- while (0 < (forward_heap.Size() + reverse_heap.Size()))
- {
- if (!forward_heap.Empty())
- {
- if (facade->IsCoreNode(forward_heap.Min()))
- {
- const NodeID node = forward_heap.DeleteMin();
- const int key = forward_heap.GetKey(node);
- forward_entry_points.emplace_back(node, key);
- }
- else
- {
- RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset,
- true);
- }
- }
- if (!reverse_heap.Empty())
- {
- if (facade->IsCoreNode(reverse_heap.Min()))
- {
- const NodeID node = reverse_heap.DeleteMin();
- const int key = reverse_heap.GetKey(node);
- reverse_entry_points.emplace_back(node, key);
- }
- else
- {
- RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset,
- false);
- }
- }
- }
-
- // TODO check if unordered_set might be faster
- // sort by id and increasing by distance
- auto entry_point_comparator = [](const std::pair<NodeID, EdgeWeight> &lhs,
- const std::pair<NodeID, EdgeWeight> &rhs)
- {
- return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second < rhs.second);
- };
- std::sort(forward_entry_points.begin(), forward_entry_points.end(), entry_point_comparator);
- std::sort(reverse_entry_points.begin(), reverse_entry_points.end(), entry_point_comparator);
-
- NodeID last_id = SPECIAL_NODEID;
- for (const auto p : forward_entry_points)
- {
- if (p.first == last_id)
- {
- continue;
- }
- forward_core_heap.Insert(p.first, p.second, p.first);
- last_id = p.first;
- }
- last_id = SPECIAL_NODEID;
- for (const auto p : reverse_entry_points)
- {
- if (p.first == last_id)
- {
- continue;
- }
- reverse_core_heap.Insert(p.first, p.second, p.first);
- last_id = p.first;
- }
-
- // get offset to account for offsets on phantom nodes on compressed edges
- int min_core_edge_offset = 0;
- if (forward_core_heap.Size() > 0)
- {
- min_core_edge_offset = std::min(min_core_edge_offset, forward_core_heap.MinKey());
- }
- if (reverse_core_heap.Size() > 0 && reverse_core_heap.MinKey() < 0)
- {
- min_core_edge_offset = std::min(min_core_edge_offset, reverse_core_heap.MinKey());
- }
- BOOST_ASSERT(min_core_edge_offset <= 0);
-
- // run two-target Dijkstra routing step on core with termination criterion
- while (0 < (forward_core_heap.Size() + reverse_core_heap.Size()) &&
- distance > (forward_core_heap.MinKey() + reverse_core_heap.MinKey()))
- {
- if (!forward_core_heap.Empty())
- {
- RoutingStep(forward_core_heap, reverse_core_heap, middle, distance,
- min_core_edge_offset, true, false);
- }
- if (!reverse_core_heap.Empty())
- {
- RoutingStep(reverse_core_heap, forward_core_heap, middle, distance,
- min_core_edge_offset, false, false);
- }
- }
-
- // No path found for both target nodes?
- if (INVALID_EDGE_WEIGHT == distance || SPECIAL_NODEID == middle)
- {
- return;
- }
-
- // Was a paths over one of the forward/reverse nodes not found?
- BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance),
- "no path found");
-
- // we need to unpack sub path from core heaps
- if (facade->IsCoreNode(middle))
- {
- std::vector<NodeID> packed_core_leg;
- RetrievePackedPathFromHeap(forward_core_heap, reverse_core_heap, middle,
- packed_core_leg);
- BOOST_ASSERT(packed_core_leg.size() > 0);
- RetrievePackedPathFromSingleHeap(forward_heap, packed_core_leg.front(), packed_leg);
- std::reverse(packed_leg.begin(), packed_leg.end());
- packed_leg.insert(packed_leg.end(), packed_core_leg.begin(), packed_core_leg.end());
- RetrievePackedPathFromSingleHeap(reverse_heap, packed_core_leg.back(), packed_leg);
- }
- else
- {
- RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
- }
- }
-
- double get_network_distance(SearchEngineData::QueryHeap &forward_heap,
- SearchEngineData::QueryHeap &reverse_heap,
- const PhantomNode &source_phantom,
- const PhantomNode &target_phantom) const
- {
- EdgeWeight upper_bound = INVALID_EDGE_WEIGHT;
- NodeID middle_node = SPECIAL_NODEID;
- EdgeWeight edge_offset = std::min(0, -source_phantom.GetForwardWeightPlusOffset());
- edge_offset = std::min(edge_offset, -source_phantom.GetReverseWeightPlusOffset());
-
- if (source_phantom.forward_node_id != SPECIAL_NODEID)
- {
- forward_heap.Insert(source_phantom.forward_node_id,
- -source_phantom.GetForwardWeightPlusOffset(),
- source_phantom.forward_node_id);
- }
- if (source_phantom.reverse_node_id != SPECIAL_NODEID)
- {
- forward_heap.Insert(source_phantom.reverse_node_id,
- -source_phantom.GetReverseWeightPlusOffset(),
- source_phantom.reverse_node_id);
- }
-
- if (target_phantom.forward_node_id != SPECIAL_NODEID)
- {
- reverse_heap.Insert(target_phantom.forward_node_id,
- target_phantom.GetForwardWeightPlusOffset(),
- target_phantom.forward_node_id);
- }
- if (target_phantom.reverse_node_id != SPECIAL_NODEID)
- {
- reverse_heap.Insert(target_phantom.reverse_node_id,
- target_phantom.GetReverseWeightPlusOffset(),
- target_phantom.reverse_node_id);
- }
-
- // search from s and t till new_min/(1+epsilon) > length_of_shortest_path
- while (0 < (forward_heap.Size() + reverse_heap.Size()))
- {
- if (0 < forward_heap.Size())
- {
- RoutingStep(forward_heap, reverse_heap, middle_node, upper_bound, edge_offset,
- true);
- }
- if (0 < reverse_heap.Size())
- {
- RoutingStep(reverse_heap, forward_heap, middle_node, upper_bound, edge_offset,
- false);
- }
- }
-
- double distance = std::numeric_limits<double>::max();
- if (upper_bound != INVALID_EDGE_WEIGHT)
- {
- std::vector<NodeID> packed_leg;
- RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle_node, packed_leg);
- std::vector<PathData> unpacked_path;
- PhantomNodes nodes;
- nodes.source_phantom = source_phantom;
- nodes.target_phantom = target_phantom;
- UnpackPath(packed_leg.begin(), packed_leg.end(), nodes, unpacked_path);
-
- FixedPointCoordinate previous_coordinate = source_phantom.location;
- FixedPointCoordinate current_coordinate;
- distance = 0;
- for (const auto &p : unpacked_path)
- {
- current_coordinate = facade->GetCoordinateOfNode(p.node);
- distance += coordinate_calculation::haversine_distance(previous_coordinate,
- current_coordinate);
- previous_coordinate = current_coordinate;
- }
- distance += coordinate_calculation::haversine_distance(previous_coordinate,
- target_phantom.location);
- }
- return distance;
- }
-};
-
-#endif // ROUTING_BASE_HPP
diff --git a/scripts/check_taginfo.py b/scripts/check_taginfo.py
new file mode 100755
index 0000000..c2c4c72
--- /dev/null
+++ b/scripts/check_taginfo.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python2
+
+import json
+import sys
+import re
+
+WHITELIST = set(["mph"])
+
+if len(sys.argv) < 3:
+ print "Not enough arguments.\nUsage: " + sys.argv[0] + " taginfo.json profile.lua"
+ sys.exit(1)
+
+taginfo_path = sys.argv[1]
+profile_path = sys.argv[2]
+
+taginfo = None
+with open(taginfo_path) as f:
+ taginfo = json.load(f)
+
+valid_strings = [t["key"] for t in taginfo["tags"]]
+valid_strings += [t["value"] for t in taginfo["tags"] if "value" in t]
+
+string_regxp = re.compile("\"([\d\w\_:]+)\"")
+
+profile = None
+with open(profile_path) as f:
+ profile = f.readlines()
+
+n_errors = 0
+for n, line in enumerate(profile):
+ # ignore comments
+ if line.strip().startswith("--"):
+ continue
+ tokens = set(string_regxp.findall(line))
+ errors = []
+ for token in tokens:
+ if token not in WHITELIST and token not in valid_strings:
+ idx = line.find("\""+token+"\"")
+ errors.append((idx, token))
+ errors = sorted(errors)
+ n_errors += len(errors)
+ if len(errors) > 0:
+ prefix = "%i: " % n
+ offset = len(prefix)
+ for idx, token in errors:
+ sys.stdout.write(prefix + line)
+ marker = " "*(idx+offset) + "~"*(len(token)+2)
+ print(marker)
+
+if n_errors > 0:
+ sys.exit(1)
diff --git a/scripts/format.sh b/scripts/format.sh
new file mode 100755
index 0000000..561db87
--- /dev/null
+++ b/scripts/format.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+# Runs the Clang Formatter in parallel on the code base.
+# Return codes:
+# - 1 there are files to be formatted
+# - 0 everything looks fine
+
+set -eu -o pipefail
+
+find src include unit_tests example -type f -name '*.hpp' -o -name '*.cpp' \
+ | xargs -I{} -P $(nproc) clang-format -i -style=file {}
+
+
+dirty=$(git ls-files --modified)
+
+if [[ $dirty ]]; then
+ echo "The following files do not adhere to the .clang-format style file:"
+ echo $dirty
+ exit 1
+else
+ exit 0
+fi
diff --git a/scripts/install_node.sh b/scripts/install_node.sh
new file mode 100644
index 0000000..a22bfd2
--- /dev/null
+++ b/scripts/install_node.sh
@@ -0,0 +1,9 @@
+# here we set up the node version on the fly. currently only node 4, but can be used for more values if need be
+# This is done manually so that the build works the same on OS X
+rm -rf ~/.nvm/ && git clone --depth 1 --branch v0.30.1 https://github.com/creationix/nvm.git ~/.nvm
+source ~/.nvm/nvm.sh
+nvm install $1
+nvm use $1
+node --version
+npm --version
+which node
diff --git a/scripts/modernize.sh b/scripts/modernize.sh
index ee0f2ed..48d90ba 100755
--- a/scripts/modernize.sh
+++ b/scripts/modernize.sh
@@ -3,4 +3,17 @@
# Runs the Clang Modernizer in parallel on the code base.
# Requires a compilation database in the build directory.
-git ls-files '*.cpp' | xargs -I{} -P $(nproc) clang-modernize -p build -final-syntax-check -format -style=file -summary -for-compilers=clang-3.4,gcc-4.8 -include . -exclude third_party {}
+find src include unit_tests -type f -name '*.hpp' -o -name '*.cpp' \
+ | xargs \
+ -I{} \
+ -P $(nproc) \
+ clang-modernize \
+ -p build \
+ -final-syntax-check \
+ -format \
+ -style=file \
+ -summary \
+ -for-compilers=clang-3.4,gcc-4.8 \
+ -include . \
+ -exclude third_party \
+ {}
diff --git a/scripts/tidy.sh b/scripts/tidy.sh
index 7ecabfa..7f4ba14 100755
--- a/scripts/tidy.sh
+++ b/scripts/tidy.sh
@@ -3,4 +3,12 @@
# Runs the Clang Tidy Tool in parallel on the code base.
# Requires a compilation database in the build directory.
-git ls-files '*.cpp' | grep -v third_party | xargs -I{} -P $(nproc) clang-tidy -p build -header-filter='.*' {}
+
+find src include unit_tests -type f -name '*.hpp' -o -name '*.cpp' \
+ | xargs \
+ -I{} \
+ -P $(nproc) \
+ clang-tidy \
+ -p build \
+ -header-filter='.*' \
+ {}
diff --git a/scripts/update_depdendencies.sh b/scripts/update_depdendencies.sh
index e443cfa..ec0210c 100755
--- a/scripts/update_depdendencies.sh
+++ b/scripts/update_depdendencies.sh
@@ -1,10 +1,10 @@
#!/usr/bin/env bash
OSMIUM_REPO=https://github.com/osmcode/libosmium.git
-OSMIUM_TAG=v2.3.0
+OSMIUM_TAG=v2.6.1
VARIANT_REPO=https://github.com/mapbox/variant.git
-VARIANT_TAG=v1.0
+VARIANT_TAG=v1.1.0
VARIANT_LATEST=$(curl https://api.github.com/repos/mapbox/variant/releases/latest | jq ".tag_name")
OSMIUM_LATEST=$(curl https://api.github.com/repos/osmcode/libosmium/releases/latest | jq ".tag_name")
diff --git a/server/api_grammar.hpp b/server/api_grammar.hpp
deleted file mode 100644
index 28bd1df..0000000
--- a/server/api_grammar.hpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
-
-Copyright (c) 2013, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef API_GRAMMAR_HPP
-#define API_GRAMMAR_HPP
-
-#include <boost/bind.hpp>
-#include <boost/spirit/include/qi.hpp>
-#include <boost/spirit/include/qi_action.hpp>
-
-namespace qi = boost::spirit::qi;
-
-template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Iterator>
-{
- explicit APIGrammar(HandlerT *h) : APIGrammar::base_type(api_call), handler(h)
- {
- api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >>
- -query;
- query = ('?') >> +(zoom | output | jsonp | checksum | uturns | location_with_options | destination_with_options | source_with_options | cmp |
- language | instruction | geometry | alt_route | old_API | num_results |
- matching_beta | gps_precision | classify | locs);
- // all combinations of timestamp, uturn, hint and bearing without duplicates
- t_u = (u >> -timestamp) | (timestamp >> -u);
- t_h = (hint >> -timestamp) | (timestamp >> -hint);
- u_h = (u >> -hint) | (hint >> -u);
- t_u_h = (hint >> -t_u) | (u >> -t_h) | (timestamp >> -u_h);
- location_options = (bearing >> -t_u_h) | (t_u_h >> -bearing) | //
- (u >> bearing >> -t_h) | (timestamp >> bearing >> -u_h) | (hint >> bearing >> t_u) | //
- (t_h >> bearing >> -u) | (u_h >> bearing >> -timestamp) | (t_u >> bearing >> -hint);
- location_with_options = location >> -location_options;
- source_with_options = source >> -location_options;
- destination_with_options = destination >> -location_options;
- zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >>
- qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
- output = (-qi::lit('&')) >> qi::lit("output") >> '=' >>
- string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)];
- jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >>
- stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
- checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >>
- qi::uint_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
- instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >>
- qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)];
- geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >>
- qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)];
- cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >>
- qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];
- location = (-qi::lit('&')) >> qi::lit("loc") >> '=' >>
- (qi::double_ >> qi::lit(',') >>
- qi::double_)[boost::bind(&HandlerT::addCoordinate, handler, ::_1)];
- destination = (-qi::lit('&')) >> qi::lit("dst") >> '=' >>
- (qi::double_ >> qi::lit(',') >>
- qi::double_)[boost::bind(&HandlerT::addDestination, handler, ::_1)];
- source = (-qi::lit('&')) >> qi::lit("src") >> '=' >>
- (qi::double_ >> qi::lit(',') >>
- qi::double_)[boost::bind(&HandlerT::addSource, handler, ::_1)];
- hint = (-qi::lit('&')) >> qi::lit("hint") >> '=' >>
- stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
- timestamp = (-qi::lit('&')) >> qi::lit("t") >> '=' >>
- qi::uint_[boost::bind(&HandlerT::addTimestamp, handler, ::_1)];
- bearing = (-qi::lit('&')) >> qi::lit("b") >> '=' >>
- (qi::int_ >> -(qi::lit(',') >> qi::int_ | qi::attr(10)))[boost::bind(&HandlerT::addBearing, handler, ::_1, ::_2, ::_3)];
- u = (-qi::lit('&')) >> qi::lit("u") >> '=' >>
- qi::bool_[boost::bind(&HandlerT::setUTurn, handler, ::_1)];
- uturns = (-qi::lit('&')) >> qi::lit("uturns") >> '=' >>
- qi::bool_[boost::bind(&HandlerT::setAllUTurns, handler, ::_1)];
- language = (-qi::lit('&')) >> qi::lit("hl") >> '=' >>
- string[boost::bind(&HandlerT::setLanguage, handler, ::_1)];
- alt_route = (-qi::lit('&')) >> qi::lit("alt") >> '=' >>
- qi::bool_[boost::bind(&HandlerT::setAlternateRouteFlag, handler, ::_1)];
- old_API = (-qi::lit('&')) >> qi::lit("geomformat") >> '=' >>
- string[boost::bind(&HandlerT::setDeprecatedAPIFlag, handler, ::_1)];
- num_results = (-qi::lit('&')) >> qi::lit("num_results") >> '=' >>
- qi::short_[boost::bind(&HandlerT::setNumberOfResults, handler, ::_1)];
- matching_beta = (-qi::lit('&')) >> qi::lit("matching_beta") >> '=' >>
- qi::float_[boost::bind(&HandlerT::setMatchingBeta, handler, ::_1)];
- gps_precision = (-qi::lit('&')) >> qi::lit("gps_precision") >> '=' >>
- qi::float_[boost::bind(&HandlerT::setGPSPrecision, handler, ::_1)];
- classify = (-qi::lit('&')) >> qi::lit("classify") >> '=' >>
- qi::bool_[boost::bind(&HandlerT::setClassify, handler, ::_1)];
- locs = (-qi::lit('&')) >> qi::lit("locs") >> '=' >>
- stringforPolyline[boost::bind(&HandlerT::getCoordinatesFromGeometry, handler, ::_1)];
-
- string = +(qi::char_("a-zA-Z"));
- stringwithDot = +(qi::char_("a-zA-Z0-9_.-"));
- stringwithPercent = +(qi::char_("a-zA-Z0-9_.-") | qi::char_('[') | qi::char_(']') |
- (qi::char_('%') >> qi::char_("0-9A-Z") >> qi::char_("0-9A-Z")));
- stringforPolyline = +(qi::char_("a-zA-Z0-9_.-[]{}@?|\\%~`^"));
- }
-
- qi::rule<Iterator> api_call, query, location_options, location_with_options, destination_with_options, source_with_options, t_u, t_h, u_h, t_u_h;
- qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location, destination, source,
- hint, timestamp, bearing, stringwithDot, stringwithPercent, language, geometry, cmp, alt_route, u,
- uturns, old_API, num_results, matching_beta, gps_precision, classify, locs, instruction, stringforPolyline;
-
- HandlerT *handler;
-};
-
-#endif /* API_GRAMMAR_HPP */
diff --git a/server/connection.hpp b/server/connection.hpp
deleted file mode 100644
index aa6fd05..0000000
--- a/server/connection.hpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef CONNECTION_HPP
-#define CONNECTION_HPP
-
-#include "http/compression_type.hpp"
-#include "http/reply.hpp"
-#include "http/request.hpp"
-#include "request_parser.hpp"
-
-#include <boost/array.hpp>
-#include <boost/asio.hpp>
-#include <boost/config.hpp>
-#include <boost/version.hpp>
-
-#include <memory>
-#include <vector>
-
-// workaround for incomplete std::shared_ptr compatibility in old boost versions
-#if BOOST_VERSION < 105300 || defined BOOST_NO_CXX11_SMART_PTR
-
-namespace boost
-{
-template <class T> const T *get_pointer(std::shared_ptr<T> const &p) { return p.get(); }
-
-template <class T> T *get_pointer(std::shared_ptr<T> &p) { return p.get(); }
-} // namespace boost
-
-#endif
-
-class RequestHandler;
-
-namespace http
-{
-
-/// Represents a single connection from a client.
-class Connection : public std::enable_shared_from_this<Connection>
-{
- public:
- explicit Connection(boost::asio::io_service &io_service, RequestHandler &handler);
- Connection(const Connection &) = delete;
- Connection() = delete;
-
- boost::asio::ip::tcp::socket &socket();
-
- /// Start the first asynchronous operation for the connection.
- void start();
-
- private:
- void handle_read(const boost::system::error_code &e, std::size_t bytes_transferred);
-
- /// Handle completion of a write operation.
- void handle_write(const boost::system::error_code &e);
-
- std::vector<char> compress_buffers(const std::vector<char> &uncompressed_data,
- const compression_type compression_type);
-
- boost::asio::io_service::strand strand;
- boost::asio::ip::tcp::socket TCP_socket;
- RequestHandler &request_handler;
- RequestParser request_parser;
- boost::array<char, 8192> incoming_data_buffer;
- request current_request;
- reply current_reply;
- std::vector<char> compressed_output;
-};
-
-} // namespace http
-
-#endif // CONNECTION_HPP
diff --git a/server/data_structures/datafacade_base.hpp b/server/data_structures/datafacade_base.hpp
deleted file mode 100644
index 5c5c522..0000000
--- a/server/data_structures/datafacade_base.hpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef DATAFACADE_BASE_HPP
-#define DATAFACADE_BASE_HPP
-
-// Exposes all data access interfaces to the algorithms via base class ptr
-
-#include "../../data_structures/edge_based_node.hpp"
-#include "../../data_structures/external_memory_node.hpp"
-#include "../../data_structures/phantom_node.hpp"
-#include "../../data_structures/turn_instructions.hpp"
-#include "../../util/integer_range.hpp"
-#include "../../util/osrm_exception.hpp"
-#include "../../util/string_util.hpp"
-#include "../../typedefs.h"
-
-#include <osrm/coordinate.hpp>
-
-#include <string>
-#include <boost/optional.hpp>
-
-using EdgeRange = osrm::range<EdgeID>;
-
-template <class EdgeDataT> class BaseDataFacade
-{
- public:
- using RTreeLeaf = EdgeBasedNode;
- using EdgeData = EdgeDataT;
- BaseDataFacade() {}
- virtual ~BaseDataFacade() {}
-
- // search graph access
- virtual unsigned GetNumberOfNodes() const = 0;
-
- virtual unsigned GetNumberOfEdges() const = 0;
-
- virtual unsigned GetOutDegree(const NodeID n) const = 0;
-
- virtual NodeID GetTarget(const EdgeID e) const = 0;
-
- virtual const EdgeDataT &GetEdgeData(const EdgeID e) const = 0;
-
- virtual EdgeID BeginEdges(const NodeID n) const = 0;
-
- virtual EdgeID EndEdges(const NodeID n) const = 0;
-
- virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
-
- // searches for a specific edge
- virtual EdgeID FindEdge(const NodeID from, const NodeID to) const = 0;
-
- virtual EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const = 0;
-
- virtual EdgeID
- FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const = 0;
-
- // node and edge information access
- virtual FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const = 0;
-
- virtual bool EdgeIsCompressed(const unsigned id) const = 0;
-
- virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const = 0;
-
- virtual void GetUncompressedGeometry(const unsigned id,
- std::vector<unsigned> &result_nodes) const = 0;
-
- virtual TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const = 0;
-
- virtual TravelMode GetTravelModeForEdgeID(const unsigned id) const = 0;
-
- virtual std::vector<PhantomNodeWithDistance>
- NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate,
- const float max_distance,
- const int bearing = 0,
- const int bearing_range = 180) = 0;
-
- virtual std::vector<PhantomNodeWithDistance>
- NearestPhantomNodes(const FixedPointCoordinate &input_coordinate,
- const unsigned max_results,
- const int bearing = 0,
- const int bearing_range = 180) = 0;
-
- virtual std::pair<PhantomNode, PhantomNode>
- NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate,
- const int bearing = 0,
- const int bearing_range = 180) = 0;
-
- virtual unsigned GetCheckSum() const = 0;
-
- virtual bool IsCoreNode(const NodeID id) const = 0;
-
- virtual unsigned GetNameIndexFromEdgeID(const unsigned id) const = 0;
-
- virtual std::string get_name_for_id(const unsigned name_id) const = 0;
-
- virtual std::size_t GetCoreSize() const = 0;
-
- virtual std::string GetTimestamp() const = 0;
-};
-
-#endif // DATAFACADE_BASE_HPP
diff --git a/server/data_structures/internal_datafacade.hpp b/server/data_structures/internal_datafacade.hpp
deleted file mode 100644
index a2f74e5..0000000
--- a/server/data_structures/internal_datafacade.hpp
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef INTERNAL_DATAFACADE_HPP
-#define INTERNAL_DATAFACADE_HPP
-
-// implements all data storage when shared memory is _NOT_ used
-
-#include "datafacade_base.hpp"
-
-#include "../../algorithms/geospatial_query.hpp"
-#include "../../data_structures/original_edge_data.hpp"
-#include "../../data_structures/query_node.hpp"
-#include "../../data_structures/query_edge.hpp"
-#include "../../data_structures/shared_memory_vector_wrapper.hpp"
-#include "../../data_structures/static_graph.hpp"
-#include "../../data_structures/static_rtree.hpp"
-#include "../../data_structures/range_table.hpp"
-#include "../../util/graph_loader.hpp"
-#include "../../util/simple_logger.hpp"
-
-#include <osrm/coordinate.hpp>
-
-#include <boost/thread.hpp>
-
-#include <limits>
-
-template <class EdgeDataT> class InternalDataFacade final : public BaseDataFacade<EdgeDataT>
-{
-
- private:
- using super = BaseDataFacade<EdgeDataT>;
- using QueryGraph = StaticGraph<typename super::EdgeData>;
- using InputEdge = typename QueryGraph::InputEdge;
- using RTreeLeaf = typename super::RTreeLeaf;
- using InternalRTree = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>;
- using InternalGeospatialQuery = GeospatialQuery<InternalRTree>;
-
- InternalDataFacade() {}
-
- unsigned m_check_sum;
- unsigned m_number_of_nodes;
- std::unique_ptr<QueryGraph> m_query_graph;
- std::string m_timestamp;
-
- std::shared_ptr<ShM<FixedPointCoordinate, false>::vector> m_coordinate_list;
- ShM<NodeID, false>::vector m_via_node_list;
- ShM<unsigned, false>::vector m_name_ID_list;
- ShM<TurnInstruction, false>::vector m_turn_instruction_list;
- ShM<TravelMode, false>::vector m_travel_mode_list;
- ShM<char, false>::vector m_names_char_list;
- ShM<bool, false>::vector m_edge_is_compressed;
- ShM<unsigned, false>::vector m_geometry_indices;
- ShM<unsigned, false>::vector m_geometry_list;
- ShM<bool, false>::vector m_is_core_node;
-
- boost::thread_specific_ptr<InternalRTree> m_static_rtree;
- boost::thread_specific_ptr<InternalGeospatialQuery> m_geospatial_query;
- boost::filesystem::path ram_index_path;
- boost::filesystem::path file_index_path;
- RangeTable<16, false> m_name_table;
-
- void LoadTimestamp(const boost::filesystem::path ×tamp_path)
- {
- if (boost::filesystem::exists(timestamp_path))
- {
- SimpleLogger().Write() << "Loading Timestamp";
- boost::filesystem::ifstream timestamp_stream(timestamp_path);
- if (!timestamp_stream)
- {
- SimpleLogger().Write(logWARNING) << timestamp_path << " not found";
- }
- getline(timestamp_stream, m_timestamp);
- timestamp_stream.close();
- }
- if (m_timestamp.empty())
- {
- m_timestamp = "n/a";
- }
- if (25 < m_timestamp.length())
- {
- m_timestamp.resize(25);
- }
- }
-
- void LoadGraph(const boost::filesystem::path &hsgr_path)
- {
- typename ShM<typename QueryGraph::NodeArrayEntry, false>::vector node_list;
- typename ShM<typename QueryGraph::EdgeArrayEntry, false>::vector edge_list;
-
- SimpleLogger().Write() << "loading graph from " << hsgr_path.string();
-
- m_number_of_nodes = readHSGRFromStream(hsgr_path, node_list, edge_list, &m_check_sum);
-
- BOOST_ASSERT_MSG(0 != node_list.size(), "node list empty");
- // BOOST_ASSERT_MSG(0 != edge_list.size(), "edge list empty");
- SimpleLogger().Write() << "loaded " << node_list.size() << " nodes and " << edge_list.size()
- << " edges";
- m_query_graph = std::unique_ptr<QueryGraph>(new QueryGraph(node_list, edge_list));
-
- BOOST_ASSERT_MSG(0 == node_list.size(), "node list not flushed");
- BOOST_ASSERT_MSG(0 == edge_list.size(), "edge list not flushed");
- SimpleLogger().Write() << "Data checksum is " << m_check_sum;
- }
-
- void LoadNodeAndEdgeInformation(const boost::filesystem::path &nodes_file,
- const boost::filesystem::path &edges_file)
- {
- boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
-
- QueryNode current_node;
- unsigned number_of_coordinates = 0;
- nodes_input_stream.read((char *)&number_of_coordinates, sizeof(unsigned));
- m_coordinate_list =
- std::make_shared<std::vector<FixedPointCoordinate>>(number_of_coordinates);
- for (unsigned i = 0; i < number_of_coordinates; ++i)
- {
- nodes_input_stream.read((char *)¤t_node, sizeof(QueryNode));
- m_coordinate_list->at(i) = FixedPointCoordinate(current_node.lat, current_node.lon);
- BOOST_ASSERT((std::abs(m_coordinate_list->at(i).lat) >> 30) == 0);
- BOOST_ASSERT((std::abs(m_coordinate_list->at(i).lon) >> 30) == 0);
- }
- nodes_input_stream.close();
-
- boost::filesystem::ifstream edges_input_stream(edges_file, std::ios::binary);
- unsigned number_of_edges = 0;
- edges_input_stream.read((char *)&number_of_edges, sizeof(unsigned));
- m_via_node_list.resize(number_of_edges);
- m_name_ID_list.resize(number_of_edges);
- m_turn_instruction_list.resize(number_of_edges);
- m_travel_mode_list.resize(number_of_edges);
- m_edge_is_compressed.resize(number_of_edges);
-
- unsigned compressed = 0;
-
- OriginalEdgeData current_edge_data;
- for (unsigned i = 0; i < number_of_edges; ++i)
- {
- edges_input_stream.read((char *)&(current_edge_data), sizeof(OriginalEdgeData));
- m_via_node_list[i] = current_edge_data.via_node;
- m_name_ID_list[i] = current_edge_data.name_id;
- m_turn_instruction_list[i] = current_edge_data.turn_instruction;
- m_travel_mode_list[i] = current_edge_data.travel_mode;
- m_edge_is_compressed[i] = current_edge_data.compressed_geometry;
- if (m_edge_is_compressed[i])
- {
- ++compressed;
- }
- }
-
- edges_input_stream.close();
- }
-
- void LoadCoreInformation(const boost::filesystem::path &core_data_file)
- {
- std::ifstream core_stream(core_data_file.string().c_str(), std::ios::binary);
- unsigned number_of_markers;
- core_stream.read((char *)&number_of_markers, sizeof(unsigned));
-
- std::vector<char> unpacked_core_markers(number_of_markers);
- core_stream.read((char *)unpacked_core_markers.data(), sizeof(char) * number_of_markers);
-
- // in this case we have nothing to do
- if (number_of_markers <= 0)
- {
- return;
- }
-
- m_is_core_node.resize(number_of_markers);
- for (auto i = 0u; i < number_of_markers; ++i)
- {
- BOOST_ASSERT(unpacked_core_markers[i] == 0 || unpacked_core_markers[i] == 1);
- m_is_core_node[i] = unpacked_core_markers[i] == 1;
- }
- }
-
- void LoadGeometries(const boost::filesystem::path &geometry_file)
- {
- std::ifstream geometry_stream(geometry_file.string().c_str(), std::ios::binary);
- unsigned number_of_indices = 0;
- unsigned number_of_compressed_geometries = 0;
-
- geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
-
- m_geometry_indices.resize(number_of_indices);
- if (number_of_indices > 0)
- {
- geometry_stream.read((char *)&(m_geometry_indices[0]),
- number_of_indices * sizeof(unsigned));
- }
-
- geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
-
- BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
- m_geometry_list.resize(number_of_compressed_geometries);
-
- if (number_of_compressed_geometries > 0)
- {
- geometry_stream.read((char *)&(m_geometry_list[0]),
- number_of_compressed_geometries * sizeof(unsigned));
- }
- geometry_stream.close();
- }
-
- void LoadRTree()
- {
- BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
-
- m_static_rtree.reset(new InternalRTree(ram_index_path, file_index_path, m_coordinate_list));
- m_geospatial_query.reset(new InternalGeospatialQuery(*m_static_rtree, m_coordinate_list));
- }
-
- void LoadStreetNames(const boost::filesystem::path &names_file)
- {
- boost::filesystem::ifstream name_stream(names_file, std::ios::binary);
-
- name_stream >> m_name_table;
-
- unsigned number_of_chars = 0;
- name_stream.read((char *)&number_of_chars, sizeof(unsigned));
- BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
- m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
- name_stream.read((char *)&m_names_char_list[0], number_of_chars * sizeof(char));
- if (0 == m_names_char_list.size())
- {
- SimpleLogger().Write(logWARNING) << "list of street names is empty";
- }
- name_stream.close();
- }
-
- public:
- virtual ~InternalDataFacade()
- {
- m_static_rtree.reset();
- m_geospatial_query.reset();
- }
-
- explicit InternalDataFacade(const std::unordered_map<std::string, boost::filesystem::path> &server_paths)
- {
- // cache end iterator to quickly check .find against
- const auto end_it = end(server_paths);
-
- const auto file_for = [&server_paths, &end_it](const std::string &path)
- {
- const auto it = server_paths.find(path);
- if (it == end_it || !boost::filesystem::is_regular_file(it->second))
- throw osrm::exception("no valid " + path + " file given in ini file");
- return it->second;
- };
-
- ram_index_path = file_for("ramindex");
- file_index_path = file_for("fileindex");
-
- SimpleLogger().Write() << "loading graph data";
- LoadGraph(file_for("hsgrdata"));
-
- SimpleLogger().Write() << "loading edge information";
- LoadNodeAndEdgeInformation(file_for("nodesdata"), file_for("edgesdata"));
-
- SimpleLogger().Write() << "loading core information";
- LoadCoreInformation(file_for("coredata"));
-
- SimpleLogger().Write() << "loading geometries";
- LoadGeometries(file_for("geometries"));
-
- SimpleLogger().Write() << "loading timestamp";
- LoadTimestamp(file_for("timestamp"));
-
- SimpleLogger().Write() << "loading street names";
- LoadStreetNames(file_for("namesdata"));
- }
-
- // search graph access
- unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); }
-
- unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); }
-
- unsigned GetOutDegree(const NodeID n) const override final
- {
- return m_query_graph->GetOutDegree(n);
- }
-
- NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
-
- EdgeDataT &GetEdgeData(const EdgeID e) const override final
- {
- return m_query_graph->GetEdgeData(e);
- }
-
- EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); }
-
- EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); }
-
- EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
- {
- return m_query_graph->GetAdjacentEdgeRange(node);
- };
-
- // searches for a specific edge
- EdgeID FindEdge(const NodeID from, const NodeID to) const override final
- {
- return m_query_graph->FindEdge(from, to);
- }
-
- EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const override final
- {
- return m_query_graph->FindEdgeInEitherDirection(from, to);
- }
-
- EdgeID
- FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const override final
- {
- return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
- }
-
- // node and edge information access
- FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const override final
- {
- return m_coordinate_list->at(id);
- };
-
- bool EdgeIsCompressed(const unsigned id) const override final
- {
- return m_edge_is_compressed.at(id);
- }
-
- TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const override final
- {
- return m_turn_instruction_list.at(id);
- }
-
- TravelMode GetTravelModeForEdgeID(const unsigned id) const override final
- {
- return m_travel_mode_list.at(id);
- }
-
-
- std::vector<PhantomNodeWithDistance>
- NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate,
- const float max_distance,
- const int bearing = 0,
- const int bearing_range = 180) override final
- {
- if (!m_static_rtree.get())
- {
- LoadRTree();
- BOOST_ASSERT(m_geospatial_query.get());
- }
-
- return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance, bearing, bearing_range);
- }
-
- std::vector<PhantomNodeWithDistance>
- NearestPhantomNodes(const FixedPointCoordinate &input_coordinate,
- const unsigned max_results,
- const int bearing = 0,
- const int bearing_range = 180) override final
- {
- if (!m_static_rtree.get())
- {
- LoadRTree();
- BOOST_ASSERT(m_geospatial_query.get());
- }
-
- return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, bearing, bearing_range);
- }
-
- std::pair<PhantomNode, PhantomNode>
- NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate,
- const int bearing = 0,
- const int bearing_range = 180) override final
- {
- if (!m_static_rtree.get())
- {
- LoadRTree();
- BOOST_ASSERT(m_geospatial_query.get());
- }
-
- return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(input_coordinate, bearing, bearing_range);
- }
-
-
- unsigned GetCheckSum() const override final { return m_check_sum; }
-
- unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
- {
- return m_name_ID_list.at(id);
- }
-
- std::string get_name_for_id(const unsigned name_id) const override final
- {
- if (std::numeric_limits<unsigned>::max() == name_id)
- {
- return "";
- }
- auto range = m_name_table.GetRange(name_id);
-
- std::string result;
- result.reserve(range.size());
- if (range.begin() != range.end())
- {
- result.resize(range.back() - range.front() + 1);
- std::copy(m_names_char_list.begin() + range.front(),
- m_names_char_list.begin() + range.back() + 1, result.begin());
- }
- return result;
- }
-
- virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const override final
- {
- return m_via_node_list.at(id);
- }
-
- virtual std::size_t GetCoreSize() const override final
- {
- return m_is_core_node.size();
- }
-
- virtual bool IsCoreNode(const NodeID id) const override final
- {
- if (m_is_core_node.size() > 0)
- {
- return m_is_core_node[id];
- }
- else
- {
- return false;
- }
- }
-
- virtual void GetUncompressedGeometry(const unsigned id,
- std::vector<unsigned> &result_nodes) const override final
- {
- const unsigned begin = m_geometry_indices.at(id);
- const unsigned end = m_geometry_indices.at(id + 1);
-
- result_nodes.clear();
- result_nodes.insert(result_nodes.begin(), m_geometry_list.begin() + begin,
- m_geometry_list.begin() + end);
- }
-
- std::string GetTimestamp() const override final { return m_timestamp; }
-};
-
-#endif // INTERNAL_DATAFACADE_HPP
diff --git a/server/data_structures/shared_barriers.hpp b/server/data_structures/shared_barriers.hpp
deleted file mode 100644
index e6f1234..0000000
--- a/server/data_structures/shared_barriers.hpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef SHARED_BARRIERS_HPP
-#define SHARED_BARRIERS_HPP
-
-#include <boost/interprocess/sync/named_mutex.hpp>
-#include <boost/interprocess/sync/named_condition.hpp>
-
-struct SharedBarriers
-{
-
- SharedBarriers()
- : pending_update_mutex(boost::interprocess::open_or_create, "pending_update"),
- update_mutex(boost::interprocess::open_or_create, "update"),
- query_mutex(boost::interprocess::open_or_create, "query"),
- no_running_queries_condition(boost::interprocess::open_or_create, "no_running_queries"),
- update_ongoing(false), number_of_queries(0)
- {
- }
-
- // Mutex to protect access to the boolean variable
- boost::interprocess::named_mutex pending_update_mutex;
- boost::interprocess::named_mutex update_mutex;
- boost::interprocess::named_mutex query_mutex;
-
- // Condition that no update is running
- boost::interprocess::named_condition no_running_queries_condition;
-
- // Is there an ongoing update?
- bool update_ongoing;
- // Is there any query?
- int number_of_queries;
-};
-
-#endif // SHARED_BARRIERS_HPP
diff --git a/server/data_structures/shared_datafacade.hpp b/server/data_structures/shared_datafacade.hpp
deleted file mode 100644
index 4bbf076..0000000
--- a/server/data_structures/shared_datafacade.hpp
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef SHARED_DATAFACADE_HPP
-#define SHARED_DATAFACADE_HPP
-
-// implements all data storage when shared memory _IS_ used
-
-#include "datafacade_base.hpp"
-#include "shared_datatype.hpp"
-
-#include "../../algorithms/geospatial_query.hpp"
-#include "../../data_structures/range_table.hpp"
-#include "../../data_structures/static_graph.hpp"
-#include "../../data_structures/static_rtree.hpp"
-#include "../../util/make_unique.hpp"
-#include "../../util/simple_logger.hpp"
-
-#include <boost/thread.hpp>
-
-#include <algorithm>
-#include <limits>
-#include <memory>
-
-template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<EdgeDataT>
-{
-
- private:
- using EdgeData = EdgeDataT;
- using super = BaseDataFacade<EdgeData>;
- using QueryGraph = StaticGraph<EdgeData, true>;
- using GraphNode = typename StaticGraph<EdgeData, true>::NodeArrayEntry;
- using GraphEdge = typename StaticGraph<EdgeData, true>::EdgeArrayEntry;
- using NameIndexBlock = typename RangeTable<16, true>::BlockT;
- using InputEdge = typename QueryGraph::InputEdge;
- using RTreeLeaf = typename super::RTreeLeaf;
- using SharedRTree = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>;
- using SharedGeospatialQuery = GeospatialQuery<SharedRTree>;
- using TimeStampedRTreePair = std::pair<unsigned, std::shared_ptr<SharedRTree>>;
- using RTreeNode = typename SharedRTree::TreeNode;
-
- SharedDataLayout *data_layout;
- char *shared_memory;
- SharedDataTimestamp *data_timestamp_ptr;
-
- SharedDataType CURRENT_LAYOUT;
- SharedDataType CURRENT_DATA;
- unsigned CURRENT_TIMESTAMP;
-
- unsigned m_check_sum;
- std::unique_ptr<QueryGraph> m_query_graph;
- std::unique_ptr<SharedMemory> m_layout_memory;
- std::unique_ptr<SharedMemory> m_large_memory;
- std::string m_timestamp;
-
- std::shared_ptr<ShM<FixedPointCoordinate, true>::vector> m_coordinate_list;
- ShM<NodeID, true>::vector m_via_node_list;
- ShM<unsigned, true>::vector m_name_ID_list;
- ShM<TurnInstruction, true>::vector m_turn_instruction_list;
- ShM<TravelMode, true>::vector m_travel_mode_list;
- ShM<char, true>::vector m_names_char_list;
- ShM<unsigned, true>::vector m_name_begin_indices;
- ShM<bool, true>::vector m_edge_is_compressed;
- ShM<unsigned, true>::vector m_geometry_indices;
- ShM<unsigned, true>::vector m_geometry_list;
- ShM<bool, true>::vector m_is_core_node;
-
- boost::thread_specific_ptr<std::pair<unsigned, std::shared_ptr<SharedRTree>>> m_static_rtree;
- boost::thread_specific_ptr<SharedGeospatialQuery> m_geospatial_query;
- boost::filesystem::path file_index_path;
-
- std::shared_ptr<RangeTable<16, true>> m_name_table;
-
- void LoadChecksum()
- {
- m_check_sum =
- *data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::HSGR_CHECKSUM);
- SimpleLogger().Write() << "set checksum: " << m_check_sum;
- }
-
- void LoadTimestamp()
- {
- char *timestamp_ptr =
- data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::TIMESTAMP);
- m_timestamp.resize(data_layout->GetBlockSize(SharedDataLayout::TIMESTAMP));
- std::copy(timestamp_ptr,
- timestamp_ptr + data_layout->GetBlockSize(SharedDataLayout::TIMESTAMP),
- m_timestamp.begin());
- }
-
- void LoadRTree()
- {
- BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
-
- RTreeNode *tree_ptr =
- data_layout->GetBlockPtr<RTreeNode>(shared_memory, SharedDataLayout::R_SEARCH_TREE);
- m_static_rtree.reset(new TimeStampedRTreePair(
- CURRENT_TIMESTAMP,
- osrm::make_unique<SharedRTree>(
- tree_ptr, data_layout->num_entries[SharedDataLayout::R_SEARCH_TREE],
- file_index_path, m_coordinate_list)));
- m_geospatial_query.reset(new SharedGeospatialQuery(*m_static_rtree->second, m_coordinate_list));
- }
-
- void LoadGraph()
- {
- GraphNode *graph_nodes_ptr =
- data_layout->GetBlockPtr<GraphNode>(shared_memory, SharedDataLayout::GRAPH_NODE_LIST);
-
- GraphEdge *graph_edges_ptr =
- data_layout->GetBlockPtr<GraphEdge>(shared_memory, SharedDataLayout::GRAPH_EDGE_LIST);
-
- typename ShM<GraphNode, true>::vector node_list(
- graph_nodes_ptr, data_layout->num_entries[SharedDataLayout::GRAPH_NODE_LIST]);
- typename ShM<GraphEdge, true>::vector edge_list(
- graph_edges_ptr, data_layout->num_entries[SharedDataLayout::GRAPH_EDGE_LIST]);
- m_query_graph.reset(new QueryGraph(node_list, edge_list));
- }
-
- void LoadNodeAndEdgeInformation()
- {
-
- FixedPointCoordinate *coordinate_list_ptr = data_layout->GetBlockPtr<FixedPointCoordinate>(
- shared_memory, SharedDataLayout::COORDINATE_LIST);
- m_coordinate_list = osrm::make_unique<ShM<FixedPointCoordinate, true>::vector>(
- coordinate_list_ptr, data_layout->num_entries[SharedDataLayout::COORDINATE_LIST]);
-
- TravelMode *travel_mode_list_ptr =
- data_layout->GetBlockPtr<TravelMode>(shared_memory, SharedDataLayout::TRAVEL_MODE);
- typename ShM<TravelMode, true>::vector travel_mode_list(
- travel_mode_list_ptr, data_layout->num_entries[SharedDataLayout::TRAVEL_MODE]);
- m_travel_mode_list.swap(travel_mode_list);
-
- TurnInstruction *turn_instruction_list_ptr = data_layout->GetBlockPtr<TurnInstruction>(
- shared_memory, SharedDataLayout::TURN_INSTRUCTION);
- typename ShM<TurnInstruction, true>::vector turn_instruction_list(
- turn_instruction_list_ptr,
- data_layout->num_entries[SharedDataLayout::TURN_INSTRUCTION]);
- m_turn_instruction_list.swap(turn_instruction_list);
-
- unsigned *name_id_list_ptr =
- data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::NAME_ID_LIST);
- typename ShM<unsigned, true>::vector name_id_list(
- name_id_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_ID_LIST]);
- m_name_ID_list.swap(name_id_list);
- }
-
- void LoadViaNodeList()
- {
- NodeID *via_node_list_ptr =
- data_layout->GetBlockPtr<NodeID>(shared_memory, SharedDataLayout::VIA_NODE_LIST);
- typename ShM<NodeID, true>::vector via_node_list(
- via_node_list_ptr, data_layout->num_entries[SharedDataLayout::VIA_NODE_LIST]);
- m_via_node_list.swap(via_node_list);
- }
-
- void LoadNames()
- {
- unsigned *offsets_ptr =
- data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::NAME_OFFSETS);
- NameIndexBlock *blocks_ptr =
- data_layout->GetBlockPtr<NameIndexBlock>(shared_memory, SharedDataLayout::NAME_BLOCKS);
- typename ShM<unsigned, true>::vector name_offsets(
- offsets_ptr, data_layout->num_entries[SharedDataLayout::NAME_OFFSETS]);
- typename ShM<NameIndexBlock, true>::vector name_blocks(
- blocks_ptr, data_layout->num_entries[SharedDataLayout::NAME_BLOCKS]);
-
- char *names_list_ptr =
- data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::NAME_CHAR_LIST);
- typename ShM<char, true>::vector names_char_list(
- names_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_CHAR_LIST]);
- m_name_table = osrm::make_unique<RangeTable<16, true>>(
- name_offsets, name_blocks, static_cast<unsigned>(names_char_list.size()));
-
- m_names_char_list.swap(names_char_list);
- }
-
- void LoadCoreInformation()
- {
- if (data_layout->num_entries[SharedDataLayout::CORE_MARKER] <= 0)
- {
- return;
- }
-
- unsigned *core_marker_ptr = data_layout->GetBlockPtr<unsigned>(
- shared_memory, SharedDataLayout::CORE_MARKER);
- typename ShM<bool, true>::vector is_core_node(
- core_marker_ptr,
- data_layout->num_entries[SharedDataLayout::CORE_MARKER]);
- m_is_core_node.swap(is_core_node);
- }
-
- void LoadGeometries()
- {
- unsigned *geometries_compressed_ptr = data_layout->GetBlockPtr<unsigned>(
- shared_memory, SharedDataLayout::GEOMETRIES_INDICATORS);
- typename ShM<bool, true>::vector edge_is_compressed(
- geometries_compressed_ptr,
- data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDICATORS]);
- m_edge_is_compressed.swap(edge_is_compressed);
-
- unsigned *geometries_index_ptr =
- data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_INDEX);
- typename ShM<unsigned, true>::vector geometry_begin_indices(
- geometries_index_ptr, data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDEX]);
- m_geometry_indices.swap(geometry_begin_indices);
-
- unsigned *geometries_list_ptr =
- data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_LIST);
- typename ShM<unsigned, true>::vector geometry_list(
- geometries_list_ptr, data_layout->num_entries[SharedDataLayout::GEOMETRIES_LIST]);
- m_geometry_list.swap(geometry_list);
- }
-
- public:
- virtual ~SharedDataFacade() {}
-
- boost::shared_mutex data_mutex;
-
- SharedDataFacade()
- {
- if (!SharedMemory::RegionExists(CURRENT_REGIONS))
- {
- throw osrm::exception("No shared memory blocks found, have you forgotten to run osrm-datastore?");
- }
- data_timestamp_ptr = (SharedDataTimestamp *)SharedMemoryFactory::Get(
- CURRENT_REGIONS, sizeof(SharedDataTimestamp), false, false)
- ->Ptr();
- CURRENT_LAYOUT = LAYOUT_NONE;
- CURRENT_DATA = DATA_NONE;
- CURRENT_TIMESTAMP = 0;
-
- // load data
- CheckAndReloadFacade();
- }
-
- void CheckAndReloadFacade()
- {
- if (CURRENT_LAYOUT != data_timestamp_ptr->layout ||
- CURRENT_DATA != data_timestamp_ptr->data ||
- CURRENT_TIMESTAMP != data_timestamp_ptr->timestamp)
- {
- // Get exclusive lock
- SimpleLogger().Write(logDEBUG) << "Updates available, getting exclusive lock";
- boost::unique_lock<boost::shared_mutex> lock(data_mutex);
-
- if (CURRENT_LAYOUT != data_timestamp_ptr->layout ||
- CURRENT_DATA != data_timestamp_ptr->data)
- {
- // release the previous shared memory segments
- SharedMemory::Remove(CURRENT_LAYOUT);
- SharedMemory::Remove(CURRENT_DATA);
-
- CURRENT_LAYOUT = data_timestamp_ptr->layout;
- CURRENT_DATA = data_timestamp_ptr->data;
- CURRENT_TIMESTAMP = 0; // Force trigger a reload
-
- SimpleLogger().Write(logDEBUG) << "Current layout was different to new layout, swapping";
- }
- else
- {
- SimpleLogger().Write(logDEBUG) << "Current layout was same to new layout, not swapping";
- }
-
- if (CURRENT_TIMESTAMP != data_timestamp_ptr->timestamp)
- {
- CURRENT_TIMESTAMP = data_timestamp_ptr->timestamp;
-
- SimpleLogger().Write(logDEBUG) << "Performing data reload";
- m_layout_memory.reset(SharedMemoryFactory::Get(CURRENT_LAYOUT));
-
- data_layout = (SharedDataLayout *) (m_layout_memory->Ptr());
-
- m_large_memory.reset(SharedMemoryFactory::Get(CURRENT_DATA));
- shared_memory = (char *) (m_large_memory->Ptr());
-
- const char *file_index_ptr =
- data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::FILE_INDEX_PATH);
- file_index_path = boost::filesystem::path(file_index_ptr);
- if (!boost::filesystem::exists(file_index_path)) {
- SimpleLogger().Write(logDEBUG) << "Leaf file name "
- << file_index_path.string();
- throw osrm::exception("Could not load leaf index file. "
- "Is any data loaded into shared memory?");
- }
-
- LoadGraph();
- LoadChecksum();
- LoadNodeAndEdgeInformation();
- LoadGeometries();
- LoadTimestamp();
- LoadViaNodeList();
- LoadNames();
- LoadCoreInformation();
-
- data_layout->PrintInformation();
-
- SimpleLogger().Write() << "number of geometries: " << m_coordinate_list->size();
- for (unsigned i = 0; i < m_coordinate_list->size(); ++i)
- {
- if (!GetCoordinateOfNode(i).is_valid())
- {
- SimpleLogger().Write() << "coordinate " << i << " not valid";
- }
- }
- }
- SimpleLogger().Write(logDEBUG) << "Releasing exclusive lock";
- }
- }
-
- // search graph access
- unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); }
-
- unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); }
-
- unsigned GetOutDegree(const NodeID n) const override final
- {
- return m_query_graph->GetOutDegree(n);
- }
-
- NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
-
- EdgeDataT &GetEdgeData(const EdgeID e) const override final
- {
- return m_query_graph->GetEdgeData(e);
- }
-
- EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); }
-
- EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); }
-
- EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
- {
- return m_query_graph->GetAdjacentEdgeRange(node);
- };
-
- // searches for a specific edge
- EdgeID FindEdge(const NodeID from, const NodeID to) const override final
- {
- return m_query_graph->FindEdge(from, to);
- }
-
- EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const override final
- {
- return m_query_graph->FindEdgeInEitherDirection(from, to);
- }
-
- EdgeID
- FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const override final
- {
- return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
- }
-
- // node and edge information access
- FixedPointCoordinate GetCoordinateOfNode(const NodeID id) const override final
- {
- return m_coordinate_list->at(id);
- };
-
- virtual bool EdgeIsCompressed(const unsigned id) const override final
- {
- return m_edge_is_compressed.at(id);
- }
-
- virtual void GetUncompressedGeometry(const unsigned id,
- std::vector<unsigned> &result_nodes) const override final
- {
- const unsigned begin = m_geometry_indices.at(id);
- const unsigned end = m_geometry_indices.at(id + 1);
-
- result_nodes.clear();
- result_nodes.insert(result_nodes.begin(), m_geometry_list.begin() + begin,
- m_geometry_list.begin() + end);
- }
-
- virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const override final
- {
- return m_via_node_list.at(id);
- }
-
- TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const override final
- {
- return m_turn_instruction_list.at(id);
- }
-
- TravelMode GetTravelModeForEdgeID(const unsigned id) const override final
- {
- return m_travel_mode_list.at(id);
- }
-
- std::vector<PhantomNodeWithDistance>
- NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate,
- const float max_distance,
- const int bearing = 0,
- const int bearing_range = 180) override final
- {
- if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
- {
- LoadRTree();
- BOOST_ASSERT(m_geospatial_query.get());
- }
-
- return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance, bearing, bearing_range);
- }
-
- std::vector<PhantomNodeWithDistance>
- NearestPhantomNodes(const FixedPointCoordinate &input_coordinate,
- const unsigned max_results,
- const int bearing = 0,
- const int bearing_range = 180) override final
- {
- if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
- {
- LoadRTree();
- BOOST_ASSERT(m_geospatial_query.get());
- }
-
- return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, bearing, bearing_range);
- }
-
- std::pair<PhantomNode, PhantomNode>
- NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate,
- const int bearing = 0,
- const int bearing_range = 180) override final
- {
- if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
- {
- LoadRTree();
- BOOST_ASSERT(m_geospatial_query.get());
- }
-
- return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(input_coordinate, bearing, bearing_range);
- }
-
- unsigned GetCheckSum() const override final { return m_check_sum; }
-
- unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
- {
- return m_name_ID_list.at(id);
- };
-
- std::string get_name_for_id(const unsigned name_id) const override final
- {
- if (std::numeric_limits<unsigned>::max() == name_id)
- {
- return "";
- }
- auto range = m_name_table->GetRange(name_id);
-
- std::string result;
- result.reserve(range.size());
- if (range.begin() != range.end())
- {
- result.resize(range.back() - range.front() + 1);
- std::copy(m_names_char_list.begin() + range.front(),
- m_names_char_list.begin() + range.back() + 1, result.begin());
- }
- return result;
- }
-
- bool IsCoreNode(const NodeID id) const override final
- {
- if (m_is_core_node.size() > 0)
- {
- return m_is_core_node.at(id);
- }
-
- return false;
- }
-
- virtual std::size_t GetCoreSize() const override final
- {
- return m_is_core_node.size();
- }
-
- std::string GetTimestamp() const override final { return m_timestamp; }
-};
-
-#endif // SHARED_DATAFACADE_HPP
diff --git a/server/data_structures/shared_datatype.hpp b/server/data_structures/shared_datatype.hpp
deleted file mode 100644
index c0ad7d4..0000000
--- a/server/data_structures/shared_datatype.hpp
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef SHARED_DATA_TYPE_HPP
-#define SHARED_DATA_TYPE_HPP
-
-#include "../../util/osrm_exception.hpp"
-#include "../../util/simple_logger.hpp"
-
-#include <cstdint>
-
-#include <array>
-
-namespace
-{
-// Added at the start and end of each block as sanity check
-static const char CANARY[] = "OSRM";
-}
-
-struct SharedDataLayout
-{
- enum BlockID
- {
- NAME_OFFSETS = 0,
- NAME_BLOCKS,
- NAME_CHAR_LIST,
- NAME_ID_LIST,
- VIA_NODE_LIST,
- GRAPH_NODE_LIST,
- GRAPH_EDGE_LIST,
- COORDINATE_LIST,
- TURN_INSTRUCTION,
- TRAVEL_MODE,
- R_SEARCH_TREE,
- GEOMETRIES_INDEX,
- GEOMETRIES_LIST,
- GEOMETRIES_INDICATORS,
- HSGR_CHECKSUM,
- TIMESTAMP,
- FILE_INDEX_PATH,
- CORE_MARKER,
- NUM_BLOCKS
- };
-
- std::array<uint64_t, NUM_BLOCKS> num_entries;
- std::array<uint64_t, NUM_BLOCKS> entry_size;
-
- SharedDataLayout() : num_entries(), entry_size() {}
-
- void PrintInformation() const
- {
- SimpleLogger().Write(logDEBUG) << "NAME_OFFSETS "
- << ": " << GetBlockSize(NAME_OFFSETS);
- SimpleLogger().Write(logDEBUG) << "NAME_BLOCKS "
- << ": " << GetBlockSize(NAME_BLOCKS);
- SimpleLogger().Write(logDEBUG) << "NAME_CHAR_LIST "
- << ": " << GetBlockSize(NAME_CHAR_LIST);
- SimpleLogger().Write(logDEBUG) << "NAME_ID_LIST "
- << ": " << GetBlockSize(NAME_ID_LIST);
- SimpleLogger().Write(logDEBUG) << "VIA_NODE_LIST "
- << ": " << GetBlockSize(VIA_NODE_LIST);
- SimpleLogger().Write(logDEBUG) << "GRAPH_NODE_LIST "
- << ": " << GetBlockSize(GRAPH_NODE_LIST);
- SimpleLogger().Write(logDEBUG) << "GRAPH_EDGE_LIST "
- << ": " << GetBlockSize(GRAPH_EDGE_LIST);
- SimpleLogger().Write(logDEBUG) << "COORDINATE_LIST "
- << ": " << GetBlockSize(COORDINATE_LIST);
- SimpleLogger().Write(logDEBUG) << "TURN_INSTRUCTION "
- << ": " << GetBlockSize(TURN_INSTRUCTION);
- SimpleLogger().Write(logDEBUG) << "TRAVEL_MODE "
- << ": " << GetBlockSize(TRAVEL_MODE);
- SimpleLogger().Write(logDEBUG) << "R_SEARCH_TREE "
- << ": " << GetBlockSize(R_SEARCH_TREE);
- SimpleLogger().Write(logDEBUG) << "GEOMETRIES_INDEX "
- << ": " << GetBlockSize(GEOMETRIES_INDEX);
- SimpleLogger().Write(logDEBUG) << "GEOMETRIES_LIST "
- << ": " << GetBlockSize(GEOMETRIES_LIST);
- SimpleLogger().Write(logDEBUG) << "GEOMETRIES_INDICATORS"
- << ": " << GetBlockSize(GEOMETRIES_INDICATORS);
- SimpleLogger().Write(logDEBUG) << "HSGR_CHECKSUM "
- << ": " << GetBlockSize(HSGR_CHECKSUM);
- SimpleLogger().Write(logDEBUG) << "TIMESTAMP "
- << ": " << GetBlockSize(TIMESTAMP);
- SimpleLogger().Write(logDEBUG) << "FILE_INDEX_PATH "
- << ": " << GetBlockSize(FILE_INDEX_PATH);
- SimpleLogger().Write(logDEBUG) << "CORE_MARKER "
- << ": " << GetBlockSize(CORE_MARKER);
- }
-
- template <typename T> inline void SetBlockSize(BlockID bid, uint64_t entries)
- {
- num_entries[bid] = entries;
- entry_size[bid] = sizeof(T);
- }
-
- inline uint64_t GetBlockSize(BlockID bid) const
- {
- // special bit encoding
- if (bid == GEOMETRIES_INDICATORS || bid == CORE_MARKER)
- {
- return (num_entries[bid] / 32 + 1) *
- entry_size[bid];
- }
-
- return num_entries[bid] * entry_size[bid];
- }
-
- inline uint64_t GetSizeOfLayout() const
- {
- return GetBlockOffset(NUM_BLOCKS) + NUM_BLOCKS * 2 * sizeof(CANARY);
- }
-
- inline uint64_t GetBlockOffset(BlockID bid) const
- {
- uint64_t result = sizeof(CANARY);
- for (auto i = 0; i < bid; i++)
- {
- result += GetBlockSize((BlockID)i) + 2 * sizeof(CANARY);
- }
- return result;
- }
-
- template <typename T, bool WRITE_CANARY = false>
- inline T *GetBlockPtr(char *shared_memory, BlockID bid)
- {
- T *ptr = (T *)(shared_memory + GetBlockOffset(bid));
- if (WRITE_CANARY)
- {
- char *start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
- char *end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
- std::copy(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
- std::copy(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
- }
- else
- {
- char *start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
- char *end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
- bool start_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
- bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
- if (!start_canary_alive)
- {
- throw osrm::exception("Start canary of block corrupted.");
- }
- if (!end_canary_alive)
- {
- throw osrm::exception("End canary of block corrupted.");
- }
- }
-
- return ptr;
- }
-};
-
-enum SharedDataType
-{
- CURRENT_REGIONS,
- LAYOUT_1,
- DATA_1,
- LAYOUT_2,
- DATA_2,
- LAYOUT_NONE,
- DATA_NONE
-};
-
-struct SharedDataTimestamp
-{
- SharedDataType layout;
- SharedDataType data;
- unsigned timestamp;
-};
-
-#endif /* SHARED_DATA_TYPE_HPP */
diff --git a/server/http/header.hpp b/server/http/header.hpp
deleted file mode 100644
index f2598ba..0000000
--- a/server/http/header.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef HEADER_HPP
-#define HEADER_HPP
-
-#include <string>
-#include <algorithm>
-
-namespace http
-{
-struct header
-{
- // explicitly use default copy c'tor as adding move c'tor
- header &operator=(const header &other) = default;
- header(std::string name, std::string value) : name(std::move(name)), value(std::move(value)) {}
- header(header &&other) : name(std::move(other.name)), value(std::move(other.value)) {}
-
- void clear()
- {
- name.clear();
- value.clear();
- }
-
- std::string name;
- std::string value;
-};
-}
-
-#endif // HEADER_HPP
diff --git a/server/http/reply.hpp b/server/http/reply.hpp
deleted file mode 100644
index 733818c..0000000
--- a/server/http/reply.hpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef REPLY_HPP
-#define REPLY_HPP
-
-#include "header.hpp"
-
-#include <boost/asio.hpp>
-
-#include <vector>
-
-namespace http
-{
-class reply
-{
- public:
- enum status_type
- {
- ok = 200,
- bad_request = 400,
- internal_server_error = 500
- } status;
-
- std::vector<header> headers;
- std::vector<boost::asio::const_buffer> to_buffers();
- std::vector<boost::asio::const_buffer> headers_to_buffers();
- std::vector<char> content;
- static reply stock_reply(const status_type status);
- void set_size(const std::size_t size);
- void set_uncompressed_size();
-
- reply();
-
- private:
- std::string status_to_string(reply::status_type status);
- boost::asio::const_buffer status_to_buffer(reply::status_type status);
-};
-}
-
-#endif // REPLY_HPP
diff --git a/server/http/request.hpp b/server/http/request.hpp
deleted file mode 100644
index c487fba..0000000
--- a/server/http/request.hpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef REQUEST_HPP
-#define REQUEST_HPP
-
-#include <boost/asio.hpp>
-
-#include <string>
-
-namespace http
-{
-
-struct request
-{
- std::string uri;
- std::string referrer;
- std::string agent;
- boost::asio::ip::address endpoint;
-};
-
-} // namespace http
-
-#endif // REQUEST_HPP
diff --git a/server/request_handler.cpp b/server/request_handler.cpp
deleted file mode 100644
index 54f0395..0000000
--- a/server/request_handler.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "request_handler.hpp"
-
-#include "api_grammar.hpp"
-#include "http/reply.hpp"
-#include "http/request.hpp"
-
-#include "../util/json_renderer.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/string_util.hpp"
-#include "../util/xml_renderer.hpp"
-#include "../typedefs.h"
-
-#include <osrm/route_parameters.hpp>
-#include <osrm/json_container.hpp>
-#include <osrm/osrm.hpp>
-
-#include <ctime>
-
-#include <algorithm>
-#include <iostream>
-#include <string>
-
-RequestHandler::RequestHandler() : routing_machine(nullptr) {}
-
-void RequestHandler::handle_request(const http::request ¤t_request,
- http::reply ¤t_reply)
-{
- osrm::json::Object json_result;
-
- // parse command
- try
- {
- std::string request_string;
- URIDecode(current_request.uri, request_string);
-
- // deactivated as GCC apparently does not implement that, not even in 4.9
- // std::time_t t = std::time(nullptr);
- // SimpleLogger().Write() << std::put_time(std::localtime(&t), "%m-%d-%Y %H:%M:%S") <<
- // " " << current_request.endpoint.to_string() << " " <<
- // current_request.referrer << ( 0 == current_request.referrer.length() ? "- " :" ") <<
- // current_request.agent << ( 0 == current_request.agent.length() ? "- " :" ") <<
- // request;
-
- time_t ltime;
- struct tm *time_stamp;
-
- ltime = time(nullptr);
- time_stamp = localtime(<ime);
-
- // log timestamp
- SimpleLogger().Write() << (time_stamp->tm_mday < 10 ? "0" : "") << time_stamp->tm_mday
- << "-" << (time_stamp->tm_mon + 1 < 10 ? "0" : "")
- << (time_stamp->tm_mon + 1) << "-" << 1900 + time_stamp->tm_year
- << " " << (time_stamp->tm_hour < 10 ? "0" : "")
- << time_stamp->tm_hour << ":" << (time_stamp->tm_min < 10 ? "0" : "")
- << time_stamp->tm_min << ":" << (time_stamp->tm_sec < 10 ? "0" : "")
- << time_stamp->tm_sec << " " << current_request.endpoint.to_string()
- << " " << current_request.referrer
- << (0 == current_request.referrer.length() ? "- " : " ")
- << current_request.agent
- << (0 == current_request.agent.length() ? "- " : " ")
- << request_string;
-
- RouteParameters route_parameters;
- APIGrammarParser api_parser(&route_parameters);
-
- auto api_iterator = request_string.begin();
- const bool result =
- boost::spirit::qi::parse(api_iterator, request_string.end(), api_parser);
-
- // check if the was an error with the request
- if (result && api_iterator == request_string.end())
- {
- // parsing done, lets call the right plugin to handle the request
- BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");
-
- if (!route_parameters.jsonp_parameter.empty())
- { // prepend response with jsonp parameter
- const std::string json_p = (route_parameters.jsonp_parameter + "(");
- current_reply.content.insert(current_reply.content.end(), json_p.begin(), json_p.end());
- }
-
- const int return_code = routing_machine->RunQuery(route_parameters, json_result);
- json_result.values["status"] = return_code;
- // 4xx bad request return code
- if (return_code / 100 == 4)
- {
- current_reply.status = http::reply::bad_request;
- current_reply.content.clear();
- route_parameters.output_format.clear();
- }
- else
- {
- // 2xx valid request
- BOOST_ASSERT(return_code / 100 == 2);
- }
- }
- else
- {
- const auto position = std::distance(request_string.begin(), api_iterator);
-
- current_reply.status = http::reply::bad_request;
- json_result.values["status"] = http::reply::bad_request;
- json_result.values["status_message"] = "Query string malformed close to position " + std::to_string(position);
- }
-
- current_reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
- current_reply.headers.emplace_back("Access-Control-Allow-Methods", "GET");
- current_reply.headers.emplace_back("Access-Control-Allow-Headers",
- "X-Requested-With, Content-Type");
-
- // set headers
- current_reply.headers.emplace_back("Content-Length",
- std::to_string(current_reply.content.size()));
- if ("gpx" == route_parameters.output_format)
- { // gpx file
- osrm::json::gpx_render(current_reply.content, json_result.values["route"]);
- current_reply.headers.emplace_back("Content-Type",
- "application/gpx+xml; charset=UTF-8");
- current_reply.headers.emplace_back("Content-Disposition",
- "attachment; filename=\"route.gpx\"");
- }
- else if (route_parameters.jsonp_parameter.empty())
- { // json file
- osrm::json::render(current_reply.content, json_result);
- current_reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
- current_reply.headers.emplace_back("Content-Disposition",
- "inline; filename=\"response.json\"");
- }
- else
- { // jsonp
- osrm::json::render(current_reply.content, json_result);
- current_reply.headers.emplace_back("Content-Type", "text/javascript; charset=UTF-8");
- current_reply.headers.emplace_back("Content-Disposition",
- "inline; filename=\"response.js\"");
- }
- if (!route_parameters.jsonp_parameter.empty())
- { // append brace to jsonp response
- current_reply.content.push_back(')');
- }
- }
- catch (const std::exception &e)
- {
- current_reply = http::reply::stock_reply(http::reply::internal_server_error);;
- SimpleLogger().Write(logWARNING) << "[server error] code: " << e.what()
- << ", uri: " << current_request.uri;
- }
-}
-
-void RequestHandler::RegisterRoutingMachine(OSRM *osrm) { routing_machine = osrm; }
diff --git a/server/request_handler.hpp b/server/request_handler.hpp
deleted file mode 100644
index b4019db..0000000
--- a/server/request_handler.hpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef REQUEST_HANDLER_HPP
-#define REQUEST_HANDLER_HPP
-
-#include <string>
-
-template <typename Iterator, class HandlerT> struct APIGrammar;
-struct RouteParameters;
-class OSRM;
-
-namespace http
-{
-class reply;
-struct request;
-}
-
-class RequestHandler
-{
-
- public:
- using APIGrammarParser = APIGrammar<std::string::iterator, RouteParameters>;
-
- RequestHandler();
- RequestHandler(const RequestHandler &) = delete;
-
- void handle_request(const http::request ¤t_request, http::reply ¤t_reply);
- void RegisterRoutingMachine(OSRM *osrm);
-
- private:
- OSRM *routing_machine;
-};
-
-#endif // REQUEST_HANDLER_HPP
diff --git a/server/request_parser.cpp b/server/request_parser.cpp
deleted file mode 100644
index b52d730..0000000
--- a/server/request_parser.cpp
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "request_parser.hpp"
-
-#include "http/compression_type.hpp"
-#include "http/header.hpp"
-#include "http/request.hpp"
-
-#include "../data_structures/tribool.hpp"
-
-#include <boost/algorithm/string/predicate.hpp>
-
-#include <string>
-
-namespace http
-{
-
-RequestParser::RequestParser()
- : state(internal_state::method_start), current_header({"", ""}),
- selected_compression(no_compression), is_post_header(false),
- content_length(0)
-{
-}
-
-std::tuple<osrm::tribool, compression_type>
-RequestParser::parse(request ¤t_request, char *begin, char *end)
-{
- while (begin != end)
- {
- osrm::tribool result = consume(current_request, *begin++);
- if (result != osrm::tribool::indeterminate)
- {
- return std::make_tuple(result, selected_compression);
- }
- }
- osrm::tribool result = osrm::tribool::indeterminate;
-
- if(state == internal_state::post_request && content_length <= 0)
- {
- result = osrm::tribool::yes;
- }
- return std::make_tuple(result, selected_compression);
-}
-
-osrm::tribool RequestParser::consume(request ¤t_request, const char input)
-{
- switch (state)
- {
- case internal_state::method_start:
- if (!is_char(input) || is_CTL(input) || is_special(input))
- {
- return osrm::tribool::no;
- }
- if(input == 'P')
- {
- state = internal_state::post_O;
- return osrm::tribool::indeterminate;
- }
- state = internal_state::method;
- return osrm::tribool::indeterminate;
- case internal_state::post_O:
- if(input == 'O')
- {
- state = internal_state::post_S;
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::post_S:
- if(input == 'S')
- {
- state = internal_state::post_T;
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::post_T:
- if(input == 'T')
- {
- is_post_header = true;
- state = internal_state::method;
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::post_request:
- current_request.uri.push_back(input);
- --content_length;
- return osrm::tribool::indeterminate;
- case internal_state::method:
- if (input == ' ')
- {
- state = internal_state::uri;
- return osrm::tribool::indeterminate;
- }
- if (!is_char(input) || is_CTL(input) || is_special(input))
- {
- return osrm::tribool::no;
- }
- return osrm::tribool::indeterminate;
- case internal_state::uri_start:
- if (is_CTL(input))
- {
- return osrm::tribool::no;
- }
- state = internal_state::uri;
- current_request.uri.push_back(input);
- return osrm::tribool::indeterminate;
- case internal_state::uri:
- if (input == ' ')
- {
- state = internal_state::http_version_h;
- return osrm::tribool::indeterminate;
- }
- if (is_CTL(input))
- {
- return osrm::tribool::no;
- }
- current_request.uri.push_back(input);
- return osrm::tribool::indeterminate;
- case internal_state::http_version_h:
- if (input == 'H')
- {
- state = internal_state::http_version_t_1;
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::http_version_t_1:
- if (input == 'T')
- {
- state = internal_state::http_version_t_2;
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::http_version_t_2:
- if (input == 'T')
- {
- state = internal_state::http_version_p;
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::http_version_p:
- if (input == 'P')
- {
- state = internal_state::http_version_slash;
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::http_version_slash:
- if (input == '/')
- {
- state = internal_state::http_version_major_start;
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::http_version_major_start:
- if (is_digit(input))
- {
- state = internal_state::http_version_major;
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::http_version_major:
- if (input == '.')
- {
- state = internal_state::http_version_minor_start;
- return osrm::tribool::indeterminate;
- }
- if (is_digit(input))
- {
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::http_version_minor_start:
- if (is_digit(input))
- {
- state = internal_state::http_version_minor;
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::http_version_minor:
- if (input == '\r')
- {
- state = internal_state::expecting_newline_1;
- return osrm::tribool::indeterminate;
- }
- if (is_digit(input))
- {
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::expecting_newline_1:
- if (input == '\n')
- {
- state = internal_state::header_line_start;
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::header_line_start:
- if (boost::iequals(current_header.name, "Accept-Encoding"))
- {
- /* giving gzip precedence over deflate */
- if (boost::icontains(current_header.value, "deflate"))
- {
- selected_compression = deflate_rfc1951;
- }
- if (boost::icontains(current_header.value, "gzip"))
- {
- selected_compression = gzip_rfc1952;
- }
- }
-
- if (boost::iequals(current_header.name, "Referer"))
- {
- current_request.referrer = current_header.value;
- }
-
- if (boost::iequals(current_header.name, "User-Agent"))
- {
- current_request.agent = current_header.value;
- }
- if (boost::iequals(current_header.name, "Content-Length"))
- {
- try
- {
- content_length = std::stoi(current_header.value);
- }
- catch (const std::exception &e)
- {
- // Ignore the header if the parameter isn't an int
- }
- }
- if (boost::iequals(current_header.name, "Content-Type"))
- {
- if (!boost::icontains(current_header.value, "application/x-www-form-urlencoded"))
- {
- return osrm::tribool::no;
- }
- }
-
- if (input == '\r')
- {
- state = internal_state::expecting_newline_3;
- return osrm::tribool::indeterminate;
- }
- if (!is_char(input) || is_CTL(input) || is_special(input))
- {
- return osrm::tribool::no;
- }
- state = internal_state::header_name;
- current_header.clear();
- current_header.name.push_back(input);
- return osrm::tribool::indeterminate;
- case internal_state::header_lws:
- if (input == '\r')
- {
- state = internal_state::expecting_newline_2;
- return osrm::tribool::indeterminate;
- }
- if (input == ' ' || input == '\t')
- {
- return osrm::tribool::indeterminate;
- }
- if (is_CTL(input))
- {
- return osrm::tribool::no;
- }
- state = internal_state::header_value;
- return osrm::tribool::indeterminate;
- case internal_state::header_name:
- if (input == ':')
- {
- state = internal_state::space_before_header_value;
- return osrm::tribool::indeterminate;
- }
- if (!is_char(input) || is_CTL(input) || is_special(input))
- {
- return osrm::tribool::no;
- }
- current_header.name.push_back(input);
- return osrm::tribool::indeterminate;
- case internal_state::space_before_header_value:
- if (input == ' ')
- {
- state = internal_state::header_value;
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::header_value:
- if (input == '\r')
- {
- state = internal_state::expecting_newline_2;
- return osrm::tribool::indeterminate;
- }
- if (is_CTL(input))
- {
- return osrm::tribool::no;
- }
- current_header.value.push_back(input);
- return osrm::tribool::indeterminate;
- case internal_state::expecting_newline_2:
- if (input == '\n')
- {
- state = internal_state::header_line_start;
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::no;
- case internal_state::expecting_newline_3:
- if (input == '\n')
- {
- if (is_post_header)
- {
- if (content_length > 0)
- {
- current_request.uri.push_back('?');
- }
- state = internal_state::post_request;
- return osrm::tribool::indeterminate;
- }
- return osrm::tribool::yes;
- }
- return osrm::tribool::no;
- default: // should never be reached
- return input == '\n' ? osrm::tribool::yes : osrm::tribool::no;
- }
-}
-
-bool RequestParser::is_char(const int character) const
-{
- return character >= 0 && character <= 127;
-}
-
-bool RequestParser::is_CTL(const int character) const
-{
- return (character >= 0 && character <= 31) || (character == 127);
-}
-
-bool RequestParser::is_special(const int character) const
-{
- switch (character)
- {
- case '(':
- case ')':
- case '<':
- case '>':
- case '@':
- case ',':
- case ';':
- case ':':
- case '\\':
- case '"':
- case '/':
- case '[':
- case ']':
- case '?':
- case '=':
- case '{':
- case '}':
- case ' ':
- case '\t':
- return true;
- default:
- return false;
- }
-}
-
-bool RequestParser::is_digit(const int character) const
-{
- return character >= '0' && character <= '9';
-}
-}
diff --git a/server/request_parser.hpp b/server/request_parser.hpp
deleted file mode 100644
index 3724613..0000000
--- a/server/request_parser.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef REQUEST_PARSER_HPP
-#define REQUEST_PARSER_HPP
-
-#include "http/compression_type.hpp"
-#include "http/header.hpp"
-#include "../data_structures/tribool.hpp"
-
-#include <tuple>
-
-namespace http
-{
-
-struct request;
-
-class RequestParser
-{
- public:
- RequestParser();
-
- std::tuple<osrm::tribool, compression_type>
- parse(request ¤t_request, char *begin, char *end);
-
- private:
- osrm::tribool consume(request ¤t_request, const char input);
-
- bool is_char(const int character) const;
-
- bool is_CTL(const int character) const;
-
- bool is_special(const int character) const;
-
- bool is_digit(const int character) const;
-
- enum class internal_state : unsigned char
- {
- method_start,
- method,
- uri_start,
- uri,
- http_version_h,
- http_version_t_1,
- http_version_t_2,
- http_version_p,
- http_version_slash,
- http_version_major_start,
- http_version_major,
- http_version_minor_start,
- http_version_minor,
- expecting_newline_1,
- header_line_start,
- header_lws,
- header_name,
- space_before_header_value,
- header_value,
- expecting_newline_2,
- expecting_newline_3,
- post_O,
- post_S,
- post_T,
- post_request
- } state;
-
- header current_header;
- compression_type selected_compression;
- bool is_post_header;
- int content_length;
-};
-
-} // namespace http
-
-#endif // REQUEST_PARSER_HPP
diff --git a/src/benchmarks/static_rtree.cpp b/src/benchmarks/static_rtree.cpp
new file mode 100644
index 0000000..32929eb
--- /dev/null
+++ b/src/benchmarks/static_rtree.cpp
@@ -0,0 +1,115 @@
+#include "engine/geospatial_query.hpp"
+#include "extractor/query_node.hpp"
+#include "extractor/edge_based_node.hpp"
+#include "util/static_rtree.hpp"
+#include "util/timing_util.hpp"
+#include "util/coordinate.hpp"
+#include "mocks/mock_datafacade.hpp"
+
+#include <iostream>
+#include <random>
+
+#include <boost/filesystem/fstream.hpp>
+
+namespace osrm
+{
+namespace benchmarks
+{
+
+using namespace osrm::test;
+
+// Choosen by a fair W20 dice roll (this value is completely arbitrary)
+constexpr unsigned RANDOM_SEED = 13;
+constexpr int32_t WORLD_MIN_LAT = -90 * COORDINATE_PRECISION;
+constexpr int32_t WORLD_MAX_LAT = 90 * COORDINATE_PRECISION;
+constexpr int32_t WORLD_MIN_LON = -180 * COORDINATE_PRECISION;
+constexpr int32_t WORLD_MAX_LON = 180 * COORDINATE_PRECISION;
+
+using RTreeLeaf = extractor::EdgeBasedNode;
+using CoordinateListPtr = std::shared_ptr<std::vector<util::Coordinate>>;
+using BenchStaticRTree =
+ util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, false>::vector, false>;
+
+CoordinateListPtr loadCoordinates(const boost::filesystem::path &nodes_file)
+{
+ boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
+
+ extractor::QueryNode current_node;
+ unsigned coordinate_count = 0;
+ nodes_input_stream.read((char *)&coordinate_count, sizeof(unsigned));
+ auto coords = std::make_shared<std::vector<Coordinate>>(coordinate_count);
+ for (unsigned i = 0; i < coordinate_count; ++i)
+ {
+ nodes_input_stream.read((char *)¤t_node, sizeof(extractor::QueryNode));
+ coords->at(i) = util::Coordinate(current_node.lon, current_node.lat);
+ }
+ return coords;
+}
+
+template <typename QueryT>
+void benchmarkQuery(const std::vector<util::Coordinate> &queries,
+ const std::string &name,
+ QueryT query)
+{
+ std::cout << "Running " << name << " with " << queries.size() << " coordinates: " << std::flush;
+
+ TIMER_START(query);
+ for (const auto &q : queries)
+ {
+ auto result = query(q);
+ (void)result;
+ }
+ TIMER_STOP(query);
+
+ std::cout << "Took " << TIMER_SEC(query) << " seconds "
+ << "(" << TIMER_MSEC(query) << "ms"
+ << ") -> " << TIMER_MSEC(query) / queries.size() << " ms/query "
+ << "(" << TIMER_MSEC(query) << "ms"
+ << ")" << std::endl;
+}
+
+void benchmark(BenchStaticRTree &rtree, unsigned num_queries)
+{
+ std::mt19937 mt_rand(RANDOM_SEED);
+ std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
+ std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
+ std::vector<util::Coordinate> queries;
+ for (unsigned i = 0; i < num_queries; i++)
+ {
+ queries.emplace_back(util::FixedLongitude{lon_udist(mt_rand)},
+ util::FixedLatitude{lat_udist(mt_rand)});
+ }
+
+ benchmarkQuery(queries, "raw RTree queries (1 result)", [&rtree](const util::Coordinate &q)
+ {
+ return rtree.Nearest(q, 1);
+ });
+ benchmarkQuery(queries, "raw RTree queries (10 results)", [&rtree](const util::Coordinate &q)
+ {
+ return rtree.Nearest(q, 10);
+ });
+}
+}
+}
+
+int main(int argc, char **argv)
+{
+ if (argc < 4)
+ {
+ std::cout << "./rtree-bench file.ramIndex file.fileIndx file.nodes"
+ << "\n";
+ return 1;
+ }
+
+ const char *ram_path = argv[1];
+ const char *file_path = argv[2];
+ const char *nodes_path = argv[3];
+
+ auto coords = osrm::benchmarks::loadCoordinates(nodes_path);
+
+ osrm::benchmarks::BenchStaticRTree rtree(ram_path, file_path, coords);
+
+ osrm::benchmarks::benchmark(rtree, 10000);
+
+ return 0;
+}
diff --git a/src/contractor/contractor.cpp b/src/contractor/contractor.cpp
new file mode 100644
index 0000000..39d6f48
--- /dev/null
+++ b/src/contractor/contractor.cpp
@@ -0,0 +1,686 @@
+#include "contractor/contractor.hpp"
+#include "contractor/crc32_processor.hpp"
+#include "contractor/graph_contractor.hpp"
+
+#include "extractor/node_based_edge.hpp"
+#include "extractor/compressed_edge_container.hpp"
+
+#include "util/static_graph.hpp"
+#include "util/static_rtree.hpp"
+#include "util/graph_loader.hpp"
+#include "util/io.hpp"
+#include "util/integer_range.hpp"
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+#include "util/string_util.hpp"
+#include "util/timing_util.hpp"
+#include "util/typedefs.hpp"
+
+#include <fast-cpp-csv-parser/csv.h>
+
+#include <boost/assert.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+#include <tbb/parallel_sort.h>
+
+#include <cstdint>
+#include <bitset>
+#include <chrono>
+#include <memory>
+#include <thread>
+#include <iterator>
+
+namespace std
+{
+
+template <> struct hash<std::pair<OSMNodeID, OSMNodeID>>
+{
+ std::size_t operator()(const std::pair<OSMNodeID, OSMNodeID> &k) const
+ {
+ return static_cast<uint64_t>(k.first) ^ (static_cast<uint64_t>(k.second) << 12);
+ }
+};
+}
+
+namespace osrm
+{
+namespace contractor
+{
+
+int Contractor::Run()
+{
+#ifdef WIN32
+#pragma message("Memory consumption on Windows can be higher due to different bit packing")
+#else
+ static_assert(sizeof(extractor::NodeBasedEdge) == 20,
+ "changing extractor::NodeBasedEdge type has influence on memory consumption!");
+ static_assert(sizeof(extractor::EdgeBasedEdge) == 16,
+ "changing EdgeBasedEdge type has influence on memory consumption!");
+#endif
+
+ if (config.core_factor > 1.0 || config.core_factor < 0)
+ {
+ throw util::exception("Core factor must be between 0.0 to 1.0 (inclusive)");
+ }
+
+ TIMER_START(preparing);
+
+ util::SimpleLogger().Write() << "Loading edge-expanded graph representation";
+
+ util::DeallocatingVector<extractor::EdgeBasedEdge> edge_based_edge_list;
+
+ std::size_t max_edge_id = LoadEdgeExpandedGraph(
+ config.edge_based_graph_path, edge_based_edge_list, config.edge_segment_lookup_path,
+ config.edge_penalty_path, config.segment_speed_lookup_paths, config.node_based_graph_path,
+ config.geometry_path, config.datasource_names_path, config.datasource_indexes_path,
+ config.rtree_leaf_path);
+
+ // Contracting the edge-expanded graph
+
+ TIMER_START(contraction);
+ std::vector<bool> is_core_node;
+ std::vector<float> node_levels;
+ if (config.use_cached_priority)
+ {
+ ReadNodeLevels(node_levels);
+ }
+
+ util::SimpleLogger().Write() << "Reading node weights.";
+ std::vector<EdgeWeight> node_weights;
+ std::string node_file_name = config.osrm_input_path.string() + ".enw";
+ if (util::deserializeVector(node_file_name, node_weights))
+ {
+ util::SimpleLogger().Write() << "Done reading node weights.";
+ }
+ else
+ {
+ throw util::exception("Failed reading node weights.");
+ }
+
+ util::DeallocatingVector<QueryEdge> contracted_edge_list;
+ ContractGraph(max_edge_id, edge_based_edge_list, contracted_edge_list, std::move(node_weights),
+ is_core_node, node_levels);
+ TIMER_STOP(contraction);
+
+ util::SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
+
+ std::size_t number_of_used_edges = WriteContractedGraph(max_edge_id, contracted_edge_list);
+ WriteCoreNodeMarker(std::move(is_core_node));
+ if (!config.use_cached_priority)
+ {
+ WriteNodeLevels(std::move(node_levels));
+ }
+
+ TIMER_STOP(preparing);
+
+ util::SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
+ util::SimpleLogger().Write() << "Contraction: " << ((max_edge_id + 1) / TIMER_SEC(contraction))
+ << " nodes/sec and "
+ << number_of_used_edges / TIMER_SEC(contraction) << " edges/sec";
+
+ util::SimpleLogger().Write() << "finished preprocessing";
+
+ return 0;
+}
+
+std::size_t Contractor::LoadEdgeExpandedGraph(
+ std::string const &edge_based_graph_filename,
+ util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
+ const std::string &edge_segment_lookup_filename,
+ const std::string &edge_penalty_filename,
+ const std::vector<std::string> &segment_speed_filenames,
+ const std::string &nodes_filename,
+ const std::string &geometry_filename,
+ const std::string &datasource_names_filename,
+ const std::string &datasource_indexes_filename,
+ const std::string &rtree_leaf_filename)
+{
+ util::SimpleLogger().Write() << "Opening " << edge_based_graph_filename;
+ boost::filesystem::ifstream input_stream(edge_based_graph_filename, std::ios::binary);
+
+ const bool update_edge_weights = !segment_speed_filenames.empty();
+
+ boost::filesystem::ifstream edge_segment_input_stream;
+ boost::filesystem::ifstream edge_fixed_penalties_input_stream;
+
+ if (update_edge_weights)
+ {
+ edge_segment_input_stream.open(edge_segment_lookup_filename, std::ios::binary);
+ edge_fixed_penalties_input_stream.open(edge_penalty_filename, std::ios::binary);
+ if (!edge_segment_input_stream || !edge_fixed_penalties_input_stream)
+ {
+ throw util::exception("Could not load .edge_segment_lookup or .edge_penalties, did you "
+ "run osrm-extract with '--generate-edge-lookup'?");
+ }
+ }
+
+ const util::FingerPrint fingerprint_valid = util::FingerPrint::GetValid();
+ util::FingerPrint fingerprint_loaded;
+ input_stream.read((char *)&fingerprint_loaded, sizeof(util::FingerPrint));
+ fingerprint_loaded.TestContractor(fingerprint_valid);
+
+ // TODO std::size_t can vary on systems. Our files are not transferable, but we might want to
+ // consider using a fixed size type for I/O
+ std::size_t number_of_edges = 0;
+ std::size_t max_edge_id = SPECIAL_EDGEID;
+ input_stream.read((char *)&number_of_edges, sizeof(std::size_t));
+ input_stream.read((char *)&max_edge_id, sizeof(std::size_t));
+
+ edge_based_edge_list.resize(number_of_edges);
+ util::SimpleLogger().Write() << "Reading " << number_of_edges
+ << " edges from the edge based graph";
+
+ std::unordered_map<std::pair<OSMNodeID, OSMNodeID>, std::pair<unsigned, uint8_t>>
+ segment_speed_lookup;
+
+ // If we update the edge weights, this file will hold the datasource information
+ // for each segment
+ std::vector<uint8_t> m_geometry_datasource;
+
+ if (update_edge_weights)
+ {
+ uint8_t file_id = 1;
+ for (auto segment_speed_filename : segment_speed_filenames)
+ {
+ util::SimpleLogger().Write()
+ << "Segment speed data supplied, will update edge weights from "
+ << segment_speed_filename;
+ io::CSVReader<3> csv_in(segment_speed_filename);
+ csv_in.set_header("from_node", "to_node", "speed");
+ uint64_t from_node_id{};
+ uint64_t to_node_id{};
+ unsigned speed{};
+ while (csv_in.read_row(from_node_id, to_node_id, speed))
+ {
+ segment_speed_lookup[std::make_pair(OSMNodeID(from_node_id),
+ OSMNodeID(to_node_id))] =
+ std::make_pair(speed, file_id);
+ }
+ ++file_id;
+
+ // Check for overflow
+ if (file_id == 0)
+ {
+ throw util::exception(
+ "Sorry, there's a limit of 254 segment speed files, you supplied too many");
+ }
+ }
+
+ std::vector<extractor::QueryNode> internal_to_external_node_map;
+
+ // Here, we have to update the compressed geometry weights
+ // First, we need the external-to-internal node lookup table
+ {
+ boost::filesystem::ifstream nodes_input_stream(nodes_filename, std::ios::binary);
+
+ if (!nodes_input_stream)
+ {
+ throw util::exception("Failed to open " + nodes_filename);
+ }
+
+ unsigned number_of_nodes = 0;
+ nodes_input_stream.read((char *)&number_of_nodes, sizeof(unsigned));
+ internal_to_external_node_map.resize(number_of_nodes);
+
+ // Load all the query nodes into a vector
+ nodes_input_stream.read(reinterpret_cast<char *>(&(internal_to_external_node_map[0])),
+ number_of_nodes * sizeof(extractor::QueryNode));
+ }
+
+ std::vector<unsigned> m_geometry_indices;
+ std::vector<extractor::CompressedEdgeContainer::CompressedEdge> m_geometry_list;
+
+ {
+ std::ifstream geometry_stream(geometry_filename, std::ios::binary);
+ if (!geometry_stream)
+ {
+ throw util::exception("Failed to open " + geometry_filename);
+ }
+ unsigned number_of_indices = 0;
+ unsigned number_of_compressed_geometries = 0;
+
+ geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
+
+ m_geometry_indices.resize(number_of_indices);
+ if (number_of_indices > 0)
+ {
+ geometry_stream.read((char *)&(m_geometry_indices[0]),
+ number_of_indices * sizeof(unsigned));
+ }
+
+ geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
+
+ BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
+ m_geometry_list.resize(number_of_compressed_geometries);
+
+ if (number_of_compressed_geometries > 0)
+ {
+ geometry_stream.read(
+ (char *)&(m_geometry_list[0]),
+ number_of_compressed_geometries *
+ sizeof(extractor::CompressedEdgeContainer::CompressedEdge));
+ }
+ }
+
+ // This is a list of the "data source id" for every segment in the compressed
+ // geometry container. We assume that everything so far has come from the
+ // profile (data source 0). Here, we replace the 0's with the index of the
+ // CSV file that supplied the value that gets used for that segment, then
+ // we write out this list so that it can be returned by the debugging
+ // vector tiles later on.
+ m_geometry_datasource.resize(m_geometry_list.size(), 0);
+
+ // Now, we iterate over all the segments stored in the StaticRTree, updating
+ // the packed geometry weights in the `.geometries` file (note: we do not
+ // update the RTree itself, we just use the leaf nodes to iterate over all segments)
+ {
+
+ using LeafNode = util::StaticRTree<extractor::EdgeBasedNode>::LeafNode;
+
+ std::ifstream leaf_node_file(rtree_leaf_filename, std::ios::binary | std::ios::in);
+ if (!leaf_node_file)
+ {
+ throw util::exception("Failed to open " + rtree_leaf_filename);
+ }
+ uint64_t m_element_count;
+ leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
+
+ LeafNode current_node;
+ while (m_element_count > 0)
+ {
+ leaf_node_file.read(reinterpret_cast<char *>(¤t_node), sizeof(current_node));
+
+ for (size_t i = 0; i < current_node.object_count; i++)
+ {
+ auto &leaf_object = current_node.objects[i];
+ extractor::QueryNode *u;
+ extractor::QueryNode *v;
+
+ if (leaf_object.forward_packed_geometry_id != SPECIAL_EDGEID)
+ {
+ const unsigned forward_begin =
+ m_geometry_indices.at(leaf_object.forward_packed_geometry_id);
+
+ if (leaf_object.fwd_segment_position == 0)
+ {
+ u = &(internal_to_external_node_map[leaf_object.u]);
+ v = &(internal_to_external_node_map[m_geometry_list[forward_begin]
+ .node_id]);
+ }
+ else
+ {
+ u = &(internal_to_external_node_map
+ [m_geometry_list[forward_begin +
+ leaf_object.fwd_segment_position - 1]
+ .node_id]);
+ v = &(internal_to_external_node_map
+ [m_geometry_list[forward_begin +
+ leaf_object.fwd_segment_position]
+ .node_id]);
+ }
+ const double segment_length =
+ util::coordinate_calculation::greatCircleDistance(
+ util::Coordinate{u->lon, u->lat}, util::Coordinate{v->lon, v->lat});
+
+ auto forward_speed_iter =
+ segment_speed_lookup.find(std::make_pair(u->node_id, v->node_id));
+ if (forward_speed_iter != segment_speed_lookup.end())
+ {
+ int new_segment_weight =
+ std::max(1, static_cast<int>(std::floor(
+ (segment_length * 10.) /
+ (forward_speed_iter->second.first / 3.6) +
+ .5)));
+ m_geometry_list[forward_begin + leaf_object.fwd_segment_position]
+ .weight = new_segment_weight;
+ m_geometry_datasource[forward_begin +
+ leaf_object.fwd_segment_position] =
+ forward_speed_iter->second.second;
+ }
+ }
+ if (leaf_object.reverse_packed_geometry_id != SPECIAL_EDGEID)
+ {
+ const unsigned reverse_begin =
+ m_geometry_indices.at(leaf_object.reverse_packed_geometry_id);
+ const unsigned reverse_end =
+ m_geometry_indices.at(leaf_object.reverse_packed_geometry_id + 1);
+
+ int rev_segment_position =
+ (reverse_end - reverse_begin) - leaf_object.fwd_segment_position - 1;
+ if (rev_segment_position == 0)
+ {
+ u = &(internal_to_external_node_map[leaf_object.v]);
+ v = &(internal_to_external_node_map[m_geometry_list[reverse_begin]
+ .node_id]);
+ }
+ else
+ {
+ u = &(internal_to_external_node_map
+ [m_geometry_list[reverse_begin + rev_segment_position - 1]
+ .node_id]);
+ v = &(
+ internal_to_external_node_map[m_geometry_list[reverse_begin +
+ rev_segment_position]
+ .node_id]);
+ }
+ const double segment_length =
+ util::coordinate_calculation::greatCircleDistance(
+ util::Coordinate{u->lon, u->lat}, util::Coordinate{v->lon, v->lat});
+
+ auto reverse_speed_iter =
+ segment_speed_lookup.find(std::make_pair(u->node_id, v->node_id));
+ if (reverse_speed_iter != segment_speed_lookup.end())
+ {
+ int new_segment_weight =
+ std::max(1, static_cast<int>(std::floor(
+ (segment_length * 10.) /
+ (reverse_speed_iter->second.first / 3.6) +
+ .5)));
+ m_geometry_list[reverse_begin + rev_segment_position].weight =
+ new_segment_weight;
+ m_geometry_datasource[reverse_begin + rev_segment_position] =
+ reverse_speed_iter->second.second;
+ }
+ }
+ }
+ m_element_count -= current_node.object_count;
+ }
+ }
+
+ // Now save out the updated compressed geometries
+ {
+ std::ofstream geometry_stream(geometry_filename, std::ios::binary);
+ if (!geometry_stream)
+ {
+ throw util::exception("Failed to open " + geometry_filename + " for writing");
+ }
+ const unsigned number_of_indices = m_geometry_indices.size();
+ const unsigned number_of_compressed_geometries = m_geometry_list.size();
+ geometry_stream.write(reinterpret_cast<const char *>(&number_of_indices),
+ sizeof(unsigned));
+ geometry_stream.write(reinterpret_cast<char *>(&(m_geometry_indices[0])),
+ number_of_indices * sizeof(unsigned));
+ geometry_stream.write(reinterpret_cast<const char *>(&number_of_compressed_geometries),
+ sizeof(unsigned));
+ geometry_stream.write(reinterpret_cast<char *>(&(m_geometry_list[0])),
+ number_of_compressed_geometries *
+ sizeof(extractor::CompressedEdgeContainer::CompressedEdge));
+ }
+ }
+
+ {
+ std::ofstream datasource_stream(datasource_indexes_filename, std::ios::binary);
+ if (!datasource_stream)
+ {
+ throw util::exception("Failed to open " + datasource_indexes_filename +
+ " for writing");
+ }
+ auto number_of_datasource_entries = m_geometry_datasource.size();
+ datasource_stream.write(reinterpret_cast<const char *>(&number_of_datasource_entries),
+ sizeof(number_of_datasource_entries));
+ if (number_of_datasource_entries > 0)
+ {
+ datasource_stream.write(reinterpret_cast<char *>(&(m_geometry_datasource[0])),
+ number_of_datasource_entries * sizeof(uint8_t));
+ }
+ }
+
+ {
+ std::ofstream datasource_stream(datasource_names_filename, std::ios::binary);
+ if (!datasource_stream)
+ {
+ throw util::exception("Failed to open " + datasource_names_filename +
+ " for writing");
+ }
+ datasource_stream << "lua profile" << std::endl;
+ for (auto const &name : segment_speed_filenames)
+ {
+ datasource_stream << name << std::endl;
+ }
+ }
+
+ // TODO: can we read this in bulk? util::DeallocatingVector isn't necessarily
+ // all stored contiguously
+ for (; number_of_edges > 0; --number_of_edges)
+ {
+ extractor::EdgeBasedEdge inbuffer;
+ input_stream.read((char *)&inbuffer, sizeof(extractor::EdgeBasedEdge));
+ if (update_edge_weights)
+ {
+ // Processing-time edge updates
+ unsigned fixed_penalty;
+ edge_fixed_penalties_input_stream.read(reinterpret_cast<char *>(&fixed_penalty),
+ sizeof(fixed_penalty));
+
+ int new_weight = 0;
+
+ unsigned num_osm_nodes = 0;
+ edge_segment_input_stream.read(reinterpret_cast<char *>(&num_osm_nodes),
+ sizeof(num_osm_nodes));
+ OSMNodeID previous_osm_node_id;
+ edge_segment_input_stream.read(reinterpret_cast<char *>(&previous_osm_node_id),
+ sizeof(previous_osm_node_id));
+ OSMNodeID this_osm_node_id;
+ double segment_length;
+ int segment_weight;
+ --num_osm_nodes;
+ for (; num_osm_nodes != 0; --num_osm_nodes)
+ {
+ edge_segment_input_stream.read(reinterpret_cast<char *>(&this_osm_node_id),
+ sizeof(this_osm_node_id));
+ edge_segment_input_stream.read(reinterpret_cast<char *>(&segment_length),
+ sizeof(segment_length));
+ edge_segment_input_stream.read(reinterpret_cast<char *>(&segment_weight),
+ sizeof(segment_weight));
+
+ auto speed_iter = segment_speed_lookup.find(
+ std::make_pair(previous_osm_node_id, this_osm_node_id));
+ if (speed_iter != segment_speed_lookup.end())
+ {
+ // This sets the segment weight using the same formula as the
+ // EdgeBasedGraphFactory for consistency. The *why* of this formula
+ // is lost in the annals of time.
+ int new_segment_weight = std::max(
+ 1, static_cast<int>(std::floor(
+ (segment_length * 10.) / (speed_iter->second.first / 3.6) + .5)));
+ new_weight += new_segment_weight;
+ }
+ else
+ {
+ // If no lookup found, use the original weight value for this segment
+ new_weight += segment_weight;
+ }
+
+ previous_osm_node_id = this_osm_node_id;
+ }
+
+ inbuffer.weight = fixed_penalty + new_weight;
+ }
+
+ edge_based_edge_list.emplace_back(std::move(inbuffer));
+ }
+
+ util::SimpleLogger().Write() << "Done reading edges";
+ return max_edge_id;
+}
+
+void Contractor::ReadNodeLevels(std::vector<float> &node_levels) const
+{
+ boost::filesystem::ifstream order_input_stream(config.level_output_path, std::ios::binary);
+
+ unsigned level_size;
+ order_input_stream.read((char *)&level_size, sizeof(unsigned));
+ node_levels.resize(level_size);
+ order_input_stream.read((char *)node_levels.data(), sizeof(float) * node_levels.size());
+}
+
+void Contractor::WriteNodeLevels(std::vector<float> &&in_node_levels) const
+{
+ std::vector<float> node_levels(std::move(in_node_levels));
+
+ boost::filesystem::ofstream order_output_stream(config.level_output_path, std::ios::binary);
+
+ unsigned level_size = node_levels.size();
+ order_output_stream.write((char *)&level_size, sizeof(unsigned));
+ order_output_stream.write((char *)node_levels.data(), sizeof(float) * node_levels.size());
+}
+
+void Contractor::WriteCoreNodeMarker(std::vector<bool> &&in_is_core_node) const
+{
+ std::vector<bool> is_core_node(std::move(in_is_core_node));
+ std::vector<char> unpacked_bool_flags(std::move(is_core_node.size()));
+ for (auto i = 0u; i < is_core_node.size(); ++i)
+ {
+ unpacked_bool_flags[i] = is_core_node[i] ? 1 : 0;
+ }
+
+ boost::filesystem::ofstream core_marker_output_stream(config.core_output_path,
+ std::ios::binary);
+ unsigned size = unpacked_bool_flags.size();
+ core_marker_output_stream.write((char *)&size, sizeof(unsigned));
+ core_marker_output_stream.write((char *)unpacked_bool_flags.data(),
+ sizeof(char) * unpacked_bool_flags.size());
+}
+
+std::size_t
+Contractor::WriteContractedGraph(unsigned max_node_id,
+ const util::DeallocatingVector<QueryEdge> &contracted_edge_list)
+{
+ // Sorting contracted edges in a way that the static query graph can read some in in-place.
+ tbb::parallel_sort(contracted_edge_list.begin(), contracted_edge_list.end());
+ const unsigned contracted_edge_count = contracted_edge_list.size();
+ util::SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
+ << " edges";
+
+ const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
+ boost::filesystem::ofstream hsgr_output_stream(config.graph_output_path, std::ios::binary);
+ hsgr_output_stream.write((char *)&fingerprint, sizeof(util::FingerPrint));
+ const unsigned max_used_node_id = [&contracted_edge_list]
+ {
+ unsigned tmp_max = 0;
+ for (const QueryEdge &edge : contracted_edge_list)
+ {
+ BOOST_ASSERT(SPECIAL_NODEID != edge.source);
+ BOOST_ASSERT(SPECIAL_NODEID != edge.target);
+ tmp_max = std::max(tmp_max, edge.source);
+ tmp_max = std::max(tmp_max, edge.target);
+ }
+ return tmp_max;
+ }();
+
+ util::SimpleLogger().Write(logDEBUG) << "input graph has " << (max_node_id + 1) << " nodes";
+ util::SimpleLogger().Write(logDEBUG) << "contracted graph has " << (max_used_node_id + 1)
+ << " nodes";
+
+ std::vector<util::StaticGraph<EdgeData>::NodeArrayEntry> node_array;
+ // make sure we have at least one sentinel
+ node_array.resize(max_node_id + 2);
+
+ util::SimpleLogger().Write() << "Building node array";
+ util::StaticGraph<EdgeData>::EdgeIterator edge = 0;
+ util::StaticGraph<EdgeData>::EdgeIterator position = 0;
+ util::StaticGraph<EdgeData>::EdgeIterator last_edge;
+
+ // initializing 'first_edge'-field of nodes:
+ for (const auto node : util::irange(0u, max_used_node_id + 1))
+ {
+ last_edge = edge;
+ while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node))
+ {
+ ++edge;
+ }
+ node_array[node].first_edge = position; //=edge
+ position += edge - last_edge; // remove
+ }
+
+ for (const auto sentinel_counter :
+ util::irange<unsigned>(max_used_node_id + 1, node_array.size()))
+ {
+ // sentinel element, guarded against underflow
+ node_array[sentinel_counter].first_edge = contracted_edge_count;
+ }
+
+ util::SimpleLogger().Write() << "Serializing node array";
+
+ RangebasedCRC32 crc32_calculator;
+ const unsigned edges_crc32 = crc32_calculator(contracted_edge_list);
+ util::SimpleLogger().Write() << "Writing CRC32: " << edges_crc32;
+
+ const unsigned node_array_size = node_array.size();
+ // serialize crc32, aka checksum
+ hsgr_output_stream.write((char *)&edges_crc32, sizeof(unsigned));
+ // serialize number of nodes
+ hsgr_output_stream.write((char *)&node_array_size, sizeof(unsigned));
+ // serialize number of edges
+ hsgr_output_stream.write((char *)&contracted_edge_count, sizeof(unsigned));
+ // serialize all nodes
+ if (node_array_size > 0)
+ {
+ hsgr_output_stream.write((char *)&node_array[0],
+ sizeof(util::StaticGraph<EdgeData>::NodeArrayEntry) *
+ node_array_size);
+ }
+
+ // serialize all edges
+ util::SimpleLogger().Write() << "Building edge array";
+ int number_of_used_edges = 0;
+
+ util::StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
+ for (const auto edge : util::irange<std::size_t>(0, contracted_edge_list.size()))
+ {
+ // some self-loops are required for oneway handling. Need to assertthat we only keep these
+ // (TODO)
+ // no eigen loops
+ // BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target ||
+ // node_represents_oneway[contracted_edge_list[edge].source]);
+ current_edge.target = contracted_edge_list[edge].target;
+ current_edge.data = contracted_edge_list[edge].data;
+
+ // every target needs to be valid
+ BOOST_ASSERT(current_edge.target <= max_used_node_id);
+#ifndef NDEBUG
+ if (current_edge.data.distance <= 0)
+ {
+ util::SimpleLogger().Write(logWARNING)
+ << "Edge: " << edge << ",source: " << contracted_edge_list[edge].source
+ << ", target: " << contracted_edge_list[edge].target
+ << ", dist: " << current_edge.data.distance;
+
+ util::SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node "
+ << contracted_edge_list[edge].source << "/"
+ << node_array.size() - 1;
+ return 1;
+ }
+#endif
+ hsgr_output_stream.write((char *)¤t_edge,
+ sizeof(util::StaticGraph<EdgeData>::EdgeArrayEntry));
+
+ ++number_of_used_edges;
+ }
+
+ return number_of_used_edges;
+}
+
+/**
+ \brief Build contracted graph.
+ */
+void Contractor::ContractGraph(
+ const unsigned max_edge_id,
+ util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
+ util::DeallocatingVector<QueryEdge> &contracted_edge_list,
+ std::vector<EdgeWeight> &&node_weights,
+ std::vector<bool> &is_core_node,
+ std::vector<float> &inout_node_levels) const
+{
+ std::vector<float> node_levels;
+ node_levels.swap(inout_node_levels);
+
+ GraphContractor graph_contractor(max_edge_id + 1, edge_based_edge_list, std::move(node_levels),
+ std::move(node_weights));
+ graph_contractor.Run(config.core_factor);
+ graph_contractor.GetEdges(contracted_edge_list);
+ graph_contractor.GetCoreMarker(is_core_node);
+ graph_contractor.GetNodeLevels(inout_node_levels);
+}
+}
+}
diff --git a/src/engine/api/json_factory.cpp b/src/engine/api/json_factory.cpp
new file mode 100644
index 0000000..5c3663d
--- /dev/null
+++ b/src/engine/api/json_factory.cpp
@@ -0,0 +1,230 @@
+#include "engine/api/json_factory.hpp"
+
+#include "engine/polyline_compressor.hpp"
+#include "engine/hint.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/range/irange.hpp>
+#include <boost/optional.hpp>
+
+#include <string>
+#include <utility>
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+using TurnType = osrm::extractor::guidance::TurnType;
+using DirectionModifier = osrm::extractor::guidance::DirectionModifier;
+using TurnInstruction = osrm::extractor::guidance::TurnInstruction;
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+namespace json
+{
+namespace detail
+{
+
+const constexpr char *modifier_names[] = {"uturn",
+ "sharp right",
+ "right",
+ "slight right",
+ "straight",
+ "slight left",
+ "left",
+ "sharp left"};
+
+// translations of TurnTypes. Not all types are exposed to the outside world.
+// invalid types should never be returned as part of the API
+const constexpr char *turn_type_names[] = {
+ "invalid", "no turn", "invalid", "new name", "continue", "turn",
+ "turn", "turn", "turn", "turn", "merge", "ramp",
+ "ramp", "ramp", "ramp", "ramp", "fork", "end of road",
+ "roundabout", "invalid", "roundabout", "invalid", "traffic circle", "invalid",
+ "traffic circle", "invalid", "invalid", "restriction", "notification"};
+const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"};
+
+// Check whether to include a modifier in the result of the API
+inline bool isValidModifier(const guidance::StepManeuver maneuver)
+{
+ if (maneuver.waypoint_type != guidance::WaypointType::None &&
+ maneuver.instruction.direction_modifier == DirectionModifier::UTurn)
+ return false;
+ return true;
+}
+
+std::string instructionTypeToString(const TurnType type)
+{
+ return turn_type_names[static_cast<std::size_t>(type)];
+}
+
+std::string instructionModifierToString(const DirectionModifier modifier)
+{
+ return modifier_names[static_cast<std::size_t>(modifier)];
+}
+
+std::string waypointTypeToString(const guidance::WaypointType waypoint_type)
+{
+ return waypoint_type_names[static_cast<std::size_t>(waypoint_type)];
+}
+
+util::json::Array coordinateToLonLat(const util::Coordinate coordinate)
+{
+ util::json::Array array;
+ array.values.push_back(static_cast<double>(toFloating(coordinate.lon)));
+ array.values.push_back(static_cast<double>(toFloating(coordinate.lat)));
+ return array;
+}
+
+// FIXME this actually needs to be configurable from the profiles
+std::string modeToString(const extractor::TravelMode mode)
+{
+ std::string token;
+ switch (mode)
+ {
+ case TRAVEL_MODE_INACCESSIBLE:
+ token = "inaccessible";
+ break;
+ case TRAVEL_MODE_DRIVING:
+ token = "driving";
+ break;
+ case TRAVEL_MODE_CYCLING:
+ token = "cycling";
+ break;
+ case TRAVEL_MODE_WALKING:
+ token = "walking";
+ break;
+ case TRAVEL_MODE_FERRY:
+ token = "ferry";
+ break;
+ case TRAVEL_MODE_TRAIN:
+ token = "train";
+ break;
+ case TRAVEL_MODE_PUSHING_BIKE:
+ token = "pushing bike";
+ break;
+ case TRAVEL_MODE_MOVABLE_BRIDGE:
+ token = "movable bridge";
+ break;
+ case TRAVEL_MODE_STEPS_UP:
+ token = "steps up";
+ break;
+ case TRAVEL_MODE_STEPS_DOWN:
+ token = "steps down";
+ break;
+ case TRAVEL_MODE_RIVER_UP:
+ token = "river upstream";
+ break;
+ case TRAVEL_MODE_RIVER_DOWN:
+ token = "river downstream";
+ break;
+ case TRAVEL_MODE_ROUTE:
+ token = "route";
+ break;
+ default:
+ token = "other";
+ break;
+ }
+ return token;
+}
+
+} // namespace detail
+
+util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
+{
+ util::json::Object step_maneuver;
+ if (maneuver.waypoint_type == guidance::WaypointType::None)
+ step_maneuver.values["type"] = detail::instructionTypeToString(maneuver.instruction.type);
+ else
+ step_maneuver.values["type"] = detail::waypointTypeToString(maneuver.waypoint_type);
+
+ if (detail::isValidModifier(maneuver))
+ step_maneuver.values["modifier"] =
+ detail::instructionModifierToString(maneuver.instruction.direction_modifier);
+ step_maneuver.values["location"] = detail::coordinateToLonLat(maneuver.location);
+ step_maneuver.values["bearing_before"] = std::round(maneuver.bearing_before);
+ step_maneuver.values["bearing_after"] = std::round(maneuver.bearing_after);
+ if (maneuver.exit != 0)
+ step_maneuver.values["exit"] = maneuver.exit;
+
+ // TODO currently we need this to comply with the api.
+ // We should move this to an additional entry, the moment we
+ // actually compute the correct locations of the intersections
+ if (!maneuver.intersections.empty() && maneuver.exit == 0)
+ step_maneuver.values["exit"] = maneuver.intersections.size();
+ return step_maneuver;
+}
+
+util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geometry)
+{
+ util::json::Object route_step;
+ route_step.values["distance"] = std::round(step.distance * 10) / 10.;
+ route_step.values["duration"] = std::round(step.duration * 10) / 10.;
+ route_step.values["name"] = std::move(step.name);
+ route_step.values["mode"] = detail::modeToString(std::move(step.mode));
+ route_step.values["maneuver"] = makeStepManeuver(std::move(step.maneuver));
+ route_step.values["geometry"] = std::move(geometry);
+ return route_step;
+}
+
+util::json::Object makeRoute(const guidance::Route &route,
+ util::json::Array legs,
+ boost::optional<util::json::Value> geometry)
+{
+ util::json::Object json_route;
+ json_route.values["distance"] = std::round(route.distance * 10) / 10.;
+ json_route.values["duration"] = std::round(route.duration * 10) / 10.;
+ json_route.values["legs"] = std::move(legs);
+ if (geometry)
+ {
+ json_route.values["geometry"] = *std::move(geometry);
+ }
+ return json_route;
+}
+
+util::json::Object makeWaypoint(const util::Coordinate location, std::string name, const Hint &hint)
+{
+ util::json::Object waypoint;
+ waypoint.values["location"] = detail::coordinateToLonLat(location);
+ waypoint.values["name"] = std::move(name);
+ waypoint.values["hint"] = hint.ToBase64();
+ return waypoint;
+}
+
+util::json::Object makeRouteLeg(guidance::RouteLeg leg, util::json::Array steps)
+{
+ util::json::Object route_leg;
+ route_leg.values["distance"] = std::round(leg.distance * 10) / 10.;
+ route_leg.values["duration"] = std::round(leg.duration * 10) / 10.;
+ route_leg.values["summary"] = std::move(leg.summary);
+ route_leg.values["steps"] = std::move(steps);
+ return route_leg;
+}
+
+util::json::Array makeRouteLegs(std::vector<guidance::RouteLeg> legs,
+ std::vector<util::json::Value> step_geometries)
+{
+ util::json::Array json_legs;
+ auto step_geometry_iter = step_geometries.begin();
+ for (const auto idx : boost::irange(0UL, legs.size()))
+ {
+ auto leg = std::move(legs[idx]);
+ util::json::Array json_steps;
+ json_steps.values.reserve(leg.steps.size());
+ std::transform(
+ std::make_move_iterator(leg.steps.begin()), std::make_move_iterator(leg.steps.end()),
+ std::back_inserter(json_steps.values), [&step_geometry_iter](guidance::RouteStep step)
+ {
+ return makeRouteStep(std::move(step), std::move(*step_geometry_iter++));
+ });
+ json_legs.values.push_back(makeRouteLeg(std::move(leg), std::move(json_steps)));
+ }
+ return json_legs;
+}
+} // namespace json
+} // namespace api
+} // namespace engine
+} // namespace osrm
diff --git a/src/engine/douglas_peucker.cpp b/src/engine/douglas_peucker.cpp
new file mode 100644
index 0000000..e7e2f90
--- /dev/null
+++ b/src/engine/douglas_peucker.cpp
@@ -0,0 +1,100 @@
+#include "engine/douglas_peucker.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/coordinate.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/range/irange.hpp>
+
+#include <cmath>
+#include <algorithm>
+#include <iterator>
+#include <stack>
+#include <utility>
+
+namespace osrm
+{
+namespace engine
+{
+
+std::vector<util::Coordinate> douglasPeucker(std::vector<util::Coordinate>::const_iterator begin,
+ std::vector<util::Coordinate>::const_iterator end,
+ const unsigned zoom_level)
+{
+ BOOST_ASSERT_MSG(zoom_level < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE,
+ "unsupported zoom level");
+
+ const auto size = std::distance(begin, end);
+ if (size < 2)
+ {
+ return {};
+ }
+
+ std::vector<bool> is_necessary(size, false);
+ BOOST_ASSERT(is_necessary.size() >= 2);
+ is_necessary.front() = true;
+ is_necessary.back() = true;
+ using GeometryRange = std::pair<std::size_t, std::size_t>;
+
+ std::stack<GeometryRange> recursion_stack;
+
+ recursion_stack.emplace(0UL, size - 1);
+
+ // mark locations as 'necessary' by divide-and-conquer
+ while (!recursion_stack.empty())
+ {
+ // pop next element
+ const GeometryRange pair = recursion_stack.top();
+ recursion_stack.pop();
+ // sanity checks
+ BOOST_ASSERT_MSG(is_necessary[pair.first], "left border must be necessary");
+ BOOST_ASSERT_MSG(is_necessary[pair.second], "right border must be necessary");
+ BOOST_ASSERT_MSG(pair.second < size, "right border outside of geometry");
+ BOOST_ASSERT_MSG(pair.first <= pair.second, "left border on the wrong side");
+
+ double max_distance = 0;
+ auto farthest_entry_index = pair.second;
+
+ // sweep over range to find the maximum
+ for (auto idx = pair.first + 1; idx != pair.second; ++idx)
+ {
+ using namespace util::coordinate_calculation;
+ const auto distance = perpendicularDistance(begin[pair.first], begin[pair.second], begin[idx]);
+ // found new feasible maximum?
+ if (distance > max_distance &&
+ distance > detail::DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
+ {
+ farthest_entry_index = idx;
+ max_distance = distance;
+ }
+ }
+
+ // check if maximum violates a zoom level dependent threshold
+ if (max_distance > detail::DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
+ {
+ // mark idx as necessary
+ is_necessary[farthest_entry_index] = true;
+ if (pair.first < farthest_entry_index)
+ {
+ recursion_stack.emplace(pair.first, farthest_entry_index);
+ }
+ if (farthest_entry_index < pair.second)
+ {
+ recursion_stack.emplace(farthest_entry_index, pair.second);
+ }
+ }
+ }
+
+ auto simplified_size = std::count(is_necessary.begin(), is_necessary.end(), true);
+ std::vector<util::Coordinate> simplified_geometry;
+ simplified_geometry.reserve(simplified_size);
+ for (auto idx : boost::irange<std::size_t>(0UL, size))
+ {
+ if (is_necessary[idx])
+ {
+ simplified_geometry.push_back(begin[idx]);
+ }
+ }
+ return simplified_geometry;
+}
+} // ns engine
+} // ns osrm
diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp
new file mode 100644
index 0000000..9207c44
--- /dev/null
+++ b/src/engine/engine.cpp
@@ -0,0 +1,190 @@
+#include "engine/engine.hpp"
+#include "engine/engine_config.hpp"
+#include "engine/api/route_parameters.hpp"
+#include "engine/status.hpp"
+
+#include "engine/plugins/table.hpp"
+#include "engine/plugins/nearest.hpp"
+#include "engine/plugins/trip.hpp"
+#include "engine/plugins/viaroute.hpp"
+#include "engine/plugins/tile.hpp"
+#include "engine/plugins/match.hpp"
+
+#include "engine/datafacade/datafacade_base.hpp"
+#include "engine/datafacade/internal_datafacade.hpp"
+#include "engine/datafacade/shared_datafacade.hpp"
+
+#include "storage/shared_barriers.hpp"
+#include "util/make_unique.hpp"
+#include "util/simple_logger.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/interprocess/sync/named_condition.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+#include <boost/thread/lock_types.hpp>
+
+#include <algorithm>
+#include <fstream>
+#include <utility>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+struct Engine::EngineLock
+{
+ // will only be initialized if shared memory is used
+ storage::SharedBarriers barrier;
+ // decrease number of concurrent queries
+ void DecreaseQueryCount();
+ // increase number of concurrent queries
+ void IncreaseQueryCount();
+};
+
+// decrease number of concurrent queries
+void Engine::EngineLock::DecreaseQueryCount()
+{
+ // lock query
+ boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
+ barrier.query_mutex);
+
+ // decrement query count
+ --(barrier.number_of_queries);
+ BOOST_ASSERT_MSG(0 <= barrier.number_of_queries, "invalid number of queries");
+
+ // notify all processes that were waiting for this condition
+ if (0 == barrier.number_of_queries)
+ {
+ barrier.no_running_queries_condition.notify_all();
+ }
+}
+
+// increase number of concurrent queries
+void Engine::EngineLock::IncreaseQueryCount()
+{
+ // lock update pending
+ boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
+ barrier.pending_update_mutex);
+
+ // lock query
+ boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
+ barrier.query_mutex);
+
+ // unlock update pending
+ pending_lock.unlock();
+
+ // increment query count
+ ++(barrier.number_of_queries);
+}
+} // ns engine
+} // ns osrm
+
+namespace
+{
+// Abstracted away the query locking into a template function
+// Works the same for every plugin.
+template <typename ParameterT, typename PluginT, typename ResultT>
+osrm::engine::Status RunQuery(const std::unique_ptr<osrm::engine::Engine::EngineLock> &lock,
+ osrm::engine::datafacade::BaseDataFacade &facade,
+ const ParameterT ¶meters,
+ PluginT &plugin,
+ ResultT &result)
+{
+ if (!lock)
+ {
+ return plugin.HandleRequest(parameters, result);
+ }
+
+ BOOST_ASSERT(lock);
+ lock->IncreaseQueryCount();
+
+ auto &shared_facade = static_cast<osrm::engine::datafacade::SharedDataFacade &>(facade);
+ shared_facade.CheckAndReloadFacade();
+ // Get a shared data lock so that other threads won't update
+ // things while the query is running
+ boost::shared_lock<boost::shared_mutex> data_lock{shared_facade.data_mutex};
+
+ osrm::engine::Status status = plugin.HandleRequest(parameters, result);
+
+ lock->DecreaseQueryCount();
+ return status;
+}
+
+template <typename Plugin, typename Facade, typename... Args>
+std::unique_ptr<Plugin> create(Facade &facade, Args... args)
+{
+ return osrm::util::make_unique<Plugin>(facade, std::forward<Args>(args)...);
+}
+
+} // anon. ns
+
+namespace osrm
+{
+namespace engine
+{
+
+Engine::Engine(EngineConfig &config)
+{
+ if (config.use_shared_memory)
+ {
+ lock = util::make_unique<EngineLock>();
+ query_data_facade = util::make_unique<datafacade::SharedDataFacade>();
+ }
+ else
+ {
+ if (!config.storage_config.IsValid())
+ {
+ throw util::exception("Invalid file paths given!");
+ }
+ query_data_facade = util::make_unique<datafacade::InternalDataFacade>(config.storage_config);
+ }
+
+ // Register plugins
+ using namespace plugins;
+
+ route_plugin = create<ViaRoutePlugin>(*query_data_facade, config.max_locations_viaroute);
+ table_plugin = create<TablePlugin>(*query_data_facade, config.max_locations_distance_table);
+ nearest_plugin = create<NearestPlugin>(*query_data_facade);
+ trip_plugin = create<TripPlugin>(*query_data_facade, config.max_locations_trip);
+ match_plugin = create<MatchPlugin>(*query_data_facade, config.max_locations_map_matching);
+ tile_plugin = create<TilePlugin>(*query_data_facade);
+}
+
+// make sure we deallocate the unique ptr at a position where we know the size of the plugins
+Engine::~Engine() = default;
+Engine::Engine(Engine &&) noexcept = default;
+Engine &Engine::operator=(Engine &&) noexcept = default;
+
+Status Engine::Route(const api::RouteParameters ¶ms, util::json::Object &result)
+{
+ return RunQuery(lock, *query_data_facade, params, *route_plugin, result);
+}
+
+Status Engine::Table(const api::TableParameters ¶ms, util::json::Object &result)
+{
+ return RunQuery(lock, *query_data_facade, params, *table_plugin, result);
+}
+
+Status Engine::Nearest(const api::NearestParameters ¶ms, util::json::Object &result)
+{
+ return RunQuery(lock, *query_data_facade, params, *nearest_plugin, result);
+}
+
+Status Engine::Trip(const api::TripParameters ¶ms, util::json::Object &result)
+{
+ return RunQuery(lock, *query_data_facade, params, *trip_plugin, result);
+}
+
+Status Engine::Match(const api::MatchParameters ¶ms, util::json::Object &result)
+{
+ return RunQuery(lock, *query_data_facade, params, *match_plugin, result);
+}
+
+Status Engine::Tile(const api::TileParameters ¶ms, std::string &result)
+{
+ return RunQuery(lock, *query_data_facade, params, *tile_plugin, result);
+}
+
+} // engine ns
+} // osrm ns
diff --git a/src/engine/engine_config.cpp b/src/engine/engine_config.cpp
new file mode 100644
index 0000000..e26a67e
--- /dev/null
+++ b/src/engine/engine_config.cpp
@@ -0,0 +1,27 @@
+#include "engine/engine_config.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+
+bool EngineConfig::IsValid() const
+{
+ const bool all_path_are_empty =
+ storage_config.ram_index_path.empty() && storage_config.file_index_path.empty() &&
+ storage_config.hsgr_data_path.empty() && storage_config.nodes_data_path.empty() &&
+ storage_config.edges_data_path.empty() && storage_config.core_data_path.empty() &&
+ storage_config.geometries_path.empty() && storage_config.timestamp_path.empty() &&
+ storage_config.datasource_names_path.empty() &&
+ storage_config.datasource_indexes_path.empty() && storage_config.names_data_path.empty();
+
+ const bool limits_valid =
+ (max_locations_distance_table == -1 || max_locations_distance_table > 2) &&
+ (max_locations_map_matching == -1 || max_locations_map_matching > 2) &&
+ (max_locations_trip == -1 || max_locations_trip > 2) &&
+ (max_locations_viaroute == -1 || max_locations_viaroute > 2);
+
+ return ((use_shared_memory && all_path_are_empty) || storage_config.IsValid()) && limits_valid;
+}
+}
+}
diff --git a/src/engine/guidance/assemble_overview.cpp b/src/engine/guidance/assemble_overview.cpp
new file mode 100644
index 0000000..aa25411
--- /dev/null
+++ b/src/engine/guidance/assemble_overview.cpp
@@ -0,0 +1,103 @@
+#ifndef ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
+#define ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
+
+#include "engine/guidance/leg_geometry.hpp"
+#include "engine/douglas_peucker.hpp"
+#include "util/viewport.hpp"
+
+#include <vector>
+#include <tuple>
+#include <numeric>
+#include <utility>
+#include <iterator>
+#include <limits>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+namespace
+{
+
+unsigned calculateOverviewZoomLevel(const std::vector<LegGeometry> &leg_geometries)
+{
+ util::Coordinate south_west{util::FixedLongitude{std::numeric_limits<int>::max()}, util::FixedLatitude{std::numeric_limits<int>::max()}};
+ util::Coordinate north_east{util::FixedLongitude{std::numeric_limits<int>::min()}, util::FixedLatitude{std::numeric_limits<int>::min()}};
+
+ for (const auto &leg_geometry : leg_geometries)
+ {
+ for (const auto coord : leg_geometry.locations)
+ {
+ south_west.lon = std::min(south_west.lon, coord.lon);
+ south_west.lat = std::min(south_west.lat, coord.lat);
+
+ north_east.lon = std::max(north_east.lon, coord.lon);
+ north_east.lat = std::max(north_east.lat, coord.lat);
+ }
+ }
+
+ return util::viewport::getFittedZoom(south_west, north_east);
+}
+
+std::vector<util::Coordinate> simplifyGeometry(const std::vector<LegGeometry> &leg_geometries,
+ const unsigned zoom_level)
+{
+ std::vector<util::Coordinate> overview_geometry;
+ auto leg_index = 0UL;
+ for (const auto geometry : leg_geometries)
+ {
+ auto simplified_geometry =
+ douglasPeucker(geometry.locations.begin(), geometry.locations.end(), zoom_level);
+ // not the last leg
+ if (leg_index < leg_geometries.size() - 1)
+ {
+ simplified_geometry.pop_back();
+ }
+ overview_geometry.insert(overview_geometry.end(), simplified_geometry.begin(),
+ simplified_geometry.end());
+ }
+ return overview_geometry;
+}
+}
+
+std::vector<util::Coordinate> assembleOverview(const std::vector<LegGeometry> &leg_geometries,
+ const bool use_simplification)
+{
+ if (use_simplification)
+ {
+ const auto zoom_level = std::min(18u, calculateOverviewZoomLevel(leg_geometries));
+ return simplifyGeometry(leg_geometries, zoom_level);
+ }
+ BOOST_ASSERT(!use_simplification);
+
+ auto overview_size = std::accumulate(leg_geometries.begin(), leg_geometries.end(), 0,
+ [](const std::size_t sum, const LegGeometry &leg_geometry)
+ {
+ return sum + leg_geometry.locations.size();
+ }) -
+ leg_geometries.size() + 1;
+ std::vector<util::Coordinate> overview_geometry;
+ overview_geometry.reserve(overview_size);
+
+ auto leg_index = 0UL;
+ for (const auto geometry : leg_geometries)
+ {
+ auto begin = geometry.locations.begin();
+ auto end = geometry.locations.end();
+ if (leg_index < leg_geometries.size() - 1)
+ {
+ end = std::prev(end);
+ }
+ overview_geometry.insert(overview_geometry.end(), begin, end);
+ }
+
+ return overview_geometry;
+}
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
+
+#endif
diff --git a/src/engine/guidance/assemble_route.cpp b/src/engine/guidance/assemble_route.cpp
new file mode 100644
index 0000000..cdc3a98
--- /dev/null
+++ b/src/engine/guidance/assemble_route.cpp
@@ -0,0 +1,30 @@
+#include "engine/guidance/assemble_route.hpp"
+
+#include <numeric>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+Route assembleRoute(const std::vector<RouteLeg> &route_legs)
+{
+ auto distance = std::accumulate(route_legs.begin(), route_legs.end(), 0.,
+ [](const double sum, const RouteLeg &leg)
+ {
+ return sum + leg.distance;
+ });
+ auto duration = std::accumulate(route_legs.begin(), route_legs.end(), 0.,
+ [](const double sum, const RouteLeg &leg)
+ {
+ return sum + leg.duration;
+ });
+
+ return Route{duration, distance};
+}
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
diff --git a/src/engine/guidance/assemble_steps.cpp b/src/engine/guidance/assemble_steps.cpp
new file mode 100644
index 0000000..207a6d2
--- /dev/null
+++ b/src/engine/guidance/assemble_steps.cpp
@@ -0,0 +1,82 @@
+#include "engine/guidance/assemble_steps.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cstddef>
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+namespace detail
+{
+
+StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
+ const WaypointType waypoint_type,
+ const LegGeometry &leg_geometry)
+{
+ BOOST_ASSERT(waypoint_type != WaypointType::None);
+ BOOST_ASSERT(leg_geometry.locations.size() >= 2);
+
+ double pre_turn_bearing = 0, post_turn_bearing = 0;
+ Coordinate turn_coordinate;
+ if (waypoint_type == WaypointType::Depart)
+ {
+ turn_coordinate = leg_geometry.locations.front();
+ const auto post_turn_coordinate = *(leg_geometry.locations.begin() + 1);
+ post_turn_bearing =
+ util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate);
+ }
+ else
+ {
+ BOOST_ASSERT(waypoint_type == WaypointType::Arrive);
+ turn_coordinate = leg_geometry.locations.back();
+ const auto pre_turn_coordinate = *(leg_geometry.locations.end() - 2);
+ pre_turn_bearing =
+ util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate);
+ }
+ return StepManeuver{
+ std::move(turn_coordinate),
+ pre_turn_bearing,
+ post_turn_bearing,
+ std::move(instruction),
+ waypoint_type,
+ INVALID_EXIT_NR,
+ {} // no intermediate intersections
+ };
+}
+
+StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
+ const LegGeometry &leg_geometry,
+ const std::size_t segment_index)
+{
+ auto turn_index = leg_geometry.BackIndex(segment_index);
+ BOOST_ASSERT(turn_index > 0);
+ BOOST_ASSERT(turn_index + 1 < leg_geometry.locations.size());
+
+ // TODO chose a bigger look-a-head to smooth complex geometry
+ const auto pre_turn_coordinate = leg_geometry.locations[turn_index - 1];
+ const auto turn_coordinate = leg_geometry.locations[turn_index];
+ const auto post_turn_coordinate = leg_geometry.locations[turn_index + 1];
+
+ const double pre_turn_bearing =
+ util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate);
+ const double post_turn_bearing =
+ util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate);
+
+ return StepManeuver{
+ std::move(turn_coordinate),
+ pre_turn_bearing,
+ post_turn_bearing,
+ std::move(instruction),
+ WaypointType::None,
+ INVALID_EXIT_NR,
+ {} // no intermediate intersections
+ };
+}
+} // ns detail
+} // ns engine
+} // ns guidance
+} // ns detail
diff --git a/src/engine/guidance/post_processing.cpp b/src/engine/guidance/post_processing.cpp
new file mode 100644
index 0000000..0f3fc34
--- /dev/null
+++ b/src/engine/guidance/post_processing.cpp
@@ -0,0 +1,494 @@
+#include "engine/guidance/post_processing.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+
+#include "engine/guidance/toolkit.hpp"
+#include "engine/guidance/assemble_steps.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/range/algorithm_ext/erase.hpp>
+
+#include <algorithm>
+#include <iostream>
+#include <cmath>
+#include <cstddef>
+#include <limits>
+#include <utility>
+
+using TurnInstruction = osrm::extractor::guidance::TurnInstruction;
+using TurnType = osrm::extractor::guidance::TurnType;
+using DirectionModifier = osrm::extractor::guidance::DirectionModifier;
+
+namespace osrm
+{
+namespace engine
+{
+namespace guidance
+{
+
+namespace detail
+{
+bool canMergeTrivially(const RouteStep &destination, const RouteStep &source)
+{
+ return destination.maneuver.exit == 0 && destination.name_id == source.name_id &&
+ isSilent(source.maneuver.instruction);
+}
+
+RouteStep forwardInto(RouteStep destination, const RouteStep &source)
+{
+ // Merge a turn into a silent turn
+ // Overwrites turn instruction and increases exit NR
+ destination.duration += source.duration;
+ destination.distance += source.distance;
+ destination.geometry_begin = std::min(destination.geometry_begin, source.geometry_begin);
+ destination.geometry_end = std::max(destination.geometry_end, source.geometry_end);
+ return destination;
+}
+
+void fixFinalRoundabout(std::vector<RouteStep> &steps)
+{
+ for (std::size_t propagation_index = steps.size() - 1; propagation_index > 0;
+ --propagation_index)
+ {
+ auto &propagation_step = steps[propagation_index];
+ if (propagation_index == 0 || entersRoundabout(propagation_step.maneuver.instruction))
+ {
+ propagation_step.maneuver.exit = 0;
+ propagation_step.geometry_end = steps.back().geometry_begin;
+ break;
+ }
+ else if (propagation_step.maneuver.instruction.type == TurnType::StayOnRoundabout)
+ {
+ // TODO this operates on the data that is in the instructions.
+ // We are missing out on the final segment after the last stay-on-roundabout
+ // instruction though. it is not contained somewhere until now
+ steps[propagation_index - 1] =
+ forwardInto(std::move(steps[propagation_index - 1]), propagation_step);
+ propagation_step.maneuver.instruction =
+ TurnInstruction::NO_TURN(); // mark intermediate instructions invalid
+ }
+ }
+}
+
+bool setUpRoundabout(RouteStep &step)
+{
+ // basic entry into a roundabout
+ // Special case handling, if an entry is directly tied to an exit
+ const auto instruction = step.maneuver.instruction;
+ if (instruction.type == TurnType::EnterRotaryAtExit ||
+ instruction.type == TurnType::EnterRoundaboutAtExit)
+ {
+ step.maneuver.exit = 1;
+ // prevent futher special case handling of these two.
+ if (instruction.type == TurnType::EnterRotaryAtExit)
+ step.maneuver.instruction = TurnType::EnterRotary;
+ else
+ step.maneuver.instruction = TurnType::EnterRoundabout;
+ }
+
+ if (leavesRoundabout(instruction))
+ {
+ step.maneuver.exit = 1; // count the otherwise missing exit
+ if (instruction.type == TurnType::EnterRotaryAtExit)
+ step.maneuver.instruction = TurnType::EnterRotary;
+ else
+ step.maneuver.instruction = TurnType::EnterRoundabout;
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+void closeOffRoundabout(const bool on_roundabout,
+ std::vector<RouteStep> &steps,
+ const std::size_t step_index)
+{
+ auto &step = steps[step_index];
+ step.maneuver.exit += 1;
+ if (!on_roundabout)
+ {
+
+ // We reached a special case that requires the addition of a special route step in
+ // the beginning.
+ // We started in a roundabout, so to announce the exit, we move use the exit
+ // instruction and
+ // move it right to the beginning to make sure to immediately announce the exit.
+ BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) ||
+ steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout);
+ steps[0].geometry_end = 1;
+ steps[1] = detail::forwardInto(steps[1], steps[0]);
+ steps[0].duration = 0;
+ steps[0].distance = 0;
+ steps[1].maneuver.instruction.type = step.maneuver.instruction.type == TurnType::ExitRotary
+ ? TurnType::EnterRotary
+ : TurnType::EnterRoundabout;
+ }
+
+ // Normal exit from the roundabout, or exit from a previously fixed roundabout.
+ // Propagate the index back to the entering
+ // location and
+ // prepare the current silent set of instructions for removal.
+ if (step_index > 1)
+ {
+ // The very first route-step is head, so we cannot iterate past that one
+ for (std::size_t propagation_index = step_index - 1; propagation_index > 0;
+ --propagation_index)
+ {
+ auto &propagation_step = steps[propagation_index];
+ propagation_step = detail::forwardInto(propagation_step, steps[propagation_index + 1]);
+ if (entersRoundabout(propagation_step.maneuver.instruction))
+ {
+ // TODO at this point, we can remember the additional name for a rotary
+ // This requires some initial thought on the data format, though
+
+ propagation_step.maneuver.exit = step.maneuver.exit;
+ propagation_step.geometry_end = step.geometry_end;
+ propagation_step.name = step.name;
+ propagation_step.name_id = step.name_id;
+ break;
+ }
+ else
+ {
+ BOOST_ASSERT(propagation_step.maneuver.instruction.type =
+ TurnType::StayOnRoundabout);
+ propagation_step.maneuver.instruction =
+ TurnInstruction::NO_TURN(); // mark intermediate instructions invalid
+ }
+ }
+ // remove exit
+ step.maneuver.instruction = TurnInstruction::NO_TURN();
+ }
+}
+} // namespace detail
+
+void print(const std::vector<RouteStep> &steps)
+{
+ std::cout << "Path\n";
+ int segment = 0;
+ for (const auto &step : steps)
+ {
+ const auto type = static_cast<int>(step.maneuver.instruction.type);
+ const auto modifier = static_cast<int>(step.maneuver.instruction.direction_modifier);
+
+ std::cout << "\t[" << ++segment << "]: " << type << " " << modifier
+ << " Duration: " << step.duration << " Distance: " << step.distance
+ << " Geometry: " << step.geometry_begin << " " << step.geometry_end
+ << " exit: " << step.maneuver.exit
+ << " Intersections: " << step.maneuver.intersections.size() << " [";
+
+ for (auto intersection : step.maneuver.intersections)
+ std::cout << "(" << intersection.duration << " " << intersection.distance << ")";
+
+ std::cout << "] name[" << step.name_id << "]: " << step.name << std::endl;
+ }
+}
+
+// Every Step Maneuver consists of the information until the turn.
+// This list contains a set of instructions, called silent, which should
+// not be part of the final output.
+// They are required for maintenance purposes. We can calculate the number
+// of exits to pass in a roundabout and the number of intersections
+// that we come across.
+
+std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
+{
+ // the steps should always include the first/last step in form of a location
+ BOOST_ASSERT(steps.size() >= 2);
+ if (steps.size() == 2)
+ return steps;
+
+ // Count Street Exits forward
+ bool on_roundabout = false;
+ bool has_entered_roundabout = false;
+
+ // adds an intersection to the initial route step
+ // It includes the length of the last step, until the intersection
+ // Also updates the length of the respective segment
+ auto addIntersection =
+ [](RouteStep into, const RouteStep &last_step, const RouteStep &intersection)
+ {
+ into.maneuver.intersections.push_back(
+ {last_step.duration, last_step.distance, intersection.maneuver.location});
+
+ return detail::forwardInto(std::move(into), intersection);
+ };
+
+ // count the exits forward. if enter/exit roundabout happen both, no further treatment is
+ // required. We might end up with only one of them (e.g. starting within a roundabout)
+ // or having a via-point in the roundabout.
+ // In this case, exits are numbered from the start of the lag.
+ std::size_t last_valid_instruction = 0;
+ for (std::size_t step_index = 0; step_index < steps.size(); ++step_index)
+ {
+ auto &step = steps[step_index];
+ const auto instruction = step.maneuver.instruction;
+ if (entersRoundabout(instruction))
+ {
+ last_valid_instruction = step_index;
+ has_entered_roundabout = detail::setUpRoundabout(step);
+
+ if (has_entered_roundabout && step_index + 1 < steps.size())
+ steps[step_index + 1].maneuver.exit = step.maneuver.exit;
+ }
+ else if (instruction.type == TurnType::StayOnRoundabout)
+ {
+ on_roundabout = true;
+ // increase the exit number we require passing the exit
+ step.maneuver.exit += 1;
+ if (step_index + 1 < steps.size())
+ steps[step_index + 1].maneuver.exit = step.maneuver.exit;
+ }
+ else if (leavesRoundabout(instruction))
+ {
+ if (!has_entered_roundabout)
+ {
+ // in case the we are not on a roundabout, the very first instruction
+ // after the depart will be transformed into a roundabout and become
+ // the first valid instruction
+ last_valid_instruction = 1;
+ }
+ detail::closeOffRoundabout(has_entered_roundabout, steps, step_index);
+ has_entered_roundabout = false;
+ on_roundabout = false;
+ }
+ else if (instruction.type == TurnType::Suppressed)
+ {
+ // count intersections. We cannot use exit, since intersections can follow directly
+ // after a roundabout
+ steps[last_valid_instruction] = addIntersection(
+ std::move(steps[last_valid_instruction]), steps[step_index - 1], step);
+ step.maneuver.instruction = TurnInstruction::NO_TURN();
+ }
+ else if (!isSilent(instruction))
+ {
+ // Remember the last non silent instruction
+ last_valid_instruction = step_index;
+ }
+ }
+ // unterminated roundabout
+ // Move backwards through the instructions until the start and remove the exit number
+ // A roundabout without exit translates to enter-roundabout.
+ if (has_entered_roundabout || on_roundabout)
+ {
+ detail::fixFinalRoundabout(steps);
+ }
+
+ // finally clean up the post-processed instructions.
+ // Remove all invalid instructions from the set of instructions.
+ // An instruction is invalid, if its NO_TURN and has WaypointType::None.
+ // Two valid NO_TURNs exist in each leg in the form of Depart/Arrive
+
+ // keep valid instructions
+ const auto not_is_valid = [](const RouteStep &step)
+ {
+ return step.maneuver.instruction == TurnInstruction::NO_TURN() &&
+ step.maneuver.waypoint_type == WaypointType::None;
+ };
+
+ boost::remove_erase_if(steps, not_is_valid);
+
+ return steps;
+}
+
+void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
+{
+ // Doing this step in post-processing provides a few challenges we cannot overcome.
+ // The removal of an initial step imposes some copy overhead in the steps, moving all later
+ // steps to the front.
+ // In addition, we cannot reduce the travel time that is accumulated at a different location.
+ // As a direct implication, we have to keep the time of the initial/final turns (which adds a
+ // few seconds of inaccuracy at both ends. This is acceptable, however, since the turn should
+ // usually not be as relevant.
+
+ if (steps.size() < 2 || geometry.locations.size() <= 2)
+ return;
+
+ // if phantom node is located at the connection of two segments, either one can be selected as
+ // turn
+ //
+ // a --- b
+ // |
+ // c
+ //
+ // If a route from b to c is requested, both a--b and b--c could be selected as start segment.
+ // In case of a--b, we end up with an unwanted turn saying turn-right onto b-c.
+ // These cases start off with an initial segment which is of zero length.
+ // We have to be careful though, since routing that starts in a roundabout has a valid.
+ // To catch these cases correctly, we have to perform trimming prior to the post-processing
+
+ BOOST_ASSERT(geometry.locations.size() >= steps.size());
+ // Look for distances under 1m
+ const bool zero_length_step = steps.front().distance <= 1;
+ const bool duplicated_coordinate = util::coordinate_calculation::haversineDistance(
+ geometry.locations[0], geometry.locations[1]) <= 1;
+ if (zero_length_step || duplicated_coordinate)
+ {
+ // fixup the coordinate
+ geometry.locations.erase(geometry.locations.begin());
+
+ // remove the initial distance value
+ geometry.segment_distances.erase(geometry.segment_distances.begin());
+
+ // We have to adjust the first step both for its name and the bearings
+ if (zero_length_step)
+ {
+ // move offsets to front
+ BOOST_ASSERT(geometry.segment_offsets[1] == 1);
+ // geometry offsets have to be adjusted. Move all offsets to the front and reduce by
+ // one. (This is an inplace forward one and reduce by one)
+ std::transform(geometry.segment_offsets.begin() + 1, geometry.segment_offsets.end(),
+ geometry.segment_offsets.begin(), [](const std::size_t val)
+ {
+ return val - 1;
+ });
+
+ geometry.segment_offsets.pop_back();
+ const auto ¤t_depart = steps.front();
+ auto &designated_depart = *(steps.begin() + 1);
+
+ // FIXME this is required to be consistent with the route durations. The initial turn is
+ // not actually part of the route, though
+ designated_depart.duration += current_depart.duration;
+
+ // update initial turn direction/bearings. Due to the duplicated first coordinate, the
+ // initial bearing is invalid
+ designated_depart.maneuver = detail::stepManeuverFromGeometry(
+ TurnInstruction::NO_TURN(), WaypointType::Depart, geometry);
+
+ // finally remove the initial (now duplicated move)
+ steps.erase(steps.begin());
+ }
+ else
+ {
+ steps.front().geometry_begin = 1;
+ // reduce all offsets by one (inplace)
+ std::transform(geometry.segment_offsets.begin(), geometry.segment_offsets.end(),
+ geometry.segment_offsets.begin(), [](const std::size_t val)
+ {
+ return val - 1;
+ });
+
+ steps.front().maneuver = detail::stepManeuverFromGeometry(
+ TurnInstruction::NO_TURN(), WaypointType::Depart, geometry);
+ }
+
+ // and update the leg geometry indices for the removed entry
+ std::for_each(steps.begin(), steps.end(), [](RouteStep &step)
+ {
+ --step.geometry_begin;
+ --step.geometry_end;
+ });
+ }
+
+ // make sure we still have enough segments
+ if (steps.size() < 2 || geometry.locations.size() == 2)
+ return;
+
+ BOOST_ASSERT(geometry.locations.size() >= steps.size());
+ auto &next_to_last_step = *(steps.end() - 2);
+ // in the end, the situation with the roundabout cannot occur. As a result, we can remove all
+ // zero-length instructions
+ if (next_to_last_step.distance <= 1)
+ {
+ geometry.locations.pop_back();
+ geometry.segment_offsets.pop_back();
+ BOOST_ASSERT(geometry.segment_distances.back() < 1);
+ geometry.segment_distances.pop_back();
+
+ next_to_last_step.maneuver = detail::stepManeuverFromGeometry(
+ TurnInstruction::NO_TURN(), WaypointType::Arrive, geometry);
+ steps.pop_back();
+
+ // Because we eliminated a really short segment, it was probably
+ // near an intersection. The convention is *not* to make the
+ // turn, so the `arrive` instruction should be on the same road
+ // as the segment before it. Thus, we have to copy the names
+ // and travel modes from the new next_to_last step.
+ auto &new_next_to_last = *(steps.end() - 2);
+ next_to_last_step.name = new_next_to_last.name;
+ next_to_last_step.name_id = new_next_to_last.name_id;
+ next_to_last_step.mode = new_next_to_last.mode;
+ // the geometry indices of the last step are already correct;
+ }
+ else if (util::coordinate_calculation::haversineDistance(
+ geometry.locations[geometry.locations.size() - 2],
+ geometry.locations[geometry.locations.size() - 1]) <= 1)
+ {
+ // correct steps but duplicated coordinate in the end.
+ // This can happen if the last coordinate snaps to a node in the unpacked geometry
+ geometry.locations.pop_back();
+ geometry.segment_offsets.back()--;
+ BOOST_ASSERT(next_to_last_step.geometry_end == steps.back().geometry_begin);
+ BOOST_ASSERT(next_to_last_step.geometry_begin < next_to_last_step.geometry_end);
+ next_to_last_step.geometry_end--;
+ steps.back().geometry_begin--;
+ steps.back().geometry_end--;
+ steps.back().maneuver = detail::stepManeuverFromGeometry(TurnInstruction::NO_TURN(),
+ WaypointType::Arrive, geometry);
+ }
+}
+
+// assign relative locations to depart/arrive instructions
+std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
+ const LegGeometry &leg_geometry,
+ const PhantomNode &source_node,
+ const PhantomNode &target_node)
+{
+ // We report the relative position of source/target to the road only within a range that is
+ // sufficiently different but not full of the path
+ BOOST_ASSERT(steps.size() >= 2);
+ BOOST_ASSERT(leg_geometry.locations.size() >= 2);
+ const constexpr double MINIMAL_RELATIVE_DISTANCE = 5., MAXIMAL_RELATIVE_DISTANCE = 300.;
+ const auto distance_to_start = util::coordinate_calculation::haversineDistance(
+ source_node.input_location, leg_geometry.locations[0]);
+ const auto initial_modifier =
+ distance_to_start >= MINIMAL_RELATIVE_DISTANCE &&
+ distance_to_start <= MAXIMAL_RELATIVE_DISTANCE
+ ? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
+ source_node.input_location, leg_geometry.locations[0], leg_geometry.locations[1]))
+ : extractor::guidance::DirectionModifier::UTurn;
+
+ steps.front().maneuver.instruction.direction_modifier = initial_modifier;
+
+ const auto distance_from_end = util::coordinate_calculation::haversineDistance(
+ target_node.input_location, leg_geometry.locations.back());
+ const auto final_modifier =
+ distance_from_end >= MINIMAL_RELATIVE_DISTANCE &&
+ distance_from_end <= MAXIMAL_RELATIVE_DISTANCE
+ ? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
+ leg_geometry.locations[leg_geometry.locations.size() - 2],
+ leg_geometry.locations[leg_geometry.locations.size() - 1],
+ target_node.input_location))
+ : extractor::guidance::DirectionModifier::UTurn;
+
+ steps.back().maneuver.instruction.direction_modifier = final_modifier;
+ return steps;
+}
+
+LegGeometry resyncGeometry(LegGeometry leg_geometry, const std::vector<RouteStep> &steps)
+{
+ // The geometry uses an adjacency array-like structure for representation.
+ // To sync it back up with the steps, we cann add a segment for every step.
+ leg_geometry.segment_offsets.clear();
+ leg_geometry.segment_distances.clear();
+ leg_geometry.segment_offsets.push_back(0);
+
+ for (const auto &step : steps)
+ {
+ leg_geometry.segment_distances.push_back(step.distance);
+ // the leg geometry does not follow the begin/end-convetion. So we have to subtract one
+ // to get the back-index.
+ leg_geometry.segment_offsets.push_back(step.geometry_end - 1);
+ }
+
+ // remove the data fromt the reached-target step again
+ leg_geometry.segment_offsets.pop_back();
+ leg_geometry.segment_distances.pop_back();
+
+ return leg_geometry;
+}
+
+} // namespace guidance
+} // namespace engine
+} // namespace osrm
diff --git a/src/engine/hint.cpp b/src/engine/hint.cpp
new file mode 100644
index 0000000..d031fbe
--- /dev/null
+++ b/src/engine/hint.cpp
@@ -0,0 +1,59 @@
+#include "engine/hint.hpp"
+#include "engine/base64.hpp"
+#include "engine/datafacade/datafacade_base.hpp"
+
+#include <boost/assert.hpp>
+
+#include <iterator>
+#include <algorithm>
+#include <ostream>
+#include <tuple>
+
+namespace osrm
+{
+namespace engine
+{
+
+bool Hint::IsValid(const util::Coordinate new_input_coordinates,
+ const datafacade::BaseDataFacade &facade) const
+{
+ auto is_same_input_coordinate = new_input_coordinates.lon == phantom.input_location.lon &&
+ new_input_coordinates.lat == phantom.input_location.lat;
+ return is_same_input_coordinate && phantom.IsValid(facade.GetNumberOfNodes()) &&
+ facade.GetCheckSum() == data_checksum;
+}
+
+std::string Hint::ToBase64() const
+{
+ auto base64 = encodeBase64Bytewise(*this);
+
+ // Make safe for usage as GET parameter in URLs
+ std::replace(begin(base64), end(base64), '+', '-');
+ std::replace(begin(base64), end(base64), '/', '_');
+
+ return base64;
+}
+
+Hint Hint::FromBase64(const std::string &base64Hint)
+{
+ BOOST_ASSERT_MSG(base64Hint.size() == ENCODED_HINT_SIZE, "Hint has invalid size");
+
+ // We need mutability but don't want to change the API
+ auto encoded = base64Hint;
+
+ // Reverses above encoding we need for GET parameters in URL
+ std::replace(begin(encoded), end(encoded), '-', '+');
+ std::replace(begin(encoded), end(encoded), '_', '/');
+
+ return decodeBase64Bytewise<Hint>(encoded);
+}
+
+bool operator==(const Hint &lhs, const Hint &rhs)
+{
+ return std::tie(lhs.phantom, lhs.data_checksum) == std::tie(rhs.phantom, rhs.data_checksum);
+}
+
+std::ostream &operator<<(std::ostream &out, const Hint &hint) { return out << hint.ToBase64(); }
+
+} // ns engine
+} // ns osrm
diff --git a/src/engine/plugins/match.cpp b/src/engine/plugins/match.cpp
new file mode 100644
index 0000000..1fff3fe
--- /dev/null
+++ b/src/engine/plugins/match.cpp
@@ -0,0 +1,197 @@
+#include "engine/plugins/plugin_base.hpp"
+#include "engine/plugins/match.hpp"
+
+#include "engine/map_matching/bayes_classifier.hpp"
+#include "engine/api/match_parameters.hpp"
+#include "engine/api/match_api.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/integer_range.hpp"
+#include "util/json_logger.hpp"
+#include "util/json_util.hpp"
+#include "util/string_util.hpp"
+
+#include <cstdlib>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+// Filters PhantomNodes to obtain a set of viable candiates
+void filterCandidates(const std::vector<util::Coordinate> &coordinates,
+ MatchPlugin::CandidateLists &candidates_lists)
+{
+ for (const auto current_coordinate : util::irange<std::size_t>(0, coordinates.size()))
+ {
+ bool allow_uturn = false;
+
+ if (coordinates.size() - 1 > current_coordinate && 0 < current_coordinate)
+ {
+ double turn_angle = util::coordinate_calculation::computeAngle(
+ coordinates[current_coordinate - 1], coordinates[current_coordinate],
+ coordinates[current_coordinate + 1]);
+
+ // sharp turns indicate a possible uturn
+ if (turn_angle <= 90.0 || turn_angle >= 270.0)
+ {
+ allow_uturn = true;
+ }
+ }
+
+ auto &candidates = candidates_lists[current_coordinate];
+ if (candidates.empty())
+ {
+ continue;
+ }
+
+ // sort by forward id, then by reverse id and then by distance
+ std::sort(
+ candidates.begin(), candidates.end(),
+ [](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
+ {
+ return lhs.phantom_node.forward_segment_id.id < rhs.phantom_node.forward_segment_id.id ||
+ (lhs.phantom_node.forward_segment_id.id == rhs.phantom_node.forward_segment_id.id &&
+ (lhs.phantom_node.reverse_segment_id.id < rhs.phantom_node.reverse_segment_id.id ||
+ (lhs.phantom_node.reverse_segment_id.id == rhs.phantom_node.reverse_segment_id.id &&
+ lhs.distance < rhs.distance)));
+ });
+
+ auto new_end = std::unique(
+ candidates.begin(), candidates.end(),
+ [](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
+ {
+ return lhs.phantom_node.forward_segment_id.id == rhs.phantom_node.forward_segment_id.id &&
+ lhs.phantom_node.reverse_segment_id.id == rhs.phantom_node.reverse_segment_id.id;
+ });
+ candidates.resize(new_end - candidates.begin());
+
+ if (!allow_uturn)
+ {
+ const auto compact_size = candidates.size();
+ for (const auto i : util::irange<std::size_t>(0, compact_size))
+ {
+ // Split edge if it is bidirectional and append reverse direction to end of list
+ if (candidates[i].phantom_node.forward_segment_id.enabled &&
+ candidates[i].phantom_node.reverse_segment_id.enabled)
+ {
+ PhantomNode reverse_node(candidates[i].phantom_node);
+ reverse_node.forward_segment_id.enabled = false;
+ candidates.push_back(
+ PhantomNodeWithDistance{reverse_node, candidates[i].distance});
+
+ candidates[i].phantom_node.reverse_segment_id.enabled = false;
+ }
+ }
+ }
+
+ // sort by distance to make pruning effective
+ std::sort(candidates.begin(), candidates.end(),
+ [](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
+ {
+ return lhs.distance < rhs.distance;
+ });
+ }
+}
+
+Status MatchPlugin::HandleRequest(const api::MatchParameters ¶meters,
+ util::json::Object &json_result)
+{
+ BOOST_ASSERT(parameters.IsValid());
+
+ // enforce maximum number of locations for performance reasons
+ if (max_locations_map_matching > 0 &&
+ static_cast<int>(parameters.coordinates.size()) > max_locations_map_matching)
+ {
+ return Error("TooBig", "Too many trace coordinates", json_result);
+ }
+
+ if (!CheckAllCoordinates(parameters.coordinates))
+ {
+ return Error("InvalidValue", "Invalid coordinate value.", json_result);
+ }
+
+ // assuming radius is the standard deviation of a normal distribution
+ // that models GPS noise (in this model), x3 should give us the correct
+ // search radius with > 99% confidence
+ std::vector<double> search_radiuses;
+ if (parameters.radiuses.empty())
+ {
+ search_radiuses.resize(parameters.coordinates.size(),
+ DEFAULT_GPS_PRECISION * RADIUS_MULTIPLIER);
+ }
+ else
+ {
+ search_radiuses.resize(parameters.coordinates.size());
+ std::transform(parameters.radiuses.begin(), parameters.radiuses.end(),
+ search_radiuses.begin(), [](const boost::optional<double> &maybe_radius)
+ {
+ if (maybe_radius)
+ {
+ return *maybe_radius * RADIUS_MULTIPLIER;
+ }
+ else
+ {
+ return DEFAULT_GPS_PRECISION * RADIUS_MULTIPLIER;
+ }
+
+ });
+ }
+
+ auto candidates_lists = GetPhantomNodesInRange(parameters, search_radiuses);
+
+ filterCandidates(parameters.coordinates, candidates_lists);
+ if (std::all_of(candidates_lists.begin(), candidates_lists.end(),
+ [](const std::vector<PhantomNodeWithDistance> &candidates)
+ {
+ return candidates.empty();
+ }))
+ {
+ return Error("NoSegment",
+ std::string("Could not find a matching segment for any coordinate."),
+ json_result);
+ }
+
+ // call the actual map matching
+ SubMatchingList sub_matchings = map_matching(candidates_lists, parameters.coordinates,
+ parameters.timestamps, parameters.radiuses);
+
+ if (sub_matchings.size() == 0)
+ {
+ return Error("NoMatch", "Could not match the trace.", json_result);
+ }
+
+ std::vector<InternalRouteResult> sub_routes(sub_matchings.size());
+ for (auto index : util::irange(0UL, sub_matchings.size()))
+ {
+ BOOST_ASSERT(sub_matchings[index].nodes.size() > 1);
+
+ // FIXME we only run this to obtain the geometry
+ // The clean way would be to get this directly from the map matching plugin
+ PhantomNodes current_phantom_node_pair;
+ for (unsigned i = 0; i < sub_matchings[index].nodes.size() - 1; ++i)
+ {
+ current_phantom_node_pair.source_phantom = sub_matchings[index].nodes[i];
+ current_phantom_node_pair.target_phantom = sub_matchings[index].nodes[i + 1];
+ BOOST_ASSERT(current_phantom_node_pair.source_phantom.IsValid());
+ BOOST_ASSERT(current_phantom_node_pair.target_phantom.IsValid());
+ sub_routes[index].segment_end_coordinates.emplace_back(current_phantom_node_pair);
+ }
+ shortest_path(sub_routes[index].segment_end_coordinates, {}, sub_routes[index]);
+ BOOST_ASSERT(sub_routes[index].shortest_path_length != INVALID_EDGE_WEIGHT);
+ }
+
+ api::MatchAPI match_api{BasePlugin::facade, parameters};
+ match_api.MakeResponse(sub_matchings, sub_routes, json_result);
+
+ return Status::Ok;
+}
+}
+}
+}
diff --git a/src/engine/plugins/nearest.cpp b/src/engine/plugins/nearest.cpp
new file mode 100644
index 0000000..96b63e3
--- /dev/null
+++ b/src/engine/plugins/nearest.cpp
@@ -0,0 +1,49 @@
+#include "engine/plugins/nearest.hpp"
+#include "engine/api/nearest_parameters.hpp"
+#include "engine/api/nearest_api.hpp"
+#include "engine/phantom_node.hpp"
+#include "util/integer_range.hpp"
+
+#include <cstddef>
+#include <string>
+
+#include <boost/assert.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+NearestPlugin::NearestPlugin(datafacade::BaseDataFacade &facade) : BasePlugin{facade} {}
+
+Status NearestPlugin::HandleRequest(const api::NearestParameters ¶ms,
+ util::json::Object &json_result)
+{
+ BOOST_ASSERT(params.IsValid());
+
+ if (!CheckAllCoordinates(params.coordinates))
+ return Error("InvalidOptions", "Coordinates are invalid", json_result);
+
+ if (params.coordinates.size() != 1)
+ {
+ return Error("InvalidOptions", "Only one input coordinate is supported", json_result);
+ }
+
+ auto phantom_nodes = GetPhantomNodes(params, params.number_of_results);
+
+ if (phantom_nodes.front().size() == 0)
+ {
+ return Error("NoSegment", "Could not find a matching segments for coordinate", json_result);
+ }
+ BOOST_ASSERT(phantom_nodes.front().size() > 0);
+
+ api::NearestAPI nearest_api(facade, params);
+ nearest_api.MakeResponse(phantom_nodes, json_result);
+
+ return Status::Ok;
+}
+}
+}
+}
diff --git a/src/engine/plugins/table.cpp b/src/engine/plugins/table.cpp
new file mode 100644
index 0000000..27e3100
--- /dev/null
+++ b/src/engine/plugins/table.cpp
@@ -0,0 +1,76 @@
+#include "engine/plugins/table.hpp"
+
+#include "engine/api/table_parameters.hpp"
+#include "engine/api/table_api.hpp"
+#include "engine/routing_algorithms/many_to_many.hpp"
+#include "engine/search_engine_data.hpp"
+#include "util/string_util.hpp"
+#include "util/json_container.hpp"
+
+#include <cstdlib>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <boost/assert.hpp>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+TablePlugin::TablePlugin(datafacade::BaseDataFacade &facade, const int max_locations_distance_table)
+ : BasePlugin{facade}, distance_table(&facade, heaps),
+ max_locations_distance_table(max_locations_distance_table)
+{
+}
+
+Status TablePlugin::HandleRequest(const api::TableParameters ¶ms, util::json::Object &result)
+{
+ BOOST_ASSERT(params.IsValid());
+
+ if (!CheckAllCoordinates(params.coordinates))
+ {
+ return Error("InvalidOptions", "Coordinates are invalid", result);
+ }
+
+ if (params.bearings.size() > 0 && params.coordinates.size() != params.bearings.size())
+ {
+ return Error("InvalidOptions", "Number of bearings does not match number of coordinates",
+ result);
+ }
+
+ // Empty sources or destinations means the user wants all of them included, respectively
+ // The ManyToMany routing algorithm we dispatch to below already handles this perfectly.
+ const auto num_sources =
+ params.sources.empty() ? params.coordinates.size() : params.sources.size();
+ const auto num_destinations =
+ params.destinations.empty() ? params.coordinates.size() : params.destinations.size();
+
+ if (max_locations_distance_table > 0 &&
+ ((num_sources * num_destinations) >
+ static_cast<std::size_t>(max_locations_distance_table * max_locations_distance_table)))
+ {
+ return Error("TooBig", "Too many table coordinates", result);
+ }
+
+ auto snapped_phantoms = SnapPhantomNodes(GetPhantomNodes(params));
+ auto result_table = distance_table(snapped_phantoms, params.sources, params.destinations);
+
+ if (result_table.empty())
+ {
+ return Error("NoTable", "No table found", result);
+ }
+
+ api::TableAPI table_api{facade, params};
+ table_api.MakeResponse(result_table, snapped_phantoms, result);
+
+ return Status::Ok;
+}
+}
+}
+}
diff --git a/src/engine/plugins/tile.cpp b/src/engine/plugins/tile.cpp
new file mode 100644
index 0000000..7d18d90
--- /dev/null
+++ b/src/engine/plugins/tile.cpp
@@ -0,0 +1,455 @@
+#include "engine/plugins/plugin_base.hpp"
+#include "engine/plugins/tile.hpp"
+
+#include "util/coordinate_calculation.hpp"
+
+#include <boost/geometry.hpp>
+#include <boost/geometry/geometries/point_xy.hpp>
+#include <boost/geometry/geometries/geometries.hpp>
+#include <boost/geometry/multi/geometries/multi_linestring.hpp>
+
+#include <protozero/varint.hpp>
+#include <protozero/pbf_writer.hpp>
+
+#include <string>
+#include <vector>
+#include <utility>
+
+#include <cmath>
+#include <cstdint>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+namespace detail
+{
+// Vector tiles are 4096 virtual pixels on each side
+const constexpr double VECTOR_TILE_EXTENT = 4096.0;
+const constexpr double VECTOR_TILE_BUFFER = 128.0;
+
+// Simple container class for WGS84 coordinates
+template <typename T> struct Point final
+{
+ Point(T _x, T _y) : x(_x), y(_y) {}
+
+ const T x;
+ const T y;
+};
+
+// from mapnik-vector-tile
+namespace pbf
+{
+inline unsigned encode_length(const unsigned len) { return (len << 3u) | 2u; }
+}
+
+struct BBox final
+{
+ BBox(const double _minx, const double _miny, const double _maxx, const double _maxy)
+ : minx(_minx), miny(_miny), maxx(_maxx), maxy(_maxy)
+ {
+ }
+
+ double width() const { return maxx - minx; }
+ double height() const { return maxy - miny; }
+
+ const double minx;
+ const double miny;
+ const double maxx;
+ const double maxy;
+};
+
+// Simple container for integer coordinates (i.e. pixel coords)
+struct point_type_i final
+{
+ point_type_i(std::int64_t _x, std::int64_t _y) : x(_x), y(_y) {}
+
+ const std::int64_t x;
+ const std::int64_t y;
+};
+
+using FixedLine = std::vector<detail::Point<std::int32_t>>;
+using FloatLine = std::vector<detail::Point<double>>;
+
+typedef boost::geometry::model::point<double, 2, boost::geometry::cs::cartesian> point_t;
+typedef boost::geometry::model::linestring<point_t> linestring_t;
+typedef boost::geometry::model::box<point_t> box_t;
+typedef boost::geometry::model::multi_linestring<linestring_t> multi_linestring_t;
+const static box_t clip_box(point_t(-detail::VECTOR_TILE_BUFFER, -detail::VECTOR_TILE_BUFFER),
+ point_t(detail::VECTOR_TILE_EXTENT + detail::VECTOR_TILE_BUFFER,
+ detail::VECTOR_TILE_EXTENT + detail::VECTOR_TILE_BUFFER));
+
+// from mapnik-vector-tile
+// Encodes a linestring using protobuf zigzag encoding
+inline bool encodeLinestring(const FixedLine &line,
+ protozero::packed_field_uint32 &geometry,
+ std::int32_t &start_x,
+ std::int32_t &start_y)
+{
+ const std::size_t line_size = line.size();
+ if (line_size < 2)
+ {
+ return false;
+ }
+
+ const unsigned line_to_length = static_cast<const unsigned>(line_size) - 1;
+
+ auto pt = line.begin();
+ geometry.add_element(9); // move_to | (1 << 3)
+ geometry.add_element(protozero::encode_zigzag32(pt->x - start_x));
+ geometry.add_element(protozero::encode_zigzag32(pt->y - start_y));
+ start_x = pt->x;
+ start_y = pt->y;
+ geometry.add_element(detail::pbf::encode_length(line_to_length));
+ for (++pt; pt != line.end(); ++pt)
+ {
+ const std::int32_t dx = pt->x - start_x;
+ const std::int32_t dy = pt->y - start_y;
+ geometry.add_element(protozero::encode_zigzag32(dx));
+ geometry.add_element(protozero::encode_zigzag32(dy));
+ start_x = pt->x;
+ start_y = pt->y;
+ }
+ return true;
+}
+
+FixedLine coordinatesToTileLine(const util::Coordinate start,
+ const util::Coordinate target,
+ const detail::BBox &tile_bbox)
+{
+ using namespace util::coordinate_calculation;
+ FloatLine geo_line;
+ geo_line.emplace_back(static_cast<double>(util::toFloating(start.lon)),
+ static_cast<double>(util::toFloating(start.lat)));
+ geo_line.emplace_back(static_cast<double>(util::toFloating(target.lon)),
+ static_cast<double>(util::toFloating(target.lat)));
+
+ linestring_t unclipped_line;
+
+ for (auto const &pt : geo_line)
+ {
+ double px_merc = pt.x * mercator::DEGREE_TO_PX;
+ double py_merc = mercator::latToY(util::FloatLatitude(pt.y)) * mercator::DEGREE_TO_PX;
+ // convert lon/lat to tile coordinates
+ const auto px = std::round(
+ ((px_merc - tile_bbox.minx) * mercator::TILE_SIZE / tile_bbox.width()) *
+ detail::VECTOR_TILE_EXTENT / util::coordinate_calculation::mercator::TILE_SIZE);
+ const auto py = std::round(
+ ((tile_bbox.maxy - py_merc) * mercator::TILE_SIZE / tile_bbox.height()) *
+ detail::VECTOR_TILE_EXTENT / util::coordinate_calculation::mercator::TILE_SIZE);
+
+ boost::geometry::append(unclipped_line, point_t(px, py));
+ }
+
+ multi_linestring_t clipped_line;
+
+ boost::geometry::intersection(clip_box, unclipped_line, clipped_line);
+
+ FixedLine tile_line;
+
+ // b::g::intersection might return a line with one point if the
+ // original line was very short and coords were dupes
+ if (!clipped_line.empty() && clipped_line[0].size() == 2)
+ {
+ if (clipped_line[0].size() == 2)
+ {
+ for (const auto &p : clipped_line[0])
+ {
+ tile_line.emplace_back(p.get<0>(), p.get<1>());
+ }
+ }
+ }
+
+ return tile_line;
+}
+}
+
+Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::string &pbf_buffer)
+{
+ BOOST_ASSERT(parameters.IsValid());
+
+ using namespace util::coordinate_calculation;
+ double min_lon, min_lat, max_lon, max_lat;
+
+ // Convert the z,x,y mercator tile coordinates into WGS84 lon/lat values
+ mercator::xyzToWGS84(parameters.x, parameters.y, parameters.z, min_lon, min_lat, max_lon,
+ max_lat);
+
+ util::Coordinate southwest{util::FloatLongitude(min_lon), util::FloatLatitude(min_lat)};
+ util::Coordinate northeast{util::FloatLongitude(max_lon), util::FloatLatitude(max_lat)};
+
+ // Fetch all the segments that are in our bounding box.
+ // This hits the OSRM StaticRTree
+ const auto edges = facade.GetEdgesInBox(southwest, northeast);
+
+ std::vector<int> used_weights;
+ std::unordered_map<int, std::size_t> weight_offsets;
+ uint8_t max_datasource_id = 0;
+
+ // Loop over all edges once to tally up all the attributes we'll need.
+ // We need to do this so that we know the attribute offsets to use
+ // when we encode each feature in the tile.
+ for (const auto &edge : edges)
+ {
+ int forward_weight = 0, reverse_weight = 0;
+ uint8_t forward_datasource = 0;
+ uint8_t reverse_datasource = 0;
+
+ if (edge.forward_packed_geometry_id != SPECIAL_EDGEID)
+ {
+ std::vector<EdgeWeight> forward_weight_vector;
+ facade.GetUncompressedWeights(edge.forward_packed_geometry_id, forward_weight_vector);
+ forward_weight = forward_weight_vector[edge.fwd_segment_position];
+
+ std::vector<uint8_t> forward_datasource_vector;
+ facade.GetUncompressedDatasources(edge.forward_packed_geometry_id,
+ forward_datasource_vector);
+ forward_datasource = forward_datasource_vector[edge.fwd_segment_position];
+
+ if (weight_offsets.find(forward_weight) == weight_offsets.end())
+ {
+ used_weights.push_back(forward_weight);
+ weight_offsets[forward_weight] = used_weights.size() - 1;
+ }
+ }
+
+ if (edge.reverse_packed_geometry_id != SPECIAL_EDGEID)
+ {
+ std::vector<EdgeWeight> reverse_weight_vector;
+ facade.GetUncompressedWeights(edge.reverse_packed_geometry_id, reverse_weight_vector);
+
+ BOOST_ASSERT(edge.fwd_segment_position < reverse_weight_vector.size());
+
+ reverse_weight =
+ reverse_weight_vector[reverse_weight_vector.size() - edge.fwd_segment_position - 1];
+
+ if (weight_offsets.find(reverse_weight) == weight_offsets.end())
+ {
+ used_weights.push_back(reverse_weight);
+ weight_offsets[reverse_weight] = used_weights.size() - 1;
+ }
+ std::vector<uint8_t> reverse_datasource_vector;
+ facade.GetUncompressedDatasources(edge.reverse_packed_geometry_id,
+ reverse_datasource_vector);
+ reverse_datasource = reverse_datasource_vector[reverse_datasource_vector.size() -
+ edge.fwd_segment_position - 1];
+ }
+ // Keep track of the highest datasource seen so that we don't write unnecessary
+ // data to the layer attribute values
+ max_datasource_id = std::max(max_datasource_id, forward_datasource);
+ max_datasource_id = std::max(max_datasource_id, reverse_datasource);
+ }
+
+ // TODO: extract speed values for compressed and uncompressed geometries
+
+ // Convert tile coordinates into mercator coordinates
+ mercator::xyzToMercator(parameters.x, parameters.y, parameters.z, min_lon, min_lat, max_lon,
+ max_lat);
+ const detail::BBox tile_bbox{min_lon, min_lat, max_lon, max_lat};
+
+ // Protobuf serialized blocks when objects go out of scope, hence
+ // the extra scoping below.
+ protozero::pbf_writer tile_writer{pbf_buffer};
+ {
+ // Add a layer object to the PBF stream. 3=='layer' from the vector tile spec (2.1)
+ protozero::pbf_writer layer_writer(tile_writer, 3);
+ // TODO: don't write a layer if there are no features
+
+ layer_writer.add_uint32(15, 2); // version
+ // Field 1 is the "layer name" field, it's a string
+ layer_writer.add_string(1, "speeds"); // name
+ // Field 5 is the tile extent. It's a uint32 and should be set to 4096
+ // for normal vector tiles.
+ layer_writer.add_uint32(5, 4096); // extent
+
+ // Begin the layer features block
+ {
+ // Each feature gets a unique id, starting at 1
+ unsigned id = 1;
+ for (const auto &edge : edges)
+ {
+ // Get coordinates for start/end nodes of segmet (NodeIDs u and v)
+ const auto a = facade.GetCoordinateOfNode(edge.u);
+ const auto b = facade.GetCoordinateOfNode(edge.v);
+ // Calculate the length in meters
+ const double length = osrm::util::coordinate_calculation::haversineDistance(a, b);
+
+ int forward_weight = 0;
+ int reverse_weight = 0;
+
+ uint8_t forward_datasource = 0;
+ uint8_t reverse_datasource = 0;
+
+ if (edge.forward_packed_geometry_id != SPECIAL_EDGEID)
+ {
+ std::vector<EdgeWeight> forward_weight_vector;
+ facade.GetUncompressedWeights(edge.forward_packed_geometry_id,
+ forward_weight_vector);
+ forward_weight = forward_weight_vector[edge.fwd_segment_position];
+
+ std::vector<uint8_t> forward_datasource_vector;
+ facade.GetUncompressedDatasources(edge.forward_packed_geometry_id,
+ forward_datasource_vector);
+ forward_datasource = forward_datasource_vector[edge.fwd_segment_position];
+ }
+
+ if (edge.reverse_packed_geometry_id != SPECIAL_EDGEID)
+ {
+ std::vector<EdgeWeight> reverse_weight_vector;
+ facade.GetUncompressedWeights(edge.reverse_packed_geometry_id,
+ reverse_weight_vector);
+
+ BOOST_ASSERT(edge.fwd_segment_position < reverse_weight_vector.size());
+
+ reverse_weight = reverse_weight_vector[reverse_weight_vector.size() -
+ edge.fwd_segment_position - 1];
+
+ std::vector<uint8_t> reverse_datasource_vector;
+ facade.GetUncompressedDatasources(edge.reverse_packed_geometry_id,
+ reverse_datasource_vector);
+ reverse_datasource =
+ reverse_datasource_vector[reverse_datasource_vector.size() -
+ edge.fwd_segment_position - 1];
+ }
+
+ // Keep track of the highest datasource seen so that we don't write unnecessary
+ // data to the layer attribute values
+ max_datasource_id = std::max(max_datasource_id, forward_datasource);
+ max_datasource_id = std::max(max_datasource_id, reverse_datasource);
+
+ const auto encode_tile_line = [&layer_writer, &edge, &id, &max_datasource_id](
+ const detail::FixedLine &tile_line, const std::uint32_t speed_kmh,
+ const std::size_t duration, const std::uint8_t datasource,
+ std::int32_t &start_x, std::int32_t &start_y)
+ {
+ // Here, we save the two attributes for our feature: the speed and the
+ // is_small
+ // boolean. We onl serve up speeds from 0-139, so all we do is save the
+ // first
+ protozero::pbf_writer feature_writer(layer_writer, 2);
+ // Field 3 is the "geometry type" field. Value 2 is "line"
+ feature_writer.add_enum(3, 2); // geometry type
+ // Field 1 for the feature is the "id" field.
+ feature_writer.add_uint64(1, id++); // id
+ {
+ // When adding attributes to a feature, we have to write
+ // pairs of numbers. The first value is the index in the
+ // keys array (written later), and the second value is the
+ // index into the "values" array (also written later). We're
+ // not writing the actual speed or bool value here, we're saving
+ // an index into the "values" array. This means many features
+ // can share the same value data, leading to smaller tiles.
+ protozero::packed_field_uint32 field(feature_writer, 2);
+
+ field.add_element(0); // "speed" tag key offset
+ field.add_element(
+ std::min(speed_kmh, 127u)); // save the speed value, capped at 127
+ field.add_element(1); // "is_small" tag key offset
+ field.add_element(128 +
+ (edge.component.is_tiny ? 0 : 1)); // is_small feature
+ field.add_element(2); // "datasource" tag key offset
+ field.add_element(130 + datasource); // datasource value offset
+ field.add_element(3); // "duration" tag key offset
+ field.add_element(130 + max_datasource_id + 1 +
+ duration); // duration value offset
+ }
+ {
+
+ // Encode the geometry for the feature
+ protozero::packed_field_uint32 geometry(feature_writer, 4);
+ encodeLinestring(tile_line, geometry, start_x, start_y);
+ }
+ };
+
+ // If this is a valid forward edge, go ahead and add it to the tile
+ if (forward_weight != 0 && edge.forward_segment_id.enabled)
+ {
+ std::int32_t start_x = 0;
+ std::int32_t start_y = 0;
+
+ // Calculate the speed for this line
+ std::uint32_t speed_kmh =
+ static_cast<std::uint32_t>(round(length / forward_weight * 10 * 3.6));
+
+ auto tile_line = coordinatesToTileLine(a, b, tile_bbox);
+ if (!tile_line.empty())
+ {
+ encode_tile_line(tile_line, speed_kmh, weight_offsets[forward_weight],
+ forward_datasource, start_x, start_y);
+ }
+ }
+
+ // Repeat the above for the coordinates reversed and using the `reverse`
+ // properties
+ if (reverse_weight != 0 && edge.reverse_segment_id.enabled)
+ {
+ std::int32_t start_x = 0;
+ std::int32_t start_y = 0;
+
+ // Calculate the speed for this line
+ std::uint32_t speed_kmh =
+ static_cast<std::uint32_t>(round(length / reverse_weight * 10 * 3.6));
+
+ auto tile_line = coordinatesToTileLine(b, a, tile_bbox);
+ if (!tile_line.empty())
+ {
+ encode_tile_line(tile_line, speed_kmh, weight_offsets[reverse_weight],
+ reverse_datasource, start_x, start_y);
+ }
+ }
+ }
+ }
+
+ // Field id 3 is the "keys" attribute
+ // We need two "key" fields, these are referred to with 0 and 1 (their array indexes)
+ // earlier
+ layer_writer.add_string(3, "speed");
+ layer_writer.add_string(3, "is_small");
+ layer_writer.add_string(3, "datasource");
+ layer_writer.add_string(3, "duration");
+
+ // Now, we write out the possible speed value arrays and possible is_tiny
+ // values. Field type 4 is the "values" field. It's a variable type field,
+ // so requires a two-step write (create the field, then write its value)
+ for (std::size_t i = 0; i < 128; i++)
+ {
+ // Writing field type 4 == variant type
+ protozero::pbf_writer values_writer(layer_writer, 4);
+ // Attribute value 5 == uin64 type
+ values_writer.add_uint64(5, i);
+ }
+ {
+ protozero::pbf_writer values_writer(layer_writer, 4);
+ // Attribute value 7 == bool type
+ values_writer.add_bool(7, true);
+ }
+ {
+ protozero::pbf_writer values_writer(layer_writer, 4);
+ // Attribute value 7 == bool type
+ values_writer.add_bool(7, false);
+ }
+ for (std::size_t i = 0; i <= max_datasource_id; i++)
+ {
+ // Writing field type 4 == variant type
+ protozero::pbf_writer values_writer(layer_writer, 4);
+ // Attribute value 1 == string type
+ values_writer.add_string(1, facade.GetDatasourceName(i));
+ }
+ for (auto weight : used_weights)
+ {
+ // Writing field type 4 == variant type
+ protozero::pbf_writer values_writer(layer_writer, 4);
+ // Attribute value 2 == float type
+ // Durations come out of OSRM in integer deciseconds, so we convert them
+ // to seconds with a simple /10 for display
+ values_writer.add_double(3, weight / 10.);
+ }
+ }
+
+ return Status::Ok;
+}
+}
+}
+}
diff --git a/src/engine/plugins/trip.cpp b/src/engine/plugins/trip.cpp
new file mode 100644
index 0000000..c834f46
--- /dev/null
+++ b/src/engine/plugins/trip.cpp
@@ -0,0 +1,245 @@
+#include "engine/plugins/trip.hpp"
+
+#include "extractor/tarjan_scc.hpp"
+
+#include "engine/api/trip_api.hpp"
+#include "engine/api/trip_parameters.hpp"
+#include "engine/trip/trip_nearest_neighbour.hpp"
+#include "engine/trip/trip_farthest_insertion.hpp"
+#include "engine/trip/trip_brute_force.hpp"
+#include "util/dist_table_wrapper.hpp" // to access the dist table more easily
+#include "util/matrix_graph_wrapper.hpp" // wrapper to use tarjan scc on dist table
+#include "util/json_container.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cstdlib>
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+#include <iterator>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+// Object to hold all strongly connected components (scc) of a graph
+// to access all graphs with component ID i, get the iterators by:
+// auto start = std::begin(scc_component.component) + scc_component.range[i];
+// auto end = std::begin(scc_component.component) + scc_component.range[i+1];
+struct SCC_Component
+{
+ // in_component: all NodeIDs sorted by component ID
+ // in_range: index where a new component starts
+ //
+ // example: NodeID 0, 1, 2, 4, 5 are in component 0
+ // NodeID 3, 6, 7, 8 are in component 1
+ // => in_component = [0, 1, 2, 4, 5, 3, 6, 7, 8]
+ // => in_range = [0, 5]
+ SCC_Component(std::vector<NodeID> in_component_nodes, std::vector<size_t> in_range)
+ : component(std::move(in_component_nodes)), range(std::move(in_range))
+ {
+ BOOST_ASSERT_MSG(component.size() > 0, "there's no scc component");
+ BOOST_ASSERT_MSG(*std::max_element(range.begin(), range.end()) == component.size(),
+ "scc component ranges are out of bound");
+ BOOST_ASSERT_MSG(*std::min_element(range.begin(), range.end()) == 0,
+ "invalid scc component range");
+ BOOST_ASSERT_MSG(std::is_sorted(std::begin(range), std::end(range)),
+ "invalid component ranges");
+ }
+
+ std::size_t GetNumberOfComponents() const
+ {
+ BOOST_ASSERT_MSG(range.size() > 0, "there's no range");
+ return range.size() - 1;
+ }
+
+ const std::vector<NodeID> component;
+ std::vector<std::size_t> range;
+};
+
+// takes the number of locations and its duration matrix,
+// identifies and splits the graph in its strongly connected components (scc)
+// and returns an SCC_Component
+SCC_Component SplitUnaccessibleLocations(const std::size_t number_of_locations,
+ const util::DistTableWrapper<EdgeWeight> &result_table)
+{
+
+ if (std::find(std::begin(result_table), std::end(result_table), INVALID_EDGE_WEIGHT) ==
+ std::end(result_table))
+ {
+ // whole graph is one scc
+ std::vector<NodeID> location_ids(number_of_locations);
+ std::iota(std::begin(location_ids), std::end(location_ids), 0);
+ std::vector<size_t> range = {0, location_ids.size()};
+ return SCC_Component(std::move(location_ids), std::move(range));
+ }
+
+ // Run TarjanSCC
+ auto wrapper = std::make_shared<util::MatrixGraphWrapper<EdgeWeight>>(result_table.GetTable(),
+ number_of_locations);
+ auto scc = extractor::TarjanSCC<util::MatrixGraphWrapper<EdgeWeight>>(wrapper);
+ scc.run();
+
+ const auto number_of_components = scc.get_number_of_components();
+
+ std::vector<std::size_t> range_insertion;
+ std::vector<std::size_t> range;
+ range_insertion.reserve(number_of_components);
+ range.reserve(number_of_components);
+
+ std::vector<NodeID> components(number_of_locations, 0);
+
+ std::size_t prefix = 0;
+ for (std::size_t j = 0; j < number_of_components; ++j)
+ {
+ range_insertion.push_back(prefix);
+ range.push_back(prefix);
+ prefix += scc.get_component_size(j);
+ }
+ // senitel
+ range.push_back(components.size());
+
+ for (std::size_t i = 0; i < number_of_locations; ++i)
+ {
+ components[range_insertion[scc.get_component_id(i)]] = i;
+ ++range_insertion[scc.get_component_id(i)];
+ }
+
+ return SCC_Component(std::move(components), std::move(range));
+}
+
+InternalRouteResult TripPlugin::ComputeRoute(const std::vector<PhantomNode> &snapped_phantoms,
+ const api::TripParameters ¶meters,
+ const std::vector<NodeID> &trip)
+{
+ InternalRouteResult min_route;
+ // given he final trip, compute total duration and return the route and location permutation
+ PhantomNodes viapoint;
+ const auto start = std::begin(trip);
+ const auto end = std::end(trip);
+ // computes a roundtrip from the nodes in trip
+ for (auto it = start; it != end; ++it)
+ {
+ const auto from_node = *it;
+ // if from_node is the last node, compute the route from the last to the first location
+ const auto to_node = std::next(it) != end ? *std::next(it) : *start;
+
+ viapoint = PhantomNodes{snapped_phantoms[from_node], snapped_phantoms[to_node]};
+ min_route.segment_end_coordinates.emplace_back(viapoint);
+ }
+ BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size());
+
+ shortest_path(min_route.segment_end_coordinates, parameters.uturns, min_route);
+
+ BOOST_ASSERT_MSG(min_route.shortest_path_length < INVALID_EDGE_WEIGHT, "unroutable route");
+ return min_route;
+}
+
+Status TripPlugin::HandleRequest(const api::TripParameters ¶meters,
+ util::json::Object &json_result)
+{
+ BOOST_ASSERT(parameters.IsValid());
+
+ // enforce maximum number of locations for performance reasons
+ if (max_locations_trip > 0 &&
+ static_cast<int>(parameters.coordinates.size()) > max_locations_trip)
+ {
+ return Error("TooBig", "Too many trip coordinates", json_result);
+ }
+
+ if (!CheckAllCoordinates(parameters.coordinates))
+ {
+ return Error("InvalidValue", "Invalid coordinate value.", json_result);
+ }
+
+ auto phantom_node_pairs = GetPhantomNodes(parameters);
+ if (phantom_node_pairs.size() != parameters.coordinates.size())
+ {
+ return Error("NoSegment",
+ std::string("Could not find a matching segment for coordinate ") +
+ std::to_string(phantom_node_pairs.size()),
+ json_result);
+ }
+ BOOST_ASSERT(phantom_node_pairs.size() == parameters.coordinates.size());
+
+ auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs);
+
+ const auto number_of_locations = snapped_phantoms.size();
+
+ // compute the duration table of all phantom nodes
+ const auto result_table = util::DistTableWrapper<EdgeWeight>(
+ duration_table(snapped_phantoms, {}, {}), number_of_locations);
+
+ if (result_table.size() == 0)
+ {
+ return Status::Error;
+ }
+
+ const constexpr std::size_t BF_MAX_FEASABLE = 10;
+ BOOST_ASSERT_MSG(result_table.size() == number_of_locations * number_of_locations,
+ "Distance Table has wrong size");
+
+ // get scc components
+ SCC_Component scc = SplitUnaccessibleLocations(number_of_locations, result_table);
+
+ std::vector<std::vector<NodeID>> trips;
+ trips.reserve(scc.GetNumberOfComponents());
+ // run Trip computation for every SCC
+ for (std::size_t k = 0; k < scc.GetNumberOfComponents(); ++k)
+ {
+ const auto component_size = scc.range[k + 1] - scc.range[k];
+
+ BOOST_ASSERT_MSG(component_size > 0, "invalid component size");
+
+ std::vector<NodeID> scc_route;
+ auto route_begin = std::begin(scc.component) + scc.range[k];
+ auto route_end = std::begin(scc.component) + scc.range[k + 1];
+
+ if (component_size > 1)
+ {
+
+ if (component_size < BF_MAX_FEASABLE)
+ {
+ scc_route =
+ trip::BruteForceTrip(route_begin, route_end, number_of_locations, result_table);
+ }
+ else
+ {
+ scc_route = trip::FarthestInsertionTrip(route_begin, route_end, number_of_locations,
+ result_table);
+ }
+ }
+ else
+ {
+ scc_route = std::vector<NodeID>(route_begin, route_end);
+ }
+
+ trips.push_back(std::move(scc_route));
+ }
+ if (trips.empty())
+ {
+ return Error("NoTrips", "Cannot find trips", json_result);
+ }
+
+ // compute all round trip routes
+ std::vector<InternalRouteResult> routes;
+ routes.reserve(trips.size());
+ for (const auto &trip : trips)
+ {
+ routes.push_back(ComputeRoute(snapped_phantoms, parameters, trip));
+ }
+
+ api::TripAPI trip_api{BasePlugin::facade, parameters};
+ trip_api.MakeResponse(trips, routes, snapped_phantoms, json_result);
+
+ return Status::Ok;
+}
+}
+}
+}
diff --git a/src/engine/plugins/viaroute.cpp b/src/engine/plugins/viaroute.cpp
new file mode 100644
index 0000000..ffd62b3
--- /dev/null
+++ b/src/engine/plugins/viaroute.cpp
@@ -0,0 +1,129 @@
+#include "engine/plugins/viaroute.hpp"
+#include "engine/datafacade/datafacade_base.hpp"
+#include "engine/api/route_api.hpp"
+#include "engine/status.hpp"
+
+#include "util/for_each_pair.hpp"
+#include "util/integer_range.hpp"
+#include "util/json_container.hpp"
+
+#include <cstdlib>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace engine
+{
+namespace plugins
+{
+
+ViaRoutePlugin::ViaRoutePlugin(datafacade::BaseDataFacade &facade_, int max_locations_viaroute)
+ : BasePlugin(facade_), shortest_path(&facade_, heaps), alternative_path(&facade_, heaps),
+ direct_shortest_path(&facade_, heaps), max_locations_viaroute(max_locations_viaroute)
+{
+}
+
+Status ViaRoutePlugin::HandleRequest(const api::RouteParameters &route_parameters,
+ util::json::Object &json_result)
+{
+ BOOST_ASSERT(route_parameters.IsValid());
+
+ if (max_locations_viaroute > 0 &&
+ (static_cast<int>(route_parameters.coordinates.size()) > max_locations_viaroute))
+ {
+ return Error("TooBig",
+ "Number of entries " + std::to_string(route_parameters.coordinates.size()) +
+ " is higher than current maximum (" +
+ std::to_string(max_locations_viaroute) + ")",
+ json_result);
+ }
+
+ if (!CheckAllCoordinates(route_parameters.coordinates))
+ {
+ return Error("InvalidValue", "Invalid coordinate value.", json_result);
+ }
+
+ auto phantom_node_pairs = GetPhantomNodes(route_parameters);
+ 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()),
+ json_result);
+ }
+ BOOST_ASSERT(phantom_node_pairs.size() == route_parameters.coordinates.size());
+
+ auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs);
+
+ const bool allow_u_turn_at_via =
+ route_parameters.uturns ? *route_parameters.uturns : facade.GetUTurnsDefault();
+
+ InternalRouteResult raw_route;
+ auto build_phantom_pairs = [&raw_route, allow_u_turn_at_via](const PhantomNode &first_node,
+ const PhantomNode &second_node)
+ {
+ raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node});
+ auto &last_inserted = raw_route.segment_end_coordinates.back();
+ // enable forward direction if possible
+ if (last_inserted.source_phantom.forward_segment_id.id != SPECIAL_SEGMENTID)
+ {
+ last_inserted.source_phantom.forward_segment_id.enabled |= allow_u_turn_at_via;
+ }
+ // enable reverse direction if possible
+ if (last_inserted.source_phantom.reverse_segment_id.id != SPECIAL_SEGMENTID)
+ {
+ last_inserted.source_phantom.reverse_segment_id.enabled |= allow_u_turn_at_via;
+ }
+ };
+ util::for_each_pair(snapped_phantoms, build_phantom_pairs);
+
+ if (1 == raw_route.segment_end_coordinates.size())
+ {
+ if (route_parameters.alternatives && facade.GetCoreSize() == 0)
+ {
+ alternative_path(raw_route.segment_end_coordinates.front(), raw_route);
+ }
+ else
+ {
+ direct_shortest_path(raw_route.segment_end_coordinates, raw_route);
+ }
+ }
+ else
+ {
+ shortest_path(raw_route.segment_end_coordinates, route_parameters.uturns, raw_route);
+ }
+
+ // we can only know this after the fact, different SCC ids still
+ // allow for connection in one direction.
+ if (raw_route.is_valid())
+ {
+ api::RouteAPI route_api{BasePlugin::facade, route_parameters};
+ route_api.MakeResponse(raw_route, json_result);
+ }
+ else
+ {
+ auto first_component_id = snapped_phantoms.front().component.id;
+ auto not_in_same_component = std::any_of(snapped_phantoms.begin(), snapped_phantoms.end(),
+ [first_component_id](const PhantomNode &node)
+ {
+ return node.component.id != first_component_id;
+ });
+
+ if (not_in_same_component)
+ {
+ return Error("NoRoute", "Impossible route between points", json_result);
+ }
+ else
+ {
+ return Error("NoRoute", "No route found between points", json_result);
+ }
+ }
+
+ return Status::Ok;
+}
+}
+}
+}
diff --git a/src/engine/polyline_compressor.cpp b/src/engine/polyline_compressor.cpp
new file mode 100644
index 0000000..4cbfe1c
--- /dev/null
+++ b/src/engine/polyline_compressor.cpp
@@ -0,0 +1,128 @@
+#include "engine/polyline_compressor.hpp"
+
+#include <boost/assert.hpp>
+#include <cstddef>
+#include <cstdlib>
+#include <cmath>
+#include <algorithm>
+
+namespace osrm
+{
+namespace engine
+{
+namespace /*detail*/ // anonymous to keep TU local
+{
+
+std::string encode(int number_to_encode)
+{
+ std::string output;
+ while (number_to_encode >= 0x20)
+ {
+ const int next_value = (0x20 | (number_to_encode & 0x1f)) + 63;
+ output += static_cast<char>(next_value);
+ number_to_encode >>= 5;
+ }
+
+ number_to_encode += 63;
+ output += static_cast<char>(number_to_encode);
+ return output;
+}
+
+std::string encode(std::vector<int> &numbers)
+{
+ std::string output;
+ for (auto &number : numbers)
+ {
+ bool isNegative = number < 0;
+
+ if (isNegative)
+ {
+ const unsigned binary = std::llabs(number);
+ const unsigned twos = (~binary) + 1u;
+ number = twos;
+ }
+
+ number <<= 1u;
+
+ if (isNegative)
+ {
+ number = ~number;
+ }
+ }
+ for (const int number : numbers)
+ {
+ output += encode(number);
+ }
+ return output;
+}
+} // anonymous ns
+
+std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter end)
+{
+ auto size = std::distance(begin, end);
+ if (size == 0)
+ {
+ return {};
+ }
+
+ std::vector<int> delta_numbers;
+ BOOST_ASSERT(size > 0);
+ delta_numbers.reserve((size - 1) * 2);
+ int current_lat = 0;
+ int current_lon = 0;
+ std::for_each(begin, end,
+ [&delta_numbers, ¤t_lat, ¤t_lon](const util::Coordinate loc)
+ {
+ const int lat_diff =
+ std::round(static_cast<int>(loc.lat) * detail::COORDINATE_TO_POLYLINE) -
+ current_lat;
+ const int lon_diff =
+ std::round(static_cast<int>(loc.lon) * detail::COORDINATE_TO_POLYLINE) -
+ current_lon;
+ delta_numbers.emplace_back(lat_diff);
+ delta_numbers.emplace_back(lon_diff);
+ current_lat += lat_diff;
+ current_lon += lon_diff;
+ });
+ return encode(delta_numbers);
+}
+
+std::vector<util::Coordinate> decodePolyline(const std::string &geometry_string)
+{
+ std::vector<util::Coordinate> new_coordinates;
+ int index = 0, len = geometry_string.size();
+ int lat = 0, lng = 0;
+
+ while (index < len)
+ {
+ int b, shift = 0, result = 0;
+ do
+ {
+ b = geometry_string.at(index++) - 63;
+ result |= (b & 0x1f) << shift;
+ shift += 5;
+ } while (b >= 0x20);
+ int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
+ lat += dlat;
+
+ shift = 0;
+ result = 0;
+ do
+ {
+ b = geometry_string.at(index++) - 63;
+ result |= (b & 0x1f) << shift;
+ shift += 5;
+ } while (b >= 0x20);
+ int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
+ lng += dlng;
+
+ util::Coordinate p;
+ p.lat = util::FixedLatitude(lat * detail::POLYLINE_TO_COORDINATE);
+ p.lon = util::FixedLongitude(lng * detail::POLYLINE_TO_COORDINATE);
+ new_coordinates.push_back(p);
+ }
+
+ return new_coordinates;
+}
+}
+}
diff --git a/src/engine/search_engine_data.cpp b/src/engine/search_engine_data.cpp
new file mode 100644
index 0000000..72963bb
--- /dev/null
+++ b/src/engine/search_engine_data.cpp
@@ -0,0 +1,80 @@
+#include "engine/search_engine_data.hpp"
+
+#include "util/binary_heap.hpp"
+
+namespace osrm
+{
+namespace engine
+{
+
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_1;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_1;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_2;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_2;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_3;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_3;
+
+void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes)
+{
+ if (forward_heap_1.get())
+ {
+ forward_heap_1->Clear();
+ }
+ else
+ {
+ forward_heap_1.reset(new QueryHeap(number_of_nodes));
+ }
+
+ if (reverse_heap_1.get())
+ {
+ reverse_heap_1->Clear();
+ }
+ else
+ {
+ reverse_heap_1.reset(new QueryHeap(number_of_nodes));
+ }
+}
+
+void SearchEngineData::InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes)
+{
+ if (forward_heap_2.get())
+ {
+ forward_heap_2->Clear();
+ }
+ else
+ {
+ forward_heap_2.reset(new QueryHeap(number_of_nodes));
+ }
+
+ if (reverse_heap_2.get())
+ {
+ reverse_heap_2->Clear();
+ }
+ else
+ {
+ reverse_heap_2.reset(new QueryHeap(number_of_nodes));
+ }
+}
+
+void SearchEngineData::InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes)
+{
+ if (forward_heap_3.get())
+ {
+ forward_heap_3->Clear();
+ }
+ else
+ {
+ forward_heap_3.reset(new QueryHeap(number_of_nodes));
+ }
+
+ if (reverse_heap_3.get())
+ {
+ reverse_heap_3->Clear();
+ }
+ else
+ {
+ reverse_heap_3.reset(new QueryHeap(number_of_nodes));
+ }
+}
+}
+}
diff --git a/data_structures/compressed_edge_container.cpp b/src/extractor/compressed_edge_container.cpp
similarity index 63%
rename from data_structures/compressed_edge_container.cpp
rename to src/extractor/compressed_edge_container.cpp
index da916ce..70b1f77 100644
--- a/data_structures/compressed_edge_container.cpp
+++ b/src/extractor/compressed_edge_container.cpp
@@ -1,32 +1,5 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "compressed_edge_container.hpp"
-#include "../util/simple_logger.hpp"
+#include "extractor/compressed_edge_container.hpp"
+#include "util/simple_logger.hpp"
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
@@ -37,6 +10,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <iostream>
+namespace osrm
+{
+namespace extractor
+{
+
CompressedEdgeContainer::CompressedEdgeContainer()
{
m_free_list.reserve(100);
@@ -81,7 +59,7 @@ void CompressedEdgeContainer::SerializeInternalVector(const std::string &path) c
{
geometry_out_stream.write((char *)&prefix_sum_of_list_indices, sizeof(unsigned));
- const std::vector<CompressedNode> ¤t_vector = elem;
+ const std::vector<CompressedEdge> ¤t_vector = elem;
const unsigned unpacked_size = current_vector.size();
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != unpacked_size);
prefix_sum_of_list_indices += unpacked_size;
@@ -96,26 +74,32 @@ void CompressedEdgeContainer::SerializeInternalVector(const std::string &path) c
// write compressed geometries
for (auto &elem : m_compressed_geometries)
{
- const std::vector<CompressedNode> ¤t_vector = elem;
+ const std::vector<CompressedEdge> ¤t_vector = elem;
const unsigned unpacked_size = current_vector.size();
control_sum += unpacked_size;
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != unpacked_size);
- for (const CompressedNode current_node : current_vector)
+ for (const auto ¤t_node : current_vector)
{
- geometry_out_stream.write((char *)&(current_node.first), sizeof(NodeID));
+ geometry_out_stream.write((char *)&(current_node), sizeof(CompressedEdge));
}
}
BOOST_ASSERT(control_sum == prefix_sum_of_list_indices);
- // all done, let's close the resource
- geometry_out_stream.close();
}
+// Adds info for a compressed edge to the container. edge_id_2
+// has been removed from the graph, so we have to save These edges/nodes
+// have already been trimmed from the graph, this function just stores
+// the original data for unpacking later.
+//
+// edge_id_1 edge_id_2
+// ----------> via_node_id -----------> target_node_id
+// weight_1 weight_2
void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
- const EdgeID edge_id_2,
- const NodeID via_node_id,
- const NodeID target_node_id,
- const EdgeWeight weight1,
- const EdgeWeight weight2)
+ const EdgeID edge_id_2,
+ const NodeID via_node_id,
+ const NodeID target_node_id,
+ const EdgeWeight weight1,
+ const EdgeWeight weight2)
{
// remove super-trivial geometries
BOOST_ASSERT(SPECIAL_EDGEID != edge_id_1);
@@ -153,13 +137,13 @@ void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
BOOST_ASSERT(edge_bucket_id1 == GetPositionForID(edge_id_1));
BOOST_ASSERT(edge_bucket_id1 < m_compressed_geometries.size());
- std::vector<CompressedNode> &edge_bucket_list1 = m_compressed_geometries[edge_bucket_id1];
+ std::vector<CompressedEdge> &edge_bucket_list1 = m_compressed_geometries[edge_bucket_id1];
// note we don't save the start coordinate: it is implicitly given by edge 1
// weight1 is the distance to the (currently) last coordinate in the bucket
if (edge_bucket_list1.empty())
{
- edge_bucket_list1.emplace_back(via_node_id, weight1);
+ edge_bucket_list1.emplace_back(CompressedEdge{via_node_id, weight1});
}
BOOST_ASSERT(0 < edge_bucket_list1.size());
@@ -171,7 +155,7 @@ void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
const unsigned list_to_remove_index = GetPositionForID(edge_id_2);
BOOST_ASSERT(list_to_remove_index < m_compressed_geometries.size());
- std::vector<CompressedNode> &edge_bucket_list2 =
+ std::vector<CompressedEdge> &edge_bucket_list2 =
m_compressed_geometries[list_to_remove_index];
// found an existing list, append it to the list of edge_id_1
@@ -190,7 +174,48 @@ void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
else
{
// we are certain that the second edge is atomic.
- edge_bucket_list1.emplace_back(target_node_id, weight2);
+ edge_bucket_list1.emplace_back(CompressedEdge{target_node_id, weight2});
+ }
+}
+
+void CompressedEdgeContainer::AddUncompressedEdge(const EdgeID edge_id,
+ const NodeID target_node_id,
+ const EdgeWeight weight)
+{
+ // remove super-trivial geometries
+ BOOST_ASSERT(SPECIAL_EDGEID != edge_id);
+ BOOST_ASSERT(SPECIAL_NODEID != target_node_id);
+ BOOST_ASSERT(INVALID_EDGE_WEIGHT != weight);
+
+ // Add via node id. List is created if it does not exist
+ if (!HasEntryForID(edge_id))
+ {
+ // create a new entry in the map
+ if (0 == m_free_list.size())
+ {
+ // make sure there is a place to put the entries
+ IncreaseFreeList();
+ }
+ BOOST_ASSERT(!m_free_list.empty());
+ m_edge_id_to_list_index_map[edge_id] = m_free_list.back();
+ m_free_list.pop_back();
+ }
+
+ // find bucket index
+ const auto iter = m_edge_id_to_list_index_map.find(edge_id);
+ BOOST_ASSERT(iter != m_edge_id_to_list_index_map.end());
+ const unsigned edge_bucket_id = iter->second;
+ BOOST_ASSERT(edge_bucket_id == GetPositionForID(edge_id));
+ BOOST_ASSERT(edge_bucket_id < m_compressed_geometries.size());
+
+ std::vector<CompressedEdge> &edge_bucket_list = m_compressed_geometries[edge_bucket_id];
+
+ // note we don't save the start coordinate: it is implicitly given by edge_id
+ // weight is the distance to the (currently) last coordinate in the bucket
+ // Don't re-add this if it's already in there.
+ if (edge_bucket_list.empty())
+ {
+ edge_bucket_list.emplace_back(CompressedEdge{target_node_id, weight});
}
}
@@ -202,24 +227,23 @@ void CompressedEdgeContainer::PrintStatistics() const
uint64_t compressed_geometries = 0;
uint64_t longest_chain_length = 0;
- for (const std::vector<CompressedNode> ¤t_vector : m_compressed_geometries)
+ for (const std::vector<CompressedEdge> ¤t_vector : m_compressed_geometries)
{
compressed_geometries += current_vector.size();
longest_chain_length = std::max(longest_chain_length, (uint64_t)current_vector.size());
}
- SimpleLogger().Write() << "Geometry successfully removed:"
- "\n compressed edges: " << compressed_edges
- << "\n compressed geometries: " << compressed_geometries
- << "\n longest chain length: " << longest_chain_length
- << "\n cmpr ratio: " << ((float)compressed_edges /
- std::max(compressed_geometries, (uint64_t)1))
- << "\n avg chain length: "
- << (float)compressed_geometries /
- std::max((uint64_t)1, compressed_edges);
+ util::SimpleLogger().Write()
+ << "Geometry successfully removed:"
+ "\n compressed edges: "
+ << compressed_edges << "\n compressed geometries: " << compressed_geometries
+ << "\n longest chain length: " << longest_chain_length << "\n cmpr ratio: "
+ << ((float)compressed_edges / std::max(compressed_geometries, (uint64_t)1))
+ << "\n avg chain length: "
+ << (float)compressed_geometries / std::max((uint64_t)1, compressed_edges);
}
-const CompressedEdgeContainer::EdgeBucket&
+const CompressedEdgeContainer::EdgeBucket &
CompressedEdgeContainer::GetBucketReference(const EdgeID edge_id) const
{
const unsigned index = m_edge_id_to_list_index_map.at(edge_id);
@@ -230,11 +254,13 @@ NodeID CompressedEdgeContainer::GetFirstEdgeTargetID(const EdgeID edge_id) const
{
const auto &bucket = GetBucketReference(edge_id);
BOOST_ASSERT(bucket.size() >= 2);
- return bucket.front().first;
+ return bucket.front().node_id;
}
NodeID CompressedEdgeContainer::GetLastEdgeSourceID(const EdgeID edge_id) const
{
const auto &bucket = GetBucketReference(edge_id);
BOOST_ASSERT(bucket.size() >= 2);
- return bucket[bucket.size() - 2].first;
+ return bucket[bucket.size() - 2].node_id;
+}
+}
}
diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp
new file mode 100644
index 0000000..4cbde57
--- /dev/null
+++ b/src/extractor/edge_based_graph_factory.cpp
@@ -0,0 +1,481 @@
+#include "extractor/edge_based_edge.hpp"
+#include "extractor/edge_based_graph_factory.hpp"
+#include "util/coordinate.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/percent.hpp"
+#include "util/integer_range.hpp"
+#include "util/lua_util.hpp"
+#include "util/simple_logger.hpp"
+#include "util/timing_util.hpp"
+#include "util/exception.hpp"
+
+#include "extractor/guidance/toolkit.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <algorithm>
+#include <cmath>
+#include <fstream>
+#include <iomanip>
+#include <limits>
+#include <sstream>
+#include <string>
+
+namespace osrm
+{
+namespace extractor
+{
+// Configuration to find representative candidate for turn angle calculations
+
+EdgeBasedGraphFactory::EdgeBasedGraphFactory(
+ std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph,
+ const CompressedEdgeContainer &compressed_edge_container,
+ const std::unordered_set<NodeID> &barrier_nodes,
+ const std::unordered_set<NodeID> &traffic_lights,
+ std::shared_ptr<const RestrictionMap> restriction_map,
+ const std::vector<QueryNode> &node_info_list,
+ ProfileProperties profile_properties,
+ const util::NameTable &name_table)
+ : m_max_edge_id(0), m_node_info_list(node_info_list),
+ m_node_based_graph(std::move(node_based_graph)),
+ m_restriction_map(std::move(restriction_map)), m_barrier_nodes(barrier_nodes),
+ m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container),
+ profile_properties(std::move(profile_properties)), name_table(name_table)
+{
+}
+
+void EdgeBasedGraphFactory::GetEdgeBasedEdges(
+ util::DeallocatingVector<EdgeBasedEdge> &output_edge_list)
+{
+ BOOST_ASSERT_MSG(0 == output_edge_list.size(), "Vector is not empty");
+ using std::swap; // Koenig swap
+ swap(m_edge_based_edge_list, output_edge_list);
+}
+
+void EdgeBasedGraphFactory::GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes)
+{
+#ifndef NDEBUG
+ for (const EdgeBasedNode &node : m_edge_based_node_list)
+ {
+ BOOST_ASSERT(
+ util::Coordinate(m_node_info_list[node.u].lon, m_node_info_list[node.u].lat).IsValid());
+ BOOST_ASSERT(
+ util::Coordinate(m_node_info_list[node.v].lon, m_node_info_list[node.v].lat).IsValid());
+ }
+#endif
+ using std::swap; // Koenig swap
+ swap(nodes, m_edge_based_node_list);
+}
+
+void EdgeBasedGraphFactory::GetStartPointMarkers(std::vector<bool> &node_is_startpoint)
+{
+ using std::swap; // Koenig swap
+ swap(m_edge_based_node_is_startpoint, node_is_startpoint);
+}
+
+void EdgeBasedGraphFactory::GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights)
+{
+ using std::swap; // Koenig swap
+ swap(m_edge_based_node_weights, output_node_weights);
+}
+
+unsigned EdgeBasedGraphFactory::GetHighestEdgeID() { return m_max_edge_id; }
+
+void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeID node_v)
+{
+ // merge edges together into one EdgeBasedNode
+ BOOST_ASSERT(node_u != SPECIAL_NODEID);
+ BOOST_ASSERT(node_v != SPECIAL_NODEID);
+
+ // find forward edge id and
+ const EdgeID edge_id_1 = m_node_based_graph->FindEdge(node_u, node_v);
+ BOOST_ASSERT(edge_id_1 != SPECIAL_EDGEID);
+
+ const EdgeData &forward_data = m_node_based_graph->GetEdgeData(edge_id_1);
+
+ // find reverse edge id and
+ const EdgeID edge_id_2 = m_node_based_graph->FindEdge(node_v, node_u);
+ BOOST_ASSERT(edge_id_2 != SPECIAL_EDGEID);
+
+ const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(edge_id_2);
+
+ if (forward_data.edge_id == SPECIAL_NODEID && reverse_data.edge_id == SPECIAL_NODEID)
+ {
+ return;
+ }
+
+ if (forward_data.edge_id != SPECIAL_NODEID && reverse_data.edge_id == SPECIAL_NODEID)
+ m_edge_based_node_weights[forward_data.edge_id] = INVALID_EDGE_WEIGHT;
+
+ BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_1) ==
+ m_compressed_edge_container.HasEntryForID(edge_id_2));
+ BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_1));
+ BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_2));
+ const auto &forward_geometry = m_compressed_edge_container.GetBucketReference(edge_id_1);
+ BOOST_ASSERT(forward_geometry.size() ==
+ m_compressed_edge_container.GetBucketReference(edge_id_2).size());
+ const auto geometry_size = forward_geometry.size();
+
+ // There should always be some geometry
+ BOOST_ASSERT(0 != geometry_size);
+
+ NodeID current_edge_source_coordinate_id = node_u;
+
+ const auto edge_id_to_segment_id = [](const NodeID edge_based_node_id)
+ {
+ if (edge_based_node_id == SPECIAL_NODEID)
+ {
+ return SegmentID{SPECIAL_SEGMENTID, false};
+ }
+
+ return SegmentID{edge_based_node_id, true};
+ };
+
+ // traverse arrays from start and end respectively
+ for (const auto i : util::irange(std::size_t{ 0 }, geometry_size))
+ {
+ BOOST_ASSERT(
+ current_edge_source_coordinate_id ==
+ m_compressed_edge_container.GetBucketReference(edge_id_2)[geometry_size - 1 - i]
+ .node_id);
+ const NodeID current_edge_target_coordinate_id = forward_geometry[i].node_id;
+ BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
+
+ // build edges
+ m_edge_based_node_list.emplace_back(
+ edge_id_to_segment_id(forward_data.edge_id),
+ edge_id_to_segment_id(reverse_data.edge_id), current_edge_source_coordinate_id,
+ current_edge_target_coordinate_id, forward_data.name_id,
+ m_compressed_edge_container.GetPositionForID(edge_id_1),
+ m_compressed_edge_container.GetPositionForID(edge_id_2), false, INVALID_COMPONENTID, i,
+ forward_data.travel_mode, reverse_data.travel_mode);
+
+ m_edge_based_node_is_startpoint.push_back(forward_data.startpoint ||
+ reverse_data.startpoint);
+ current_edge_source_coordinate_id = current_edge_target_coordinate_id;
+ }
+
+ BOOST_ASSERT(current_edge_source_coordinate_id == node_v);
+}
+
+void EdgeBasedGraphFactory::FlushVectorToStream(
+ std::ofstream &edge_data_file, std::vector<OriginalEdgeData> &original_edge_data_vector) const
+{
+ if (original_edge_data_vector.empty())
+ {
+ return;
+ }
+ edge_data_file.write((char *)&(original_edge_data_vector[0]),
+ original_edge_data_vector.size() * sizeof(OriginalEdgeData));
+ original_edge_data_vector.clear();
+}
+
+void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
+ lua_State *lua_state,
+ const std::string &edge_segment_lookup_filename,
+ const std::string &edge_penalty_filename,
+ const bool generate_edge_lookup)
+{
+ TIMER_START(renumber);
+ m_max_edge_id = RenumberEdges() - 1;
+ TIMER_STOP(renumber);
+
+ TIMER_START(generate_nodes);
+ m_edge_based_node_weights.reserve(m_max_edge_id + 1);
+ GenerateEdgeExpandedNodes();
+ TIMER_STOP(generate_nodes);
+
+ TIMER_START(generate_edges);
+ GenerateEdgeExpandedEdges(original_edge_data_filename, lua_state, edge_segment_lookup_filename,
+ edge_penalty_filename, generate_edge_lookup);
+
+ TIMER_STOP(generate_edges);
+
+ util::SimpleLogger().Write() << "Timing statistics for edge-expanded graph:";
+ util::SimpleLogger().Write() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
+ util::SimpleLogger().Write() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
+ util::SimpleLogger().Write() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
+}
+
+/// Renumbers all _forward_ edges and sets the edge_id.
+/// A specific numbering is not important. Any unique ID will do.
+/// Returns the number of edge based nodes.
+unsigned EdgeBasedGraphFactory::RenumberEdges()
+{
+ // renumber edge based node of outgoing edges
+ unsigned numbered_edges_count = 0;
+ for (const auto current_node : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
+ {
+ for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
+ {
+ EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
+
+ // only number incoming edges
+ if (edge_data.reversed)
+ {
+ continue;
+ }
+
+ // oneway streets always require this self-loop. Other streets only if a u-turn plus
+ // traversal
+ // of the street takes longer than the loop
+ m_edge_based_node_weights.push_back(edge_data.distance +
+ profile_properties.u_turn_penalty);
+
+ BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges());
+ edge_data.edge_id = numbered_edges_count;
+ ++numbered_edges_count;
+
+ BOOST_ASSERT(SPECIAL_NODEID != edge_data.edge_id);
+ }
+ }
+
+ return numbered_edges_count;
+}
+
+/// Creates the nodes in the edge expanded graph from edges in the node-based graph.
+void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
+{
+ util::Percent progress(m_node_based_graph->GetNumberOfNodes());
+
+ // loop over all edges and generate new set of nodes
+ for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
+ {
+ BOOST_ASSERT(node_u != SPECIAL_NODEID);
+ BOOST_ASSERT(node_u < m_node_based_graph->GetNumberOfNodes());
+ progress.printStatus(node_u);
+ for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
+ {
+ const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
+ BOOST_ASSERT(e1 != SPECIAL_EDGEID);
+ const NodeID node_v = m_node_based_graph->GetTarget(e1);
+
+ BOOST_ASSERT(SPECIAL_NODEID != node_v);
+ // pick only every other edge, since we have every edge as an outgoing
+ // and incoming egde
+ if (node_u > node_v)
+ {
+ continue;
+ }
+
+ BOOST_ASSERT(node_u < node_v);
+
+ // if we found a non-forward edge reverse and try again
+ if (edge_data.edge_id == SPECIAL_NODEID)
+ {
+ InsertEdgeBasedNode(node_v, node_u);
+ }
+ else
+ {
+ InsertEdgeBasedNode(node_u, node_v);
+ }
+ }
+ }
+
+ BOOST_ASSERT(m_edge_based_node_list.size() == m_edge_based_node_is_startpoint.size());
+ BOOST_ASSERT(m_max_edge_id + 1 == m_edge_based_node_weights.size());
+
+ util::SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
+ << " nodes in edge-expanded graph";
+}
+
+/// Actually it also generates OriginalEdgeData and serializes them...
+void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
+ const std::string &original_edge_data_filename,
+ lua_State *lua_state,
+ const std::string &edge_segment_lookup_filename,
+ const std::string &edge_fixed_penalties_filename,
+ const bool generate_edge_lookup)
+{
+ util::SimpleLogger().Write() << "generating edge-expanded edges";
+
+ BOOST_ASSERT(lua_state != nullptr);
+ const bool use_turn_function = util::luaFunctionExists(lua_state, "turn_function");
+
+ std::size_t node_based_edge_counter = 0;
+ std::size_t original_edges_counter = 0;
+ restricted_turns_counter = 0;
+ skipped_uturns_counter = 0;
+ skipped_barrier_turns_counter = 0;
+
+ std::ofstream edge_data_file(original_edge_data_filename.c_str(), std::ios::binary);
+ std::ofstream edge_segment_file;
+ std::ofstream edge_penalty_file;
+
+ if (generate_edge_lookup)
+ {
+ edge_segment_file.open(edge_segment_lookup_filename.c_str(), std::ios::binary);
+ edge_penalty_file.open(edge_fixed_penalties_filename.c_str(), std::ios::binary);
+ }
+
+ // Writes a dummy value at the front that is updated later with the total length
+ const unsigned length_prefix_empty_space{0};
+ edge_data_file.write(reinterpret_cast<const char *>(&length_prefix_empty_space),
+ sizeof(length_prefix_empty_space));
+
+ std::vector<OriginalEdgeData> original_edge_data_vector;
+ original_edge_data_vector.reserve(1024 * 1024);
+
+ // Loop over all turns and generate new set of edges.
+ // Three nested loop look super-linear, but we are dealing with a (kind of)
+ // linear number of turns only.
+ util::Percent progress(m_node_based_graph->GetNumberOfNodes());
+ guidance::TurnAnalysis turn_analysis(*m_node_based_graph, m_node_info_list, *m_restriction_map,
+ m_barrier_nodes, m_compressed_edge_container, name_table);
+ for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
+ {
+ // progress.printStatus(node_u);
+ for (const EdgeID edge_from_u : m_node_based_graph->GetAdjacentEdgeRange(node_u))
+ {
+ if (m_node_based_graph->GetEdgeData(edge_from_u).reversed)
+ {
+ continue;
+ }
+
+ ++node_based_edge_counter;
+ auto possible_turns = turn_analysis.getTurns(node_u, edge_from_u);
+
+ const NodeID node_v = m_node_based_graph->GetTarget(edge_from_u);
+
+ for (const auto turn : possible_turns)
+ {
+ const double turn_angle = turn.angle;
+
+ // only add an edge if turn is not prohibited
+ const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(edge_from_u);
+ const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(turn.eid);
+
+ BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
+ BOOST_ASSERT(!edge_data1.reversed);
+ BOOST_ASSERT(!edge_data2.reversed);
+
+ // the following is the core of the loop.
+ unsigned distance = edge_data1.distance;
+ if (m_traffic_lights.find(node_v) != m_traffic_lights.end())
+ {
+ distance += profile_properties.traffic_signal_penalty;
+ }
+
+ const int turn_penalty =
+ use_turn_function ? GetTurnPenalty(turn_angle, lua_state) : 0;
+ const auto turn_instruction = turn.instruction;
+
+ if (guidance::isUturn(turn_instruction))
+ {
+ distance += profile_properties.u_turn_penalty;
+ }
+
+ distance += turn_penalty;
+
+ BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_from_u));
+ original_edge_data_vector.emplace_back(
+ m_compressed_edge_container.GetPositionForID(edge_from_u), edge_data1.name_id,
+ turn_instruction, edge_data1.travel_mode);
+
+ ++original_edges_counter;
+
+ if (original_edge_data_vector.size() > 1024 * 1024 * 10)
+ {
+ FlushVectorToStream(edge_data_file, original_edge_data_vector);
+ }
+
+ BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
+ BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
+
+ // NOTE: potential overflow here if we hit 2^32 routable edges
+ BOOST_ASSERT(m_edge_based_edge_list.size() <= std::numeric_limits<NodeID>::max());
+ m_edge_based_edge_list.emplace_back(edge_data1.edge_id, edge_data2.edge_id,
+ m_edge_based_edge_list.size(), distance, true,
+ false);
+
+ // Here is where we write out the mapping between the edge-expanded edges, and
+ // the node-based edges that are originally used to calculate the `distance`
+ // for the edge-expanded edges. About 40 lines back, there is:
+ //
+ // unsigned distance = edge_data1.distance;
+ //
+ // This tells us that the weight for an edge-expanded-edge is based on the weight
+ // of the *source* node-based edge. Therefore, we will look up the individual
+ // segments of the source node-based edge, and write out a mapping between
+ // those and the edge-based-edge ID.
+ // External programs can then use this mapping to quickly perform
+ // updates to the edge-expanded-edge based directly on its ID.
+ if (generate_edge_lookup)
+ {
+ unsigned fixed_penalty = distance - edge_data1.distance;
+ edge_penalty_file.write(reinterpret_cast<const char *>(&fixed_penalty),
+ sizeof(fixed_penalty));
+ const auto node_based_edges =
+ m_compressed_edge_container.GetBucketReference(edge_from_u);
+ NodeID previous = node_u;
+
+ const unsigned node_count = node_based_edges.size() + 1;
+ edge_segment_file.write(reinterpret_cast<const char *>(&node_count),
+ sizeof(node_count));
+ const QueryNode &first_node = m_node_info_list[previous];
+ edge_segment_file.write(reinterpret_cast<const char *>(&first_node.node_id),
+ sizeof(first_node.node_id));
+
+ for (auto target_node : node_based_edges)
+ {
+ const QueryNode &from = m_node_info_list[previous];
+ const QueryNode &to = m_node_info_list[target_node.node_id];
+ const double segment_length =
+ util::coordinate_calculation::greatCircleDistance(from, to);
+
+ edge_segment_file.write(reinterpret_cast<const char *>(&to.node_id),
+ sizeof(to.node_id));
+ edge_segment_file.write(reinterpret_cast<const char *>(&segment_length),
+ sizeof(segment_length));
+ edge_segment_file.write(reinterpret_cast<const char *>(&target_node.weight),
+ sizeof(target_node.weight));
+ previous = target_node.node_id;
+ }
+ }
+ }
+ }
+ }
+
+ FlushVectorToStream(edge_data_file, original_edge_data_vector);
+
+ // Finally jump back to the empty space at the beginning and write length prefix
+ edge_data_file.seekp(std::ios::beg);
+
+ const auto length_prefix = boost::numeric_cast<unsigned>(original_edges_counter);
+ static_assert(sizeof(length_prefix_empty_space) == sizeof(length_prefix), "type mismatch");
+
+ edge_data_file.write(reinterpret_cast<const char *>(&length_prefix), sizeof(length_prefix));
+
+ util::SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
+ << " edge based nodes";
+ util::SimpleLogger().Write() << "Node-based graph contains " << node_based_edge_counter
+ << " edges";
+ util::SimpleLogger().Write() << "Edge-expanded graph ...";
+ util::SimpleLogger().Write() << " contains " << m_edge_based_edge_list.size() << " edges";
+ util::SimpleLogger().Write() << " skips " << restricted_turns_counter << " turns, "
+ "defined by "
+ << m_restriction_map->size() << " restrictions";
+ util::SimpleLogger().Write() << " skips " << skipped_uturns_counter << " U turns";
+ util::SimpleLogger().Write() << " skips " << skipped_barrier_turns_counter
+ << " turns over barriers";
+}
+
+int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) const
+{
+ BOOST_ASSERT(lua_state != nullptr);
+ try
+ {
+ // call lua profile to compute turn penalty
+ double penalty = luabind::call_function<double>(lua_state, "turn_function", 180. - angle);
+ return boost::numeric_cast<int>(penalty);
+ }
+ catch (const luabind::error &er)
+ {
+ util::SimpleLogger().Write(logWARNING) << er.what();
+ }
+ return 0;
+}
+
+} // namespace extractor
+} // namespace osrm
diff --git a/extractor/extraction_containers.cpp b/src/extractor/extraction_containers.cpp
similarity index 74%
rename from extractor/extraction_containers.cpp
rename to src/extractor/extraction_containers.cpp
index 48a626b..5106ca9 100644
--- a/extractor/extraction_containers.cpp
+++ b/src/extractor/extraction_containers.cpp
@@ -1,48 +1,20 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "extraction_containers.hpp"
-#include "extraction_way.hpp"
-
-#include "../algorithms/coordinate_calculation.hpp"
-#include "../data_structures/node_id.hpp"
-#include "../data_structures/range_table.hpp"
-
-#include "../util/osrm_exception.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/timing_util.hpp"
-#include "../util/fingerprint.hpp"
-#include "../util/lua_util.hpp"
+#include "extractor/extraction_containers.hpp"
+#include "extractor/extraction_way.hpp"
+
+#include "util/coordinate_calculation.hpp"
+#include "util/range_table.hpp"
+
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+#include "util/timing_util.hpp"
+#include "util/fingerprint.hpp"
+#include "util/lua_util.hpp"
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
-#include <boost/ref.hpp>
#include <boost/numeric/conversion/cast.hpp>
+#include <boost/ref.hpp>
#include <luabind/luabind.hpp>
@@ -51,6 +23,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <chrono>
#include <limits>
+namespace
+{
+// Needed for STXXL comparison - STXXL requires max_value(), min_value(), so we can not use
+// std::less<OSMNodeId>{}. Anonymous namespace to keep translation unit local.
+struct OSMNodeIDSTXXLLess
+{
+ using value_type = OSMNodeID;
+ bool operator()(const value_type left, const value_type right) const { return left < right; }
+ value_type max_value() { return MAX_OSM_NODEID; }
+ value_type min_value() { return MIN_OSM_NODEID; }
+};
+}
+
+namespace osrm
+{
+namespace extractor
+{
+
static const int WRITE_BLOCK_BUFFER_SIZE = 8000;
ExtractionContainers::ExtractionContainers()
@@ -92,16 +82,14 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
{
std::ofstream file_out_stream;
file_out_stream.open(output_file_name.c_str(), std::ios::binary);
- const FingerPrint fingerprint = FingerPrint::GetValid();
- file_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
+ const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
+ file_out_stream.write((char *)&fingerprint, sizeof(util::FingerPrint));
PrepareNodes();
WriteNodes(file_out_stream);
PrepareEdges(segment_state);
WriteEdges(file_out_stream);
- file_out_stream.close();
-
PrepareRestrictions();
WriteRestrictions(restrictions_file_name);
@@ -113,7 +101,7 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
}
}
-void ExtractionContainers::WriteNames(const std::string& names_file_name) const
+void ExtractionContainers::WriteNames(const std::string &names_file_name) const
{
std::cout << "[extractor] writing street name index ... " << std::flush;
TIMER_START(write_name_index);
@@ -127,12 +115,11 @@ void ExtractionContainers::WriteNames(const std::string& names_file_name) const
}
// builds and writes the index
- RangeTable<> name_index_range(name_lengths);
+ util::RangeTable<> name_index_range(name_lengths);
name_file_stream << name_index_range;
name_file_stream.write((char *)&total_length, sizeof(unsigned));
-
// write all chars consecutively
char write_buffer[WRITE_BLOCK_BUFFER_SIZE];
unsigned buffer_len = 0;
@@ -150,7 +137,6 @@ void ExtractionContainers::WriteNames(const std::string& names_file_name) const
name_file_stream.write(write_buffer, buffer_len);
- name_file_stream.close();
TIMER_STOP(write_name_index);
std::cout << "ok, after " << TIMER_SEC(write_name_index) << "s" << std::endl;
}
@@ -159,7 +145,8 @@ void ExtractionContainers::PrepareNodes()
{
std::cout << "[extractor] Sorting used nodes ... " << std::flush;
TIMER_START(sorting_used_nodes);
- stxxl::sort(used_node_id_list.begin(), used_node_id_list.end(), Cmp(), stxxl_memory);
+ stxxl::sort(used_node_id_list.begin(), used_node_id_list.end(), OSMNodeIDSTXXLLess(),
+ stxxl_memory);
TIMER_STOP(sorting_used_nodes);
std::cout << "ok, after " << TIMER_SEC(sorting_used_nodes) << "s" << std::endl;
@@ -210,12 +197,12 @@ void ExtractionContainers::PrepareNodes()
}
if (internal_id > std::numeric_limits<NodeID>::max())
{
- throw osrm::exception("There are too many nodes remaining after filtering, OSRM only supports 2^32 unique nodes");
+ throw util::exception("There are too many nodes remaining after filtering, OSRM only "
+ "supports 2^32 unique nodes");
}
max_internal_node_id = boost::numeric_cast<NodeID>(internal_id);
TIMER_STOP(id_map);
std::cout << "ok, after " << TIMER_SEC(id_map) << "s" << std::endl;
-
}
void ExtractionContainers::PrepareEdges(lua_State *segment_state)
@@ -240,7 +227,8 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
{
if (edge_iterator->result.osm_source_id < node_iterator->node_id)
{
- SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference " << edge_iterator->result.source;
+ util::SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference "
+ << edge_iterator->result.source;
edge_iterator->result.source = SPECIAL_NODEID;
++edge_iterator;
continue;
@@ -276,8 +264,8 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
// them. This happens when using osmosis with bbox or polygon to extract smaller areas.
auto markSourcesInvalid = [](InternalExtractorEdge &edge)
{
- SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference "
- << edge.result.source;
+ util::SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference "
+ << edge.result.source;
edge.result.source = SPECIAL_NODEID;
edge.result.osm_source_id = SPECIAL_OSM_NODEID;
};
@@ -288,8 +276,7 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
// Sort Edges by target
std::cout << "[extractor] Sorting edges by target ... " << std::flush;
TIMER_START(sort_edges_by_target);
- stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByOSMTargetID(),
- stxxl_memory);
+ stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByOSMTargetID(), stxxl_memory);
TIMER_STOP(sort_edges_by_target);
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_target) << "s" << std::endl;
@@ -301,6 +288,8 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
const auto all_edges_list_end_ = all_edges_list.end();
const auto all_nodes_list_end_ = all_nodes_list.end();
+ const auto has_segment_function = util::luaFunctionExists(segment_state, "segment_function");
+
while (edge_iterator != all_edges_list_end_ && node_iterator != all_nodes_list_end_)
{
// skip all invalid edges
@@ -312,7 +301,9 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
if (edge_iterator->result.osm_target_id < node_iterator->node_id)
{
- SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference " << OSMNodeID_to_uint64_t(edge_iterator->result.osm_target_id);
+ util::SimpleLogger().Write(LogLevel::logWARNING)
+ << "Found invalid node reference "
+ << static_cast<uint64_t>(edge_iterator->result.osm_target_id);
edge_iterator->result.target = SPECIAL_NODEID;
++edge_iterator;
continue;
@@ -325,40 +316,40 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
BOOST_ASSERT(edge_iterator->result.osm_target_id == node_iterator->node_id);
BOOST_ASSERT(edge_iterator->weight_data.speed >= 0);
- BOOST_ASSERT(edge_iterator->source_coordinate.lat != std::numeric_limits<int>::min());
- BOOST_ASSERT(edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min());
+ BOOST_ASSERT(edge_iterator->source_coordinate.lat !=
+ util::FixedLatitude(std::numeric_limits<int>::min()));
+ BOOST_ASSERT(edge_iterator->source_coordinate.lon !=
+ util::FixedLongitude(std::numeric_limits<int>::min()));
- const double distance = coordinate_calculation::great_circle_distance(
- edge_iterator->source_coordinate.lat, edge_iterator->source_coordinate.lon,
- node_iterator->lat, node_iterator->lon);
+ const double distance = util::coordinate_calculation::greatCircleDistance(
+ edge_iterator->source_coordinate,
+ util::Coordinate(node_iterator->lon, node_iterator->lat));
- if (lua_function_exists(segment_state, "segment_function"))
+ if (has_segment_function)
{
luabind::call_function<void>(
- segment_state, "segment_function",
- boost::cref(edge_iterator->source_coordinate),
- boost::cref(*node_iterator),
- distance,
- boost::ref(edge_iterator->weight_data));
+ segment_state, "segment_function", boost::cref(edge_iterator->source_coordinate),
+ boost::cref(*node_iterator), distance, boost::ref(edge_iterator->weight_data));
}
- const double weight = [distance](const InternalExtractorEdge::WeightData& data) {
+ const double weight = [distance](const InternalExtractorEdge::WeightData &data)
+ {
switch (data.type)
{
- case InternalExtractorEdge::WeightType::EDGE_DURATION:
- case InternalExtractorEdge::WeightType::WAY_DURATION:
- return data.duration * 10.;
- break;
- case InternalExtractorEdge::WeightType::SPEED:
- return (distance * 10.) / (data.speed / 3.6);
- break;
- case InternalExtractorEdge::WeightType::INVALID:
- osrm::exception("invalid weight type");
+ case InternalExtractorEdge::WeightType::EDGE_DURATION:
+ case InternalExtractorEdge::WeightType::WAY_DURATION:
+ return data.duration * 10.;
+ break;
+ case InternalExtractorEdge::WeightType::SPEED:
+ return (distance * 10.) / (data.speed / 3.6);
+ break;
+ case InternalExtractorEdge::WeightType::INVALID:
+ util::exception("invalid weight type");
}
return -1.0;
}(edge_iterator->weight_data);
- auto& edge = edge_iterator->result;
+ auto &edge = edge_iterator->result;
edge.weight = std::max(1, static_cast<int>(std::floor(weight + .5)));
// assign new node id
@@ -384,8 +375,8 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
// them. This happens when using osmosis with bbox or polygon to extract smaller areas.
auto markTargetsInvalid = [](InternalExtractorEdge &edge)
{
- SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference "
- << edge.result.target;
+ util::SimpleLogger().Write(LogLevel::logWARNING) << "Found invalid node reference "
+ << edge.result.target;
edge.result.target = SPECIAL_NODEID;
};
std::for_each(edge_iterator, all_edges_list_end_, markTargetsInvalid);
@@ -395,7 +386,8 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
// Sort edges by start.
std::cout << "[extractor] Sorting edges by renumbered start ... " << std::flush;
TIMER_START(sort_edges_by_renumbered_start);
- stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByInternalStartThenInternalTargetID(), stxxl_memory);
+ stxxl::sort(all_edges_list.begin(), all_edges_list.end(),
+ CmpEdgeByInternalStartThenInternalTargetID(), stxxl_memory);
TIMER_STOP(sort_edges_by_renumbered_start);
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_renumbered_start) << "s" << std::endl;
@@ -427,11 +419,13 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
while (all_edges_list[i].result.source == source &&
all_edges_list[i].result.target == target)
{
- if (all_edges_list[i].result.forward && all_edges_list[i].result.weight < min_forward_weight)
+ if (all_edges_list[i].result.forward &&
+ all_edges_list[i].result.weight < min_forward_weight)
{
min_forward_idx = i;
}
- if (all_edges_list[i].result.backward && all_edges_list[i].result.weight < min_backward_weight)
+ if (all_edges_list[i].result.backward &&
+ all_edges_list[i].result.weight < min_backward_weight)
{
min_backward_idx = i;
}
@@ -440,8 +434,10 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
i++;
}
- BOOST_ASSERT(min_forward_idx == std::numeric_limits<unsigned>::max() || min_forward_idx < i);
- BOOST_ASSERT(min_backward_idx == std::numeric_limits<unsigned>::max() || min_backward_idx < i);
+ BOOST_ASSERT(min_forward_idx == std::numeric_limits<unsigned>::max() ||
+ min_forward_idx < i);
+ BOOST_ASSERT(min_backward_idx == std::numeric_limits<unsigned>::max() ||
+ min_backward_idx < i);
BOOST_ASSERT(min_backward_idx != std::numeric_limits<unsigned>::max() ||
min_forward_idx != std::numeric_limits<unsigned>::max());
@@ -484,7 +480,7 @@ void ExtractionContainers::PrepareEdges(lua_State *segment_state)
}
}
-void ExtractionContainers::WriteEdges(std::ofstream& file_out_stream) const
+void ExtractionContainers::WriteEdges(std::ofstream &file_out_stream) const
{
std::cout << "[extractor] Writing used edges ... " << std::flush;
TIMER_START(write_edges);
@@ -495,7 +491,7 @@ void ExtractionContainers::WriteEdges(std::ofstream& file_out_stream) const
auto start_position = file_out_stream.tellp();
file_out_stream.write((char *)&used_edges_counter_buffer, sizeof(unsigned));
- for (const auto& edge : all_edges_list)
+ for (const auto &edge : all_edges_list)
{
if (edge.result.source == SPECIAL_NODEID || edge.result.target == SPECIAL_NODEID)
{
@@ -505,13 +501,13 @@ void ExtractionContainers::WriteEdges(std::ofstream& file_out_stream) const
// IMPORTANT: here, we're using slicing to only write the data from the base
// class of NodeBasedEdgeWithOSM
NodeBasedEdge tmp = edge.result;
- file_out_stream.write((char*) &tmp, sizeof(NodeBasedEdge));
+ file_out_stream.write((char *)&tmp, sizeof(NodeBasedEdge));
used_edges_counter++;
}
if (used_edges_counter > std::numeric_limits<unsigned>::max())
{
- throw osrm::exception("There are too many edges, OSRM only supports 2^32");
+ throw util::exception("There are too many edges, OSRM only supports 2^32");
}
TIMER_STOP(write_edges);
std::cout << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
@@ -524,10 +520,10 @@ void ExtractionContainers::WriteEdges(std::ofstream& file_out_stream) const
file_out_stream.write((char *)&used_edges_counter_buffer, sizeof(unsigned));
std::cout << "ok" << std::endl;
- SimpleLogger().Write() << "Processed " << used_edges_counter << " edges";
+ util::SimpleLogger().Write() << "Processed " << used_edges_counter << " edges";
}
-void ExtractionContainers::WriteNodes(std::ofstream& file_out_stream) const
+void ExtractionContainers::WriteNodes(std::ofstream &file_out_stream) const
{
// write dummy value, will be overwritten later
std::cout << "[extractor] setting number of nodes ... " << std::flush;
@@ -564,18 +560,17 @@ void ExtractionContainers::WriteNodes(std::ofstream& file_out_stream) const
TIMER_STOP(write_nodes);
std::cout << "ok, after " << TIMER_SEC(write_nodes) << "s" << std::endl;
-
- SimpleLogger().Write() << "Processed " << max_internal_node_id << " nodes";
+ util::SimpleLogger().Write() << "Processed " << max_internal_node_id << " nodes";
}
-void ExtractionContainers::WriteRestrictions(const std::string& path) const
+void ExtractionContainers::WriteRestrictions(const std::string &path) const
{
// serialize restrictions
std::ofstream restrictions_out_stream;
unsigned written_restriction_count = 0;
restrictions_out_stream.open(path.c_str(), std::ios::binary);
- const FingerPrint fingerprint = FingerPrint::GetValid();
- restrictions_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
+ const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
+ restrictions_out_stream.write((char *)&fingerprint, sizeof(util::FingerPrint));
const auto count_position = restrictions_out_stream.tellp();
restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
@@ -592,8 +587,7 @@ void ExtractionContainers::WriteRestrictions(const std::string& path) const
}
restrictions_out_stream.seekp(count_position);
restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
- restrictions_out_stream.close();
- SimpleLogger().Write() << "usable restrictions: " << written_restriction_count;
+ util::SimpleLogger().Write() << "usable restrictions: " << written_restriction_count;
}
void ExtractionContainers::PrepareRestrictions()
@@ -605,11 +599,11 @@ void ExtractionContainers::PrepareRestrictions()
TIMER_STOP(sort_ways);
std::cout << "ok, after " << TIMER_SEC(sort_ways) << "s" << std::endl;
- std::cout << "[extractor] Sorting " << restrictions_list.size()
- << " restriction. by from... " << std::flush;
+ std::cout << "[extractor] Sorting " << restrictions_list.size() << " restriction. by from... "
+ << std::flush;
TIMER_START(sort_restrictions);
- stxxl::sort(restrictions_list.begin(), restrictions_list.end(),
- CmpRestrictionContainerByFrom(), stxxl_memory);
+ stxxl::sort(restrictions_list.begin(), restrictions_list.end(), CmpRestrictionContainerByFrom(),
+ stxxl_memory);
TIMER_STOP(sort_restrictions);
std::cout << "ok, after " << TIMER_SEC(sort_restrictions) << "s" << std::endl;
@@ -623,15 +617,19 @@ void ExtractionContainers::PrepareRestrictions()
while (way_start_and_end_iterator != way_start_end_id_list_end &&
restrictions_iterator != restrictions_list_end)
{
- if (way_start_and_end_iterator->way_id < OSMWayID(restrictions_iterator->restriction.from.way))
+ if (way_start_and_end_iterator->way_id <
+ OSMWayID(restrictions_iterator->restriction.from.way))
{
++way_start_and_end_iterator;
continue;
}
- if (way_start_and_end_iterator->way_id > OSMWayID(restrictions_iterator->restriction.from.way))
+ if (way_start_and_end_iterator->way_id >
+ OSMWayID(restrictions_iterator->restriction.from.way))
{
- SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid way: " << restrictions_iterator->restriction.from.way;
+ util::SimpleLogger().Write(LogLevel::logWARNING)
+ << "Restriction references invalid way: "
+ << restrictions_iterator->restriction.from.way;
restrictions_iterator->restriction.from.node = SPECIAL_NODEID;
++restrictions_iterator;
continue;
@@ -644,9 +642,11 @@ void ExtractionContainers::PrepareRestrictions()
// check if via is actually valid, if not invalidate
auto via_id_iter = external_to_internal_node_id_map.find(via_node_id);
- if(via_id_iter == external_to_internal_node_id_map.end())
+ if (via_id_iter == external_to_internal_node_id_map.end())
{
- SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid node: " << restrictions_iterator->restriction.via.node;
+ util::SimpleLogger().Write(LogLevel::logWARNING)
+ << "Restriction references invalid node: "
+ << restrictions_iterator->restriction.via.node;
restrictions_iterator->restriction.via.node = SPECIAL_NODEID;
++restrictions_iterator;
continue;
@@ -656,16 +656,34 @@ void ExtractionContainers::PrepareRestrictions()
{
// assign new from node id
auto id_iter = external_to_internal_node_id_map.find(
- OSMNodeID(way_start_and_end_iterator->first_segment_target_id));
- BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
+ OSMNodeID(way_start_and_end_iterator->first_segment_target_id));
+ if (id_iter == external_to_internal_node_id_map.end())
+ {
+ util::SimpleLogger().Write(LogLevel::logWARNING)
+ << "Way references invalid node: "
+ << way_start_and_end_iterator->first_segment_target_id;
+ restrictions_iterator->restriction.from.node = SPECIAL_NODEID;
+ ++restrictions_iterator;
+ ++way_start_and_end_iterator;
+ continue;
+ }
restrictions_iterator->restriction.from.node = id_iter->second;
}
else if (OSMNodeID(way_start_and_end_iterator->last_segment_target_id) == via_node_id)
{
// assign new from node id
auto id_iter = external_to_internal_node_id_map.find(
- OSMNodeID(way_start_and_end_iterator->last_segment_source_id));
- BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
+ OSMNodeID(way_start_and_end_iterator->last_segment_source_id));
+ if (id_iter == external_to_internal_node_id_map.end())
+ {
+ util::SimpleLogger().Write(LogLevel::logWARNING)
+ << "Way references invalid node: "
+ << way_start_and_end_iterator->last_segment_target_id;
+ restrictions_iterator->restriction.from.node = SPECIAL_NODEID;
+ ++restrictions_iterator;
+ ++way_start_and_end_iterator;
+ continue;
+ }
restrictions_iterator->restriction.from.node = id_iter->second;
}
++restrictions_iterator;
@@ -676,8 +694,8 @@ void ExtractionContainers::PrepareRestrictions()
std::cout << "[extractor] Sorting restrictions. by to ... " << std::flush;
TIMER_START(sort_restrictions_to);
- stxxl::sort(restrictions_list.begin(), restrictions_list.end(),
- CmpRestrictionContainerByTo(), stxxl_memory);
+ stxxl::sort(restrictions_list.begin(), restrictions_list.end(), CmpRestrictionContainerByTo(),
+ stxxl_memory);
TIMER_STOP(sort_restrictions_to);
std::cout << "ok, after " << TIMER_SEC(sort_restrictions_to) << "s" << std::endl;
@@ -691,7 +709,8 @@ void ExtractionContainers::PrepareRestrictions()
while (way_start_and_end_iterator != way_start_end_id_list_end_ &&
restrictions_iterator != restrictions_list_end_)
{
- if (way_start_and_end_iterator->way_id < OSMWayID(restrictions_iterator->restriction.to.way))
+ if (way_start_and_end_iterator->way_id <
+ OSMWayID(restrictions_iterator->restriction.to.way))
{
++way_start_and_end_iterator;
continue;
@@ -702,9 +721,12 @@ void ExtractionContainers::PrepareRestrictions()
++restrictions_iterator;
continue;
}
- if (way_start_and_end_iterator->way_id > OSMWayID(restrictions_iterator->restriction.to.way))
+ if (way_start_and_end_iterator->way_id >
+ OSMWayID(restrictions_iterator->restriction.to.way))
{
- SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid way: " << restrictions_iterator->restriction.to.way;
+ util::SimpleLogger().Write(LogLevel::logDEBUG)
+ << "Restriction references invalid way: "
+ << restrictions_iterator->restriction.to.way;
restrictions_iterator->restriction.to.way = SPECIAL_NODEID;
++restrictions_iterator;
continue;
@@ -721,15 +743,33 @@ void ExtractionContainers::PrepareRestrictions()
if (OSMNodeID(way_start_and_end_iterator->first_segment_source_id) == via_node_id)
{
auto to_id_iter = external_to_internal_node_id_map.find(
- OSMNodeID(way_start_and_end_iterator->first_segment_target_id));
- BOOST_ASSERT(to_id_iter != external_to_internal_node_id_map.end());
+ OSMNodeID(way_start_and_end_iterator->first_segment_target_id));
+ if (to_id_iter == external_to_internal_node_id_map.end())
+ {
+ util::SimpleLogger().Write(LogLevel::logWARNING)
+ << "Way references invalid node: "
+ << way_start_and_end_iterator->first_segment_source_id;
+ restrictions_iterator->restriction.to.node = SPECIAL_NODEID;
+ ++restrictions_iterator;
+ ++way_start_and_end_iterator;
+ continue;
+ }
restrictions_iterator->restriction.to.node = to_id_iter->second;
}
else if (OSMNodeID(way_start_and_end_iterator->last_segment_target_id) == via_node_id)
{
auto to_id_iter = external_to_internal_node_id_map.find(
- OSMNodeID(way_start_and_end_iterator->last_segment_source_id));
- BOOST_ASSERT(to_id_iter != external_to_internal_node_id_map.end());
+ OSMNodeID(way_start_and_end_iterator->last_segment_source_id));
+ if (to_id_iter == external_to_internal_node_id_map.end())
+ {
+ util::SimpleLogger().Write(LogLevel::logWARNING)
+ << "Way references invalid node: "
+ << way_start_and_end_iterator->last_segment_source_id;
+ restrictions_iterator->restriction.to.node = SPECIAL_NODEID;
+ ++restrictions_iterator;
+ ++way_start_and_end_iterator;
+ continue;
+ }
restrictions_iterator->restriction.to.node = to_id_iter->second;
}
++restrictions_iterator;
@@ -737,3 +777,5 @@ void ExtractionContainers::PrepareRestrictions()
TIMER_STOP(fix_restriction_ends);
std::cout << "ok, after " << TIMER_SEC(fix_restriction_ends) << "s" << std::endl;
}
+}
+}
diff --git a/extractor/extractor.cpp b/src/extractor/extractor.cpp
similarity index 57%
rename from extractor/extractor.cpp
rename to src/extractor/extractor.cpp
index 80bd33d..368867d 100644
--- a/extractor/extractor.cpp
+++ b/src/extractor/extractor.cpp
@@ -1,55 +1,30 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "extractor.hpp"
-
-#include "extraction_containers.hpp"
-#include "extraction_node.hpp"
-#include "extraction_way.hpp"
-#include "extractor_callbacks.hpp"
-#include "restriction_parser.hpp"
-#include "scripting_environment.hpp"
-
-#include "../data_structures/raster_source.hpp"
-#include "../util/make_unique.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/timing_util.hpp"
-#include "../util/lua_util.hpp"
-#include "../util/graph_loader.hpp"
-
-#include "../typedefs.h"
-
-#include "../data_structures/static_graph.hpp"
-#include "../data_structures/static_rtree.hpp"
-#include "../data_structures/restriction_map.hpp"
-#include "../data_structures/compressed_edge_container.hpp"
-
-#include "../algorithms/tarjan_scc.hpp"
-#include "../algorithms/crc32_processor.hpp"
+#include "extractor/extractor.hpp"
+
+#include "extractor/edge_based_edge.hpp"
+#include "extractor/extraction_containers.hpp"
+#include "extractor/extraction_node.hpp"
+#include "extractor/extraction_way.hpp"
+#include "extractor/extractor_callbacks.hpp"
+#include "extractor/restriction_parser.hpp"
+#include "extractor/scripting_environment.hpp"
+
+#include "extractor/raster_source.hpp"
+#include "util/io.hpp"
+#include "util/make_unique.hpp"
+#include "util/simple_logger.hpp"
+#include "util/timing_util.hpp"
+#include "util/lua_util.hpp"
+#include "util/graph_loader.hpp"
+#include "util/name_table.hpp"
+
+#include "util/typedefs.hpp"
+
+#include "util/static_graph.hpp"
+#include "util/static_rtree.hpp"
+#include "extractor/compressed_edge_container.hpp"
+#include "extractor/restriction_map.hpp"
+
+#include "extractor/tarjan_scc.hpp"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@@ -72,6 +47,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <thread>
#include <unordered_map>
#include <vector>
+#include <bitset>
+#include <chrono>
+
+namespace osrm
+{
+namespace extractor
+{
/**
* TODO: Refactor this function into smaller functions for better readability.
@@ -87,16 +69,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The result of this process are the following files:
* .names : Names of all streets, stored as long consecutive string with prefix sum based index
- * .osrm : Nodes and edges in a intermediate format that easy to digest for osrm-prepare
- * .restrictions : Turn restrictions that are used my osrm-prepare to construct the edge-expanded
+ * .osrm : Nodes and edges in a intermediate format that easy to digest for osrm-contract
+ * .restrictions : Turn restrictions that are used by osrm-contract to construct the edge-expanded
* graph
*
*/
-int extractor::run()
+int Extractor::run()
{
+ // setup scripting environment
+ ScriptingEnvironment scripting_environment(config.profile_path.string().c_str());
+
try
{
- LogPolicy::GetInstance().Unmute();
+ util::LogPolicy::GetInstance().Unmute();
TIMER_START(extracting);
const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
@@ -104,15 +89,12 @@ int extractor::run()
std::min(recommended_num_threads, config.requested_num_threads);
tbb::task_scheduler_init init(number_of_threads);
- SimpleLogger().Write() << "Input file: " << config.input_path.filename().string();
- SimpleLogger().Write() << "Profile: " << config.profile_path.filename().string();
- SimpleLogger().Write() << "Threads: " << number_of_threads;
-
- // setup scripting environment
- ScriptingEnvironment scripting_environment(config.profile_path.string().c_str());
+ util::SimpleLogger().Write() << "Input file: " << config.input_path.filename().string();
+ util::SimpleLogger().Write() << "Profile: " << config.profile_path.filename().string();
+ util::SimpleLogger().Write() << "Threads: " << number_of_threads;
ExtractionContainers extraction_containers;
- auto extractor_callbacks = osrm::make_unique<ExtractorCallbacks>(extraction_containers);
+ auto extractor_callbacks = util::make_unique<ExtractorCallbacks>(extraction_containers);
const osmium::io::File input_file(config.input_path.string());
osmium::io::Reader reader(input_file);
@@ -123,18 +105,15 @@ int extractor::run()
std::atomic<unsigned> number_of_relations{0};
std::atomic<unsigned> number_of_others{0};
- SimpleLogger().Write() << "Parsing in progress..";
+ util::SimpleLogger().Write() << "Parsing in progress..";
TIMER_START(parsing);
- lua_State *segment_state = scripting_environment.get_lua_state();
+ auto &main_context = scripting_environment.GetContex();
- if (lua_function_exists(segment_state, "source_function"))
+ // setup raster sources
+ if (util::luaFunctionExists(main_context.state, "source_function"))
{
- // bind a single instance of SourceContainer class to relevant lua state
- SourceContainer sources;
- luabind::globals(segment_state)["sources"] = sources;
-
- luabind::call_function<void>(segment_state, "source_function");
+ luabind::call_function<void>(main_context.state, "source_function");
}
std::string generator = header.get("generator");
@@ -142,7 +121,7 @@ int extractor::run()
{
generator = "unknown tool";
}
- SimpleLogger().Write() << "input file generated by " << generator;
+ util::SimpleLogger().Write() << "input file generated by " << generator;
// write .timestamp data file
std::string timestamp = header.get("osmosis_replication_timestamp");
@@ -150,11 +129,10 @@ int extractor::run()
{
timestamp = "n/a";
}
- SimpleLogger().Write() << "timestamp: " << timestamp;
+ util::SimpleLogger().Write() << "timestamp: " << timestamp;
boost::filesystem::ofstream timestamp_out(config.timestamp_file_name);
timestamp_out.write(timestamp.c_str(), timestamp.length());
- timestamp_out.close();
// initialize vectors holding parsed objects
tbb::concurrent_vector<std::pair<std::size_t, ExtractionNode>> resulting_nodes;
@@ -162,7 +140,7 @@ int extractor::run()
tbb::concurrent_vector<boost::optional<InputRestrictionContainer>> resulting_restrictions;
// setup restriction parser
- const RestrictionParser restriction_parser(scripting_environment.get_lua_state());
+ const RestrictionParser restriction_parser(main_context.state, main_context.properties);
while (const osmium::memory::Buffer buffer = reader.read())
{
@@ -185,7 +163,7 @@ int extractor::run()
{
ExtractionNode result_node;
ExtractionWay result_way;
- lua_State *local_state = scripting_environment.get_lua_state();
+ auto &local_context = scripting_environment.GetContex();
for (auto x = range.begin(), end = range.end(); x != end; ++x)
{
@@ -197,7 +175,7 @@ int extractor::run()
result_node.clear();
++number_of_nodes;
luabind::call_function<void>(
- local_state, "node_function",
+ local_context.state, "node_function",
boost::cref(static_cast<const osmium::Node &>(*entity)),
boost::ref(result_node));
resulting_nodes.push_back(std::make_pair(x, result_node));
@@ -206,7 +184,7 @@ int extractor::run()
result_way.clear();
++number_of_ways;
luabind::call_function<void>(
- local_state, "way_function",
+ local_context.state, "way_function",
boost::cref(static_cast<const osmium::Way &>(*entity)),
boost::ref(result_way));
resulting_ways.push_back(std::make_pair(x, result_way));
@@ -241,134 +219,117 @@ int extractor::run()
}
}
TIMER_STOP(parsing);
- SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing) << " seconds";
+ util::SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing)
+ << " seconds";
- SimpleLogger().Write() << "Raw input contains " << number_of_nodes.load() << " nodes, "
- << number_of_ways.load() << " ways, and "
- << number_of_relations.load() << " relations, and "
- << number_of_others.load() << " unknown entities";
+ util::SimpleLogger().Write() << "Raw input contains " << number_of_nodes.load()
+ << " nodes, " << number_of_ways.load() << " ways, and "
+ << number_of_relations.load() << " relations, and "
+ << number_of_others.load() << " unknown entities";
extractor_callbacks.reset();
if (extraction_containers.all_edges_list.empty())
{
- SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
+ util::SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
return 1;
}
extraction_containers.PrepareData(config.output_file_name, config.restriction_file_name,
- config.names_file_name, segment_state);
+ config.names_file_name, main_context.state);
+
+ WriteProfileProperties(config.profile_properties_output_path, main_context.properties);
TIMER_STOP(extracting);
- SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting) << "s";
+ util::SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting)
+ << "s";
}
+ // we do this for scoping
+ // TODO move to own functions
catch (const std::exception &e)
{
- SimpleLogger().Write(logWARNING) << e.what();
+ util::SimpleLogger().Write(logWARNING) << e.what();
return 1;
}
-
try
{
// Transform the node-based graph that OSM is based on into an edge-based graph
// that is better for routing. Every edge becomes a node, and every valid
// movement (e.g. turn from A->B, and B->A) becomes an edge
//
- //
- // // Create a new lua state
- SimpleLogger().Write() << "Generating edge-expanded graph representation";
+ auto &main_context = scripting_environment.GetContex();
+
+ util::SimpleLogger().Write() << "Generating edge-expanded graph representation";
TIMER_START(expansion);
- std::vector<EdgeBasedNode> node_based_edge_list;
- DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
+ std::vector<EdgeBasedNode> edge_based_node_list;
+ util::DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
std::vector<bool> node_is_startpoint;
+ std::vector<EdgeWeight> edge_based_node_weights;
std::vector<QueryNode> internal_to_external_node_map;
- auto graph_size =
- BuildEdgeExpandedGraph(internal_to_external_node_map, node_based_edge_list,
- node_is_startpoint, edge_based_edge_list);
+ auto graph_size = BuildEdgeExpandedGraph(main_context.state, main_context.properties,
+ internal_to_external_node_map,
+ edge_based_node_list, node_is_startpoint,
+ edge_based_node_weights, edge_based_edge_list);
auto number_of_node_based_nodes = graph_size.first;
auto max_edge_id = graph_size.second;
TIMER_STOP(expansion);
- SimpleLogger().Write() << "building r-tree ...";
+ util::SimpleLogger().Write() << "Saving edge-based node weights to file.";
+ TIMER_START(timer_write_node_weights);
+ util::serializeVector(config.edge_based_node_weights_output_path, edge_based_node_weights);
+ TIMER_STOP(timer_write_node_weights);
+ util::SimpleLogger().Write() << "Done writing. (" << TIMER_SEC(timer_write_node_weights)
+ << ")";
+
+ util::SimpleLogger().Write() << "building r-tree ...";
TIMER_START(rtree);
- FindComponents(max_edge_id, edge_based_edge_list, node_based_edge_list);
+ FindComponents(max_edge_id, edge_based_edge_list, edge_based_node_list);
- BuildRTree(std::move(node_based_edge_list), std::move(node_is_startpoint),
+ BuildRTree(std::move(edge_based_node_list), std::move(node_is_startpoint),
internal_to_external_node_map);
TIMER_STOP(rtree);
- SimpleLogger().Write() << "writing node map ...";
+ util::SimpleLogger().Write() << "writing node map ...";
WriteNodeMapping(internal_to_external_node_map);
WriteEdgeBasedGraph(config.edge_graph_output_path, max_edge_id, edge_based_edge_list);
- SimpleLogger().Write() << "Expansion : "
- << (number_of_node_based_nodes / TIMER_SEC(expansion))
- << " nodes/sec and " << ((max_edge_id + 1) / TIMER_SEC(expansion))
- << " edges/sec";
- SimpleLogger().Write() << "To prepare the data for routing, run: "
- << "./osrm-prepare " << config.output_file_name << std::endl;
+ util::SimpleLogger().Write()
+ << "Expansion : " << (number_of_node_based_nodes / TIMER_SEC(expansion))
+ << " nodes/sec and " << ((max_edge_id + 1) / TIMER_SEC(expansion)) << " edges/sec";
+ util::SimpleLogger().Write() << "To prepare the data for routing, run: "
+ << "./osrm-contract " << config.output_file_name << std::endl;
}
catch (const std::exception &e)
{
- SimpleLogger().Write(logWARNING) << e.what();
+ util::SimpleLogger().Write(logWARNING) << e.what();
return 1;
}
return 0;
}
-/**
- \brief Setups scripting environment (lua-scripting)
- Also initializes speed profile.
-*/
-void extractor::SetupScriptingEnvironment(lua_State *lua_state,
- SpeedProfileProperties &speed_profile)
+void Extractor::WriteProfileProperties(const std::string &output_path,
+ const ProfileProperties &properties) const
{
- // open utility libraries string library;
- luaL_openlibs(lua_state);
-
- // adjust lua load path
- luaAddScriptFolderToLoadPath(lua_state, config.profile_path.string().c_str());
-
- // Now call our function in a lua script
- if (0 != luaL_dofile(lua_state, config.profile_path.string().c_str()))
- {
- std::stringstream msg;
- msg << lua_tostring(lua_state, -1) << " occured in scripting block";
- throw osrm::exception(msg.str());
- }
-
- if (0 != luaL_dostring(lua_state, "return traffic_signal_penalty\n"))
- {
- std::stringstream msg;
- msg << lua_tostring(lua_state, -1) << " occured in scripting block";
- throw osrm::exception(msg.str());
- }
- speed_profile.traffic_signal_penalty = 10 * lua_tointeger(lua_state, -1);
- SimpleLogger().Write(logDEBUG) << "traffic_signal_penalty: "
- << speed_profile.traffic_signal_penalty;
-
- if (0 != luaL_dostring(lua_state, "return u_turn_penalty\n"))
+ boost::filesystem::ofstream out_stream(output_path);
+ if (!out_stream)
{
- std::stringstream msg;
- msg << lua_tostring(lua_state, -1) << " occured in scripting block";
- throw osrm::exception(msg.str());
+ throw util::exception("Could not open " + output_path + " for writing.");
}
- speed_profile.u_turn_penalty = 10 * lua_tointeger(lua_state, -1);
- speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function");
+ out_stream.write(reinterpret_cast<const char *>(&properties), sizeof(properties));
}
-void extractor::FindComponents(unsigned max_edge_id,
- const DeallocatingVector<EdgeBasedEdge> &input_edge_list,
+void Extractor::FindComponents(unsigned max_edge_id,
+ const util::DeallocatingVector<EdgeBasedEdge> &input_edge_list,
std::vector<EdgeBasedNode> &input_nodes) const
{
struct UncontractedEdgeData
@@ -390,7 +351,7 @@ void extractor::FindComponents(unsigned max_edge_id,
return source == rhs.source && target == rhs.target;
}
};
- using UncontractedGraph = StaticGraph<UncontractedEdgeData>;
+ using UncontractedGraph = util::StaticGraph<UncontractedEdgeData>;
std::vector<InputEdge> edges;
edges.reserve(input_edge_list.size() * 2);
@@ -398,6 +359,8 @@ void extractor::FindComponents(unsigned max_edge_id,
{
BOOST_ASSERT_MSG(static_cast<unsigned int>(std::max(edge.weight, 1)) > 0,
"edge distance < 1");
+ BOOST_ASSERT(edge.source <= max_edge_id);
+ BOOST_ASSERT(edge.target <= max_edge_id);
if (edge.forward)
{
edges.push_back({edge.source, edge.target, {}});
@@ -412,10 +375,12 @@ void extractor::FindComponents(unsigned max_edge_id,
// connect forward and backward nodes of each edge
for (const auto &node : input_nodes)
{
- if (node.reverse_edge_based_node_id != SPECIAL_NODEID)
+ if (node.reverse_segment_id.enabled)
{
- edges.push_back({node.forward_edge_based_node_id, node.reverse_edge_based_node_id, {}});
- edges.push_back({node.reverse_edge_based_node_id, node.forward_edge_based_node_id, {}});
+ BOOST_ASSERT(node.forward_segment_id.id <= max_edge_id);
+ BOOST_ASSERT(node.reverse_segment_id.id <= max_edge_id);
+ edges.push_back({node.forward_segment_id.id, node.reverse_segment_id.id, {}});
+ edges.push_back({node.reverse_segment_id.id, node.forward_segment_id.id, {}});
}
}
@@ -431,10 +396,10 @@ void extractor::FindComponents(unsigned max_edge_id,
for (auto &node : input_nodes)
{
- auto forward_component = component_search.get_component_id(node.forward_edge_based_node_id);
- BOOST_ASSERT(node.reverse_edge_based_node_id == SPECIAL_EDGEID ||
+ auto forward_component = component_search.get_component_id(node.forward_segment_id.id);
+ BOOST_ASSERT(!node.reverse_segment_id.enabled ||
forward_component ==
- component_search.get_component_id(node.reverse_edge_based_node_id));
+ component_search.get_component_id(node.reverse_segment_id.id));
const unsigned component_size = component_search.get_component_size(forward_component);
node.component.is_tiny = component_size < config.small_component_size;
@@ -445,15 +410,15 @@ void extractor::FindComponents(unsigned max_edge_id,
/**
\brief Build load restrictions from .restriction file
*/
-std::shared_ptr<RestrictionMap> extractor::LoadRestrictionMap()
+std::shared_ptr<RestrictionMap> Extractor::LoadRestrictionMap()
{
boost::filesystem::ifstream input_stream(config.restriction_file_name,
std::ios::in | std::ios::binary);
std::vector<TurnRestriction> restriction_list;
- loadRestrictionsFromFile(input_stream, restriction_list);
+ util::loadRestrictionsFromFile(input_stream, restriction_list);
- SimpleLogger().Write() << " - " << restriction_list.size() << " restrictions.";
+ util::SimpleLogger().Write() << " - " << restriction_list.size() << " restrictions.";
return std::make_shared<RestrictionMap>(restriction_list);
}
@@ -461,8 +426,8 @@ std::shared_ptr<RestrictionMap> extractor::LoadRestrictionMap()
/**
\brief Load node based graph from .osrm file
*/
-std::shared_ptr<NodeBasedDynamicGraph>
-extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
+std::shared_ptr<util::NodeBasedDynamicGraph>
+Extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
std::unordered_set<NodeID> &traffic_lights,
std::vector<QueryNode> &internal_to_external_node_map)
{
@@ -473,11 +438,11 @@ extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
std::vector<NodeID> barrier_list;
std::vector<NodeID> traffic_light_list;
- NodeID number_of_node_based_nodes = loadNodesFromFile(
+ NodeID number_of_node_based_nodes = util::loadNodesFromFile(
input_stream, barrier_list, traffic_light_list, internal_to_external_node_map);
- SimpleLogger().Write() << " - " << barrier_list.size() << " bollard nodes, "
- << traffic_light_list.size() << " traffic lights";
+ util::SimpleLogger().Write() << " - " << barrier_list.size() << " bollard nodes, "
+ << traffic_light_list.size() << " traffic lights";
// insert into unordered sets for fast lookup
barrier_nodes.insert(barrier_list.begin(), barrier_list.end());
@@ -488,32 +453,29 @@ extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
traffic_light_list.clear();
traffic_light_list.shrink_to_fit();
- loadEdgesFromFile(input_stream, edge_list);
+ util::loadEdgesFromFile(input_stream, edge_list);
if (edge_list.empty())
{
- SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
- return std::shared_ptr<NodeBasedDynamicGraph>();
+ util::SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
+ return std::shared_ptr<util::NodeBasedDynamicGraph>();
}
- return NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list);
+ return util::NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list);
}
/**
\brief Building an edge-expanded graph from node-based input and turn restrictions
*/
std::pair<std::size_t, std::size_t>
-extractor::BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
+Extractor::BuildEdgeExpandedGraph(lua_State *lua_state,
+ const ProfileProperties &profile_properties,
+ std::vector<QueryNode> &internal_to_external_node_map,
std::vector<EdgeBasedNode> &node_based_edge_list,
std::vector<bool> &node_is_startpoint,
- DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list)
+ std::vector<EdgeWeight> &edge_based_node_weights,
+ util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list)
{
- lua_State *lua_state = luaL_newstate();
- luabind::open(lua_state);
-
- SpeedProfileProperties speed_profile;
- SetupScriptingEnvironment(lua_state, speed_profile);
-
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
@@ -522,30 +484,27 @@ extractor::BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_n
LoadNodeBasedGraph(barrier_nodes, traffic_lights, internal_to_external_node_map);
CompressedEdgeContainer compressed_edge_container;
- GraphCompressor graph_compressor(speed_profile);
+ GraphCompressor graph_compressor;
graph_compressor.Compress(barrier_nodes, traffic_lights, *restriction_map, *node_based_graph,
compressed_edge_container);
+ compressed_edge_container.SerializeInternalVector(config.geometry_output_path);
+
+ util::NameTable name_table(config.names_file_name);
+
EdgeBasedGraphFactory edge_based_graph_factory(
node_based_graph, compressed_edge_container, barrier_nodes, traffic_lights,
std::const_pointer_cast<RestrictionMap const>(restriction_map),
- internal_to_external_node_map, speed_profile);
-
- compressed_edge_container.SerializeInternalVector(config.geometry_output_path);
+ internal_to_external_node_map, profile_properties, name_table);
edge_based_graph_factory.Run(config.edge_output_path, lua_state,
config.edge_segment_lookup_path, config.edge_penalty_path,
- config.generate_edge_lookup
-#ifdef DEBUG_GEOMETRY
- ,
- config.debug_turns_path
-#endif
- );
- lua_close(lua_state);
+ config.generate_edge_lookup);
edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list);
edge_based_graph_factory.GetEdgeBasedNodes(node_based_edge_list);
edge_based_graph_factory.GetStartPointMarkers(node_is_startpoint);
+ edge_based_graph_factory.GetEdgeBasedNodeWeights(edge_based_node_weights);
auto max_edge_id = edge_based_graph_factory.GetHighestEdgeID();
const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes();
@@ -555,7 +514,7 @@ extractor::BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_n
/**
\brief Writing info on original (node-based) nodes
*/
-void extractor::WriteNodeMapping(const std::vector<QueryNode> &internal_to_external_node_map)
+void Extractor::WriteNodeMapping(const std::vector<QueryNode> &internal_to_external_node_map)
{
boost::filesystem::ofstream node_stream(config.node_output_path, std::ios::binary);
const unsigned size_of_mapping = internal_to_external_node_map.size();
@@ -565,7 +524,6 @@ void extractor::WriteNodeMapping(const std::vector<QueryNode> &internal_to_exter
node_stream.write((char *)internal_to_external_node_map.data(),
size_of_mapping * sizeof(QueryNode));
}
- node_stream.close();
}
/**
@@ -573,20 +531,20 @@ void extractor::WriteNodeMapping(const std::vector<QueryNode> &internal_to_exter
Saves tree into '.ramIndex' and leaves into '.fileIndex'.
*/
-void extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
+void Extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
std::vector<bool> node_is_startpoint,
const std::vector<QueryNode> &internal_to_external_node_map)
{
- SimpleLogger().Write() << "constructing r-tree of " << node_based_edge_list.size()
- << " edge elements build on-top of "
- << internal_to_external_node_map.size() << " coordinates";
+ util::SimpleLogger().Write() << "constructing r-tree of " << node_based_edge_list.size()
+ << " edge elements build on-top of "
+ << internal_to_external_node_map.size() << " coordinates";
BOOST_ASSERT(node_is_startpoint.size() == node_based_edge_list.size());
// Filter node based edges based on startpoint
auto out_iter = node_based_edge_list.begin();
auto in_iter = node_based_edge_list.begin();
- for (auto index : osrm::irange<std::size_t>(0, node_is_startpoint.size()))
+ for (auto index : util::irange<std::size_t>(0, node_is_startpoint.size()))
{
BOOST_ASSERT(in_iter != node_based_edge_list.end());
if (node_is_startpoint[index])
@@ -600,25 +558,28 @@ void extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
node_based_edge_list.resize(new_size);
TIMER_START(construction);
- StaticRTree<EdgeBasedNode>(node_based_edge_list, config.rtree_nodes_output_path,
- config.rtree_leafs_output_path, internal_to_external_node_map);
+ util::StaticRTree<EdgeBasedNode> rtree(node_based_edge_list, config.rtree_nodes_output_path,
+ config.rtree_leafs_output_path,
+ internal_to_external_node_map);
TIMER_STOP(construction);
- SimpleLogger().Write() << "finished r-tree construction in " << TIMER_SEC(construction)
- << " seconds";
+ util::SimpleLogger().Write() << "finished r-tree construction in " << TIMER_SEC(construction)
+ << " seconds";
}
-void extractor::WriteEdgeBasedGraph(std::string const &output_file_filename,
- size_t const max_edge_id,
- DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list)
+void Extractor::WriteEdgeBasedGraph(
+ std::string const &output_file_filename,
+ size_t const max_edge_id,
+ util::DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list)
{
std::ofstream file_out_stream;
file_out_stream.open(output_file_filename.c_str(), std::ios::binary);
- const FingerPrint fingerprint = FingerPrint::GetValid();
- file_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
+ const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
+ file_out_stream.write((char *)&fingerprint, sizeof(util::FingerPrint));
- std::cout << "[extractor] Writing edge-based-graph egdes ... " << std::flush;
+ util::SimpleLogger().Write() << "[extractor] Writing edge-based-graph edges ... "
+ << std::flush;
TIMER_START(write_edges);
size_t number_of_used_edges = edge_based_edge_list.size();
@@ -631,8 +592,9 @@ void extractor::WriteEdgeBasedGraph(std::string const &output_file_filename,
}
TIMER_STOP(write_edges);
- std::cout << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
+ util::SimpleLogger().Write() << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
- SimpleLogger().Write() << "Processed " << number_of_used_edges << " edges";
- file_out_stream.close();
+ util::SimpleLogger().Write() << "Processed " << number_of_used_edges << " edges";
+}
+}
}
diff --git a/extractor/extractor_callbacks.cpp b/src/extractor/extractor_callbacks.cpp
similarity index 65%
rename from extractor/extractor_callbacks.cpp
rename to src/extractor/extractor_callbacks.cpp
index 2eb1a9b..a289ec6 100644
--- a/extractor/extractor_callbacks.cpp
+++ b/src/extractor/extractor_callbacks.cpp
@@ -1,50 +1,28 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "extractor_callbacks.hpp"
-#include "extraction_containers.hpp"
-#include "extraction_node.hpp"
-#include "extraction_way.hpp"
-
-#include "../data_structures/external_memory_node.hpp"
-#include "../data_structures/restriction.hpp"
-#include "../util/container.hpp"
-#include "../util/simple_logger.hpp"
+#include "extractor/extractor_callbacks.hpp"
+#include "extractor/extraction_containers.hpp"
+#include "extractor/extraction_node.hpp"
+#include "extractor/extraction_way.hpp"
+
+#include "extractor/external_memory_node.hpp"
+#include "extractor/restriction.hpp"
+#include "util/simple_logger.hpp"
+#include "util/for_each_pair.hpp"
#include <boost/optional/optional.hpp>
#include <osmium/osm.hpp>
-#include <osrm/coordinate.hpp>
+#include "osrm/coordinate.hpp"
#include <limits>
#include <string>
#include <vector>
+namespace osrm
+{
+namespace extractor
+{
+
ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers)
: external_memory(extraction_containers)
{
@@ -61,11 +39,9 @@ void ExtractorCallbacks::ProcessNode(const osmium::Node &input_node,
const ExtractionNode &result_node)
{
external_memory.all_nodes_list.push_back(
- {static_cast<int>(input_node.location().lat() * COORDINATE_PRECISION),
- static_cast<int>(input_node.location().lon() * COORDINATE_PRECISION),
- OSMNodeID(input_node.id()),
- result_node.barrier,
- result_node.traffic_lights});
+ {util::toFixed(util::FloatLongitude(input_node.location().lon())),
+ util::toFixed(util::FloatLatitude(input_node.location().lat())),
+ OSMNodeID(input_node.id()), result_node.barrier, result_node.traffic_lights});
}
void ExtractorCallbacks::ProcessRestriction(
@@ -74,7 +50,7 @@ void ExtractorCallbacks::ProcessRestriction(
if (restriction)
{
external_memory.restrictions_list.push_back(restriction.get());
- // SimpleLogger().Write() << "from: " << restriction.get().restriction.from.node <<
+ // util::SimpleLogger().Write() << "from: " << restriction.get().restriction.from.node <<
// ",via: " << restriction.get().restriction.via.node <<
// ", to: " << restriction.get().restriction.to.node <<
// ", only: " << (restriction.get().restriction.flags.is_only ?
@@ -108,8 +84,8 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
if (std::numeric_limits<decltype(input_way.id())>::max() == input_way.id())
{
- SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << input_way.id()
- << " of size " << input_way.nodes().size();
+ util::SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << input_way.id()
+ << " of size " << input_way.nodes().size();
return;
}
@@ -147,17 +123,27 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
if (forward_weight_data.type == InternalExtractorEdge::WeightType::INVALID &&
backward_weight_data.type == InternalExtractorEdge::WeightType::INVALID)
{
- SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << input_way.id();
+ util::SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: "
+ << input_way.id();
return;
}
+ // FIXME this need to be moved into the profiles
+ const char *data = input_way.get_value_by_key("highway");
+ guidance::RoadClassificationData road_classification;
+ if (data)
+ {
+ road_classification.road_class = guidance::functionalRoadClassFromTag(data);
+ }
+
// Get the unique identifier for the street name
const auto &string_map_iterator = string_map.find(parsed_way.name);
unsigned name_id = external_memory.name_lengths.size();
if (string_map.end() == string_map_iterator)
{
auto name_length = std::min<unsigned>(255u, parsed_way.name.size());
- std::copy(parsed_way.name.c_str(), parsed_way.name.c_str() + name_length, std::back_inserter(external_memory.name_char_data));
+ std::copy(parsed_way.name.c_str(), parsed_way.name.c_str() + name_length,
+ std::back_inserter(external_memory.name_char_data));
external_memory.name_lengths.push_back(name_length);
string_map.insert(std::make_pair(parsed_way.name, name_id));
}
@@ -187,55 +173,56 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
{
BOOST_ASSERT(split_edge == false);
BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
- osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
+ util::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
{
external_memory.all_edges_list.push_back(InternalExtractorEdge(
- OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id,
- backward_weight_data, true, false, parsed_way.roundabout,
- parsed_way.is_access_restricted, parsed_way.is_startpoint,
- parsed_way.backward_travel_mode, false));
+ OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()),
+ name_id, backward_weight_data, true, false,
+ parsed_way.roundabout, parsed_way.is_access_restricted,
+ parsed_way.is_startpoint, parsed_way.backward_travel_mode,
+ false, road_classification));
});
external_memory.way_start_end_id_list.push_back(
- {OSMWayID(input_way.id()),
- OSMNodeID(input_way.nodes().back().ref()),
+ {OSMWayID(input_way.id()), OSMNodeID(input_way.nodes().back().ref()),
OSMNodeID(input_way.nodes()[input_way.nodes().size() - 2].ref()),
- OSMNodeID(input_way.nodes()[1].ref()),
- OSMNodeID(input_way.nodes()[0].ref())});
+ OSMNodeID(input_way.nodes()[1].ref()), OSMNodeID(input_way.nodes()[0].ref())});
}
else
{
const bool forward_only =
split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode;
- osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
+ util::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
{
external_memory.all_edges_list.push_back(InternalExtractorEdge(
- OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id, forward_weight_data,
- true, !forward_only, parsed_way.roundabout,
- parsed_way.is_access_restricted, parsed_way.is_startpoint, parsed_way.forward_travel_mode,
- split_edge));
+ OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()),
+ name_id, forward_weight_data, true, !forward_only,
+ parsed_way.roundabout, parsed_way.is_access_restricted,
+ parsed_way.is_startpoint, parsed_way.forward_travel_mode,
+ split_edge, road_classification));
});
if (split_edge)
{
BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
- osrm::for_each_pair(
+ util::for_each_pair(
input_way.nodes().cbegin(), input_way.nodes().cend(),
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
{
external_memory.all_edges_list.push_back(InternalExtractorEdge(
- OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id, backward_weight_data, false,
- true, parsed_way.roundabout, parsed_way.is_access_restricted,
- parsed_way.is_startpoint, parsed_way.backward_travel_mode, true));
+ OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id,
+ backward_weight_data, false, true, parsed_way.roundabout,
+ parsed_way.is_access_restricted, parsed_way.is_startpoint,
+ parsed_way.backward_travel_mode, true, road_classification));
});
}
external_memory.way_start_end_id_list.push_back(
- {OSMWayID(input_way.id()),
- OSMNodeID(input_way.nodes().back().ref()),
+ {OSMWayID(input_way.id()), OSMNodeID(input_way.nodes().back().ref()),
OSMNodeID(input_way.nodes()[input_way.nodes().size() - 2].ref()),
- OSMNodeID(input_way.nodes()[1].ref()),
- OSMNodeID(input_way.nodes()[0].ref())});
+ OSMNodeID(input_way.nodes()[1].ref()), OSMNodeID(input_way.nodes()[0].ref())});
}
}
+}
+}
diff --git a/algorithms/graph_compressor.cpp b/src/extractor/graph_compressor.cpp
similarity index 65%
rename from algorithms/graph_compressor.cpp
rename to src/extractor/graph_compressor.cpp
index f3b5f8d..6df9a38 100644
--- a/algorithms/graph_compressor.cpp
+++ b/src/extractor/graph_compressor.cpp
@@ -1,31 +1,30 @@
-#include "graph_compressor.hpp"
+#include "extractor/graph_compressor.hpp"
-#include "../data_structures/compressed_edge_container.hpp"
-#include "../data_structures/dynamic_graph.hpp"
-#include "../data_structures/node_based_graph.hpp"
-#include "../data_structures/restriction_map.hpp"
-#include "../data_structures/percent.hpp"
+#include "extractor/compressed_edge_container.hpp"
+#include "extractor/restriction_map.hpp"
+#include "util/dynamic_graph.hpp"
+#include "util/node_based_graph.hpp"
+#include "util/percent.hpp"
-#include "../util/simple_logger.hpp"
+#include "util/simple_logger.hpp"
-GraphCompressor::GraphCompressor(SpeedProfileProperties speed_profile)
- : speed_profile(std::move(speed_profile))
+namespace osrm
+{
+namespace extractor
{
-}
-
-void GraphCompressor::Compress(const std::unordered_set<NodeID>& barrier_nodes,
- const std::unordered_set<NodeID>& traffic_lights,
- RestrictionMap& restriction_map,
- NodeBasedDynamicGraph& graph,
- CompressedEdgeContainer& geometry_compressor)
+void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
+ const std::unordered_set<NodeID> &traffic_lights,
+ RestrictionMap &restriction_map,
+ util::NodeBasedDynamicGraph &graph,
+ CompressedEdgeContainer &geometry_compressor)
{
const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
const unsigned original_number_of_edges = graph.GetNumberOfEdges();
- Percent progress(original_number_of_nodes);
+ util::Percent progress(original_number_of_nodes);
- for (const NodeID node_v : osrm::irange(0u, original_number_of_nodes))
+ for (const NodeID node_v : util::irange(0u, original_number_of_nodes))
{
progress.printStatus(node_v);
@@ -64,12 +63,10 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID>& barrier_nodes,
const bool reverse_edge_order = graph.GetEdgeData(graph.BeginEdges(node_v)).reversed;
const EdgeID forward_e2 = graph.BeginEdges(node_v) + reverse_edge_order;
BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
- BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) &&
- forward_e2 < graph.EndEdges(node_v));
+ BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) && forward_e2 < graph.EndEdges(node_v));
const EdgeID reverse_e2 = graph.BeginEdges(node_v) + 1 - reverse_edge_order;
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
- BOOST_ASSERT(reverse_e2 >= graph.BeginEdges(node_v) &&
- reverse_e2 < graph.EndEdges(node_v));
+ BOOST_ASSERT(reverse_e2 >= graph.BeginEdges(node_v) && reverse_e2 < graph.EndEdges(node_v));
const EdgeData &fwd_edge_data2 = graph.GetEdgeData(forward_e2);
const EdgeData &rev_edge_data2 = graph.GetEdgeData(reverse_e2);
@@ -103,13 +100,24 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID>& barrier_nodes,
continue;
}
- if (fwd_edge_data1.IsCompatibleTo(fwd_edge_data2) && rev_edge_data1.IsCompatibleTo(rev_edge_data2))
+ if (fwd_edge_data1.IsCompatibleTo(fwd_edge_data2) &&
+ rev_edge_data1.IsCompatibleTo(rev_edge_data2))
{
BOOST_ASSERT(graph.GetEdgeData(forward_e1).name_id ==
graph.GetEdgeData(reverse_e1).name_id);
BOOST_ASSERT(graph.GetEdgeData(forward_e2).name_id ==
graph.GetEdgeData(reverse_e2).name_id);
+ // Do not compress edge if it crosses a traffic signal.
+ // This can't be done in IsCompatibleTo, becase we only store the
+ // traffic signals in the `traffic_lights` list, which EdgeData
+ // doesn't have access to.
+ const bool has_node_penalty = traffic_lights.find(node_v) != traffic_lights.end();
+ if (has_node_penalty)
+ {
+ continue;
+ }
+
// Get distances before graph is modified
const int forward_weight1 = graph.GetEdgeData(forward_e1).distance;
const int forward_weight2 = graph.GetEdgeData(forward_e2).distance;
@@ -123,18 +131,9 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID>& barrier_nodes,
BOOST_ASSERT(0 != reverse_weight1);
BOOST_ASSERT(0 != reverse_weight2);
- const bool has_node_penalty = traffic_lights.find(node_v) != traffic_lights.end();
-
// add weight of e2's to e1
graph.GetEdgeData(forward_e1).distance += fwd_edge_data2.distance;
graph.GetEdgeData(reverse_e1).distance += rev_edge_data2.distance;
- if (has_node_penalty)
- {
- graph.GetEdgeData(forward_e1).distance +=
- speed_profile.traffic_signal_penalty;
- graph.GetEdgeData(reverse_e1).distance +=
- speed_profile.traffic_signal_penalty;
- }
// extend e1's to targets of e2's
graph.SetTarget(forward_e1, node_w);
@@ -152,28 +151,38 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID>& barrier_nodes,
restriction_map.FixupArrivingTurnRestriction(node_w, node_v, node_u, graph);
// store compressed geometry in container
- geometry_compressor.CompressEdge(
- forward_e1, forward_e2, node_v, node_w,
- forward_weight1 + (has_node_penalty ? speed_profile.traffic_signal_penalty : 0),
- forward_weight2);
- geometry_compressor.CompressEdge(
- reverse_e1, reverse_e2, node_v, node_u, reverse_weight1,
- reverse_weight2 + (has_node_penalty ? speed_profile.traffic_signal_penalty : 0));
+ geometry_compressor.CompressEdge(forward_e1, forward_e2, node_v, node_w,
+ forward_weight1, forward_weight2);
+ geometry_compressor.CompressEdge(reverse_e1, reverse_e2, node_v, node_u,
+ reverse_weight1, reverse_weight2);
}
}
PrintStatistics(original_number_of_nodes, original_number_of_edges, graph);
+
+ // Repeate the loop, but now add all edges as uncompressed values.
+ // The function AddUncompressedEdge does nothing if the edge is already
+ // in the CompressedEdgeContainer.
+ for (const NodeID node_u : util::irange(0u, original_number_of_nodes))
+ {
+ for (const auto edge_id : util::irange(graph.BeginEdges(node_u), graph.EndEdges(node_u)))
+ {
+ const EdgeData &data = graph.GetEdgeData(edge_id);
+ const NodeID target = graph.GetTarget(edge_id);
+ geometry_compressor.AddUncompressedEdge(edge_id, target, data.distance);
+ }
+ }
}
void GraphCompressor::PrintStatistics(unsigned original_number_of_nodes,
unsigned original_number_of_edges,
- const NodeBasedDynamicGraph& graph) const
+ const util::NodeBasedDynamicGraph &graph) const
{
unsigned new_node_count = 0;
unsigned new_edge_count = 0;
- for (const auto i : osrm::irange(0u, graph.GetNumberOfNodes()))
+ for (const auto i : util::irange(0u, graph.GetNumberOfNodes()))
{
if (graph.GetOutDegree(i) > 0)
{
@@ -181,8 +190,10 @@ void GraphCompressor::PrintStatistics(unsigned original_number_of_nodes,
new_edge_count += (graph.EndEdges(i) - graph.BeginEdges(i));
}
}
- SimpleLogger().Write() << "Node compression ratio: "
- << new_node_count / (double)original_number_of_nodes;
- SimpleLogger().Write() << "Edge compression ratio: "
- << new_edge_count / (double)original_number_of_edges;
+ util::SimpleLogger().Write() << "Node compression ratio: "
+ << new_node_count / (double)original_number_of_nodes;
+ util::SimpleLogger().Write() << "Edge compression ratio: "
+ << new_edge_count / (double)original_number_of_edges;
+}
+}
}
diff --git a/src/extractor/guidance/classification_data.cpp b/src/extractor/guidance/classification_data.cpp
new file mode 100644
index 0000000..70ccaff
--- /dev/null
+++ b/src/extractor/guidance/classification_data.cpp
@@ -0,0 +1,53 @@
+#include "extractor/guidance/classification_data.hpp"
+#include "util/simple_logger.hpp"
+
+#include <unordered_map>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+
+FunctionalRoadClass functionalRoadClassFromTag(std::string const &value)
+{
+ // FIXME at some point this should be part of the profiles
+ const static auto class_hash = []
+ {
+ std::unordered_map<std::string, FunctionalRoadClass> hash;
+ hash["motorway"] = FunctionalRoadClass::MOTORWAY;
+ hash["motorway_link"] = FunctionalRoadClass::MOTORWAY_LINK;
+ hash["trunk"] = FunctionalRoadClass::TRUNK;
+ hash["trunk_link"] = FunctionalRoadClass::TRUNK_LINK;
+ hash["primary"] = FunctionalRoadClass::PRIMARY;
+ hash["primary_link"] = FunctionalRoadClass::PRIMARY_LINK;
+ hash["secondary"] = FunctionalRoadClass::SECONDARY;
+ hash["secondary_link"] = FunctionalRoadClass::SECONDARY_LINK;
+ hash["tertiary"] = FunctionalRoadClass::TERTIARY;
+ hash["tertiary_link"] = FunctionalRoadClass::TERTIARY_LINK;
+ hash["unclassified"] = FunctionalRoadClass::UNCLASSIFIED;
+ hash["residential"] = FunctionalRoadClass::RESIDENTIAL;
+ hash["service"] = FunctionalRoadClass::SERVICE;
+ hash["living_street"] = FunctionalRoadClass::LIVING_STREET;
+ hash["track"] = FunctionalRoadClass::LOW_PRIORITY_ROAD;
+ hash["road"] = FunctionalRoadClass::LOW_PRIORITY_ROAD;
+ hash["path"] = FunctionalRoadClass::LOW_PRIORITY_ROAD;
+ hash["driveway"] = FunctionalRoadClass::LOW_PRIORITY_ROAD;
+ return hash;
+ }();
+
+ if (class_hash.find(value) != class_hash.end())
+ {
+ return class_hash.find(value)->second;
+ }
+ else
+ {
+ util::SimpleLogger().Write(logDEBUG) << "Unknown road class encountered: " << value;
+ return FunctionalRoadClass::UNKNOWN;
+ }
+}
+
+} // ns guidance
+} // ns extractor
+} // ns osrm
diff --git a/src/extractor/guidance/turn_analysis.cpp b/src/extractor/guidance/turn_analysis.cpp
new file mode 100644
index 0000000..0281e16
--- /dev/null
+++ b/src/extractor/guidance/turn_analysis.cpp
@@ -0,0 +1,2313 @@
+#include "extractor/guidance/turn_analysis.hpp"
+
+#include "util/simple_logger.hpp"
+#include "util/coordinate.hpp"
+
+#include <cstddef>
+#include <limits>
+#include <iomanip>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace guidance
+{
+// configuration of turn classification
+const bool constexpr INVERT = true;
+
+// what angle is interpreted as going straight
+const double constexpr STRAIGHT_ANGLE = 180.;
+// if a turn deviates this much from going straight, it will be kept straight
+const double constexpr MAXIMAL_ALLOWED_NO_TURN_DEVIATION = 3.;
+// angle that lies between two nearly indistinguishable roads
+const double constexpr NARROW_TURN_ANGLE = 30.;
+const double constexpr GROUP_ANGLE = 90;
+// angle difference that can be classified as straight, if its the only narrow turn
+const double constexpr FUZZY_ANGLE_DIFFERENCE = 15.;
+const double constexpr DISTINCTION_RATIO = 2;
+const unsigned constexpr INVALID_NAME_ID = 0;
+
+using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
+
+ConnectedRoad::ConnectedRoad(const TurnOperation turn, const bool entry_allowed)
+ : turn(turn), entry_allowed(entry_allowed)
+{
+}
+
+bool requiresAnnouncement(const EdgeData &from, const EdgeData &to)
+{
+ return !from.IsCompatibleTo(to);
+}
+
+struct Localizer
+{
+ const std::vector<QueryNode> *node_info_list = nullptr;
+
+ util::Coordinate operator()(const NodeID nid)
+ {
+ if (node_info_list)
+ {
+ return {(*node_info_list)[nid].lon, (*node_info_list)[nid].lat};
+ }
+ return {};
+ }
+};
+
+static Localizer localizer;
+
+TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
+ const std::vector<QueryNode> &node_info_list,
+ const RestrictionMap &restriction_map,
+ const std::unordered_set<NodeID> &barrier_nodes,
+ const CompressedEdgeContainer &compressed_edge_container,
+ const util::NameTable &name_table)
+ : node_based_graph(node_based_graph), node_info_list(node_info_list),
+ restriction_map(restriction_map), barrier_nodes(barrier_nodes),
+ compressed_edge_container(compressed_edge_container), name_table(name_table)
+{
+}
+
+// some small tool functions to simplify decisions down the line
+namespace detail
+{
+
+inline FunctionalRoadClass roadClass(const ConnectedRoad &road,
+ const util::NodeBasedDynamicGraph &graph)
+{
+ return graph.GetEdgeData(road.turn.eid).road_classification.road_class;
+}
+
+inline bool isMotorwayClass(FunctionalRoadClass road_class)
+{
+ return road_class == FunctionalRoadClass::MOTORWAY || road_class == FunctionalRoadClass::TRUNK;
+}
+
+inline bool isMotorwayClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
+{
+ return isMotorwayClass(node_based_graph.GetEdgeData(eid).road_classification.road_class);
+}
+
+inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
+{
+ return isRampClass(node_based_graph.GetEdgeData(eid).road_classification.road_class);
+}
+
+} // namespace detail
+
+std::vector<TurnOperation> TurnAnalysis::getTurns(const NodeID from, const EdgeID via_edge) const
+{
+ localizer.node_info_list = &node_info_list;
+ auto intersection = getConnectedRoads(from, via_edge);
+
+ const auto &in_edge_data = node_based_graph.GetEdgeData(via_edge);
+
+ // main priority: roundabouts
+ bool on_roundabout = in_edge_data.roundabout;
+ bool can_enter_roundabout = false;
+ bool can_exit_roundabout_separately = false;
+ for (const auto &road : intersection)
+ {
+ const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
+ // only check actual outgoing edges
+ if (edge_data.reversed)
+ continue;
+
+ if (edge_data.roundabout)
+ {
+ can_enter_roundabout = true;
+ }
+ // Exiting roundabouts at an entry point is technically a data-modelling issue.
+ // This workaround handles cases in which an exit follows the entry.
+ // To correctly represent perceived exits, we only count exits leading to a
+ // separate vertex than the one we are coming from that are in the direction of
+ // the roundabout.
+ // The sorting of the angles represents a problem for left-sided driving, though.
+ // FIXME in case of left-sided driving, we have to check whether we can enter the
+ // roundabout later in the cycle, rather than prior.
+ else if (node_based_graph.GetTarget(road.turn.eid) != from && !can_enter_roundabout)
+ {
+ can_exit_roundabout_separately = true;
+ }
+ }
+ if (on_roundabout || can_enter_roundabout)
+ {
+ intersection = handleRoundabouts(via_edge, on_roundabout, can_exit_roundabout_separately,
+ std::move(intersection));
+ }
+ else
+ {
+ // set initial defaults for normal turns and modifier based on angle
+ intersection = setTurnTypes(from, via_edge, std::move(intersection));
+ if (isMotorwayJunction(via_edge, intersection))
+ {
+ intersection = handleMotorwayJunction(via_edge, std::move(intersection));
+ }
+
+ else if (intersection.size() == 1)
+ {
+ intersection = handleOneWayTurn(std::move(intersection));
+ }
+ else if (intersection.size() == 2)
+ {
+ intersection = handleTwoWayTurn(via_edge, std::move(intersection));
+ }
+ else if (intersection.size() == 3)
+ {
+ intersection = handleThreeWayTurn(via_edge, std::move(intersection));
+ }
+ else
+ {
+ intersection = handleComplexTurn(via_edge, std::move(intersection));
+ }
+ // complex intersection, potentially requires conflict resolution
+ }
+
+ std::vector<TurnOperation> turns;
+ for (auto road : intersection)
+ if (road.entry_allowed)
+ turns.emplace_back(road.turn);
+
+ return turns;
+}
+
+inline std::size_t countValid(const std::vector<ConnectedRoad> &intersection)
+{
+ return std::count_if(intersection.begin(), intersection.end(), [](const ConnectedRoad &road)
+ {
+ return road.entry_allowed;
+ });
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleRoundabouts(const EdgeID via_edge,
+ const bool on_roundabout,
+ const bool can_exit_roundabout_separately,
+ std::vector<ConnectedRoad> intersection) const
+{
+ // TODO requires differentiation between roundabouts and rotaries
+ // detect via radius (get via circle through three vertices)
+ NodeID node_v = node_based_graph.GetTarget(via_edge);
+ if (on_roundabout)
+ {
+ // Shoule hopefully have only a single exit and continue
+ // at least for cars. How about bikes?
+ for (auto &road : intersection)
+ {
+ auto &turn = road.turn;
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ if (out_data.roundabout)
+ {
+ // TODO can forks happen in roundabouts? E.g. required lane changes
+ if (1 == node_based_graph.GetDirectedOutDegree(node_v))
+ {
+ // No turn possible.
+ turn.instruction = TurnInstruction::NO_TURN();
+ }
+ else
+ {
+ turn.instruction =
+ TurnInstruction::REMAIN_ROUNDABOUT(getTurnDirection(turn.angle));
+ }
+ }
+ else
+ {
+ turn.instruction = TurnInstruction::EXIT_ROUNDABOUT(getTurnDirection(turn.angle));
+ }
+ }
+ return intersection;
+ }
+ else
+ {
+ for (auto &road : intersection)
+ {
+ if (!road.entry_allowed)
+ continue;
+ auto &turn = road.turn;
+ const auto &out_data = node_based_graph.GetEdgeData(turn.eid);
+ if (out_data.roundabout)
+ {
+ turn.instruction = TurnInstruction::ENTER_ROUNDABOUT(getTurnDirection(turn.angle));
+ if (can_exit_roundabout_separately)
+ {
+ if (turn.instruction.type == TurnType::EnterRotary)
+ turn.instruction.type = TurnType::EnterRotaryAtExit;
+ if (turn.instruction.type == TurnType::EnterRoundabout)
+ turn.instruction.type = TurnType::EnterRoundaboutAtExit;
+ }
+ }
+ else
+ {
+ turn.instruction = {TurnType::EnterAndExitRoundabout, getTurnDirection(turn.angle)};
+ }
+ }
+ return intersection;
+ }
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::fallbackTurnAssignmentMotorway(std::vector<ConnectedRoad> intersection) const
+{
+ for (auto &road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+
+ util::SimpleLogger().Write(logWARNING)
+ << "road: " << road.toString() << " Name: " << out_data.name_id
+ << " Road Class: " << (int)out_data.road_classification.road_class
+ << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
+
+ if (!road.entry_allowed)
+ continue;
+
+ const auto type = detail::isMotorwayClass(out_data.road_classification.road_class)
+ ? TurnType::Merge
+ : TurnType::Turn;
+ if (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
+ road.turn.instruction = {type, DirectionModifier::Straight};
+ else
+ {
+ road.turn.instruction = {type,
+ road.turn.angle > STRAIGHT_ANGLE
+ ? DirectionModifier::SlightLeft
+ : DirectionModifier::SlightRight};
+ }
+ }
+ return intersection;
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection) const
+{
+ const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+ BOOST_ASSERT(detail::isMotorwayClass(in_data.road_classification.road_class));
+
+ const auto countExitingMotorways = [this](const std::vector<ConnectedRoad> &intersection)
+ {
+ unsigned count = 0;
+ for (const auto &road : intersection)
+ {
+ if (road.entry_allowed && detail::isMotorwayClass(road.turn.eid, node_based_graph))
+ ++count;
+ }
+ return count;
+ };
+
+ // find the angle that continues on our current highway
+ const auto getContinueAngle = [this, in_data](const std::vector<ConnectedRoad> &intersection)
+ {
+ for (const auto &road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ if (road.turn.angle != 0 && in_data.name_id == out_data.name_id &&
+ in_data.name_id != 0 &&
+ detail::isMotorwayClass(out_data.road_classification.road_class))
+ return road.turn.angle;
+ }
+ return intersection[0].turn.angle;
+ };
+
+ const auto getMostLikelyContinue =
+ [this, in_data](const std::vector<ConnectedRoad> &intersection)
+ {
+ double angle = intersection[0].turn.angle;
+ double best = 180;
+ for (const auto &road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ if (detail::isMotorwayClass(out_data.road_classification.road_class) &&
+ angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < best)
+ {
+ best = angularDeviation(road.turn.angle, STRAIGHT_ANGLE);
+ angle = road.turn.angle;
+ }
+ }
+ return angle;
+ };
+
+ const auto findBestContinue = [&]()
+ {
+ const double continue_angle = getContinueAngle(intersection);
+ if (continue_angle != intersection[0].turn.angle)
+ return continue_angle;
+ else
+ return getMostLikelyContinue(intersection);
+ };
+
+ // find continue angle
+ const double continue_angle = findBestContinue();
+
+ // highway does not continue and has no obvious choice
+ if (continue_angle == intersection[0].turn.angle)
+ {
+ if (intersection.size() == 2)
+ {
+ // do not announce ramps at the end of a highway
+ intersection[1].turn.instruction = {TurnType::NoTurn,
+ getTurnDirection(intersection[1].turn.angle)};
+ }
+ else if (intersection.size() == 3)
+ {
+ // splitting ramp at the end of a highway
+ if (intersection[1].entry_allowed && intersection[2].entry_allowed)
+ {
+ assignFork(via_edge, intersection[2], intersection[1]);
+ }
+ else
+ {
+ // ending in a passing ramp
+ if (intersection[1].entry_allowed)
+ intersection[1].turn.instruction = {
+ TurnType::NoTurn, getTurnDirection(intersection[1].turn.angle)};
+ else
+ intersection[2].turn.instruction = {
+ TurnType::NoTurn, getTurnDirection(intersection[2].turn.angle)};
+ }
+ }
+ else if (intersection.size() == 4 &&
+ detail::roadClass(intersection[1], node_based_graph) ==
+ detail::roadClass(intersection[2], node_based_graph) &&
+ detail::roadClass(intersection[2], node_based_graph) ==
+ detail::roadClass(intersection[3], node_based_graph))
+ {
+ // tripple fork at the end
+ assignFork(via_edge, intersection[3], intersection[2], intersection[1]);
+ }
+ else if (countValid(intersection) > 0) // check whether turns exist at all
+ {
+ // FALLBACK, this should hopefully never be reached
+ auto coord = localizer(node_based_graph.GetTarget(via_edge));
+ util::SimpleLogger().Write(logWARNING)
+ << "Fallback reached from motorway at " << std::setprecision(12)
+ << toFloating(coord.lat) << " " << toFloating(coord.lon) << ", no continue angle, "
+ << intersection.size() << " roads, " << countValid(intersection) << " valid ones.";
+ fallbackTurnAssignmentMotorway(intersection);
+ }
+ }
+ else
+ {
+ const unsigned exiting_motorways = countExitingMotorways(intersection);
+
+ if (exiting_motorways == 0)
+ {
+ // Ending in Ramp
+ for (auto &road : intersection)
+ {
+ if (road.entry_allowed)
+ {
+ BOOST_ASSERT(detail::isRampClass(road.turn.eid, node_based_graph));
+ road.turn.instruction =
+ TurnInstruction::SUPPRESSED(getTurnDirection(road.turn.angle));
+ }
+ }
+ }
+ else if (exiting_motorways == 1)
+ {
+ // normal motorway passing some ramps or mering onto another motorway
+ if (intersection.size() == 2)
+ {
+ BOOST_ASSERT(!detail::isRampClass(intersection[1].turn.eid, node_based_graph));
+
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+ }
+ else
+ {
+ // continue on the same highway
+ bool continues = (getContinueAngle(intersection) != intersection[0].turn.angle);
+ // Normal Highway exit or merge
+ for (auto &road : intersection)
+ {
+ // ignore invalid uturns/other
+ if (!road.entry_allowed)
+ continue;
+
+ if (road.turn.angle == continue_angle)
+ {
+ if (continues)
+ road.turn.instruction =
+ TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
+ else // TODO handle turn direction correctly
+ road.turn.instruction = {TurnType::Merge, DirectionModifier::Straight};
+ }
+ else if (road.turn.angle < continue_angle)
+ {
+ road.turn.instruction = {
+ detail::isRampClass(road.turn.eid, node_based_graph) ? TurnType::Ramp
+ : TurnType::Turn,
+ (road.turn.angle < 145) ? DirectionModifier::Right
+ : DirectionModifier::SlightRight};
+ }
+ else if (road.turn.angle > continue_angle)
+ {
+ road.turn.instruction = {
+ detail::isRampClass(road.turn.eid, node_based_graph) ? TurnType::Ramp
+ : TurnType::Turn,
+ (road.turn.angle > 215) ? DirectionModifier::Left
+ : DirectionModifier::SlightLeft};
+ }
+ }
+ }
+ }
+ // handle motorway forks
+ else if (exiting_motorways > 1)
+ {
+ if (exiting_motorways == 2 && intersection.size() == 2)
+ {
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+ util::SimpleLogger().Write(logWARNING)
+ << "Disabled U-Turn on a freeway at "
+ << localizer(node_based_graph.GetTarget(via_edge));
+ intersection[0].entry_allowed = false; // UTURN on the freeway
+ }
+ else if (exiting_motorways == 2)
+ {
+ // standard fork
+ std::size_t first_valid = std::numeric_limits<std::size_t>::max(),
+ second_valid = std::numeric_limits<std::size_t>::max();
+ for (std::size_t i = 0; i < intersection.size(); ++i)
+ {
+ if (intersection[i].entry_allowed &&
+ detail::isMotorwayClass(intersection[i].turn.eid, node_based_graph))
+ {
+ if (first_valid < intersection.size())
+ {
+ second_valid = i;
+ break;
+ }
+ else
+ {
+ first_valid = i;
+ }
+ }
+ }
+ assignFork(via_edge, intersection[second_valid], intersection[first_valid]);
+ }
+ else if (exiting_motorways == 3)
+ {
+ // triple fork
+ std::size_t first_valid = std::numeric_limits<std::size_t>::max(),
+ second_valid = std::numeric_limits<std::size_t>::max(),
+ third_valid = std::numeric_limits<std::size_t>::max();
+ for (std::size_t i = 0; i < intersection.size(); ++i)
+ {
+ if (intersection[i].entry_allowed &&
+ detail::isMotorwayClass(intersection[i].turn.eid, node_based_graph))
+ {
+ if (second_valid < intersection.size())
+ {
+ third_valid = i;
+ break;
+ }
+ else if (first_valid < intersection.size())
+ {
+ second_valid = i;
+ }
+ else
+ {
+ first_valid = i;
+ }
+ }
+ }
+ assignFork(via_edge, intersection[third_valid], intersection[second_valid],
+ intersection[first_valid]);
+ }
+ else
+ {
+ auto coord = localizer(node_based_graph.GetTarget(via_edge));
+ util::SimpleLogger().Write(logWARNING)
+ << "Found motorway junction with more than "
+ "2 exiting motorways or additional ramps at " << std::setprecision(12)
+ << toFloating(coord.lat) << " " << toFloating(coord.lon);
+ fallbackTurnAssignmentMotorway(intersection);
+ }
+ } // done for more than one highway exit
+ }
+ return intersection;
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection) const
+{
+ auto num_valid_turns = countValid(intersection);
+ // ramp straight into a motorway/ramp
+ if (intersection.size() == 2 && num_valid_turns == 1)
+ {
+ BOOST_ASSERT(!intersection[0].entry_allowed);
+ BOOST_ASSERT(detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph));
+
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+ }
+ else if (intersection.size() == 3)
+ {
+ // merging onto a passing highway / or two ramps merging onto the same highway
+ if (num_valid_turns == 1)
+ {
+ BOOST_ASSERT(!intersection[0].entry_allowed);
+ // check order of highways
+ // 4
+ // 5 3
+ //
+ // 6 2
+ //
+ // 7 1
+ // 0
+ if (intersection[1].entry_allowed)
+ {
+ if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph))
+ {
+ // circular order indicates a merge to the left (0-3 onto 4
+ if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <
+ NARROW_TURN_ANGLE)
+ intersection[1].turn.instruction = {TurnType::Merge,
+ DirectionModifier::SlightLeft};
+ else // fallback
+ intersection[1].turn.instruction = {
+ TurnType::Merge, getTurnDirection(intersection[1].turn.angle)};
+ }
+ else // passing by the end of a motorway
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+ }
+ else
+ {
+ BOOST_ASSERT(intersection[2].entry_allowed);
+ if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph))
+ {
+ // circular order (5-0) onto 4
+ if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) <
+ NARROW_TURN_ANGLE)
+ intersection[2].turn.instruction = {TurnType::Merge,
+ DirectionModifier::SlightRight};
+ else // fallback
+ intersection[2].turn.instruction = {
+ TurnType::Merge, getTurnDirection(intersection[2].turn.angle)};
+ }
+ else // passing the end of a highway
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(num_valid_turns == 2);
+ // UTurn on ramps is not possible
+ BOOST_ASSERT(!intersection[0].entry_allowed);
+ BOOST_ASSERT(intersection[1].entry_allowed);
+ BOOST_ASSERT(intersection[2].entry_allowed);
+ // two motorways starting at end of ramp (fork)
+ // M M
+ // \ /
+ // |
+ // R
+ if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph) &&
+ detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph))
+ {
+ assignFork(via_edge, intersection[2], intersection[1]);
+ }
+ else
+ {
+ // continued ramp passing motorway entry
+ // M R
+ // M R
+ // | /
+ // R
+ if (detail::isMotorwayClass(node_based_graph.GetEdgeData(intersection[1].turn.eid)
+ .road_classification.road_class))
+ {
+ intersection[1].turn.instruction = {TurnType::Merge,
+ DirectionModifier::SlightRight};
+ intersection[2].turn.instruction = {TurnType::Fork,
+ DirectionModifier::SlightLeft};
+ }
+ else
+ {
+ intersection[1].turn.instruction = {TurnType::Fork,
+ DirectionModifier::SlightRight};
+ intersection[2].turn.instruction = {TurnType::Merge,
+ DirectionModifier::SlightLeft};
+ }
+ }
+ }
+ }
+ // On - Off Ramp on passing Motorway, Ramp onto Fork(?)
+ else if (intersection.size() == 4)
+ {
+ bool passed_highway_entry = false;
+ for (auto &road : intersection)
+ {
+ const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
+ if (!road.entry_allowed &&
+ detail::isMotorwayClass(edge_data.road_classification.road_class))
+ {
+ passed_highway_entry = true;
+ }
+ else if (detail::isMotorwayClass(edge_data.road_classification.road_class))
+ {
+ road.turn.instruction = {TurnType::Merge,
+ passed_highway_entry ? DirectionModifier::SlightRight
+ : DirectionModifier::SlightLeft};
+ }
+ else
+ {
+ BOOST_ASSERT(isRampClass(edge_data.road_classification.road_class));
+ road.turn.instruction = {TurnType::Ramp, getTurnDirection(road.turn.angle)};
+ }
+ }
+ }
+ else
+ { // FALLBACK, hopefully this should never been reached
+ util::SimpleLogger().Write(logWARNING) << "Reached fallback on motorway ramp with "
+ << intersection.size() << " roads and "
+ << countValid(intersection) << " valid turns.";
+ fallbackTurnAssignmentMotorway(intersection);
+ }
+ return intersection;
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleMotorwayJunction(const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection) const
+{
+ // BOOST_ASSERT(!intersection[0].entry_allowed); //This fails due to @themarex handling of dead
+ // end
+ // streets
+ const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+
+ // coming from motorway
+ if (detail::isMotorwayClass(in_data.road_classification.road_class))
+ {
+ return handleFromMotorway(via_edge, std::move(intersection));
+ }
+ else // coming from a ramp
+ {
+ return handleMotorwayRamp(via_edge, std::move(intersection));
+ // ramp merging straight onto motorway
+ }
+}
+
+bool TurnAnalysis::isMotorwayJunction(const EdgeID via_edge,
+ const std::vector<ConnectedRoad> &intersection) const
+{
+ bool has_motorway = false;
+ bool has_normal_roads = false;
+
+ for (const auto &road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ // not merging or forking?
+ if ((angularDeviation(road.turn.angle, 0) > 35 &&
+ angularDeviation(road.turn.angle, 180) > 35) ||
+ (road.entry_allowed && angularDeviation(road.turn.angle, 0) < 35))
+ return false;
+ else if (out_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY ||
+ out_data.road_classification.road_class == FunctionalRoadClass::TRUNK)
+ {
+ if (road.entry_allowed)
+ has_motorway = true;
+ }
+ else if (!isRampClass(out_data.road_classification.road_class))
+ has_normal_roads = true;
+ }
+
+ if (has_normal_roads)
+ return false;
+
+ const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+ return has_motorway ||
+ in_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY ||
+ in_data.road_classification.road_class == FunctionalRoadClass::TRUNK;
+}
+
+TurnType TurnAnalysis::findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &road) const
+{
+
+ const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+
+ bool on_ramp = isRampClass(in_data.road_classification.road_class);
+
+ bool onto_ramp = isRampClass(out_data.road_classification.road_class);
+
+ if (!on_ramp && onto_ramp)
+ return TurnType::Ramp;
+
+ if (in_data.name_id == out_data.name_id && in_data.name_id != INVALID_NAME_ID)
+ {
+ return TurnType::Continue;
+ }
+
+ return TurnType::Turn;
+}
+
+TurnInstruction TurnAnalysis::getInstructionForObvious(const std::size_t num_roads,
+ const EdgeID via_edge,
+ const ConnectedRoad &road) const
+{
+ const auto type = findBasicTurnType(via_edge, road);
+ // handle travel modes:
+ const auto in_mode = node_based_graph.GetEdgeData(via_edge).travel_mode;
+ const auto out_mode = node_based_graph.GetEdgeData(road.turn.eid).travel_mode;
+ if (type == TurnType::Ramp)
+ {
+ return {TurnType::Ramp, getTurnDirection(road.turn.angle)};
+ }
+
+ if (angularDeviation(road.turn.angle, 0) < 0.01)
+ {
+ return {TurnType::Turn, DirectionModifier::UTurn};
+ }
+ if (type == TurnType::Turn)
+ {
+ const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ if (in_data.name_id != out_data.name_id &&
+ requiresNameAnnounced(name_table.GetNameForID(in_data.name_id),
+ name_table.GetNameForID(out_data.name_id)))
+ return {TurnType::NewName, getTurnDirection(road.turn.angle)};
+ else
+ {
+ if (in_mode == out_mode)
+ return {TurnType::Suppressed, getTurnDirection(road.turn.angle)};
+ else
+ return {TurnType::Notification, getTurnDirection(road.turn.angle)};
+ }
+ }
+ BOOST_ASSERT(type == TurnType::Continue);
+ if (in_mode != out_mode)
+ {
+ return {TurnType::Notification, getTurnDirection(road.turn.angle)};
+ }
+ if (num_roads > 2)
+ {
+ return {TurnType::Suppressed, getTurnDirection(road.turn.angle)};
+ }
+ else
+ {
+ return {TurnType::NoTurn, getTurnDirection(road.turn.angle)};
+ }
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleOneWayTurn(std::vector<ConnectedRoad> intersection) const
+{
+ BOOST_ASSERT(intersection[0].turn.angle < 0.001);
+ return intersection;
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleTwoWayTurn(const EdgeID via_edge, std::vector<ConnectedRoad> intersection) const
+{
+ BOOST_ASSERT(intersection[0].turn.angle < 0.001);
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+
+ if (intersection[1].turn.instruction.type == TurnType::Suppressed)
+ intersection[1].turn.instruction.type = TurnType::NoTurn;
+
+ return intersection;
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection) const
+{
+ BOOST_ASSERT(intersection[0].turn.angle < 0.001);
+ const auto isObviousOfTwo = [](const ConnectedRoad road, const ConnectedRoad other)
+ {
+ return (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
+ angularDeviation(other.turn.angle, STRAIGHT_ANGLE) > 85) ||
+ (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <
+ std::numeric_limits<double>::epsilon()) ||
+ (angularDeviation(other.turn.angle, STRAIGHT_ANGLE) /
+ angularDeviation(road.turn.angle, STRAIGHT_ANGLE) >
+ 1.4);
+ };
+
+ /* Two nearly straight turns -> FORK
+ OOOOOOO
+ /
+ IIIIII
+ \
+ OOOOOOO
+ */
+ if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE)
+ {
+ if (intersection[1].entry_allowed && intersection[2].entry_allowed)
+ {
+ const auto left_class = node_based_graph.GetEdgeData(intersection[2].turn.eid)
+ .road_classification.road_class;
+ const auto right_class = node_based_graph.GetEdgeData(intersection[1].turn.eid)
+ .road_classification.road_class;
+ if (canBeSeenAsFork(left_class, right_class))
+ assignFork(via_edge, intersection[2], intersection[1]);
+ else if (getPriority(left_class) > getPriority(right_class))
+ {
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ DirectionModifier::SlightLeft};
+ }
+ else
+ {
+ intersection[2].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ DirectionModifier::SlightRight};
+ }
+ }
+ else
+ {
+ if (intersection[1].entry_allowed)
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+ if (intersection[2].entry_allowed)
+ intersection[2].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
+ }
+ }
+ /* T Intersection
+
+ OOOOOOO T OOOOOOOO
+ I
+ I
+ I
+ */
+ else if (angularDeviation(intersection[1].turn.angle, 90) < NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[2].turn.angle, 270) < NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
+ NARROW_TURN_ANGLE)
+ {
+ if (intersection[1].entry_allowed)
+ {
+ if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[1]))
+ intersection[1].turn.instruction = {TurnType::EndOfRoad, DirectionModifier::Right};
+ else
+ intersection[1].turn.instruction = {TurnType::Ramp, DirectionModifier::Right};
+ }
+ if (intersection[2].entry_allowed)
+ {
+ if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[2]))
+
+ intersection[2].turn.instruction = {TurnType::EndOfRoad, DirectionModifier::Left};
+ else
+ intersection[2].turn.instruction = {TurnType::Ramp, DirectionModifier::Left};
+ }
+ }
+ /* T Intersection, Cross left
+ O
+ O
+ O
+ IIIIIIII - OOOOOOOOOO
+ */
+ else if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[2].turn.angle, 270) < NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
+ NARROW_TURN_ANGLE)
+ {
+ if (intersection[1].entry_allowed)
+ {
+ if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[1]))
+ intersection[1].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
+ else
+ intersection[1].turn.instruction = {TurnType::Ramp, DirectionModifier::Straight};
+ }
+ if (intersection[2].entry_allowed)
+ {
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ DirectionModifier::Left};
+ }
+ }
+ /* T Intersection, Cross right
+
+ IIIIIIII T OOOOOOOOOO
+ O
+ O
+ O
+ */
+ else if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[1].turn.angle, 90) < NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
+ NARROW_TURN_ANGLE)
+ {
+ if (intersection[2].entry_allowed)
+ intersection[2].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
+ if (intersection[1].entry_allowed)
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ DirectionModifier::Right};
+ }
+ // merge onto a through street
+ else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id &&
+ node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id ==
+ node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id)
+ {
+ const auto findTurn = [isObviousOfTwo](const ConnectedRoad turn, const ConnectedRoad other)
+ -> TurnInstruction
+ {
+ return {isObviousOfTwo(turn, other) ? TurnType::Merge : TurnType::Turn,
+ getTurnDirection(turn.turn.angle)};
+ };
+ intersection[1].turn.instruction = findTurn(intersection[1], intersection[2]);
+ intersection[2].turn.instruction = findTurn(intersection[2], intersection[1]);
+ }
+
+ // other street merges from the left
+ else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(via_edge).name_id &&
+ node_based_graph.GetEdgeData(via_edge).name_id ==
+ node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
+ {
+ if (isObviousOfTwo(intersection[1], intersection[2]))
+ {
+ intersection[1].turn.instruction =
+ TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
+ }
+ else
+ {
+ intersection[1].turn.instruction = {TurnType::Continue,
+ getTurnDirection(intersection[1].turn.angle)};
+ }
+ intersection[2].turn.instruction = {TurnType::Turn,
+ getTurnDirection(intersection[2].turn.angle)};
+ }
+ // other street merges from the right
+ else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(via_edge).name_id &&
+ node_based_graph.GetEdgeData(via_edge).name_id ==
+ node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id)
+ {
+ if (isObviousOfTwo(intersection[2], intersection[1]))
+ {
+ intersection[2].turn.instruction =
+ TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
+ }
+ else
+ {
+ intersection[2].turn.instruction = {TurnType::Continue,
+ getTurnDirection(intersection[2].turn.angle)};
+ }
+ intersection[1].turn.instruction = {TurnType::Turn,
+ getTurnDirection(intersection[1].turn.angle)};
+ }
+ else
+ {
+ if (isObviousOfTwo(intersection[1], intersection[2]))
+ {
+ intersection[1].turn.instruction = getInstructionForObvious(3,via_edge,intersection[1]);
+ }
+ else
+ {
+ intersection[1].turn.instruction = {TurnType::Turn,
+ getTurnDirection(intersection[1].turn.angle)};
+ }
+
+ if (isObviousOfTwo(intersection[2], intersection[1]))
+ {
+ intersection[2].turn.instruction = getInstructionForObvious(3,via_edge,intersection[2]);
+ }
+ else
+ {
+ intersection[2].turn.instruction = {TurnType::Turn,
+ getTurnDirection(intersection[2].turn.angle)};
+ }
+ }
+ // unnamed intersections or basic three way turn
+
+ // remain at basic turns
+ // TODO handle obviousness, Handle Merges
+ return intersection;
+}
+
+void TurnAnalysis::handleDistinctConflict(const EdgeID via_edge,
+ ConnectedRoad &left,
+ ConnectedRoad &right) const
+{
+ // single turn of both is valid (don't change the valid one)
+ // or multiple identical angles -> bad OSM intersection
+ if ((!left.entry_allowed || !right.entry_allowed) || (left.turn.angle == right.turn.angle))
+ {
+ if (left.entry_allowed)
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ getTurnDirection(left.turn.angle)};
+ if (right.entry_allowed)
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ getTurnDirection(right.turn.angle)};
+ return;
+ }
+
+ if (getTurnDirection(left.turn.angle) == DirectionModifier::Straight ||
+ getTurnDirection(left.turn.angle) == DirectionModifier::SlightLeft ||
+ getTurnDirection(right.turn.angle) == DirectionModifier::SlightRight)
+ {
+ const auto left_class =
+ node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class;
+ const auto right_class =
+ node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class;
+ if (canBeSeenAsFork(left_class, right_class))
+ assignFork(via_edge, left, right);
+ else if (getPriority(left_class) > getPriority(right_class))
+ {
+ // FIXME this should possibly know about the actual roads?
+ right.turn.instruction = getInstructionForObvious(4, via_edge, right);
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ DirectionModifier::SlightLeft};
+ }
+ else
+ {
+ // FIXME this should possibly know about the actual roads?
+ left.turn.instruction = getInstructionForObvious(4, via_edge, left);
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ DirectionModifier::SlightRight};
+ }
+ }
+
+ const auto left_type = findBasicTurnType(via_edge, left);
+ const auto right_type = findBasicTurnType(via_edge, right);
+ // Two Right Turns
+ if (angularDeviation(left.turn.angle, 90) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+ {
+ // Keep left perfect, shift right
+ left.turn.instruction = {left_type, DirectionModifier::Right};
+ right.turn.instruction = {right_type, DirectionModifier::SharpRight};
+ return;
+ }
+ if (angularDeviation(right.turn.angle, 90) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+ {
+ // Keep Right perfect, shift left
+ left.turn.instruction = {left_type, DirectionModifier::SlightRight};
+ right.turn.instruction = {right_type, DirectionModifier::Right};
+ return;
+ }
+ // Two Right Turns
+ if (angularDeviation(left.turn.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+ {
+ // Keep left perfect, shift right
+ left.turn.instruction = {left_type, DirectionModifier::Left};
+ right.turn.instruction = {right_type, DirectionModifier::SlightLeft};
+ return;
+ }
+ if (angularDeviation(right.turn.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+ {
+ // Keep Right perfect, shift left
+ left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
+ right.turn.instruction = {right_type, DirectionModifier::Left};
+ return;
+ }
+ // Both turns?
+ if (TurnType::Ramp != left_type && TurnType::Ramp != right_type)
+ {
+ if (left.turn.angle < STRAIGHT_ANGLE)
+ {
+ left.turn.instruction = {TurnType::FirstTurn, getTurnDirection(left.turn.angle)};
+ right.turn.instruction = {TurnType::SecondTurn, getTurnDirection(right.turn.angle)};
+ }
+ else
+ {
+ left.turn.instruction = {TurnType::SecondTurn, getTurnDirection(left.turn.angle)};
+ right.turn.instruction = {TurnType::FirstTurn, getTurnDirection(right.turn.angle)};
+ }
+ return;
+ }
+ // Shift the lesser penalty
+ if (getTurnDirection(left.turn.angle) == DirectionModifier::SharpLeft)
+ {
+ left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
+ right.turn.instruction = {right_type, DirectionModifier::Left};
+ return;
+ }
+ if (getTurnDirection(right.turn.angle) == DirectionModifier::SharpRight)
+ {
+ left.turn.instruction = {left_type, DirectionModifier::Right};
+ right.turn.instruction = {right_type, DirectionModifier::SharpRight};
+ return;
+ }
+
+ if (getTurnDirection(left.turn.angle) == DirectionModifier::Right)
+ {
+ if (angularDeviation(left.turn.angle, 90) > angularDeviation(right.turn.angle, 90))
+ {
+ left.turn.instruction = {left_type, DirectionModifier::SlightRight};
+ right.turn.instruction = {right_type, DirectionModifier::Right};
+ }
+ else
+ {
+ left.turn.instruction = {left_type, DirectionModifier::Right};
+ right.turn.instruction = {right_type, DirectionModifier::SharpRight};
+ }
+ }
+ else
+ {
+ if (angularDeviation(left.turn.angle, 270) > angularDeviation(right.turn.angle, 270))
+ {
+ left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
+ right.turn.instruction = {right_type, DirectionModifier::Left};
+ }
+ else
+ {
+ left.turn.instruction = {left_type, DirectionModifier::Left};
+ right.turn.instruction = {right_type, DirectionModifier::SlightLeft};
+ }
+ }
+}
+
+std::vector<ConnectedRoad>
+TurnAnalysis::handleComplexTurn(const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection) const
+{
+ static int fallback_count = 0;
+ const std::size_t obvious_index = findObviousTurn(via_edge, intersection);
+ const auto fork_range = findFork(intersection);
+ std::size_t straightmost_turn = 0;
+ double straightmost_deviation = 180;
+ for (std::size_t i = 0; i < intersection.size(); ++i)
+ {
+ const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
+ if (deviation < straightmost_deviation)
+ {
+ straightmost_deviation = deviation;
+ straightmost_turn = i;
+ }
+ }
+
+ if (obvious_index != 0)
+ {
+ intersection[obvious_index].turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, intersection[obvious_index]);
+
+ // assign left/right turns
+ intersection = assignLeftTurns(via_edge, std::move(intersection), obvious_index + 1);
+ intersection = assignRightTurns(via_edge, std::move(intersection), obvious_index);
+ }
+ else if (fork_range.first != 0 && fork_range.second - fork_range.first <= 2) // found fork
+ {
+ if (fork_range.second - fork_range.first == 1)
+ {
+ auto &left = intersection[fork_range.second];
+ auto &right = intersection[fork_range.first];
+ const auto left_class =
+ node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class;
+ const auto right_class =
+ node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class;
+ if (canBeSeenAsFork(left_class, right_class))
+ assignFork(via_edge, left, right);
+ else if (getPriority(left_class) > getPriority(right_class))
+ {
+ right.turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, right);
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ DirectionModifier::SlightLeft};
+ }
+ else
+ {
+ left.turn.instruction =
+ getInstructionForObvious(intersection.size(), via_edge, left);
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ DirectionModifier::SlightRight};
+ }
+ }
+ else if (fork_range.second - fork_range.second == 2)
+ {
+ assignFork(via_edge, intersection[fork_range.second],
+ intersection[fork_range.first + 1], intersection[fork_range.first]);
+ }
+ // assign left/right turns
+ intersection = assignLeftTurns(via_edge, std::move(intersection), fork_range.second + 1);
+ intersection = assignRightTurns(via_edge, std::move(intersection), fork_range.first);
+ }
+ else if (straightmost_deviation < FUZZY_ANGLE_DIFFERENCE &&
+ !intersection[straightmost_turn].entry_allowed)
+ {
+ // invalid straight turn
+ intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn + 1);
+ intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn);
+ }
+ // no straight turn
+ else if (intersection[straightmost_turn].turn.angle > 180)
+ {
+ // at most three turns on either side
+ intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn);
+ intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn);
+ }
+ else if (intersection[straightmost_turn].turn.angle < 180)
+ {
+ intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn + 1);
+ intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn + 1);
+ }
+ else
+ {
+ if (fallback_count++ < 10)
+ {
+ const auto coord = localizer(node_based_graph.GetTarget(via_edge));
+ util::SimpleLogger().Write(logWARNING)
+ << "Resolved to keep fallback on complex turn assignment at "
+ << std::setprecision(12) << toFloating(coord.lat) << " " << toFloating(coord.lon)
+ << "Straightmost: " << straightmost_turn;
+ ;
+ for (const auto &road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ util::SimpleLogger().Write(logWARNING)
+ << "road: " << road.toString() << " Name: " << out_data.name_id
+ << " Road Class: " << (int)out_data.road_classification.road_class
+ << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
+ }
+ }
+ }
+ return intersection;
+}
+
+// Sets basic turn types as fallback for otherwise unhandled turns
+std::vector<ConnectedRoad> TurnAnalysis::setTurnTypes(const NodeID from,
+ const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection) const
+{
+ for (auto &road : intersection)
+ {
+ if (!road.entry_allowed)
+ continue;
+
+ const EdgeID onto_edge = road.turn.eid;
+ const NodeID to_node = node_based_graph.GetTarget(onto_edge);
+
+ road.turn.instruction = (from == to_node)
+ ? TurnInstruction{TurnType::Turn, DirectionModifier::UTurn}
+ : TurnInstruction{findBasicTurnType(via_edge, road),
+ getTurnDirection(road.turn.angle)};
+ }
+ return intersection;
+}
+
+// a
+// |
+// |
+// v
+// For an intersection from_node --via_edi--> turn_node ----> c
+// ^
+// |
+// |
+// b
+// This functions returns _all_ turns as if the graph was undirected.
+// That means we not only get (from_node, turn_node, c) in the above example
+// but also (from_node, turn_node, a), (from_node, turn_node, b). These turns are
+// marked as invalid and only needed for intersection classification.
+std::vector<ConnectedRoad> TurnAnalysis::getConnectedRoads(const NodeID from_node,
+ const EdgeID via_eid) const
+{
+ std::vector<ConnectedRoad> intersection;
+ const NodeID turn_node = node_based_graph.GetTarget(via_eid);
+ const NodeID only_restriction_to_node =
+ restriction_map.CheckForEmanatingIsOnlyTurn(from_node, turn_node);
+ const bool is_barrier_node = barrier_nodes.find(turn_node) != barrier_nodes.end();
+
+ bool has_uturn_edge = false;
+ for (const EdgeID onto_edge : node_based_graph.GetAdjacentEdgeRange(turn_node))
+ {
+ BOOST_ASSERT(onto_edge != SPECIAL_EDGEID);
+ const NodeID to_node = node_based_graph.GetTarget(onto_edge);
+
+ bool turn_is_valid =
+ // reverse edges are never valid turns because the resulting turn would look like this:
+ // from_node --via_edge--> turn_node <--onto_edge-- to_node
+ // however we need this for capture intersection shape for incoming one-ways
+ !node_based_graph.GetEdgeData(onto_edge).reversed &&
+ // we are not turning over a barrier
+ (!is_barrier_node || from_node == to_node) &&
+ // We are at an only_-restriction but not at the right turn.
+ (only_restriction_to_node == SPECIAL_NODEID || to_node == only_restriction_to_node) &&
+ // the turn is not restricted
+ !restriction_map.CheckIfTurnIsRestricted(from_node, turn_node, to_node);
+
+ auto angle = 0.;
+ if (from_node == to_node)
+ {
+ if (turn_is_valid && !is_barrier_node)
+ {
+ // we only add u-turns for dead-end streets.
+ if (node_based_graph.GetOutDegree(turn_node) > 1)
+ {
+ auto number_of_emmiting_bidirectional_edges = 0;
+ for (auto edge : node_based_graph.GetAdjacentEdgeRange(turn_node))
+ {
+ auto target = node_based_graph.GetTarget(edge);
+ auto reverse_edge = node_based_graph.FindEdge(target, turn_node);
+ BOOST_ASSERT(reverse_edge != SPECIAL_EDGEID);
+ if (!node_based_graph.GetEdgeData(reverse_edge).reversed)
+ {
+ ++number_of_emmiting_bidirectional_edges;
+ }
+ }
+ // is a dead-end
+ turn_is_valid = number_of_emmiting_bidirectional_edges <= 1;
+ }
+ }
+ has_uturn_edge = true;
+ BOOST_ASSERT(angle >= 0. && angle < std::numeric_limits<double>::epsilon());
+ }
+ else
+ {
+ // unpack first node of second segment if packed
+ const auto first_coordinate = getRepresentativeCoordinate(
+ from_node, turn_node, via_eid, INVERT, compressed_edge_container, node_info_list);
+ const auto third_coordinate = getRepresentativeCoordinate(
+ turn_node, to_node, onto_edge, !INVERT, compressed_edge_container, node_info_list);
+ angle = util::coordinate_calculation::computeAngle(
+ first_coordinate, node_info_list[turn_node], third_coordinate);
+ if (angle < std::numeric_limits<double>::epsilon())
+ has_uturn_edge = true;
+ }
+
+ intersection.push_back(ConnectedRoad(
+ TurnOperation{onto_edge, angle, {TurnType::Invalid, DirectionModifier::UTurn}},
+ turn_is_valid));
+ }
+
+ // We hit the case of a street leading into nothing-ness. Since the code here assumes that this
+ // will
+ // never happen we add an artificial invalid uturn in this case.
+ if (!has_uturn_edge)
+ {
+ intersection.push_back(
+ {TurnOperation{via_eid, 0., {TurnType::Invalid, DirectionModifier::UTurn}}, false});
+ }
+
+ const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second)
+ {
+ return first.turn.angle < second.turn.angle;
+ };
+ std::sort(std::begin(intersection), std::end(intersection), ByAngle);
+
+ BOOST_ASSERT(intersection[0].turn.angle >= 0. &&
+ intersection[0].turn.angle < std::numeric_limits<double>::epsilon());
+
+ return mergeSegregatedRoads(std::move(intersection));
+}
+
+/*
+ * Segregated Roads often merge onto a single intersection.
+ * While technically representing different roads, they are
+ * often looked at as a single road.
+ * Due to the merging, turn Angles seem off, wenn we compute them from the
+ * initial positions.
+ *
+ * b<b<b<b(1)<b<b<b
+ * aaaaa-b
+ * b>b>b>b(2)>b>b>b
+ *
+ * Would be seen as a slight turn going fro a to (2). A Sharp turn going from
+ * (1) to (2).
+ *
+ * In cases like these, we megre this segregated roads into a single road to
+ * end up with a case like:
+ *
+ * aaaaa-bbbbbb
+ *
+ * for the turn representation.
+ * Anything containing the first u-turn in a merge affects all other angles
+ * and is handled separately from all others.
+ */
+std::vector<ConnectedRoad>
+TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) const
+{
+ const auto getRight = [&](std::size_t index)
+ {
+ return (index + intersection.size() - 1) % intersection.size();
+ };
+
+ const auto mergable = [&](std::size_t first, std::size_t second) -> bool
+ {
+ const auto &first_data = node_based_graph.GetEdgeData(intersection[first].turn.eid);
+ const auto &second_data = node_based_graph.GetEdgeData(intersection[second].turn.eid);
+
+ return first_data.name_id != INVALID_NAME_ID && first_data.name_id == second_data.name_id &&
+ !first_data.roundabout && !second_data.roundabout &&
+ first_data.travel_mode == second_data.travel_mode &&
+ first_data.road_classification == second_data.road_classification &&
+ // compatible threshold
+ angularDeviation(intersection[first].turn.angle, intersection[second].turn.angle) <
+ 60 &&
+ first_data.reversed != second_data.reversed;
+ };
+
+ const auto merge = [](const ConnectedRoad &first, const ConnectedRoad &second) -> ConnectedRoad
+ {
+ if (!first.entry_allowed)
+ {
+ ConnectedRoad result = second;
+ result.turn.angle = (first.turn.angle + second.turn.angle) / 2;
+ if (first.turn.angle - second.turn.angle > 180)
+ result.turn.angle += 180;
+ if (result.turn.angle > 360)
+ result.turn.angle -= 360;
+
+ return result;
+ }
+ else
+ {
+ BOOST_ASSERT(!second.entry_allowed);
+ ConnectedRoad result = first;
+ result.turn.angle = (first.turn.angle + second.turn.angle) / 2;
+
+ if (first.turn.angle - second.turn.angle > 180)
+ result.turn.angle += 180;
+ if (result.turn.angle > 360)
+ result.turn.angle -= 360;
+
+ return result;
+ }
+ };
+ if (intersection.size() == 1)
+ return intersection;
+
+ // check for merges including the basic u-turn
+ // these result in an adjustment of all other angles
+ if (mergable(0, intersection.size() - 1))
+ {
+ // std::cout << "First merge" << std::endl;
+ const double correction_factor =
+ (360 - intersection[intersection.size() - 1].turn.angle) / 2;
+ for (std::size_t i = 1; i + 1 < intersection.size(); ++i)
+ intersection[i].turn.angle += correction_factor;
+ intersection[0] = merge(intersection.front(), intersection.back());
+ intersection[0].turn.angle = 0;
+ intersection.pop_back();
+ }
+ else if (mergable(0, 1))
+ {
+ // std::cout << "First merge" << std::endl;
+ const double correction_factor = (intersection[1].turn.angle) / 2;
+ for (std::size_t i = 2; i < intersection.size(); ++i)
+ intersection[i].turn.angle += correction_factor;
+ intersection[0] = merge(intersection[0], intersection[1]);
+ intersection[0].turn.angle = 0;
+ intersection.erase(intersection.begin() + 1);
+ }
+
+ // a merge including the first u-turn requres an adjustment of the turn angles
+ // therefore these are handled prior to this step
+ for (std::size_t index = 2; index < intersection.size(); ++index)
+ {
+ if (mergable(index, getRight(index)))
+ {
+ intersection[getRight(index)] =
+ merge(intersection[getRight(index)], intersection[index]);
+ intersection.erase(intersection.begin() + index);
+ --index;
+ }
+ }
+
+ const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second)
+ {
+ return first.turn.angle < second.turn.angle;
+ };
+ std::sort(std::begin(intersection), std::end(intersection), ByAngle);
+ return intersection;
+}
+
+void TurnAnalysis::assignFork(const EdgeID via_edge,
+ ConnectedRoad &left,
+ ConnectedRoad &right) const
+{
+ const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+ const bool low_priority_left = isLowPriorityRoadClass(
+ node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class);
+ const bool low_priority_right = isLowPriorityRoadClass(
+ node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class);
+ if ((angularDeviation(left.turn.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
+ angularDeviation(right.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE))
+ {
+ // left side is actually straight
+ const auto &out_data = node_based_graph.GetEdgeData(left.turn.eid);
+ if (requiresAnnouncement(in_data, out_data))
+ {
+ if (low_priority_right && !low_priority_left)
+ {
+ left.turn.instruction = getInstructionForObvious(3, via_edge, left);
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ DirectionModifier::SlightRight};
+ }
+ else
+ {
+ if (low_priority_left && !low_priority_right)
+ {
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ DirectionModifier::SlightLeft};
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ DirectionModifier::SlightRight};
+ }
+ else
+ {
+ left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
+ right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
+ }
+ }
+ }
+ else
+ {
+ left.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ DirectionModifier::SlightRight};
+ }
+ }
+ else if (angularDeviation(right.turn.angle, STRAIGHT_ANGLE) <
+ MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
+ angularDeviation(left.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
+ {
+ // right side is actually straight
+ const auto &out_data = node_based_graph.GetEdgeData(right.turn.eid);
+ if (angularDeviation(right.turn.angle, STRAIGHT_ANGLE) <
+ MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
+ angularDeviation(left.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
+ {
+ if (requiresAnnouncement(in_data, out_data))
+ {
+ if (low_priority_left && !low_priority_right)
+ {
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ DirectionModifier::SlightLeft};
+ right.turn.instruction = getInstructionForObvious(3, via_edge, right);
+ }
+ else
+ {
+ if (low_priority_right && !low_priority_left)
+ {
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ DirectionModifier::SlightLeft};
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ DirectionModifier::SlightRight};
+ }
+ else
+ {
+ right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
+ left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
+ }
+ }
+ }
+ else
+ {
+ right.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ DirectionModifier::SlightLeft};
+ }
+ }
+ }
+ else
+ {
+ // left side of fork
+ if (low_priority_right && !low_priority_left)
+ left.turn.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
+ else
+ {
+ if (low_priority_left && !low_priority_right)
+ left.turn.instruction = {TurnType::Turn, DirectionModifier::SlightLeft};
+ else
+ left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
+ }
+
+ // right side of fork
+ if (low_priority_left && !low_priority_right)
+ right.turn.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
+ else
+ {
+ if (low_priority_right && !low_priority_left)
+ right.turn.instruction = {TurnType::Turn, DirectionModifier::SlightRight};
+ else
+ right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
+ }
+ }
+}
+
+void TurnAnalysis::assignFork(const EdgeID via_edge,
+ ConnectedRoad &left,
+ ConnectedRoad ¢er,
+ ConnectedRoad &right) const
+{
+ // TODO handle low priority road classes in a reasonable way
+ if (left.entry_allowed && center.entry_allowed && right.entry_allowed)
+ {
+ left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
+ if (angularDeviation(center.turn.angle, 180) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+ {
+ const auto &in_data = node_based_graph.GetEdgeData(via_edge);
+ const auto &out_data = node_based_graph.GetEdgeData(center.turn.eid);
+ if (requiresAnnouncement(in_data, out_data))
+ {
+ center.turn.instruction = {TurnType::Fork, DirectionModifier::Straight};
+ }
+ else
+ {
+ center.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
+ }
+ }
+ else
+ {
+ center.turn.instruction = {TurnType::Fork, DirectionModifier::Straight};
+ }
+ right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
+ }
+ else if (left.entry_allowed)
+ {
+ if (right.entry_allowed)
+ assignFork(via_edge, left, right);
+ else if (center.entry_allowed)
+ assignFork(via_edge, left, center);
+ else
+ left.turn.instruction = {findBasicTurnType(via_edge, left),
+ getTurnDirection(left.turn.angle)};
+ }
+ else if (right.entry_allowed)
+ {
+ if (center.entry_allowed)
+ assignFork(via_edge, center, right);
+ else
+ right.turn.instruction = {findBasicTurnType(via_edge, right),
+ getTurnDirection(right.turn.angle)};
+ }
+ else
+ {
+ if (center.entry_allowed)
+ center.turn.instruction = {findBasicTurnType(via_edge, center),
+ getTurnDirection(center.turn.angle)};
+ }
+}
+
+std::size_t TurnAnalysis::findObviousTurn(const EdgeID via_edge,
+ const std::vector<ConnectedRoad> &intersection) const
+{
+ // no obvious road
+ if (intersection.size() == 1)
+ return 0;
+
+ // a single non u-turn is obvious
+ if (intersection.size() == 2)
+ return 1;
+
+ // at least three roads
+ std::size_t best = 0;
+ double best_deviation = 180;
+
+ std::size_t best_continue = 0;
+ double best_continue_deviation = 180;
+
+ const EdgeData &in_data = node_based_graph.GetEdgeData(via_edge);
+ for (std::size_t i = 1; i < intersection.size(); ++i)
+ {
+ const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
+ if (intersection[i].entry_allowed && deviation < best_deviation)
+ {
+ best_deviation = deviation;
+ best = i;
+ }
+
+ const auto out_data = node_based_graph.GetEdgeData(intersection[i].turn.eid);
+ if (intersection[i].entry_allowed && out_data.name_id == in_data.name_id &&
+ deviation < best_continue_deviation)
+ {
+ best_continue_deviation = deviation;
+ best_continue = i;
+ }
+ }
+
+ if (best == 0)
+ return 0;
+
+ if (best_deviation >= 2 * NARROW_TURN_ANGLE)
+ return 0;
+
+ // TODO incorporate road class in decision
+ if (best != 0 && best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
+ {
+ return best;
+ }
+
+ // has no obvious continued road
+ if (best_continue == 0 || true)
+ {
+ // Find left/right deviation
+ const double left_deviation = angularDeviation(
+ intersection[(best + 1) % intersection.size()].turn.angle, STRAIGHT_ANGLE);
+ const double right_deviation =
+ angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE);
+
+ if (best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
+ std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
+ return best;
+
+ // other narrow turns?
+ if (angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE) <=
+ FUZZY_ANGLE_DIFFERENCE)
+ return 0;
+ if (angularDeviation(intersection[(best + 1) % intersection.size()].turn.angle,
+ STRAIGHT_ANGLE) <= FUZZY_ANGLE_DIFFERENCE)
+ return 0;
+
+ // Well distinct turn that is nearly straight
+ if (left_deviation / best_deviation >= DISTINCTION_RATIO &&
+ right_deviation / best_deviation >= DISTINCTION_RATIO)
+ {
+ return best;
+ }
+ }
+
+ return 0; // no obvious turn
+}
+
+std::pair<std::size_t, std::size_t>
+TurnAnalysis::findFork(const std::vector<ConnectedRoad> &intersection) const
+{
+
+ std::size_t best = 0;
+ double best_deviation = 180;
+
+ // TODO handle road classes
+ for (std::size_t i = 1; i < intersection.size(); ++i)
+ {
+ const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
+ if (intersection[i].entry_allowed && deviation < best_deviation)
+ {
+ best_deviation = deviation;
+ best = i;
+ }
+ }
+
+ if (best_deviation <= NARROW_TURN_ANGLE)
+ {
+ std::size_t left = best, right = best;
+ while (left + 1 < intersection.size() &&
+ angularDeviation(intersection[left].turn.angle, intersection[left + 1].turn.angle) <
+ NARROW_TURN_ANGLE)
+ ++left;
+ while (right > 1 &&
+ angularDeviation(intersection[right].turn.angle,
+ intersection[right - 1].turn.angle) < NARROW_TURN_ANGLE)
+ --right;
+
+ // TODO check whether 2*NARROW_TURN is too large
+ if (right < left &&
+ angularDeviation(intersection[left].turn.angle,
+ intersection[(left + 1) % intersection.size()].turn.angle) >=
+ 2 * NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[right].turn.angle, intersection[right - 1].turn.angle) >=
+ 2 * NARROW_TURN_ANGLE)
+ return std::make_pair(right, left);
+ }
+ return std::make_pair(0llu, 0llu);
+}
+
+// Can only assign three turns
+std::vector<ConnectedRoad> TurnAnalysis::assignLeftTurns(const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection,
+ const std::size_t starting_at) const
+{
+ const auto count_valid = [&intersection, starting_at]()
+ {
+ std::size_t count = 0;
+ for (std::size_t i = starting_at; i < intersection.size(); ++i)
+ if (intersection[i].entry_allowed)
+ ++count;
+ return count;
+ };
+ if (starting_at == intersection.size() || count_valid() == 0)
+ return intersection;
+ // handle single turn
+ if (intersection.size() - starting_at == 1)
+ {
+ if (!intersection[starting_at].entry_allowed)
+ return intersection;
+
+ if (angularDeviation(intersection[starting_at].turn.angle, STRAIGHT_ANGLE) >
+ NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[starting_at].turn.angle, 0) > NARROW_TURN_ANGLE)
+ {
+ // assign left turn
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]), DirectionModifier::Left};
+ }
+ else if (angularDeviation(intersection[starting_at].turn.angle, STRAIGHT_ANGLE) <=
+ NARROW_TURN_ANGLE)
+ {
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]),
+ DirectionModifier::SlightLeft};
+ }
+ else
+ {
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]),
+ DirectionModifier::SharpLeft};
+ }
+ }
+ // two turns on at the side
+ else if (intersection.size() - starting_at == 2)
+ {
+ const auto first_direction = getTurnDirection(intersection[starting_at].turn.angle);
+ const auto second_direction = getTurnDirection(intersection[starting_at + 1].turn.angle);
+ if (first_direction == second_direction)
+ {
+ // conflict
+ handleDistinctConflict(via_edge, intersection[starting_at + 1],
+ intersection[starting_at]);
+ }
+ else
+ {
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
+ intersection[starting_at + 1].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
+ }
+ }
+ else if (intersection.size() - starting_at == 3)
+ {
+ const auto first_direction = getTurnDirection(intersection[starting_at].turn.angle);
+ const auto second_direction = getTurnDirection(intersection[starting_at + 1].turn.angle);
+ const auto third_direction = getTurnDirection(intersection[starting_at + 2].turn.angle);
+ if (first_direction != second_direction && second_direction != third_direction)
+ {
+ // implies first != third, based on the angles and clockwise order
+ if (intersection[starting_at].entry_allowed)
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
+ if (intersection[starting_at + 1].entry_allowed)
+ intersection[starting_at + 1].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
+ if (intersection[starting_at + 2].entry_allowed)
+ intersection[starting_at + 2].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 2]), second_direction};
+ }
+ else if (2 >= (intersection[starting_at].entry_allowed +
+ intersection[starting_at + 1].entry_allowed +
+ intersection[starting_at + 2].entry_allowed))
+ {
+ // at least one invalid turn
+ if (!intersection[starting_at].entry_allowed)
+ {
+ handleDistinctConflict(via_edge, intersection[starting_at + 2],
+ intersection[starting_at + 1]);
+ }
+ else if (!intersection[starting_at + 1].entry_allowed)
+ {
+ handleDistinctConflict(via_edge, intersection[starting_at + 2],
+ intersection[starting_at]);
+ }
+ else
+ {
+ handleDistinctConflict(via_edge, intersection[starting_at + 1],
+ intersection[starting_at]);
+ }
+ }
+ else if (intersection[starting_at].entry_allowed &&
+ intersection[starting_at + 1].entry_allowed &&
+ intersection[starting_at + 2].entry_allowed &&
+ angularDeviation(intersection[starting_at].turn.angle,
+ intersection[starting_at + 1].turn.angle) >= NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[starting_at + 1].turn.angle,
+ intersection[starting_at + 2].turn.angle) >= NARROW_TURN_ANGLE)
+ {
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]),
+ DirectionModifier::SlightLeft};
+ intersection[starting_at + 1].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 1]),
+ DirectionModifier::Left};
+ intersection[starting_at + 2].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 2]),
+ DirectionModifier::SharpLeft};
+ }
+ else if (intersection[starting_at].entry_allowed &&
+ intersection[starting_at + 1].entry_allowed &&
+ intersection[starting_at + 2].entry_allowed &&
+ ((first_direction == second_direction && second_direction == third_direction) ||
+ (third_direction == second_direction &&
+ angularDeviation(intersection[starting_at].turn.angle,
+ intersection[starting_at + 1].turn.angle) < GROUP_ANGLE) ||
+ (second_direction == first_direction &&
+ angularDeviation(intersection[starting_at + 1].turn.angle,
+ intersection[starting_at + 2].turn.angle) < GROUP_ANGLE)))
+ {
+ intersection[starting_at].turn.instruction = {
+ detail::isRampClass(intersection[starting_at].turn.eid, node_based_graph)
+ ? FirstRamp
+ : FirstTurn,
+ second_direction};
+ intersection[starting_at + 1].turn.instruction = {
+ detail::isRampClass(intersection[starting_at + 1].turn.eid, node_based_graph)
+ ? SecondRamp
+ : SecondTurn,
+ second_direction};
+ intersection[starting_at + 2].turn.instruction = {
+ detail::isRampClass(intersection[starting_at + 2].turn.eid, node_based_graph)
+ ? ThirdRamp
+ : ThirdTurn,
+ second_direction};
+ }
+ else if (intersection[starting_at].entry_allowed &&
+ intersection[starting_at + 1].entry_allowed &&
+ intersection[starting_at + 2].entry_allowed &&
+ ((third_direction == second_direction &&
+ angularDeviation(intersection[starting_at].turn.angle,
+ intersection[starting_at + 1].turn.angle) >= GROUP_ANGLE) ||
+ (second_direction == first_direction &&
+ angularDeviation(intersection[starting_at + 1].turn.angle,
+ intersection[starting_at + 2].turn.angle) >= GROUP_ANGLE)))
+ {
+ // conflict one side with an additional very sharp turn
+ if (angularDeviation(intersection[starting_at + 1].turn.angle,
+ intersection[starting_at + 2].turn.angle) >= GROUP_ANGLE)
+ {
+ handleDistinctConflict(via_edge, intersection[starting_at + 1],
+ intersection[starting_at]);
+ intersection[starting_at + 2].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 2]), third_direction};
+ }
+ else
+ {
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
+ handleDistinctConflict(via_edge, intersection[starting_at + 2],
+ intersection[starting_at + 1]);
+ }
+ }
+
+ else if ((first_direction == second_direction &&
+ intersection[starting_at].entry_allowed !=
+ intersection[starting_at + 1].entry_allowed) ||
+ (second_direction == third_direction &&
+ intersection[starting_at + 1].entry_allowed !=
+ intersection[starting_at + 2].entry_allowed))
+ {
+ // no conflict, due to conflict being restricted to valid/invalid
+ if (intersection[starting_at].entry_allowed)
+ intersection[starting_at].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
+ if (intersection[starting_at + 1].entry_allowed)
+ intersection[starting_at + 1].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
+ if (intersection[starting_at + 2].entry_allowed)
+ intersection[starting_at + 2].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[starting_at + 2]), third_direction};
+ }
+ else
+ {
+ auto coord = localizer(node_based_graph.GetTarget(via_edge));
+ util::SimpleLogger().Write(logWARNING)
+ << "Reached fallback for left turns, size 3: " << std::setprecision(12)
+ << toFloating(coord.lat) << " " << toFloating(coord.lon);
+ for (const auto road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ util::SimpleLogger().Write(logWARNING)
+ << "\troad: " << road.toString() << " Name: " << out_data.name_id
+ << " Road Class: " << (int)out_data.road_classification.road_class
+ << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
+ }
+
+ for (std::size_t i = starting_at; i < intersection.size(); ++i)
+ if (intersection[i].entry_allowed)
+ intersection[i].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[i]),
+ getTurnDirection(intersection[i].turn.angle)};
+ }
+ }
+ else if (intersection.size() - starting_at == 4)
+ {
+ if (intersection[starting_at].entry_allowed)
+ intersection[starting_at].turn.instruction = {
+ detail::isRampClass(intersection[starting_at].turn.eid, node_based_graph)
+ ? FirstRamp
+ : FirstTurn,
+ DirectionModifier::Left};
+ if (intersection[starting_at + 1].entry_allowed)
+ intersection[starting_at + 1].turn.instruction = {
+ detail::isRampClass(intersection[starting_at + 1].turn.eid, node_based_graph)
+ ? SecondRamp
+ : SecondTurn,
+ DirectionModifier::Left};
+ if (intersection[starting_at + 2].entry_allowed)
+ intersection[starting_at + 2].turn.instruction = {
+ detail::isRampClass(intersection[starting_at + 2].turn.eid, node_based_graph)
+ ? ThirdRamp
+ : ThirdTurn,
+ DirectionModifier::Left};
+ if (intersection[starting_at + 3].entry_allowed)
+ intersection[starting_at + 3].turn.instruction = {
+ detail::isRampClass(intersection[starting_at + 3].turn.eid, node_based_graph)
+ ? FourthRamp
+ : FourthTurn,
+ DirectionModifier::Left};
+ }
+ else
+ {
+ for (auto &road : intersection)
+ {
+ if (!road.entry_allowed)
+ continue;
+ road.turn.instruction = {detail::isRampClass(road.turn.eid, node_based_graph) ? Ramp
+ : Turn,
+ getTurnDirection(road.turn.angle)};
+ }
+ /*
+ auto coord = localizer(node_based_graph.GetTarget(via_edge));
+ util::SimpleLogger().Write(logWARNING)
+ << "Reached fallback for left turns (" << starting_at << ") " << std::setprecision(12)
+ << toFloating(coord.lat) << " " << toFloating(coord.lon);
+ for (const auto road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ util::SimpleLogger().Write(logWARNING)
+ << "\troad: " << road.toString() << " Name: " << out_data.name_id
+ << " Road Class: " << (int)out_data.road_classification.road_class
+ << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
+ }
+ */
+ }
+ return intersection;
+}
+
+// can only assign three turns
+std::vector<ConnectedRoad> TurnAnalysis::assignRightTurns(const EdgeID via_edge,
+ std::vector<ConnectedRoad> intersection,
+ const std::size_t up_to) const
+{
+ BOOST_ASSERT(up_to <= intersection.size());
+ const auto count_valid = [&intersection, up_to]()
+ {
+ std::size_t count = 0;
+ for (std::size_t i = 1; i < up_to; ++i)
+ if (intersection[i].entry_allowed)
+ ++count;
+ return count;
+ };
+ if (up_to <= 1 || count_valid() == 0)
+ return intersection;
+ // handle single turn
+ if (up_to == 2)
+ {
+ if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) > NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[1].turn.angle, 0) > NARROW_TURN_ANGLE)
+ {
+ // assign left turn
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ DirectionModifier::Right};
+ }
+ else if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <= NARROW_TURN_ANGLE)
+ {
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ DirectionModifier::SlightRight};
+ }
+ else
+ {
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ DirectionModifier::SharpRight};
+ }
+ }
+ else if (up_to == 3)
+ {
+ const auto first_direction = getTurnDirection(intersection[1].turn.angle);
+ const auto second_direction = getTurnDirection(intersection[2].turn.angle);
+ if (first_direction == second_direction)
+ {
+ // conflict
+ handleDistinctConflict(via_edge, intersection[2], intersection[1]);
+ }
+ else
+ {
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ first_direction};
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ second_direction};
+ }
+ }
+ else if (up_to == 4)
+ {
+ const auto first_direction = getTurnDirection(intersection[1].turn.angle);
+ const auto second_direction = getTurnDirection(intersection[2].turn.angle);
+ const auto third_direction = getTurnDirection(intersection[3].turn.angle);
+ if (first_direction != second_direction && second_direction != third_direction)
+ {
+ if (intersection[1].entry_allowed)
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ first_direction};
+ if (intersection[2].entry_allowed)
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ second_direction};
+ if (intersection[3].entry_allowed)
+ intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
+ third_direction};
+ }
+ else if (2 >= (intersection[1].entry_allowed + intersection[2].entry_allowed +
+ intersection[3].entry_allowed))
+ {
+ // at least a single invalid
+ if (!intersection[3].entry_allowed)
+ {
+ handleDistinctConflict(via_edge, intersection[2], intersection[1]);
+ }
+ else if (!intersection[1].entry_allowed)
+ {
+ handleDistinctConflict(via_edge, intersection[3], intersection[2]);
+ }
+ else // handles one-valid as well as two valid (1,3)
+ {
+ handleDistinctConflict(via_edge, intersection[3], intersection[1]);
+ }
+ }
+
+ else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
+ intersection[3].entry_allowed &&
+ angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >=
+ NARROW_TURN_ANGLE &&
+ angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
+ NARROW_TURN_ANGLE)
+ {
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ DirectionModifier::SharpRight};
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ DirectionModifier::Right};
+ intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
+ DirectionModifier::SlightRight};
+ }
+ else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
+ intersection[3].entry_allowed &&
+ ((first_direction == second_direction && second_direction == third_direction) ||
+ (first_direction == second_direction &&
+ angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) <
+ GROUP_ANGLE) ||
+ (second_direction == third_direction &&
+ angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) <
+ GROUP_ANGLE)))
+ {
+ intersection[1].turn.instruction = {
+ detail::isRampClass(intersection[1].turn.eid, node_based_graph) ? ThirdRamp
+ : ThirdTurn,
+ second_direction};
+ intersection[2].turn.instruction = {
+ detail::isRampClass(intersection[2].turn.eid, node_based_graph) ? SecondRamp
+ : SecondTurn,
+ second_direction};
+ intersection[3].turn.instruction = {
+ detail::isRampClass(intersection[3].turn.eid, node_based_graph) ? FirstRamp
+ : FirstTurn,
+ second_direction};
+ }
+ else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
+ intersection[3].entry_allowed &&
+ ((first_direction == second_direction &&
+ angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
+ GROUP_ANGLE) ||
+ (second_direction == third_direction &&
+ angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >=
+ GROUP_ANGLE)))
+ {
+ if (angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
+ GROUP_ANGLE)
+ {
+ handleDistinctConflict(via_edge, intersection[2], intersection[1]);
+ intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
+ third_direction};
+ }
+ else
+ {
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ first_direction};
+ handleDistinctConflict(via_edge, intersection[3], intersection[2]);
+ }
+ }
+ else if ((first_direction == second_direction &&
+ intersection[1].entry_allowed != intersection[2].entry_allowed) ||
+ (second_direction == third_direction &&
+ intersection[2].entry_allowed != intersection[3].entry_allowed))
+ {
+ if (intersection[1].entry_allowed)
+ intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
+ first_direction};
+ if (intersection[2].entry_allowed)
+ intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
+ second_direction};
+ if (intersection[3].entry_allowed)
+ intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
+ third_direction};
+ }
+ else
+ {
+ auto coord = localizer(node_based_graph.GetTarget(via_edge));
+ util::SimpleLogger().Write(logWARNING)
+ << "Reached fallback for right turns, size 3: " << std::setprecision(12)
+ << toFloating(coord.lat) << " " << toFloating(coord.lon)
+ << " Valids: " << (intersection[1].entry_allowed + intersection[2].entry_allowed +
+ intersection[3].entry_allowed);
+ for (const auto road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ util::SimpleLogger().Write(logWARNING)
+ << "\troad: " << road.toString() << " Name: " << out_data.name_id
+ << " Road Class: " << (int)out_data.road_classification.road_class
+ << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
+ }
+
+ for (std::size_t i = 1; i < up_to; ++i)
+ if (intersection[i].entry_allowed)
+ intersection[i].turn.instruction = {
+ findBasicTurnType(via_edge, intersection[i]),
+ getTurnDirection(intersection[i].turn.angle)};
+ }
+ }
+ else if (up_to == 5)
+ {
+ if (intersection[4].entry_allowed)
+ intersection[4].turn.instruction = {
+ detail::isRampClass(intersection[4].turn.eid, node_based_graph) ? FirstRamp
+ : FirstTurn,
+ DirectionModifier::Right};
+ if (intersection[3].entry_allowed)
+ intersection[3].turn.instruction = {
+ detail::isRampClass(intersection[3].turn.eid, node_based_graph) ? SecondRamp
+ : SecondTurn,
+ DirectionModifier::Right};
+ if (intersection[2].entry_allowed)
+ intersection[2].turn.instruction = {
+ detail::isRampClass(intersection[2].turn.eid, node_based_graph) ? ThirdRamp
+ : ThirdTurn,
+ DirectionModifier::Right};
+ if (intersection[1].entry_allowed)
+ intersection[1].turn.instruction = {
+ detail::isRampClass(intersection[1].turn.eid, node_based_graph) ? FourthRamp
+ : FourthTurn,
+ DirectionModifier::Right};
+ }
+ else
+ {
+ for (std::size_t i = 1; i < up_to; ++i)
+ {
+ auto &road = intersection[i];
+ if (!road.entry_allowed)
+ continue;
+ road.turn.instruction = {detail::isRampClass(road.turn.eid, node_based_graph) ? Ramp
+ : Turn,
+ getTurnDirection(road.turn.angle)};
+ }
+
+ /*
+ auto coord = localizer(node_based_graph.GetTarget(via_edge));
+ util::SimpleLogger().Write(logWARNING)
+ << "Reached fallback for right turns (" << up_to << ") " << std::setprecision(12)
+ << toFloating(coord.lat) << " " << toFloating(coord.lon);
+ for (const auto road : intersection)
+ {
+ const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
+ util::SimpleLogger().Write(logWARNING)
+ << "\troad: " << road.toString() << " Name: " << out_data.name_id
+ << " Road Class: " << (int)out_data.road_classification.road_class
+ << " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
+ }
+ */
+ }
+ return intersection;
+}
+
+} // namespace guidance
+} // namespace extractor
+} // namespace osrm
diff --git a/data_structures/raster_source.cpp b/src/extractor/raster_source.cpp
similarity index 59%
rename from data_structures/raster_source.cpp
rename to src/extractor/raster_source.cpp
index 9e880a2..16e41f9 100644
--- a/data_structures/raster_source.cpp
+++ b/src/extractor/raster_source.cpp
@@ -1,39 +1,15 @@
-/*
+#include "extractor/raster_source.hpp"
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "raster_source.hpp"
-
-#include "../util/simple_logger.hpp"
-#include "../util/timing_util.hpp"
-
-#include <osrm/coordinate.hpp>
+#include "util/simple_logger.hpp"
+#include "util/timing_util.hpp"
#include <cmath>
+namespace osrm
+{
+namespace extractor
+{
+
RasterSource::RasterSource(RasterGrid _raster_data,
std::size_t _width,
std::size_t _height,
@@ -106,28 +82,28 @@ int SourceContainer::loadRasterSource(const std::string &path_string,
std::size_t nrows,
std::size_t ncols)
{
- const auto _xmin = static_cast<int>(xmin * COORDINATE_PRECISION);
- const auto _xmax = static_cast<int>(xmax * COORDINATE_PRECISION);
- const auto _ymin = static_cast<int>(ymin * COORDINATE_PRECISION);
- const auto _ymax = static_cast<int>(ymax * COORDINATE_PRECISION);
+ const auto _xmin = static_cast<int>(util::toFixed(util::FloatLongitude(xmin)));
+ const auto _xmax = static_cast<int>(util::toFixed(util::FloatLongitude(xmax)));
+ const auto _ymin = static_cast<int>(util::toFixed(util::FloatLatitude(ymin)));
+ const auto _ymax = static_cast<int>(util::toFixed(util::FloatLatitude(ymax)));
const auto itr = LoadedSourcePaths.find(path_string);
if (itr != LoadedSourcePaths.end())
{
- SimpleLogger().Write() << "[source loader] Already loaded source '" << path_string
- << "' at source_id " << itr->second;
+ util::SimpleLogger().Write() << "[source loader] Already loaded source '" << path_string
+ << "' at source_id " << itr->second;
return itr->second;
}
int source_id = static_cast<int>(LoadedSources.size());
- SimpleLogger().Write() << "[source loader] Loading from " << path_string << " ... ";
+ util::SimpleLogger().Write() << "[source loader] Loading from " << path_string << " ... ";
TIMER_START(loading_source);
boost::filesystem::path filepath(path_string);
if (!boost::filesystem::exists(filepath))
{
- throw osrm::exception("error reading: no such path");
+ throw util::exception("error reading: no such path");
}
RasterGrid rasterData{filepath, ncols, nrows};
@@ -137,42 +113,47 @@ int SourceContainer::loadRasterSource(const std::string &path_string,
LoadedSourcePaths.emplace(path_string, source_id);
LoadedSources.push_back(std::move(source));
- SimpleLogger().Write() << "[source loader] ok, after " << TIMER_SEC(loading_source) << "s";
+ util::SimpleLogger().Write() << "[source loader] ok, after " << TIMER_SEC(loading_source)
+ << "s";
return source_id;
}
// External function for looking up nearest data point from a specified source
-RasterDatum SourceContainer::getRasterDataFromSource(unsigned int source_id, int lon, int lat)
+RasterDatum SourceContainer::getRasterDataFromSource(unsigned int source_id, double lon, double lat)
{
if (LoadedSources.size() < source_id + 1)
{
- throw osrm::exception("error reading: no such loaded source");
+ throw util::exception("error reading: no such loaded source");
}
- BOOST_ASSERT(lat < (90 * COORDINATE_PRECISION));
- BOOST_ASSERT(lat > (-90 * COORDINATE_PRECISION));
- BOOST_ASSERT(lon < (180 * COORDINATE_PRECISION));
- BOOST_ASSERT(lon > (-180 * COORDINATE_PRECISION));
+ BOOST_ASSERT(lat < 90);
+ BOOST_ASSERT(lat > -90);
+ BOOST_ASSERT(lon < 180);
+ BOOST_ASSERT(lon > -180);
const auto &found = LoadedSources[source_id];
- return found.getRasterData(lon, lat);
+ return found.getRasterData(static_cast<int>(util::toFixed(util::FloatLongitude(lon))),
+ static_cast<int>(util::toFixed(util::FloatLatitude(lat))));
}
// External function for looking up interpolated data from a specified source
RasterDatum
-SourceContainer::getRasterInterpolateFromSource(unsigned int source_id, int lon, int lat)
+SourceContainer::getRasterInterpolateFromSource(unsigned int source_id, double lon, double lat)
{
if (LoadedSources.size() < source_id + 1)
{
- throw osrm::exception("error reading: no such loaded source");
+ throw util::exception("error reading: no such loaded source");
}
- BOOST_ASSERT(lat < (90 * COORDINATE_PRECISION));
- BOOST_ASSERT(lat > (-90 * COORDINATE_PRECISION));
- BOOST_ASSERT(lon < (180 * COORDINATE_PRECISION));
- BOOST_ASSERT(lon > (-180 * COORDINATE_PRECISION));
+ BOOST_ASSERT(lat < 90);
+ BOOST_ASSERT(lat > -90);
+ BOOST_ASSERT(lon < 180);
+ BOOST_ASSERT(lon > -180);
const auto &found = LoadedSources[source_id];
- return found.getRasterInterpolate(lon, lat);
+ return found.getRasterInterpolate(static_cast<int>(util::toFixed(util::FloatLongitude(lon))),
+ static_cast<int>(util::toFixed(util::FloatLatitude(lat))));
+}
+}
}
diff --git a/data_structures/restriction_map.cpp b/src/extractor/restriction_map.cpp
similarity index 78%
rename from data_structures/restriction_map.cpp
rename to src/extractor/restriction_map.cpp
index eb685be..d41b1c4 100644
--- a/data_structures/restriction_map.cpp
+++ b/src/extractor/restriction_map.cpp
@@ -1,31 +1,9 @@
-/*
+#include "extractor/restriction_map.hpp"
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "restriction_map.hpp"
+namespace osrm
+{
+namespace extractor
+{
RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_list) : m_count(0)
{
@@ -42,7 +20,8 @@ RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_l
m_no_turn_via_node_set.insert(restriction.via.node);
// This explicit downcasting is also OK for the same reason.
- RestrictionSource restriction_source = {static_cast<NodeID>(restriction.from.node), static_cast<NodeID>(restriction.via.node)};
+ RestrictionSource restriction_source = {static_cast<NodeID>(restriction.from.node),
+ static_cast<NodeID>(restriction.via.node)};
std::size_t index;
auto restriction_iter = m_restriction_map.find(restriction_source);
@@ -176,9 +155,7 @@ bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
// check of node is the start of any restriction
bool RestrictionMap::IsSourceNode(const NodeID node) const
{
- if (m_restriction_start_nodes.find(node) == m_restriction_start_nodes.end())
- {
- return false;
- }
- return true;
+ return m_restriction_start_nodes.find(node) != m_restriction_start_nodes.end();
+}
+}
}
diff --git a/extractor/restriction_parser.cpp b/src/extractor/restriction_parser.cpp
similarity index 63%
rename from extractor/restriction_parser.cpp
rename to src/extractor/restriction_parser.cpp
index afb1947..b56af20 100644
--- a/extractor/restriction_parser.cpp
+++ b/src/extractor/restriction_parser.cpp
@@ -1,256 +1,213 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "restriction_parser.hpp"
-#include "extraction_way.hpp"
-
-#include "../data_structures/external_memory_node.hpp"
-#include "../util/lua_util.hpp"
-#include "../util/osrm_exception.hpp"
-#include "../util/simple_logger.hpp"
-
-#include <boost/algorithm/string.hpp>
-#include <boost/algorithm/string/regex.hpp>
-#include <boost/algorithm/string/predicate.hpp>
-#include <boost/ref.hpp>
-#include <boost/regex.hpp>
-#include <boost/optional/optional.hpp>
-
-#include <osmium/osm.hpp>
-#include <osmium/tags/regex_filter.hpp>
-
-#include <algorithm>
-#include <iterator>
-
-namespace
-{
-int lua_error_callback(lua_State *lua_state)
-{
- std::string error_msg = lua_tostring(lua_state, -1);
- throw osrm::exception("ERROR occured in profile script:\n" + error_msg);
-}
-}
-
-RestrictionParser::RestrictionParser(lua_State *lua_state) : use_turn_restrictions(true)
-{
- ReadUseRestrictionsSetting(lua_state);
-
- if (use_turn_restrictions)
- {
- ReadRestrictionExceptions(lua_state);
- }
-}
-
-void RestrictionParser::ReadUseRestrictionsSetting(lua_State *lua_state)
-{
- if (0 == luaL_dostring(lua_state, "return use_turn_restrictions\n") &&
- lua_isboolean(lua_state, -1))
- {
- use_turn_restrictions = lua_toboolean(lua_state, -1);
- }
-
- if (use_turn_restrictions)
- {
- SimpleLogger().Write() << "Using turn restrictions";
- }
- else
- {
- SimpleLogger().Write() << "Ignoring turn restrictions";
- }
-}
-
-void RestrictionParser::ReadRestrictionExceptions(lua_State *lua_state)
-{
- if (lua_function_exists(lua_state, "get_exceptions"))
- {
- luabind::set_pcall_callback(&lua_error_callback);
- // get list of turn restriction exceptions
- luabind::call_function<void>(lua_state, "get_exceptions",
- boost::ref(restriction_exceptions));
- const unsigned exception_count = restriction_exceptions.size();
- SimpleLogger().Write() << "Found " << exception_count
- << " exceptions to turn restrictions:";
- for (const std::string &str : restriction_exceptions)
- {
- SimpleLogger().Write() << " " << str;
- }
- }
- else
- {
- SimpleLogger().Write() << "Found no exceptions to turn restrictions";
- }
-}
-
-/**
- * Tries to parse an relation as turn restriction. This can fail for a number of
- * reasons, this the return type is a boost::optional<T>.
- *
- * Some restrictions can also be ignored: See the ```get_exceptions``` function
- * in the corresponding profile.
- */
-boost::optional<InputRestrictionContainer>
-RestrictionParser::TryParse(const osmium::Relation &relation) const
-{
- // return if turn restrictions should be ignored
- if (!use_turn_restrictions)
- {
- return {};
- }
-
- osmium::tags::KeyPrefixFilter filter(false);
- filter.add(true, "restriction");
-
- const osmium::TagList &tag_list = relation.tags();
-
- osmium::tags::KeyPrefixFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end());
- osmium::tags::KeyPrefixFilter::iterator fi_end(filter, tag_list.end(), tag_list.end());
-
- // if it's a restriction, continue;
- if (std::distance(fi_begin, fi_end) == 0)
- {
- return {};
- }
-
- // check if the restriction should be ignored
- const char *except = relation.get_value_by_key("except");
- if (except != nullptr && ShouldIgnoreRestriction(except))
- {
- return {};
- }
-
- bool is_only_restriction = false;
-
- for (; fi_begin != fi_end; ++fi_begin)
- {
- const std::string key(fi_begin->key());
- const std::string value(fi_begin->value());
-
- if (value.find("only_") == 0)
- {
- is_only_restriction = true;
- }
-
- // if the "restriction*" key is longer than 11 chars, it is a conditional exception (i.e.
- // "restriction:<transportation_type>")
- if (key.size() > 11)
- {
- const auto ex_suffix = [&](const std::string &exception)
- {
- return boost::algorithm::ends_with(key, exception);
- };
- bool is_actually_restricted =
- std::any_of(begin(restriction_exceptions), end(restriction_exceptions), ex_suffix);
-
- if (!is_actually_restricted)
- {
- return {};
- }
- }
- }
-
- InputRestrictionContainer restriction_container(is_only_restriction);
-
- for (const auto &member : relation.members())
- {
- const char *role = member.role();
- if (strcmp("from", role) != 0 && strcmp("to", role) != 0 && strcmp("via", role) != 0)
- {
- continue;
- }
-
- switch (member.type())
- {
- case osmium::item_type::node:
- // Make sure nodes appear only in the role if a via node
- if (0 == strcmp("from", role) || 0 == strcmp("to", role))
- {
- continue;
- }
- BOOST_ASSERT(0 == strcmp("via", role));
-
- // set via node id
- restriction_container.restriction.via.node = member.ref();
- break;
-
- case osmium::item_type::way:
- BOOST_ASSERT(0 == strcmp("from", role) || 0 == strcmp("to", role) ||
- 0 == strcmp("via", role));
- if (0 == strcmp("from", role))
- {
- restriction_container.restriction.from.way = member.ref();
- }
- else if (0 == strcmp("to", role))
- {
- restriction_container.restriction.to.way = member.ref();
- }
- // else if (0 == strcmp("via", role))
- // {
- // not yet suppported
- // restriction_container.restriction.via.way = member.ref();
- // }
- break;
- case osmium::item_type::relation:
- // not yet supported, but who knows what the future holds...
- break;
- default:
- // shouldn't ever happen
- break;
- }
- }
- return boost::make_optional(std::move(restriction_container));
-}
-
-bool RestrictionParser::ShouldIgnoreRestriction(const std::string &except_tag_string) const
-{
- // should this restriction be ignored? yes if there's an overlap between:
- // a) the list of modes in the except tag of the restriction
- // (except_tag_string), eg: except=bus;bicycle
- // b) the lua profile defines a hierachy of modes,
- // eg: [access, vehicle, bicycle]
-
- if (except_tag_string.empty())
- {
- return false;
- }
-
- // Be warned, this is quadratic work here, but we assume that
- // only a few exceptions are actually defined.
- std::vector<std::string> exceptions;
- boost::algorithm::split_regex(exceptions, except_tag_string, boost::regex("[;][ ]*"));
-
- return std::any_of(std::begin(exceptions), std::end(exceptions),
- [&](const std::string ¤t_string)
- {
- if (std::end(restriction_exceptions) !=
- std::find(std::begin(restriction_exceptions),
- std::end(restriction_exceptions), current_string))
- {
- return true;
- }
- return false;
- });
-}
+#include "extractor/restriction_parser.hpp"
+#include "extractor/profile_properties.hpp"
+
+#include "extractor/external_memory_node.hpp"
+#include "util/lua_util.hpp"
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/regex.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/optional/optional.hpp>
+#include <boost/ref.hpp>
+#include <boost/regex.hpp>
+
+#include <osmium/osm.hpp>
+#include <osmium/tags/regex_filter.hpp>
+
+#include <algorithm>
+#include <iterator>
+
+namespace osrm
+{
+namespace extractor
+{
+
+namespace
+{
+int luaErrorCallback(lua_State *lua_state)
+{
+ std::string error_msg = lua_tostring(lua_state, -1);
+ throw util::exception("ERROR occurred in profile script:\n" + error_msg);
+}
+}
+
+RestrictionParser::RestrictionParser(lua_State *lua_state, const ProfileProperties &properties)
+ : use_turn_restrictions(properties.use_turn_restrictions)
+{
+ if (use_turn_restrictions)
+ {
+ ReadRestrictionExceptions(lua_state);
+ }
+}
+
+void RestrictionParser::ReadRestrictionExceptions(lua_State *lua_state)
+{
+ if (util::luaFunctionExists(lua_state, "get_exceptions"))
+ {
+ luabind::set_pcall_callback(&luaErrorCallback);
+ // get list of turn restriction exceptions
+ luabind::call_function<void>(lua_state, "get_exceptions",
+ boost::ref(restriction_exceptions));
+ const unsigned exception_count = restriction_exceptions.size();
+ util::SimpleLogger().Write() << "Found " << exception_count
+ << " exceptions to turn restrictions:";
+ for (const std::string &str : restriction_exceptions)
+ {
+ util::SimpleLogger().Write() << " " << str;
+ }
+ }
+ else
+ {
+ util::SimpleLogger().Write() << "Found no exceptions to turn restrictions";
+ }
+}
+
+/**
+ * Tries to parse an relation as turn restriction. This can fail for a number of
+ * reasons, this the return type is a boost::optional<T>.
+ *
+ * Some restrictions can also be ignored: See the ```get_exceptions``` function
+ * in the corresponding profile.
+ */
+boost::optional<InputRestrictionContainer>
+RestrictionParser::TryParse(const osmium::Relation &relation) const
+{
+ // return if turn restrictions should be ignored
+ if (!use_turn_restrictions)
+ {
+ return {};
+ }
+
+ osmium::tags::KeyPrefixFilter filter(false);
+ filter.add(true, "restriction");
+
+ const osmium::TagList &tag_list = relation.tags();
+
+ osmium::tags::KeyPrefixFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end());
+ osmium::tags::KeyPrefixFilter::iterator fi_end(filter, tag_list.end(), tag_list.end());
+
+ // if it's a restriction, continue;
+ if (std::distance(fi_begin, fi_end) == 0)
+ {
+ return {};
+ }
+
+ // check if the restriction should be ignored
+ const char *except = relation.get_value_by_key("except");
+ if (except != nullptr && ShouldIgnoreRestriction(except))
+ {
+ return {};
+ }
+
+ bool is_only_restriction = false;
+
+ for (; fi_begin != fi_end; ++fi_begin)
+ {
+ const std::string key(fi_begin->key());
+ const std::string value(fi_begin->value());
+
+ if (value.find("only_") == 0)
+ {
+ is_only_restriction = true;
+ }
+
+ // if the "restriction*" key is longer than 11 chars, it is a conditional exception (i.e.
+ // "restriction:<transportation_type>")
+ if (key.size() > 11)
+ {
+ const auto ex_suffix = [&](const std::string &exception)
+ {
+ return boost::algorithm::ends_with(key, exception);
+ };
+ bool is_actually_restricted =
+ std::any_of(begin(restriction_exceptions), end(restriction_exceptions), ex_suffix);
+
+ if (!is_actually_restricted)
+ {
+ return {};
+ }
+ }
+ }
+
+ InputRestrictionContainer restriction_container(is_only_restriction);
+
+ for (const auto &member : relation.members())
+ {
+ const char *role = member.role();
+ if (strcmp("from", role) != 0 && strcmp("to", role) != 0 && strcmp("via", role) != 0)
+ {
+ continue;
+ }
+
+ switch (member.type())
+ {
+ case osmium::item_type::node:
+ // Make sure nodes appear only in the role if a via node
+ if (0 == strcmp("from", role) || 0 == strcmp("to", role))
+ {
+ continue;
+ }
+ BOOST_ASSERT(0 == strcmp("via", role));
+
+ // set via node id
+ restriction_container.restriction.via.node = member.ref();
+ break;
+
+ case osmium::item_type::way:
+ BOOST_ASSERT(0 == strcmp("from", role) || 0 == strcmp("to", role) ||
+ 0 == strcmp("via", role));
+ if (0 == strcmp("from", role))
+ {
+ restriction_container.restriction.from.way = member.ref();
+ }
+ else if (0 == strcmp("to", role))
+ {
+ restriction_container.restriction.to.way = member.ref();
+ }
+ // else if (0 == strcmp("via", role))
+ // {
+ // not yet suppported
+ // restriction_container.restriction.via.way = member.ref();
+ // }
+ break;
+ case osmium::item_type::relation:
+ // not yet supported, but who knows what the future holds...
+ break;
+ default:
+ // shouldn't ever happen
+ break;
+ }
+ }
+ return boost::make_optional(std::move(restriction_container));
+}
+
+bool RestrictionParser::ShouldIgnoreRestriction(const std::string &except_tag_string) const
+{
+ // should this restriction be ignored? yes if there's an overlap between:
+ // a) the list of modes in the except tag of the restriction
+ // (except_tag_string), eg: except=bus;bicycle
+ // b) the lua profile defines a hierachy of modes,
+ // eg: [access, vehicle, bicycle]
+
+ if (except_tag_string.empty())
+ {
+ return false;
+ }
+
+ // Be warned, this is quadratic work here, but we assume that
+ // only a few exceptions are actually defined.
+ std::vector<std::string> exceptions;
+ boost::algorithm::split_regex(exceptions, except_tag_string, boost::regex("[;][ ]*"));
+
+ return std::any_of(std::begin(exceptions), std::end(exceptions),
+ [&](const std::string ¤t_string)
+ {
+ return std::end(restriction_exceptions) !=
+ std::find(std::begin(restriction_exceptions),
+ std::end(restriction_exceptions), current_string);
+ });
+}
+}
+}
diff --git a/src/extractor/scripting_environment.cpp b/src/extractor/scripting_environment.cpp
new file mode 100644
index 0000000..53cc8e1
--- /dev/null
+++ b/src/extractor/scripting_environment.cpp
@@ -0,0 +1,184 @@
+#include "extractor/scripting_environment.hpp"
+
+#include "extractor/extraction_helper_functions.hpp"
+#include "extractor/extraction_node.hpp"
+#include "extractor/extraction_way.hpp"
+#include "extractor/internal_extractor_edge.hpp"
+#include "extractor/external_memory_node.hpp"
+#include "extractor/raster_source.hpp"
+#include "extractor/profile_properties.hpp"
+#include "util/lua_util.hpp"
+#include "util/make_unique.hpp"
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+#include "util/typedefs.hpp"
+
+#include <luabind/tag_function.hpp>
+#include <luabind/operator.hpp>
+
+#include <osmium/osm.hpp>
+
+#include <sstream>
+
+namespace osrm
+{
+namespace extractor
+{
+namespace
+{
+// wrapper method as luabind doesn't automatically overload funcs w/ default parameters
+template <class T>
+auto get_value_by_key(T const &object, const char *key) -> decltype(object.get_value_by_key(key))
+{
+ return object.get_value_by_key(key, "");
+}
+
+template <class T> double latToDouble(T const &object)
+{
+ return static_cast<double>(util::toFloating(object.lat));
+}
+
+template <class T> double lonToDouble(T const &object)
+{
+ return static_cast<double>(util::toFloating(object.lon));
+}
+
+// Error handler
+int luaErrorCallback(lua_State *state)
+{
+ std::string error_msg = lua_tostring(state, -1);
+ std::ostringstream error_stream;
+ error_stream << error_msg;
+ throw util::exception("ERROR occurred in profile script:\n" + error_stream.str());
+}
+}
+
+ScriptingEnvironment::ScriptingEnvironment(const std::string &file_name) : file_name(file_name)
+{
+ util::SimpleLogger().Write() << "Using script " << file_name;
+}
+
+void ScriptingEnvironment::InitContext(ScriptingEnvironment::Context &context)
+{
+ typedef double (osmium::Location::*location_member_ptr_type)() const;
+
+ luabind::open(context.state);
+ // open utility libraries string library;
+ luaL_openlibs(context.state);
+
+ util::luaAddScriptFolderToLoadPath(context.state, file_name.c_str());
+
+ // Add our function to the state's global scope
+ luabind::module(context.state)
+ [luabind::def("durationIsValid", durationIsValid),
+ luabind::def("parseDuration", parseDuration),
+ luabind::class_<TravelMode>("mode")
+ .enum_("enums")[luabind::value("inaccessible", TRAVEL_MODE_INACCESSIBLE),
+ luabind::value("driving", TRAVEL_MODE_DRIVING),
+ luabind::value("cycling", TRAVEL_MODE_CYCLING),
+ luabind::value("walking", TRAVEL_MODE_WALKING),
+ luabind::value("ferry", TRAVEL_MODE_FERRY),
+ luabind::value("train", TRAVEL_MODE_TRAIN),
+ luabind::value("pushing_bike", TRAVEL_MODE_PUSHING_BIKE),
+ luabind::value("movable_bridge", TRAVEL_MODE_MOVABLE_BRIDGE),
+ luabind::value("steps_up", TRAVEL_MODE_STEPS_UP),
+ luabind::value("steps_down", TRAVEL_MODE_STEPS_DOWN),
+ luabind::value("river_up", TRAVEL_MODE_RIVER_UP),
+ luabind::value("river_down", TRAVEL_MODE_RIVER_DOWN),
+ luabind::value("route", TRAVEL_MODE_ROUTE)],
+ luabind::class_<SourceContainer>("sources")
+ .def(luabind::constructor<>())
+ .def("load", &SourceContainer::loadRasterSource)
+ .def("query", &SourceContainer::getRasterDataFromSource)
+ .def("interpolate", &SourceContainer::getRasterInterpolateFromSource),
+ luabind::class_<const float>("constants")
+ .enum_("enums")[luabind::value("precision", COORDINATE_PRECISION)],
+
+ luabind::class_<ProfileProperties>("ProfileProperties")
+ .def(luabind::constructor<>())
+ .property("traffic_signal_penalty", &ProfileProperties::GetTrafficSignalPenalty,
+ &ProfileProperties::SetTrafficSignalPenalty)
+ .property("u_turn_penalty", &ProfileProperties::GetUturnPenalty,
+ &ProfileProperties::SetUturnPenalty)
+ .def_readwrite("use_turn_restrictions", &ProfileProperties::use_turn_restrictions)
+ .def_readwrite("allow_u_turn_at_via", &ProfileProperties::allow_u_turn_at_via),
+
+ luabind::class_<std::vector<std::string>>("vector")
+ .def("Add", static_cast<void (std::vector<std::string>::*)(const std::string &)>(
+ &std::vector<std::string>::push_back)),
+
+ luabind::class_<osmium::Location>("Location")
+ .def<location_member_ptr_type>("lat", &osmium::Location::lat)
+ .def<location_member_ptr_type>("lon", &osmium::Location::lon),
+
+ luabind::class_<osmium::Node>("Node")
+ // .def<node_member_ptr_type>("tags", &osmium::Node::tags)
+ .def("location", &osmium::Node::location)
+ .def("get_value_by_key", &osmium::Node::get_value_by_key)
+ .def("get_value_by_key", &get_value_by_key<osmium::Node>)
+ .def("id", &osmium::Node::id),
+
+ luabind::class_<ExtractionNode>("ResultNode")
+ .def_readwrite("traffic_lights", &ExtractionNode::traffic_lights)
+ .def_readwrite("barrier", &ExtractionNode::barrier),
+
+ luabind::class_<ExtractionWay>("ResultWay")
+ // .def(luabind::constructor<>())
+ .def_readwrite("forward_speed", &ExtractionWay::forward_speed)
+ .def_readwrite("backward_speed", &ExtractionWay::backward_speed)
+ .def_readwrite("name", &ExtractionWay::name)
+ .def_readwrite("roundabout", &ExtractionWay::roundabout)
+ .def_readwrite("is_access_restricted", &ExtractionWay::is_access_restricted)
+ .def_readwrite("is_startpoint", &ExtractionWay::is_startpoint)
+ .def_readwrite("duration", &ExtractionWay::duration)
+ .property("forward_mode", &ExtractionWay::get_forward_mode,
+ &ExtractionWay::set_forward_mode)
+ .property("backward_mode", &ExtractionWay::get_backward_mode,
+ &ExtractionWay::set_backward_mode),
+ luabind::class_<osmium::Way>("Way")
+ .def("get_value_by_key", &osmium::Way::get_value_by_key)
+ .def("get_value_by_key", &get_value_by_key<osmium::Way>)
+ .def("id", &osmium::Way::id),
+ luabind::class_<InternalExtractorEdge>("EdgeSource")
+ .def_readonly("source_coordinate", &InternalExtractorEdge::source_coordinate)
+ .def_readwrite("weight_data", &InternalExtractorEdge::weight_data),
+ luabind::class_<InternalExtractorEdge::WeightData>("WeightData")
+ .def_readwrite("speed", &InternalExtractorEdge::WeightData::speed),
+ luabind::class_<ExternalMemoryNode>("EdgeTarget")
+ .property("lon", &lonToDouble<ExternalMemoryNode>)
+ .property("lat", &latToDouble<ExternalMemoryNode>),
+ luabind::class_<util::Coordinate>("Coordinate")
+ .property("lon", &lonToDouble<util::Coordinate>)
+ .property("lat", &latToDouble<util::Coordinate>),
+ luabind::class_<RasterDatum>("RasterDatum")
+ .def_readonly("datum", &RasterDatum::datum)
+ .def("invalid_data", &RasterDatum::get_invalid)];
+
+ luabind::globals(context.state)["properties"] = &context.properties;
+ luabind::globals(context.state)["sources"] = &context.sources;
+
+ if (0 != luaL_dofile(context.state, file_name.c_str()))
+ {
+ luabind::object error_msg(luabind::from_stack(context.state, -1));
+ std::ostringstream error_stream;
+ error_stream << error_msg;
+ throw util::exception("ERROR occurred in profile script:\n" + error_stream.str());
+ }
+}
+
+ScriptingEnvironment::Context &ScriptingEnvironment::GetContex()
+{
+ std::lock_guard<std::mutex> lock(init_mutex);
+ bool initialized = false;
+ auto &ref = script_contexts.local(initialized);
+ if (!initialized)
+ {
+ ref = util::make_unique<Context>();
+ InitContext(*ref);
+ }
+ luabind::set_pcall_callback(&luaErrorCallback);
+
+ return *ref;
+}
+}
+}
diff --git a/src/osrm/osrm.cpp b/src/osrm/osrm.cpp
new file mode 100644
index 0000000..9a69e2e
--- /dev/null
+++ b/src/osrm/osrm.cpp
@@ -0,0 +1,54 @@
+#include "osrm/osrm.hpp"
+#include "engine/api/route_parameters.hpp"
+#include "engine/api/table_parameters.hpp"
+#include "engine/api/nearest_parameters.hpp"
+#include "engine/api/trip_parameters.hpp"
+#include "engine/api/match_parameters.hpp"
+#include "engine/engine.hpp"
+#include "engine/status.hpp"
+#include "engine/engine_config.hpp"
+#include "util/make_unique.hpp"
+
+namespace osrm
+{
+
+// Pimpl idiom
+
+OSRM::OSRM(engine::EngineConfig &config) : engine_(util::make_unique<engine::Engine>(config)) {}
+OSRM::~OSRM() = default;
+OSRM::OSRM(OSRM &&) noexcept = default;
+OSRM &OSRM::operator=(OSRM &&) noexcept = default;
+
+// Forward to implementation
+
+engine::Status OSRM::Route(const engine::api::RouteParameters ¶ms, util::json::Object &result)
+{
+ return engine_->Route(params, result);
+}
+
+engine::Status OSRM::Table(const engine::api::TableParameters ¶ms, json::Object &result)
+{
+ return engine_->Table(params, result);
+}
+
+engine::Status OSRM::Nearest(const engine::api::NearestParameters ¶ms, json::Object &result)
+{
+ return engine_->Nearest(params, result);
+}
+
+engine::Status OSRM::Trip(const engine::api::TripParameters ¶ms, json::Object &result)
+{
+ return engine_->Trip(params, result);
+}
+
+engine::Status OSRM::Match(const engine::api::MatchParameters ¶ms, json::Object &result)
+{
+ return engine_->Match(params, result);
+}
+
+engine::Status OSRM::Tile(const engine::api::TileParameters ¶ms, std::string &result)
+{
+ return engine_->Tile(params, result);
+}
+
+} // ns osrm
diff --git a/src/server/api/parameters_parser.cpp b/src/server/api/parameters_parser.cpp
new file mode 100644
index 0000000..1cf3050
--- /dev/null
+++ b/src/server/api/parameters_parser.cpp
@@ -0,0 +1,86 @@
+#include "server/api/parameters_parser.hpp"
+
+#include "server/api/route_parameters_grammar.hpp"
+#include "server/api/table_parameter_grammar.hpp"
+#include "server/api/nearest_parameter_grammar.hpp"
+#include "server/api/trip_parameter_grammar.hpp"
+#include "server/api/match_parameter_grammar.hpp"
+#include "server/api/tile_parameter_grammar.hpp"
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace detail
+{
+template <typename T>
+using is_grammar_t = std::integral_constant<bool,
+ std::is_base_of<BaseParametersGrammar, T>::value ||
+ std::is_same<TileParametersGrammar, T>::value>;
+
+template <typename ParameterT,
+ typename GrammarT,
+ typename std::enable_if<detail::is_parameter_t<ParameterT>::value, int>::type = 0,
+ typename std::enable_if<detail::is_grammar_t<GrammarT>::value, int>::type = 0>
+boost::optional<ParameterT> parseParameters(std::string::iterator &iter, std::string::iterator end)
+{
+ GrammarT grammar;
+ const auto result = boost::spirit::qi::parse(iter, end, grammar);
+
+ boost::optional<ParameterT> parameters;
+ if (result && iter == end)
+ parameters = std::move(grammar.parameters);
+
+ return parameters;
+}
+} // ns detail
+
+template <>
+boost::optional<engine::api::RouteParameters> parseParameters(std::string::iterator &iter,
+ std::string::iterator end)
+{
+ return detail::parseParameters<engine::api::RouteParameters, RouteParametersGrammar>(iter, end);
+}
+
+template <>
+boost::optional<engine::api::TableParameters> parseParameters(std::string::iterator &iter,
+ std::string::iterator end)
+{
+ return detail::parseParameters<engine::api::TableParameters, TableParametersGrammar>(iter, end);
+}
+
+template <>
+boost::optional<engine::api::NearestParameters> parseParameters(std::string::iterator &iter,
+ std::string::iterator end)
+{
+ return detail::parseParameters<engine::api::NearestParameters, NearestParametersGrammar>(iter,
+ end);
+}
+
+template <>
+boost::optional<engine::api::TripParameters> parseParameters(std::string::iterator &iter,
+ std::string::iterator end)
+{
+ return detail::parseParameters<engine::api::TripParameters, TripParametersGrammar>(iter, end);
+}
+
+template <>
+boost::optional<engine::api::MatchParameters> parseParameters(std::string::iterator &iter,
+ std::string::iterator end)
+{
+ return detail::parseParameters<engine::api::MatchParameters, MatchParametersGrammar>(iter, end);
+}
+
+template <>
+boost::optional<engine::api::TileParameters> parseParameters(std::string::iterator &iter,
+ std::string::iterator end)
+{
+ return detail::parseParameters<engine::api::TileParameters, TileParametersGrammar>(iter, end);
+}
+
+} // ns api
+} // ns server
+} // ns osrm
diff --git a/src/server/api/url_parser.cpp b/src/server/api/url_parser.cpp
new file mode 100644
index 0000000..661b1f6
--- /dev/null
+++ b/src/server/api/url_parser.cpp
@@ -0,0 +1,88 @@
+#include "server/api/url_parser.hpp"
+
+#include "engine/polyline_compressor.hpp"
+
+#include <boost/bind.hpp>
+#include <boost/spirit/include/qi_char_.hpp>
+#include <boost/spirit/include/qi_grammar.hpp>
+#include <boost/spirit/include/qi_uint.hpp>
+#include <boost/spirit/include/qi_real.hpp>
+#include <boost/spirit/include/qi_lit.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_as_string.hpp>
+#include <boost/spirit/include/qi_operator.hpp>
+#include <boost/spirit/include/qi_plus.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+
+namespace
+{
+
+namespace qi = boost::spirit::qi;
+using Iterator = std::string::iterator;
+struct URLGrammar : boost::spirit::qi::grammar<Iterator>
+{
+ URLGrammar() : URLGrammar::base_type(url_rule)
+ {
+ const auto set_service = [this](std::string &service)
+ {
+ parsed_url.service = std::move(service);
+ };
+ const auto set_version = [this](const unsigned version)
+ {
+ parsed_url.version = version;
+ };
+ const auto set_profile = [this](std::string &profile)
+ {
+ parsed_url.profile = std::move(profile);
+ };
+ const auto set_query = [this](std::string &query)
+ {
+ parsed_url.query = std::move(query);
+ };
+
+ alpha_numeral = qi::char_("a-zA-Z0-9");
+ polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\%~`^");
+ all_chars = polyline_chars | qi::char_("=,;:&().");
+
+ service_rule = +alpha_numeral;
+ version_rule = qi::uint_;
+ profile_rule = +alpha_numeral;
+ query_rule = +all_chars;
+
+ url_rule = qi::lit('/') >> service_rule[set_service] >> qi::lit('/') >> qi::lit('v') >>
+ version_rule[set_version] >> qi::lit('/') >> profile_rule[set_profile] >>
+ qi::lit('/') >> query_rule[set_query];
+ }
+
+ ParsedURL parsed_url;
+
+ qi::rule<Iterator> url_rule;
+ qi::rule<Iterator, std::string()> service_rule, profile_rule, query_rule;
+ qi::rule<Iterator, unsigned()> version_rule;
+ qi::rule<Iterator, char()> alpha_numeral, all_chars, polyline_chars;
+};
+}
+
+boost::optional<ParsedURL> parseURL(std::string::iterator &iter, std::string::iterator end)
+{
+ boost::optional<ParsedURL> parsed_url;
+
+ URLGrammar grammar;
+ const auto result = boost::spirit::qi::parse(iter, end, grammar);
+
+ if (result && iter == end)
+ {
+ parsed_url = std::move(grammar.parsed_url);
+ }
+
+ return parsed_url;
+}
+}
+}
+}
diff --git a/server/connection.cpp b/src/server/connection.cpp
similarity index 70%
rename from server/connection.cpp
rename to src/server/connection.cpp
index dbf85fd..e7725fb 100644
--- a/server/connection.cpp
+++ b/src/server/connection.cpp
@@ -1,33 +1,6 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "connection.hpp"
-#include "request_handler.hpp"
-#include "request_parser.hpp"
+#include "server/connection.hpp"
+#include "server/request_handler.hpp"
+#include "server/request_parser.hpp"
#include <boost/assert.hpp>
#include <boost/bind.hpp>
@@ -37,7 +10,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
#include <vector>
-namespace http
+namespace osrm
+{
+namespace server
{
Connection::Connection(boost::asio::io_service &io_service, RequestHandler &handler)
@@ -65,25 +40,22 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
}
// no error detected, let's parse the request
- compression_type compression_type(no_compression);
- osrm::tribool result;
+ http::compression_type compression_type(http::no_compression);
+ RequestParser::RequestStatus result;
std::tie(result, compression_type) =
request_parser.parse(current_request, incoming_data_buffer.data(),
incoming_data_buffer.data() + bytes_transferred);
// the request has been parsed
- if (result == osrm::tribool::yes)
+ if (result == RequestParser::RequestStatus::valid)
{
current_request.endpoint = TCP_socket.remote_endpoint().address();
- request_handler.handle_request(current_request, current_reply);
-
- // Header compression_header;
- std::vector<boost::asio::const_buffer> output_buffer;
+ request_handler.HandleRequest(current_request, current_reply);
// compress the result w/ gzip/deflate if requested
switch (compression_type)
{
- case deflate_rfc1951:
+ case http::deflate_rfc1951:
// use deflate for compression
current_reply.headers.insert(current_reply.headers.begin(),
{"Content-Encoding", "deflate"});
@@ -92,7 +64,7 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
output_buffer = current_reply.headers_to_buffers();
output_buffer.push_back(boost::asio::buffer(compressed_output));
break;
- case gzip_rfc1952:
+ case http::gzip_rfc1952:
// use gzip for compression
current_reply.headers.insert(current_reply.headers.begin(),
{"Content-Encoding", "gzip"});
@@ -101,7 +73,7 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
output_buffer = current_reply.headers_to_buffers();
output_buffer.push_back(boost::asio::buffer(compressed_output));
break;
- case no_compression:
+ case http::no_compression:
// don't use any compression
current_reply.set_uncompressed_size();
output_buffer = current_reply.to_buffers();
@@ -113,9 +85,9 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
strand.wrap(boost::bind(&Connection::handle_write, this->shared_from_this(),
boost::asio::placeholders::error)));
}
- else if (result == osrm::tribool::no)
+ else if (result == RequestParser::RequestStatus::invalid)
{ // request is not parseable
- current_reply = reply::stock_reply(reply::bad_request);
+ current_reply = http::reply::stock_reply(http::reply::bad_request);
boost::asio::async_write(
TCP_socket, current_reply.to_buffers(),
@@ -145,14 +117,14 @@ void Connection::handle_write(const boost::system::error_code &error)
}
std::vector<char> Connection::compress_buffers(const std::vector<char> &uncompressed_data,
- const compression_type compression_type)
+ const http::compression_type compression_type)
{
boost::iostreams::gzip_params compression_parameters;
// there's a trade-off between speed and size. speed wins
compression_parameters.level = boost::iostreams::zlib::best_speed;
// check which compression flavor is used
- if (deflate_rfc1951 == compression_type)
+ if (http::deflate_rfc1951 == compression_type)
{
compression_parameters.noheader = true;
}
@@ -168,3 +140,4 @@ std::vector<char> Connection::compress_buffers(const std::vector<char> &uncompre
return compressed_data;
}
}
+}
diff --git a/server/http/reply.cpp b/src/server/http/reply.cpp
similarity index 66%
rename from server/http/reply.cpp
rename to src/server/http/reply.cpp
index a3d3d96..d279417 100644
--- a/server/http/reply.cpp
+++ b/src/server/http/reply.cpp
@@ -1,41 +1,18 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "reply.hpp"
+#include "server/http/reply.hpp"
#include <string>
+namespace osrm
+{
+namespace server
+{
namespace http
{
const char ok_html[] = "";
-const char bad_request_html[] = "{\"status\": 400,\"status_message\":\"Bad Request\"}";
+const char bad_request_html[] = "";
const char internal_server_error_html[] =
- "{\"status\": 500,\"status_message\":\"Internal Server Error\"}";
+ "{\"code\": \"InternalError\",\"message\":\"Internal Server Error\"}";
const char seperators[] = {':', ' '};
const char crlf[] = {'\r', '\n'};
const std::string http_ok_string = "HTTP/1.0 200 OK\r\n";
@@ -126,5 +103,11 @@ boost::asio::const_buffer reply::status_to_buffer(const reply::status_type statu
return boost::asio::buffer(http_bad_request_string);
}
-reply::reply() : status(ok) {}
+reply::reply() : status(ok)
+{
+ // We do not currently support keep alive. Always set 'Connection: close'.
+ headers.emplace_back("Connection", "close");
+}
+}
+}
}
diff --git a/src/server/request_handler.cpp b/src/server/request_handler.cpp
new file mode 100644
index 0000000..888a92b
--- /dev/null
+++ b/src/server/request_handler.cpp
@@ -0,0 +1,151 @@
+#include "server/request_handler.hpp"
+#include "server/service_handler.hpp"
+
+#include "server/api/url_parser.hpp"
+#include "server/http/reply.hpp"
+#include "server/http/request.hpp"
+
+#include "util/json_renderer.hpp"
+#include "util/simple_logger.hpp"
+#include "util/string_util.hpp"
+#include "util/typedefs.hpp"
+
+#include "engine/status.hpp"
+#include "util/json_container.hpp"
+#include "osrm/osrm.hpp"
+
+#include <boost/iostreams/filtering_streambuf.hpp>
+#include <boost/iostreams/copy.hpp>
+#include <boost/iostreams/filter/gzip.hpp>
+
+#include <ctime>
+
+#include <algorithm>
+#include <iostream>
+#include <string>
+
+namespace osrm
+{
+namespace server
+{
+
+void RequestHandler::RegisterServiceHandler(std::unique_ptr<ServiceHandler> service_handler_)
+{
+ service_handler = std::move(service_handler_);
+}
+
+void RequestHandler::HandleRequest(const http::request ¤t_request, http::reply ¤t_reply)
+{
+ if (!service_handler)
+ {
+ current_reply = http::reply::stock_reply(http::reply::internal_server_error);
+ util::SimpleLogger().Write(logWARNING) << "No service handler registered." << std::endl;
+ return;
+ }
+
+ // parse command
+ try
+ {
+ std::string request_string;
+ util::URIDecode(current_request.uri, request_string);
+
+ // deactivated as GCC apparently does not implement that, not even in 4.9
+ // std::time_t t = std::time(nullptr);
+ // util::SimpleLogger().Write() << std::put_time(std::localtime(&t), "%m-%d-%Y %H:%M:%S") <<
+ // " " << current_request.endpoint.to_string() << " " <<
+ // current_request.referrer << ( 0 == current_request.referrer.length() ? "- " :" ") <<
+ // current_request.agent << ( 0 == current_request.agent.length() ? "- " :" ") <<
+ // request;
+
+ time_t ltime;
+ struct tm *time_stamp;
+
+ ltime = time(nullptr);
+ time_stamp = localtime(<ime);
+
+ // log timestamp
+ util::SimpleLogger().Write()
+ << (time_stamp->tm_mday < 10 ? "0" : "") << time_stamp->tm_mday << "-"
+ << (time_stamp->tm_mon + 1 < 10 ? "0" : "") << (time_stamp->tm_mon + 1) << "-"
+ << 1900 + time_stamp->tm_year << " " << (time_stamp->tm_hour < 10 ? "0" : "")
+ << time_stamp->tm_hour << ":" << (time_stamp->tm_min < 10 ? "0" : "")
+ << time_stamp->tm_min << ":" << (time_stamp->tm_sec < 10 ? "0" : "")
+ << time_stamp->tm_sec << " " << current_request.endpoint.to_string() << " "
+ << current_request.referrer << (0 == current_request.referrer.length() ? "- " : " ")
+ << current_request.agent << (0 == current_request.agent.length() ? "- " : " ")
+ << request_string;
+
+ auto api_iterator = request_string.begin();
+ auto maybe_parsed_url = api::parseURL(api_iterator, request_string.end());
+ ;
+ ServiceHandler::ResultT result;
+
+ // check if the was an error with the request
+ if (maybe_parsed_url && api_iterator == request_string.end())
+ {
+
+ const engine::Status status =
+ service_handler->RunQuery(std::move(*maybe_parsed_url), result);
+ if (status != engine::Status::Ok)
+ {
+ // 4xx bad request return code
+ current_reply.status = http::reply::bad_request;
+ }
+ else
+ {
+ BOOST_ASSERT(status == engine::Status::Ok);
+ }
+ }
+ else
+ {
+ const auto position = std::distance(request_string.begin(), api_iterator);
+ BOOST_ASSERT(position >= 0);
+ const auto context_begin = request_string.begin() + ((position < 3) ? 0 : (position - 3UL));
+ BOOST_ASSERT(context_begin >= request_string.begin());
+ const auto context_end =
+ request_string.begin() + std::min(position + 3UL, request_string.size());
+ BOOST_ASSERT(context_end <= request_string.end());
+ std::string context(context_begin, context_end);
+
+ current_reply.status = http::reply::bad_request;
+ result = util::json::Object();
+ auto &json_result = result.get<util::json::Object>();
+ json_result.values["code"] = "InvalidUrl";
+ json_result.values["message"] = "URL string malformed close to position " +
+ std::to_string(position) + ": \"" + context + "\"";
+ }
+
+ current_reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
+ current_reply.headers.emplace_back("Access-Control-Allow-Methods", "GET");
+ current_reply.headers.emplace_back("Access-Control-Allow-Headers",
+ "X-Requested-With, Content-Type");
+ if (result.is<util::json::Object>())
+ {
+ current_reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
+ current_reply.headers.emplace_back("Content-Disposition",
+ "inline; filename=\"response.json\"");
+
+ util::json::render(current_reply.content, result.get<util::json::Object>());
+ }
+ else
+ {
+ BOOST_ASSERT(result.is<std::string>());
+ std::copy(result.get<std::string>().cbegin(), result.get<std::string>().cend(),
+ std::back_inserter(current_reply.content));
+
+ current_reply.headers.emplace_back("Content-Type", "application/x-protobuf");
+ }
+
+ // set headers
+ current_reply.headers.emplace_back("Content-Length",
+ std::to_string(current_reply.content.size()));
+ }
+ catch (const std::exception &e)
+ {
+ current_reply = http::reply::stock_reply(http::reply::internal_server_error);
+ util::SimpleLogger().Write(logWARNING) << "[server error] code: " << e.what()
+ << ", uri: " << current_request.uri;
+ }
+}
+}
+}
diff --git a/src/server/request_parser.cpp b/src/server/request_parser.cpp
new file mode 100644
index 0000000..e408a79
--- /dev/null
+++ b/src/server/request_parser.cpp
@@ -0,0 +1,299 @@
+#include "server/request_parser.hpp"
+
+#include "server/http/compression_type.hpp"
+#include "server/http/header.hpp"
+#include "server/http/request.hpp"
+
+#include <boost/algorithm/string/predicate.hpp>
+
+#include <string>
+
+namespace osrm
+{
+namespace server
+{
+
+RequestParser::RequestParser()
+ : state(internal_state::method_start), current_header({"", ""}),
+ selected_compression(http::no_compression)
+{
+}
+
+std::tuple<RequestParser::RequestStatus, http::compression_type>
+RequestParser::parse(http::request ¤t_request, char *begin, char *end)
+{
+ while (begin != end)
+ {
+ RequestStatus result = consume(current_request, *begin++);
+ if (result != RequestStatus::indeterminate)
+ {
+ return std::make_tuple(result, selected_compression);
+ }
+ }
+ RequestStatus result = RequestStatus::indeterminate;
+
+ return std::make_tuple(result, selected_compression);
+}
+
+RequestParser::RequestStatus RequestParser::consume(http::request ¤t_request,
+ const char input)
+{
+ switch (state)
+ {
+ case internal_state::method_start:
+ if (!is_char(input) || is_CTL(input) || is_special(input))
+ {
+ return RequestStatus::invalid;
+ }
+ state = internal_state::method;
+ return RequestStatus::indeterminate;
+ case internal_state::method:
+ if (input == ' ')
+ {
+ state = internal_state::uri;
+ return RequestStatus::indeterminate;
+ }
+ if (!is_char(input) || is_CTL(input) || is_special(input))
+ {
+ return RequestStatus::invalid;
+ }
+ return RequestStatus::indeterminate;
+ case internal_state::uri_start:
+ if (is_CTL(input))
+ {
+ return RequestStatus::invalid;
+ }
+ state = internal_state::uri;
+ current_request.uri.push_back(input);
+ return RequestStatus::indeterminate;
+ case internal_state::uri:
+ if (input == ' ')
+ {
+ state = internal_state::http_version_h;
+ return RequestStatus::indeterminate;
+ }
+ if (is_CTL(input))
+ {
+ return RequestStatus::invalid;
+ }
+ current_request.uri.push_back(input);
+ return RequestStatus::indeterminate;
+ case internal_state::http_version_h:
+ if (input == 'H')
+ {
+ state = internal_state::http_version_t_1;
+ return RequestStatus::indeterminate;
+ }
+ return RequestStatus::invalid;
+ case internal_state::http_version_t_1:
+ if (input == 'T')
+ {
+ state = internal_state::http_version_t_2;
+ return RequestStatus::indeterminate;
+ }
+ return RequestStatus::invalid;
+ case internal_state::http_version_t_2:
+ if (input == 'T')
+ {
+ state = internal_state::http_version_p;
+ return RequestStatus::indeterminate;
+ }
+ return RequestStatus::invalid;
+ case internal_state::http_version_p:
+ if (input == 'P')
+ {
+ state = internal_state::http_version_slash;
+ return RequestStatus::indeterminate;
+ }
+ return RequestStatus::invalid;
+ case internal_state::http_version_slash:
+ if (input == '/')
+ {
+ state = internal_state::http_version_major_start;
+ return RequestStatus::indeterminate;
+ }
+ return RequestStatus::invalid;
+ case internal_state::http_version_major_start:
+ if (is_digit(input))
+ {
+ state = internal_state::http_version_major;
+ return RequestStatus::indeterminate;
+ }
+ return RequestStatus::invalid;
+ case internal_state::http_version_major:
+ if (input == '.')
+ {
+ state = internal_state::http_version_minor_start;
+ return RequestStatus::indeterminate;
+ }
+ if (is_digit(input))
+ {
+ return RequestStatus::indeterminate;
+ }
+ return RequestStatus::invalid;
+ case internal_state::http_version_minor_start:
+ if (is_digit(input))
+ {
+ state = internal_state::http_version_minor;
+ return RequestStatus::indeterminate;
+ }
+ return RequestStatus::invalid;
+ case internal_state::http_version_minor:
+ if (input == '\r')
+ {
+ state = internal_state::expecting_newline_1;
+ return RequestStatus::indeterminate;
+ }
+ if (is_digit(input))
+ {
+ return RequestStatus::indeterminate;
+ }
+ return RequestStatus::invalid;
+ case internal_state::expecting_newline_1:
+ if (input == '\n')
+ {
+ state = internal_state::header_line_start;
+ return RequestStatus::indeterminate;
+ }
+ return RequestStatus::invalid;
+ case internal_state::header_line_start:
+ if (boost::iequals(current_header.name, "Accept-Encoding"))
+ {
+ /* giving gzip precedence over deflate */
+ if (boost::icontains(current_header.value, "deflate"))
+ {
+ selected_compression = http::deflate_rfc1951;
+ }
+ if (boost::icontains(current_header.value, "gzip"))
+ {
+ selected_compression = http::gzip_rfc1952;
+ }
+ }
+
+ if (boost::iequals(current_header.name, "Referer"))
+ {
+ current_request.referrer = current_header.value;
+ }
+
+ if (boost::iequals(current_header.name, "User-Agent"))
+ {
+ current_request.agent = current_header.value;
+ }
+
+ if (input == '\r')
+ {
+ state = internal_state::expecting_newline_3;
+ return RequestStatus::indeterminate;
+ }
+ if (!is_char(input) || is_CTL(input) || is_special(input))
+ {
+ return RequestStatus::invalid;
+ }
+ state = internal_state::header_name;
+ current_header.clear();
+ current_header.name.push_back(input);
+ return RequestStatus::indeterminate;
+ case internal_state::header_lws:
+ if (input == '\r')
+ {
+ state = internal_state::expecting_newline_2;
+ return RequestStatus::indeterminate;
+ }
+ if (input == ' ' || input == '\t')
+ {
+ return RequestStatus::indeterminate;
+ }
+ if (is_CTL(input))
+ {
+ return RequestStatus::invalid;
+ }
+ state = internal_state::header_value;
+ return RequestStatus::indeterminate;
+ case internal_state::header_name:
+ if (input == ':')
+ {
+ state = internal_state::space_before_header_value;
+ return RequestStatus::indeterminate;
+ }
+ if (!is_char(input) || is_CTL(input) || is_special(input))
+ {
+ return RequestStatus::invalid;
+ }
+ current_header.name.push_back(input);
+ return RequestStatus::indeterminate;
+ case internal_state::space_before_header_value:
+ if (input == ' ')
+ {
+ state = internal_state::header_value;
+ return RequestStatus::indeterminate;
+ }
+ return RequestStatus::invalid;
+ case internal_state::header_value:
+ if (input == '\r')
+ {
+ state = internal_state::expecting_newline_2;
+ return RequestStatus::indeterminate;
+ }
+ if (is_CTL(input))
+ {
+ return RequestStatus::invalid;
+ }
+ current_header.value.push_back(input);
+ return RequestStatus::indeterminate;
+ case internal_state::expecting_newline_2:
+ if (input == '\n')
+ {
+ state = internal_state::header_line_start;
+ return RequestStatus::indeterminate;
+ }
+ return RequestStatus::invalid;
+ default: // expecting_newline_3
+ return input == '\n' ? RequestStatus::valid : RequestStatus::invalid;
+ }
+}
+
+bool RequestParser::is_char(const int character) const
+{
+ return character >= 0 && character <= 127;
+}
+
+bool RequestParser::is_CTL(const int character) const
+{
+ return (character >= 0 && character <= 31) || (character == 127);
+}
+
+bool RequestParser::is_special(const int character) const
+{
+ switch (character)
+ {
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case ':':
+ case '\\':
+ case '"':
+ case '/':
+ case '[':
+ case ']':
+ case '?':
+ case '=':
+ case '{':
+ case '}':
+ case ' ':
+ case '\t':
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool RequestParser::is_digit(const int character) const
+{
+ return character >= '0' && character <= '9';
+}
+}
+}
diff --git a/src/server/service/match_service.cpp b/src/server/service/match_service.cpp
new file mode 100644
index 0000000..dec8006
--- /dev/null
+++ b/src/server/service/match_service.cpp
@@ -0,0 +1,73 @@
+#include "server/service/match_service.hpp"
+
+#include "engine/api/match_parameters.hpp"
+#include "server/api/parameters_parser.hpp"
+#include "server/service/utils.hpp"
+
+#include "util/json_container.hpp"
+
+#include <boost/format.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+namespace
+{
+std::string getWrongOptionHelp(const engine::api::MatchParameters ¶meters)
+{
+ std::string help;
+
+ const auto coord_size = parameters.coordinates.size();
+
+ const bool param_size_mismatch = constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "hints",
+ parameters.hints, coord_size, help) ||
+ constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "bearings",
+ parameters.bearings, coord_size, help) ||
+ constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "radiuses",
+ parameters.radiuses, coord_size, help) ||
+ constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "timestamps",
+ parameters.timestamps, coord_size, help);
+
+ if (!param_size_mismatch && parameters.coordinates.size() < 2)
+ {
+ help = "Number of coordinates needs to be at least two.";
+ }
+
+ return help;
+}
+} // anon. ns
+
+engine::Status MatchService::RunQuery(std::string &query, ResultT &result)
+{
+ result = util::json::Object();
+ auto &json_result = result.get<util::json::Object>();
+
+ auto query_iterator = query.begin();
+ auto parameters =
+ api::parseParameters<engine::api::MatchParameters>(query_iterator, query.end());
+ if (!parameters || query_iterator != query.end())
+ {
+ const auto position = std::distance(query.begin(), query_iterator);
+ json_result.values["code"] = "InvalidQuery";
+ json_result.values["message"] =
+ "Query string malformed close to position " + std::to_string(position);
+ return engine::Status::Error;
+ }
+
+ BOOST_ASSERT(parameters);
+ if (!parameters->IsValid())
+ {
+ json_result.values["code"] = "InvalidOptions";
+ json_result.values["message"] = getWrongOptionHelp(*parameters);
+ return engine::Status::Error;
+ }
+ BOOST_ASSERT(parameters->IsValid());
+
+ return BaseService::routing_machine.Match(*parameters, json_result);
+}
+}
+}
+}
diff --git a/src/server/service/nearest_service.cpp b/src/server/service/nearest_service.cpp
new file mode 100644
index 0000000..1ea1fa8
--- /dev/null
+++ b/src/server/service/nearest_service.cpp
@@ -0,0 +1,72 @@
+#include "server/service/nearest_service.hpp"
+#include "server/service/utils.hpp"
+
+#include "engine/api/nearest_parameters.hpp"
+#include "server/api/parameters_parser.hpp"
+
+#include "util/json_container.hpp"
+
+#include <boost/format.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+namespace
+{
+std::string getWrongOptionHelp(const engine::api::NearestParameters ¶meters)
+{
+ std::string help;
+
+ const auto coord_size = parameters.coordinates.size();
+
+ const bool param_size_mismatch = constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "hints",
+ parameters.hints, coord_size, help) ||
+ constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "bearings",
+ parameters.bearings, coord_size, help) ||
+ constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "radiuses",
+ parameters.radiuses, coord_size, help);
+
+ if (!param_size_mismatch && parameters.coordinates.size() < 2)
+ {
+ help = "Number of coordinates needs to be at least two.";
+ }
+
+ return help;
+}
+} // anon. ns
+
+engine::Status NearestService::RunQuery(std::string &query, ResultT &result)
+{
+ result = util::json::Object();
+ auto &json_result = result.get<util::json::Object>();
+
+ auto query_iterator = query.begin();
+ auto parameters =
+ api::parseParameters<engine::api::NearestParameters>(query_iterator, query.end());
+ if (!parameters || query_iterator != query.end())
+ {
+ const auto position = std::distance(query.begin(), query_iterator);
+ json_result.values["code"] = "InvalidQuery";
+ json_result.values["message"] =
+ "Query string malformed close to position " + std::to_string(position);
+ return engine::Status::Error;
+ }
+ BOOST_ASSERT(parameters);
+
+ if (!parameters->IsValid())
+ {
+ json_result.values["code"] = "InvalidOptions";
+ json_result.values["message"] = getWrongOptionHelp(*parameters);
+ return engine::Status::Error;
+ }
+ BOOST_ASSERT(parameters->IsValid());
+
+ return BaseService::routing_machine.Nearest(*parameters, json_result);
+}
+}
+}
+}
diff --git a/src/server/service/route_service.cpp b/src/server/service/route_service.cpp
new file mode 100644
index 0000000..f06cbdb
--- /dev/null
+++ b/src/server/service/route_service.cpp
@@ -0,0 +1,69 @@
+#include "server/service/route_service.hpp"
+#include "server/service/utils.hpp"
+
+#include "engine/api/route_parameters.hpp"
+#include "server/api/parameters_parser.hpp"
+
+#include "util/json_container.hpp"
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+namespace
+{
+std::string getWrongOptionHelp(const engine::api::RouteParameters ¶meters)
+{
+ std::string help;
+
+ const auto coord_size = parameters.coordinates.size();
+
+ const bool param_size_mismatch = constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "hints",
+ parameters.hints, coord_size, help) ||
+ constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "bearings",
+ parameters.bearings, coord_size, help) ||
+ constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "radiuses",
+ parameters.radiuses, coord_size, help);
+
+ if (!param_size_mismatch && parameters.coordinates.size() < 2)
+ {
+ help = "Number of coordinates needs to be at least two.";
+ }
+
+ return help;
+}
+} // anon. ns
+
+engine::Status RouteService::RunQuery(std::string &query, ResultT &result)
+{
+ result = util::json::Object();
+ auto &json_result = result.get<util::json::Object>();
+
+ auto query_iterator = query.begin();
+ auto parameters =
+ api::parseParameters<engine::api::RouteParameters>(query_iterator, query.end());
+ if (!parameters || query_iterator != query.end())
+ {
+ const auto position = std::distance(query.begin(), query_iterator);
+ json_result.values["code"] = "InvalidQuery";
+ json_result.values["message"] =
+ "Query string malformed close to position " + std::to_string(position);
+ return engine::Status::Error;
+ }
+ BOOST_ASSERT(parameters);
+
+ if (!parameters->IsValid())
+ {
+ json_result.values["code"] = "InvalidOptions";
+ json_result.values["message"] = getWrongOptionHelp(*parameters);
+ return engine::Status::Error;
+ }
+ BOOST_ASSERT(parameters->IsValid());
+
+ return BaseService::routing_machine.Route(*parameters, json_result);
+}
+}
+}
+}
diff --git a/src/server/service/table_service.cpp b/src/server/service/table_service.cpp
new file mode 100644
index 0000000..9b0f817
--- /dev/null
+++ b/src/server/service/table_service.cpp
@@ -0,0 +1,90 @@
+#include "server/service/table_service.hpp"
+
+#include "engine/api/table_parameters.hpp"
+#include "server/api/parameters_parser.hpp"
+
+#include "util/json_container.hpp"
+
+#include <boost/format.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+namespace
+{
+
+const constexpr char PARAMETER_SIZE_MISMATCH_MSG[] =
+ "Number of elements in %1% size %2% does not match coordinate size %3%";
+
+template <typename ParamT>
+bool constrainParamSize(const char *msg_template,
+ const char *name,
+ const ParamT ¶m,
+ const std::size_t target_size,
+ std::string &help)
+{
+ if (param.size() > 0 && param.size() != target_size)
+ {
+ help = (boost::format(msg_template) % name % param.size() % target_size).str();
+ return true;
+ }
+ return false;
+}
+
+std::string getWrongOptionHelp(const engine::api::TableParameters ¶meters)
+{
+ std::string help;
+
+ const auto coord_size = parameters.coordinates.size();
+
+ const bool param_size_mismatch = constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "hints",
+ parameters.hints, coord_size, help) ||
+ constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "bearings",
+ parameters.bearings, coord_size, help) ||
+ constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "radiuses",
+ parameters.radiuses, coord_size, help);
+
+ if (!param_size_mismatch && parameters.coordinates.size() < 2)
+ {
+ help = "Number of coordinates needs to be at least two.";
+ }
+
+ return help;
+}
+} // anon. ns
+
+engine::Status TableService::RunQuery(std::string &query, ResultT &result)
+{
+ result = util::json::Object();
+ auto &json_result = result.get<util::json::Object>();
+
+ auto query_iterator = query.begin();
+ auto parameters =
+ api::parseParameters<engine::api::TableParameters>(query_iterator, query.end());
+ if (!parameters || query_iterator != query.end())
+ {
+ const auto position = std::distance(query.begin(), query_iterator);
+ json_result.values["code"] = "InvalidQuery";
+ json_result.values["message"] =
+ "Query string malformed close to position " + std::to_string(position);
+ return engine::Status::Error;
+ }
+ BOOST_ASSERT(parameters);
+
+ if (!parameters->IsValid())
+ {
+ json_result.values["code"] = "InvalidOptions";
+ json_result.values["message"] = getWrongOptionHelp(*parameters);
+ return engine::Status::Error;
+ }
+ BOOST_ASSERT(parameters->IsValid());
+
+ return BaseService::routing_machine.Table(*parameters, json_result);
+}
+}
+}
+}
diff --git a/src/server/service/tile_service.cpp b/src/server/service/tile_service.cpp
new file mode 100644
index 0000000..d8f1ba8
--- /dev/null
+++ b/src/server/service/tile_service.cpp
@@ -0,0 +1,51 @@
+#include "server/service/tile_service.hpp"
+#include "server/service/utils.hpp"
+
+#include "engine/api/tile_parameters.hpp"
+#include "server/api/parameters_parser.hpp"
+
+#include "util/json_container.hpp"
+
+#include <boost/format.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+
+engine::Status TileService::RunQuery(std::string &query, ResultT &result)
+{
+ auto query_iterator = query.begin();
+ auto parameters =
+ api::parseParameters<engine::api::TileParameters>(query_iterator, query.end());
+ if (!parameters || query_iterator != query.end())
+ {
+ const auto position = std::distance(query.begin(), query_iterator);
+ result = util::json::Object();
+ auto &json_result = result.get<util::json::Object>();
+ json_result.values["code"] = "InvalidQuery";
+ json_result.values["message"] =
+ "Query string malformed close to position " + std::to_string(position);
+ return engine::Status::Error;
+ }
+ BOOST_ASSERT(parameters);
+
+ if (!parameters->IsValid())
+ {
+ result = util::json::Object();
+ auto &json_result = result.get<util::json::Object>();
+ json_result.values["code"] = "InvalidOptions";
+ json_result.values["message"] = "Invalid coodinates. Only zoomlevel 12+ is supported";
+ return engine::Status::Error;
+ }
+ BOOST_ASSERT(parameters->IsValid());
+
+ result = std::string();
+ auto &string_result = result.get<std::string>();
+ return BaseService::routing_machine.Tile(*parameters, string_result);
+}
+}
+}
+}
diff --git a/src/server/service/trip_service.cpp b/src/server/service/trip_service.cpp
new file mode 100644
index 0000000..82a1bfd
--- /dev/null
+++ b/src/server/service/trip_service.cpp
@@ -0,0 +1,73 @@
+#include "server/service/trip_service.hpp"
+#include "server/service/utils.hpp"
+
+#include "engine/api/trip_parameters.hpp"
+#include "server/api/parameters_parser.hpp"
+
+#include "util/json_container.hpp"
+
+#include <boost/format.hpp>
+
+namespace osrm
+{
+namespace server
+{
+namespace service
+{
+namespace
+{
+std::string getWrongOptionHelp(const engine::api::TripParameters ¶meters)
+{
+ std::string help;
+
+ const auto coord_size = parameters.coordinates.size();
+
+ const bool param_size_mismatch = constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "hints",
+ parameters.hints, coord_size, help) ||
+ constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "bearings",
+ parameters.bearings, coord_size, help) ||
+ constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "radiuses",
+ parameters.radiuses, coord_size, help);
+
+ if (!param_size_mismatch && parameters.coordinates.size() < 2)
+ {
+ help = "Number of coordinates needs to be at least two.";
+ }
+
+ return help;
+}
+} // anon. ns
+
+engine::Status TripService::RunQuery(std::string &query, ResultT &result)
+{
+ result = util::json::Object();
+ auto &json_result = result.get<util::json::Object>();
+
+ auto query_iterator = query.begin();
+ auto parameters =
+ api::parseParameters<engine::api::TripParameters>(query_iterator, query.end());
+ if (!parameters || query_iterator != query.end())
+ {
+ const auto position = std::distance(query.begin(), query_iterator);
+ result = util::json::Object();
+ auto &json_result = result.get<util::json::Object>();
+ json_result.values["code"] = "InvalidQuery";
+ json_result.values["message"] =
+ "Query string malformed close to position " + std::to_string(position);
+ return engine::Status::Error;
+ }
+ BOOST_ASSERT(parameters);
+
+ if (!parameters->IsValid())
+ {
+ json_result.values["code"] = "InvalidOptions";
+ json_result.values["message"] = getWrongOptionHelp(*parameters);
+ return engine::Status::Error;
+ }
+ BOOST_ASSERT(parameters->IsValid());
+
+ return BaseService::routing_machine.Trip(*parameters, json_result);
+}
+}
+}
+}
diff --git a/src/server/service_handler.cpp b/src/server/service_handler.cpp
new file mode 100644
index 0000000..98ba6a6
--- /dev/null
+++ b/src/server/service_handler.cpp
@@ -0,0 +1,54 @@
+#include "server/service_handler.hpp"
+
+#include "server/service/route_service.hpp"
+#include "server/service/table_service.hpp"
+#include "server/service/nearest_service.hpp"
+#include "server/service/trip_service.hpp"
+#include "server/service/match_service.hpp"
+#include "server/service/tile_service.hpp"
+
+#include "server/api/parsed_url.hpp"
+#include "util/json_util.hpp"
+#include "util/make_unique.hpp"
+
+namespace osrm
+{
+namespace server
+{
+ServiceHandler::ServiceHandler(osrm::EngineConfig &config) : routing_machine(config)
+{
+ service_map["route"] = util::make_unique<service::RouteService>(routing_machine);
+ service_map["table"] = util::make_unique<service::TableService>(routing_machine);
+ service_map["nearest"] = util::make_unique<service::NearestService>(routing_machine);
+ service_map["trip"] = util::make_unique<service::TripService>(routing_machine);
+ service_map["match"] = util::make_unique<service::MatchService>(routing_machine);
+ service_map["tile"] = util::make_unique<service::TileService>(routing_machine);
+}
+
+engine::Status ServiceHandler::RunQuery(api::ParsedURL parsed_url,
+ service::BaseService::ResultT &result)
+{
+ const auto &service_iter = service_map.find(parsed_url.service);
+ if (service_iter == service_map.end())
+ {
+ result = util::json::Object();
+ auto &json_result = result.get<util::json::Object>();
+ json_result.values["code"] = "InvalidService";
+ json_result.values["message"] = "Service " + parsed_url.service + " not found!";
+ return engine::Status::Error;
+ }
+ auto &service = service_iter->second;
+
+ if (service->GetVersion() != parsed_url.version)
+ {
+ result = util::json::Object();
+ auto &json_result = result.get<util::json::Object>();
+ json_result.values["code"] = "InvalidVersion";
+ json_result.values["message"] = "Service " + parsed_url.service + " not found!";
+ return engine::Status::Error;
+ }
+
+ return service->RunQuery(parsed_url.query, result);
+}
+}
+}
diff --git a/datastore.cpp b/src/storage/storage.cpp
similarity index 53%
rename from datastore.cpp
rename to src/storage/storage.cpp
index 504dd3d..862ca3c 100644
--- a/datastore.cpp
+++ b/src/storage/storage.cpp
@@ -1,54 +1,24 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "data_structures/original_edge_data.hpp"
-#include "data_structures/range_table.hpp"
-#include "data_structures/query_edge.hpp"
-#include "data_structures/query_node.hpp"
-#include "data_structures/shared_memory_factory.hpp"
-#include "data_structures/shared_memory_vector_wrapper.hpp"
-#include "data_structures/static_graph.hpp"
-#include "data_structures/static_rtree.hpp"
-#include "data_structures/travel_mode.hpp"
-#include "data_structures/turn_instructions.hpp"
-#include "server/data_structures/datafacade_base.hpp"
-#include "server/data_structures/shared_datatype.hpp"
-#include "server/data_structures/shared_barriers.hpp"
-#include "util/datastore_options.hpp"
-#include "util/simple_logger.hpp"
-#include "util/osrm_exception.hpp"
+#include "extractor/original_edge_data.hpp"
+#include "util/range_table.hpp"
+#include "contractor/query_edge.hpp"
+#include "extractor/query_node.hpp"
+#include "extractor/profile_properties.hpp"
+#include "extractor/compressed_edge_container.hpp"
+#include "util/shared_memory_vector_wrapper.hpp"
+#include "util/static_graph.hpp"
+#include "util/static_rtree.hpp"
+#include "engine/datafacade/datafacade_base.hpp"
+#include "extractor/travel_mode.hpp"
+#include "extractor/guidance/turn_instruction.hpp"
+#include "storage/storage.hpp"
+#include "storage/shared_datatype.hpp"
+#include "storage/shared_barriers.hpp"
+#include "storage/shared_memory.hpp"
#include "util/fingerprint.hpp"
-#include "typedefs.h"
-
-#include <osrm/coordinate.hpp>
-
-using RTreeLeaf = BaseDataFacade<QueryEdge::EdgeData>::RTreeLeaf;
-using RTreeNode = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode;
-using QueryGraph = StaticGraph<QueryEdge::EdgeData>;
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+#include "util/typedefs.hpp"
+#include "util/coordinate.hpp"
#ifdef __linux__
#include <sys/mman.h>
@@ -60,11 +30,21 @@ using QueryGraph = StaticGraph<QueryEdge::EdgeData>;
#include <cstdint>
#include <fstream>
-#include <string>
#include <new>
+#include <string>
+
+namespace osrm
+{
+namespace storage
+{
+
+using RTreeLeaf = typename engine::datafacade::BaseDataFacade::RTreeLeaf;
+using RTreeNode =
+ util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, true>::vector, true>::TreeNode;
+using QueryGraph = util::StaticGraph<contractor::QueryEdge::EdgeData>;
// delete a shared memory region. report warning if it could not be deleted
-void delete_region(const SharedDataType region)
+void deleteRegion(const SharedDataType region)
{
if (SharedMemory::RegionExists(region) && !SharedMemory::Remove(region))
{
@@ -89,13 +69,17 @@ void delete_region(const SharedDataType region)
}
}();
- SimpleLogger().Write(logWARNING) << "could not delete shared memory region " << name;
+ util::SimpleLogger().Write(logWARNING) << "could not delete shared memory region " << name;
}
}
-int main(const int argc, const char *argv[]) try
+Storage::Storage(StorageConfig config_) : config(std::move(config_)) {}
+
+int Storage::Run()
{
- LogPolicy::GetInstance().Unmute();
+ BOOST_ASSERT_MSG(config.IsValid(), "Invalid storage config");
+
+ util::LogPolicy::GetInstance().Unmute();
SharedBarriers barrier;
#ifdef __linux__
@@ -103,7 +87,7 @@ int main(const int argc, const char *argv[]) try
const bool lock_flags = MCL_CURRENT | MCL_FUTURE;
if (-1 == mlockall(lock_flags))
{
- SimpleLogger().Write(logWARNING) << "Process " << argv[0] << " could not request RAM lock";
+ util::SimpleLogger().Write(logWARNING) << "Could not request RAM lock";
}
#endif
@@ -118,122 +102,47 @@ int main(const int argc, const char *argv[]) try
barrier.pending_update_mutex.unlock();
}
- SimpleLogger().Write(logDEBUG) << "Checking input parameters";
-
- std::unordered_map<std::string, boost::filesystem::path> server_paths;
- if (!GenerateDataStoreOptions(argc, argv, server_paths))
- {
- return EXIT_SUCCESS;
- }
-
- if (server_paths.find("hsgrdata") == server_paths.end())
- {
- throw osrm::exception("no hsgr file found");
- }
- if (server_paths.find("ramindex") == server_paths.end())
- {
- throw osrm::exception("no ram index file found");
- }
- if (server_paths.find("fileindex") == server_paths.end())
- {
- throw osrm::exception("no leaf index file found");
- }
- if (server_paths.find("nodesdata") == server_paths.end())
- {
- throw osrm::exception("no nodes file found");
- }
- if (server_paths.find("edgesdata") == server_paths.end())
- {
- throw osrm::exception("no edges file found");
- }
- if (server_paths.find("namesdata") == server_paths.end())
- {
- throw osrm::exception("no names file found");
- }
- if (server_paths.find("geometry") == server_paths.end())
- {
- throw osrm::exception("no geometry file found");
- }
- if (server_paths.find("core") == server_paths.end())
- {
- throw osrm::exception("no core file found");
- }
-
- auto paths_iterator = server_paths.find("hsgrdata");
- BOOST_ASSERT(server_paths.end() != paths_iterator);
- BOOST_ASSERT(!paths_iterator->second.empty());
- const boost::filesystem::path &hsgr_path = paths_iterator->second;
- paths_iterator = server_paths.find("timestamp");
- BOOST_ASSERT(server_paths.end() != paths_iterator);
- BOOST_ASSERT(!paths_iterator->second.empty());
- const boost::filesystem::path ×tamp_path = paths_iterator->second;
- paths_iterator = server_paths.find("ramindex");
- BOOST_ASSERT(server_paths.end() != paths_iterator);
- BOOST_ASSERT(!paths_iterator->second.empty());
- const boost::filesystem::path &ram_index_path = paths_iterator->second;
- paths_iterator = server_paths.find("fileindex");
- BOOST_ASSERT(server_paths.end() != paths_iterator);
- BOOST_ASSERT(!paths_iterator->second.empty());
- const boost::filesystem::path index_file_path_absolute =
- boost::filesystem::canonical(paths_iterator->second);
- const std::string &file_index_path = index_file_path_absolute.string();
- paths_iterator = server_paths.find("nodesdata");
- BOOST_ASSERT(server_paths.end() != paths_iterator);
- BOOST_ASSERT(!paths_iterator->second.empty());
- const boost::filesystem::path &nodes_data_path = paths_iterator->second;
- paths_iterator = server_paths.find("edgesdata");
- BOOST_ASSERT(server_paths.end() != paths_iterator);
- BOOST_ASSERT(!paths_iterator->second.empty());
- const boost::filesystem::path &edges_data_path = paths_iterator->second;
- paths_iterator = server_paths.find("namesdata");
- BOOST_ASSERT(server_paths.end() != paths_iterator);
- BOOST_ASSERT(!paths_iterator->second.empty());
- const boost::filesystem::path &names_data_path = paths_iterator->second;
- paths_iterator = server_paths.find("geometry");
- BOOST_ASSERT(server_paths.end() != paths_iterator);
- BOOST_ASSERT(!paths_iterator->second.empty());
- const boost::filesystem::path &geometries_data_path = paths_iterator->second;
- paths_iterator = server_paths.find("core");
- BOOST_ASSERT(server_paths.end() != paths_iterator);
- BOOST_ASSERT(!paths_iterator->second.empty());
- const boost::filesystem::path &core_marker_path = paths_iterator->second;
-
// determine segment to use
bool segment2_in_use = SharedMemory::RegionExists(LAYOUT_2);
- const SharedDataType layout_region = [&]
+ const storage::SharedDataType layout_region = [&]
{
return segment2_in_use ? LAYOUT_1 : LAYOUT_2;
}();
- const SharedDataType data_region = [&]
+ const storage::SharedDataType data_region = [&]
{
return segment2_in_use ? DATA_1 : DATA_2;
}();
- const SharedDataType previous_layout_region = [&]
+ const storage::SharedDataType previous_layout_region = [&]
{
return segment2_in_use ? LAYOUT_2 : LAYOUT_1;
}();
- const SharedDataType previous_data_region = [&]
+ const storage::SharedDataType previous_data_region = [&]
{
return segment2_in_use ? DATA_2 : DATA_1;
}();
// Allocate a memory layout in shared memory, deallocate previous
- auto *layout_memory = SharedMemoryFactory::Get(layout_region, sizeof(SharedDataLayout));
- auto *shared_layout_ptr = new (layout_memory->Ptr()) SharedDataLayout();
+ auto *layout_memory = makeSharedMemory(layout_region, sizeof(SharedDataLayout));
+ auto shared_layout_ptr = new (layout_memory->Ptr()) SharedDataLayout();
+ auto absolute_file_index_path = boost::filesystem::absolute(config.file_index_path);
shared_layout_ptr->SetBlockSize<char>(SharedDataLayout::FILE_INDEX_PATH,
- file_index_path.length() + 1);
+ absolute_file_index_path.string().length() + 1);
// collect number of elements to store in shared memory object
- SimpleLogger().Write() << "load names from: " << names_data_path;
+ util::SimpleLogger().Write() << "load names from: " << config.names_data_path;
// number of entries in name index
- boost::filesystem::ifstream name_stream(names_data_path, std::ios::binary);
+ boost::filesystem::ifstream name_stream(config.names_data_path, std::ios::binary);
+ if (!name_stream)
+ {
+ throw util::exception("Could not open " + config.names_data_path.string() + " for reading.");
+ }
unsigned name_blocks = 0;
name_stream.read((char *)&name_blocks, sizeof(unsigned));
shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::NAME_OFFSETS, name_blocks);
- shared_layout_ptr->SetBlockSize<typename RangeTable<16, true>::BlockT>(
+ shared_layout_ptr->SetBlockSize<typename util::RangeTable<16, true>::BlockT>(
SharedDataLayout::NAME_BLOCKS, name_blocks);
- SimpleLogger().Write() << "name offsets size: " << name_blocks;
+ util::SimpleLogger().Write() << "name offsets size: " << name_blocks;
BOOST_ASSERT_MSG(0 != name_blocks, "name file broken");
unsigned number_of_chars = 0;
@@ -241,7 +150,11 @@ int main(const int argc, const char *argv[]) try
shared_layout_ptr->SetBlockSize<char>(SharedDataLayout::NAME_CHAR_LIST, number_of_chars);
// Loading information for original edges
- boost::filesystem::ifstream edges_input_stream(edges_data_path, std::ios::binary);
+ boost::filesystem::ifstream edges_input_stream(config.edges_data_path, std::ios::binary);
+ if (!edges_input_stream)
+ {
+ throw util::exception("Could not open " + config.edges_data_path.string() + " for reading.");
+ }
unsigned number_of_original_edges = 0;
edges_input_stream.read((char *)&number_of_original_edges, sizeof(unsigned));
@@ -250,27 +163,28 @@ int main(const int argc, const char *argv[]) try
number_of_original_edges);
shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::NAME_ID_LIST,
number_of_original_edges);
- shared_layout_ptr->SetBlockSize<TravelMode>(SharedDataLayout::TRAVEL_MODE,
- number_of_original_edges);
- shared_layout_ptr->SetBlockSize<TurnInstruction>(SharedDataLayout::TURN_INSTRUCTION,
- number_of_original_edges);
- // note: there are 32 geometry indicators in one unsigned block
- shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::GEOMETRIES_INDICATORS,
- number_of_original_edges);
+ shared_layout_ptr->SetBlockSize<extractor::TravelMode>(SharedDataLayout::TRAVEL_MODE,
+ number_of_original_edges);
+ shared_layout_ptr->SetBlockSize<extractor::guidance::TurnInstruction>(
+ SharedDataLayout::TURN_INSTRUCTION, number_of_original_edges);
- boost::filesystem::ifstream hsgr_input_stream(hsgr_path, std::ios::binary);
+ boost::filesystem::ifstream hsgr_input_stream(config.hsgr_data_path, std::ios::binary);
+ if (!hsgr_input_stream)
+ {
+ throw util::exception("Could not open " + config.hsgr_data_path.string() + " for reading.");
+ }
- FingerPrint fingerprint_valid = FingerPrint::GetValid();
- FingerPrint fingerprint_loaded;
- hsgr_input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
+ util::FingerPrint fingerprint_valid = util::FingerPrint::GetValid();
+ util::FingerPrint fingerprint_loaded;
+ hsgr_input_stream.read((char *)&fingerprint_loaded, sizeof(util::FingerPrint));
if (fingerprint_loaded.TestGraphUtil(fingerprint_valid))
{
- SimpleLogger().Write(logDEBUG) << "Fingerprint checked out ok";
+ util::SimpleLogger().Write(logDEBUG) << "Fingerprint checked out ok";
}
else
{
- SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build. "
- "Reprocess to get rid of this warning.";
+ util::SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build. "
+ "Reprocess to get rid of this warning.";
}
// load checksum
@@ -293,39 +207,27 @@ int main(const int argc, const char *argv[]) try
number_of_graph_edges);
// load rsearch tree size
- boost::filesystem::ifstream tree_node_file(ram_index_path, std::ios::binary);
+ boost::filesystem::ifstream tree_node_file(config.ram_index_path, std::ios::binary);
uint32_t tree_size = 0;
tree_node_file.read((char *)&tree_size, sizeof(uint32_t));
shared_layout_ptr->SetBlockSize<RTreeNode>(SharedDataLayout::R_SEARCH_TREE, tree_size);
+ // load profile properties
+ shared_layout_ptr->SetBlockSize<extractor::ProfileProperties>(SharedDataLayout::PROPERTIES, 1);
+
// load timestamp size
+ boost::filesystem::ifstream timestamp_stream(config.timestamp_path);
std::string m_timestamp;
- if (boost::filesystem::exists(timestamp_path))
- {
- boost::filesystem::ifstream timestamp_stream(timestamp_path);
- if (!timestamp_stream)
- {
- SimpleLogger().Write(logWARNING) << timestamp_path << " not found. setting to default";
- }
- else
- {
- getline(timestamp_stream, m_timestamp);
- timestamp_stream.close();
- }
- }
- if (m_timestamp.empty())
- {
- m_timestamp = "n/a";
- }
- if (25 < m_timestamp.length())
- {
- m_timestamp.resize(25);
- }
+ getline(timestamp_stream, m_timestamp);
shared_layout_ptr->SetBlockSize<char>(SharedDataLayout::TIMESTAMP, m_timestamp.length());
// load core marker size
- boost::filesystem::ifstream core_marker_file(core_marker_path, std::ios::binary);
+ boost::filesystem::ifstream core_marker_file(config.core_data_path, std::ios::binary);
+ if (!core_marker_file)
+ {
+ throw util::exception("Could not open " + config.core_data_path.string() + " for reading.");
+ }
uint32_t number_of_core_markers = 0;
core_marker_file.read((char *)&number_of_core_markers, sizeof(uint32_t));
@@ -333,14 +235,22 @@ int main(const int argc, const char *argv[]) try
number_of_core_markers);
// load coordinate size
- boost::filesystem::ifstream nodes_input_stream(nodes_data_path, std::ios::binary);
+ boost::filesystem::ifstream nodes_input_stream(config.nodes_data_path, std::ios::binary);
+ if (!nodes_input_stream)
+ {
+ throw util::exception("Could not open " + config.core_data_path.string() + " for reading.");
+ }
unsigned coordinate_list_size = 0;
nodes_input_stream.read((char *)&coordinate_list_size, sizeof(unsigned));
- shared_layout_ptr->SetBlockSize<FixedPointCoordinate>(SharedDataLayout::COORDINATE_LIST,
- coordinate_list_size);
+ shared_layout_ptr->SetBlockSize<util::Coordinate>(SharedDataLayout::COORDINATE_LIST,
+ coordinate_list_size);
// load geometries sizes
- std::ifstream geometry_input_stream(geometries_data_path.string().c_str(), std::ios::binary);
+ boost::filesystem::ifstream geometry_input_stream(config.geometries_path, std::ios::binary);
+ if (!geometry_input_stream)
+ {
+ throw util::exception("Could not open " + config.geometries_path.string() + " for reading.");
+ }
unsigned number_of_geometries_indices = 0;
unsigned number_of_compressed_geometries = 0;
@@ -350,13 +260,59 @@ int main(const int argc, const char *argv[]) try
boost::iostreams::seek(geometry_input_stream, number_of_geometries_indices * sizeof(unsigned),
BOOST_IOS::cur);
geometry_input_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
- shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::GEOMETRIES_LIST,
- number_of_compressed_geometries);
+ shared_layout_ptr->SetBlockSize<extractor::CompressedEdgeContainer::CompressedEdge>(
+ SharedDataLayout::GEOMETRIES_LIST, number_of_compressed_geometries);
+
+ // load datasource sizes. This file is optional, and it's non-fatal if it doesn't
+ // exist.
+ boost::filesystem::ifstream geometry_datasource_input_stream(config.datasource_indexes_path,
+ std::ios::binary);
+ if (!geometry_datasource_input_stream)
+ {
+ throw util::exception("Could not open " + config.datasource_indexes_path.string() + " for reading.");
+ }
+ std::size_t number_of_compressed_datasources = 0;
+ if (geometry_datasource_input_stream)
+ {
+ geometry_datasource_input_stream.read(
+ reinterpret_cast<char *>(&number_of_compressed_datasources), sizeof(std::size_t));
+ }
+ shared_layout_ptr->SetBlockSize<uint8_t>(SharedDataLayout::DATASOURCES_LIST,
+ number_of_compressed_datasources);
+
+ // Load datasource name sizes. This file is optional, and it's non-fatal if it doesn't
+ // exist
+ boost::filesystem::ifstream datasource_names_input_stream(config.datasource_names_path,
+ std::ios::binary);
+ if (!datasource_names_input_stream)
+ {
+ throw util::exception("Could not open " + config.datasource_names_path.string() + " for reading.");
+ }
+ std::vector<char> m_datasource_name_data;
+ std::vector<std::size_t> m_datasource_name_offsets;
+ std::vector<std::size_t> m_datasource_name_lengths;
+ if (datasource_names_input_stream)
+ {
+ std::string name;
+ while (std::getline(datasource_names_input_stream, name))
+ {
+ m_datasource_name_offsets.push_back(m_datasource_name_data.size());
+ std::copy(name.c_str(), name.c_str() + name.size(),
+ std::back_inserter(m_datasource_name_data));
+ m_datasource_name_lengths.push_back(name.size());
+ }
+ }
+ shared_layout_ptr->SetBlockSize<char>(SharedDataLayout::DATASOURCE_NAME_DATA,
+ m_datasource_name_data.size());
+ shared_layout_ptr->SetBlockSize<std::size_t>(SharedDataLayout::DATASOURCE_NAME_OFFSETS,
+ m_datasource_name_offsets.size());
+ shared_layout_ptr->SetBlockSize<std::size_t>(SharedDataLayout::DATASOURCE_NAME_LENGTHS,
+ m_datasource_name_lengths.size());
+
// allocate shared memory block
- SimpleLogger().Write() << "allocating shared memory of " << shared_layout_ptr->GetSizeOfLayout()
- << " bytes";
- SharedMemory *shared_memory =
- SharedMemoryFactory::Get(data_region, shared_layout_ptr->GetSizeOfLayout());
+ util::SimpleLogger().Write() << "allocating shared memory of "
+ << shared_layout_ptr->GetSizeOfLayout() << " bytes";
+ auto *shared_memory = makeSharedMemory(data_region, shared_layout_ptr->GetSizeOfLayout());
char *shared_memory_ptr = static_cast<char *>(shared_memory->Ptr());
// read actual data into shared memory object //
@@ -374,7 +330,7 @@ int main(const int argc, const char *argv[]) try
file_index_path_ptr +
shared_layout_ptr->GetBlockSize(SharedDataLayout::FILE_INDEX_PATH),
0);
- std::copy(file_index_path.begin(), file_index_path.end(), file_index_path_ptr);
+ std::copy(absolute_file_index_path.string().begin(), absolute_file_index_path.string().end(), file_index_path_ptr);
// Loading street names
unsigned *name_offsets_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
@@ -417,39 +373,22 @@ int main(const int argc, const char *argv[]) try
unsigned *name_id_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
shared_memory_ptr, SharedDataLayout::NAME_ID_LIST);
- TravelMode *travel_mode_ptr = shared_layout_ptr->GetBlockPtr<TravelMode, true>(
- shared_memory_ptr, SharedDataLayout::TRAVEL_MODE);
-
- TurnInstruction *turn_instructions_ptr = shared_layout_ptr->GetBlockPtr<TurnInstruction, true>(
- shared_memory_ptr, SharedDataLayout::TURN_INSTRUCTION);
+ extractor::TravelMode *travel_mode_ptr =
+ shared_layout_ptr->GetBlockPtr<extractor::TravelMode, true>(shared_memory_ptr,
+ SharedDataLayout::TRAVEL_MODE);
- unsigned *geometries_indicator_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
- shared_memory_ptr, SharedDataLayout::GEOMETRIES_INDICATORS);
+ extractor::guidance::TurnInstruction *turn_instructions_ptr =
+ shared_layout_ptr->GetBlockPtr<extractor::guidance::TurnInstruction, true>(
+ shared_memory_ptr, SharedDataLayout::TURN_INSTRUCTION);
- OriginalEdgeData current_edge_data;
+ extractor::OriginalEdgeData current_edge_data;
for (unsigned i = 0; i < number_of_original_edges; ++i)
{
- edges_input_stream.read((char *)&(current_edge_data), sizeof(OriginalEdgeData));
+ edges_input_stream.read((char *)&(current_edge_data), sizeof(extractor::OriginalEdgeData));
via_node_ptr[i] = current_edge_data.via_node;
name_id_ptr[i] = current_edge_data.name_id;
travel_mode_ptr[i] = current_edge_data.travel_mode;
turn_instructions_ptr[i] = current_edge_data.turn_instruction;
-
- const unsigned bucket = i / 32;
- const unsigned offset = i % 32;
- const unsigned value = [&]
- {
- unsigned return_value = 0;
- if (0 != offset)
- {
- return_value = geometries_indicator_ptr[bucket];
- }
- return return_value;
- }();
- if (current_edge_data.compressed_geometry)
- {
- geometries_indicator_ptr[bucket] = (value | (1 << offset));
- }
}
edges_input_stream.close();
@@ -468,8 +407,9 @@ int main(const int argc, const char *argv[]) try
(char *)geometries_index_ptr,
shared_layout_ptr->GetBlockSize(SharedDataLayout::GEOMETRIES_INDEX));
}
- unsigned *geometries_list_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
- shared_memory_ptr, SharedDataLayout::GEOMETRIES_LIST);
+ extractor::CompressedEdgeContainer::CompressedEdge *geometries_list_ptr =
+ shared_layout_ptr->GetBlockPtr<extractor::CompressedEdgeContainer::CompressedEdge, true>(
+ shared_memory_ptr, SharedDataLayout::GEOMETRIES_LIST);
geometry_input_stream.read((char *)&temporary_value, sizeof(unsigned));
BOOST_ASSERT(temporary_value ==
@@ -482,16 +422,52 @@ int main(const int argc, const char *argv[]) try
shared_layout_ptr->GetBlockSize(SharedDataLayout::GEOMETRIES_LIST));
}
+ // load datasource information (if it exists)
+ uint8_t *datasources_list_ptr = shared_layout_ptr->GetBlockPtr<uint8_t, true>(
+ shared_memory_ptr, SharedDataLayout::DATASOURCES_LIST);
+ if (shared_layout_ptr->GetBlockSize(SharedDataLayout::DATASOURCES_LIST) > 0)
+ {
+ geometry_datasource_input_stream.read(
+ reinterpret_cast<char *>(datasources_list_ptr),
+ shared_layout_ptr->GetBlockSize(SharedDataLayout::DATASOURCES_LIST));
+ }
+
+ // load datasource name information (if it exists)
+ char *datasource_name_data_ptr = shared_layout_ptr->GetBlockPtr<char, true>(
+ shared_memory_ptr, SharedDataLayout::DATASOURCE_NAME_DATA);
+ if (shared_layout_ptr->GetBlockSize(SharedDataLayout::DATASOURCE_NAME_DATA) > 0)
+ {
+ std::cout << "Copying " << (m_datasource_name_data.end() - m_datasource_name_data.begin())
+ << " chars into name data ptr\n";
+ std::copy(m_datasource_name_data.begin(), m_datasource_name_data.end(),
+ datasource_name_data_ptr);
+ }
+
+ auto datasource_name_offsets_ptr = shared_layout_ptr->GetBlockPtr<std::size_t, true>(
+ shared_memory_ptr, SharedDataLayout::DATASOURCE_NAME_OFFSETS);
+ if (shared_layout_ptr->GetBlockSize(SharedDataLayout::DATASOURCE_NAME_OFFSETS) > 0)
+ {
+ std::copy(m_datasource_name_offsets.begin(), m_datasource_name_offsets.end(),
+ datasource_name_offsets_ptr);
+ }
+
+ auto datasource_name_lengths_ptr = shared_layout_ptr->GetBlockPtr<std::size_t, true>(
+ shared_memory_ptr, SharedDataLayout::DATASOURCE_NAME_LENGTHS);
+ if (shared_layout_ptr->GetBlockSize(SharedDataLayout::DATASOURCE_NAME_LENGTHS) > 0)
+ {
+ std::copy(m_datasource_name_lengths.begin(), m_datasource_name_lengths.end(),
+ datasource_name_lengths_ptr);
+ }
+
// Loading list of coordinates
- FixedPointCoordinate *coordinates_ptr =
- shared_layout_ptr->GetBlockPtr<FixedPointCoordinate, true>(
- shared_memory_ptr, SharedDataLayout::COORDINATE_LIST);
+ util::Coordinate *coordinates_ptr = shared_layout_ptr->GetBlockPtr<util::Coordinate, true>(
+ shared_memory_ptr, SharedDataLayout::COORDINATE_LIST);
- QueryNode current_node;
+ extractor::QueryNode current_node;
for (unsigned i = 0; i < coordinate_list_size; ++i)
{
- nodes_input_stream.read((char *)¤t_node, sizeof(QueryNode));
- coordinates_ptr[i] = FixedPointCoordinate(current_node.lat, current_node.lon);
+ nodes_input_stream.read((char *)¤t_node, sizeof(extractor::QueryNode));
+ coordinates_ptr[i] = util::Coordinate(current_node.lon, current_node.lat);
}
nodes_input_stream.close();
@@ -536,7 +512,7 @@ int main(const int argc, const char *argv[]) try
return return_value;
}();
- core_marker_ptr[bucket] = (value | (1 << offset));
+ core_marker_ptr[bucket] = (value | (1u << offset));
}
}
@@ -561,9 +537,18 @@ int main(const int argc, const char *argv[]) try
}
hsgr_input_stream.close();
+ // load profile properties
+ auto profile_properties_ptr = shared_layout_ptr->GetBlockPtr<extractor::ProfileProperties, true>(shared_memory_ptr, SharedDataLayout::PROPERTIES);
+ boost::filesystem::ifstream profile_properties_stream(config.properties_path);
+ if (!profile_properties_stream)
+ {
+ util::exception("Could not open " + config.properties_path.string() + " for reading!");
+ }
+ profile_properties_stream.read(reinterpret_cast<char*>(profile_properties_ptr), sizeof(extractor::ProfileProperties));
+
// acquire lock
SharedMemory *data_type_memory =
- SharedMemoryFactory::Get(CURRENT_REGIONS, sizeof(SharedDataTimestamp), true, false);
+ makeSharedMemory(CURRENT_REGIONS, sizeof(SharedDataTimestamp), true, false);
SharedDataTimestamp *data_timestamp_ptr =
static_cast<SharedDataTimestamp *>(data_type_memory->Ptr());
@@ -579,20 +564,11 @@ int main(const int argc, const char *argv[]) try
data_timestamp_ptr->layout = layout_region;
data_timestamp_ptr->data = data_region;
data_timestamp_ptr->timestamp += 1;
- delete_region(previous_data_region);
- delete_region(previous_layout_region);
- SimpleLogger().Write() << "all data loaded";
+ deleteRegion(previous_data_region);
+ deleteRegion(previous_layout_region);
+ util::SimpleLogger().Write() << "all data loaded";
- shared_layout_ptr->PrintInformation();
+ return EXIT_SUCCESS;
}
-catch (const std::bad_alloc &e)
-{
- SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
- SimpleLogger().Write(logWARNING) << "Please provide more memory or disable locking the virtual "
- "address space (note: this makes OSRM swap, i.e. slow)";
- return EXIT_FAILURE;
}
-catch (const std::exception &e)
-{
- SimpleLogger().Write(logWARNING) << "caught exception: " << e.what();
}
diff --git a/src/storage/storage_config.cpp b/src/storage/storage_config.cpp
new file mode 100644
index 0000000..6ade34a
--- /dev/null
+++ b/src/storage/storage_config.cpp
@@ -0,0 +1,38 @@
+#include "storage/storage_config.hpp"
+
+#include <boost/filesystem/operations.hpp>
+
+namespace osrm
+{
+namespace storage
+{
+
+StorageConfig::StorageConfig(const boost::filesystem::path &base)
+ : ram_index_path{base.string() + ".ramIndex"}, file_index_path{base.string() + ".fileIndex"},
+ hsgr_data_path{base.string() + ".hsgr"}, nodes_data_path{base.string() + ".nodes"},
+ edges_data_path{base.string() + ".edges"}, core_data_path{base.string() + ".core"},
+ geometries_path{base.string() + ".geometry"}, timestamp_path{base.string() + ".timestamp"},
+ datasource_names_path{base.string() + ".datasource_names"},
+ datasource_indexes_path{base.string() + ".datasource_indexes"},
+ names_data_path{base.string() + ".names"},
+ properties_path{base.string() + ".properties"}
+{
+}
+
+bool StorageConfig::IsValid() const
+{
+ return boost::filesystem::is_regular_file(ram_index_path) &&
+ boost::filesystem::is_regular_file(file_index_path) &&
+ boost::filesystem::is_regular_file(hsgr_data_path) &&
+ boost::filesystem::is_regular_file(nodes_data_path) &&
+ boost::filesystem::is_regular_file(edges_data_path) &&
+ boost::filesystem::is_regular_file(core_data_path) &&
+ boost::filesystem::is_regular_file(geometries_path) &&
+ boost::filesystem::is_regular_file(timestamp_path) &&
+ boost::filesystem::is_regular_file(datasource_names_path) &&
+ boost::filesystem::is_regular_file(datasource_indexes_path) &&
+ boost::filesystem::is_regular_file(names_data_path) &&
+ boost::filesystem::is_regular_file(properties_path);
+}
+}
+}
diff --git a/tools/.gitignore b/src/tools/.gitignore
similarity index 100%
rename from tools/.gitignore
rename to src/tools/.gitignore
diff --git a/src/tools/components.cpp b/src/tools/components.cpp
new file mode 100644
index 0000000..45131a8
--- /dev/null
+++ b/src/tools/components.cpp
@@ -0,0 +1,233 @@
+#include "util/typedefs.hpp"
+#include "extractor/tarjan_scc.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/dynamic_graph.hpp"
+#include "util/static_graph.hpp"
+#include "util/fingerprint.hpp"
+#include "util/graph_loader.hpp"
+#include "util/make_unique.hpp"
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+
+#include <boost/filesystem.hpp>
+
+#if defined(__APPLE__) || defined(_WIN32)
+#include <gdal.h>
+#include <ogrsf_frmts.h>
+#else
+#include <gdal/gdal.h>
+#include <gdal/ogrsf_frmts.h>
+#endif
+
+#include "osrm/coordinate.hpp"
+
+#include <fstream>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace osrm
+{
+namespace tools
+{
+
+struct TarjanEdgeData
+{
+ TarjanEdgeData() : distance(INVALID_EDGE_WEIGHT), name_id(INVALID_NAMEID) {}
+ TarjanEdgeData(unsigned distance, unsigned name_id) : distance(distance), name_id(name_id) {}
+ unsigned distance;
+ unsigned name_id;
+};
+
+using TarjanGraph = util::StaticGraph<TarjanEdgeData>;
+using TarjanEdge = TarjanGraph::InputEdge;
+
+void deleteFileIfExists(const std::string &file_name)
+{
+ if (boost::filesystem::exists(file_name))
+ {
+ boost::filesystem::remove(file_name);
+ }
+}
+
+std::size_t loadGraph(const char *path,
+ std::vector<extractor::QueryNode> &coordinate_list,
+ std::vector<TarjanEdge> &graph_edge_list)
+{
+ std::ifstream input_stream(path, std::ifstream::in | std::ifstream::binary);
+ if (!input_stream.is_open())
+ {
+ throw util::exception("Cannot open osrm file");
+ }
+
+ // load graph data
+ std::vector<extractor::NodeBasedEdge> edge_list;
+ std::vector<NodeID> traffic_light_node_list;
+ std::vector<NodeID> barrier_node_list;
+
+ auto number_of_nodes = util::loadNodesFromFile(input_stream, barrier_node_list,
+ traffic_light_node_list, coordinate_list);
+
+ util::loadEdgesFromFile(input_stream, edge_list);
+
+ traffic_light_node_list.clear();
+ traffic_light_node_list.shrink_to_fit();
+
+ // Building an node-based graph
+ for (const auto &input_edge : edge_list)
+ {
+ if (input_edge.source == input_edge.target)
+ {
+ continue;
+ }
+
+ if (input_edge.forward)
+ {
+ graph_edge_list.emplace_back(input_edge.source, input_edge.target,
+ (std::max)(input_edge.weight, 1), input_edge.name_id);
+ }
+ if (input_edge.backward)
+ {
+ graph_edge_list.emplace_back(input_edge.target, input_edge.source,
+ (std::max)(input_edge.weight, 1), input_edge.name_id);
+ }
+ }
+
+ return number_of_nodes;
+}
+}
+}
+
+int main(int argc, char *argv[]) try
+{
+ std::vector<osrm::extractor::QueryNode> coordinate_list;
+ osrm::util::LogPolicy::GetInstance().Unmute();
+
+ // enable logging
+ if (argc < 2)
+ {
+ osrm::util::SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0] << " <osrm>";
+ return EXIT_FAILURE;
+ }
+
+ std::vector<osrm::tools::TarjanEdge> graph_edge_list;
+ auto number_of_nodes = osrm::tools::loadGraph(argv[1], coordinate_list, graph_edge_list);
+
+ tbb::parallel_sort(graph_edge_list.begin(), graph_edge_list.end());
+ const auto graph = std::make_shared<osrm::tools::TarjanGraph>(number_of_nodes, graph_edge_list);
+ graph_edge_list.clear();
+ graph_edge_list.shrink_to_fit();
+
+ osrm::util::SimpleLogger().Write() << "Starting SCC graph traversal";
+
+ auto tarjan =
+ osrm::util::make_unique<osrm::extractor::TarjanSCC<osrm::tools::TarjanGraph>>(graph);
+ tarjan->run();
+ osrm::util::SimpleLogger().Write() << "identified: " << tarjan->get_number_of_components()
+ << " many components";
+ osrm::util::SimpleLogger().Write() << "identified " << tarjan->get_size_one_count()
+ << " size 1 SCCs";
+
+ // output
+ TIMER_START(SCC_RUN_SETUP);
+
+ // remove files from previous run if exist
+ osrm::tools::deleteFileIfExists("component.dbf");
+ osrm::tools::deleteFileIfExists("component.shx");
+ osrm::tools::deleteFileIfExists("component.shp");
+
+ osrm::util::Percent percentage(graph->GetNumberOfNodes());
+
+ OGRRegisterAll();
+
+ const char *psz_driver_name = "ESRI Shapefile";
+ auto *po_driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(psz_driver_name);
+ if (nullptr == po_driver)
+ {
+ throw osrm::util::exception("ESRI Shapefile driver not available");
+ }
+ auto *po_datasource = po_driver->CreateDataSource("component.shp", nullptr);
+
+ if (nullptr == po_datasource)
+ {
+ throw osrm::util::exception("Creation of output file failed");
+ }
+
+ auto *po_srs = new OGRSpatialReference();
+ po_srs->importFromEPSG(4326);
+
+ auto *po_layer = po_datasource->CreateLayer("component", po_srs, wkbLineString, nullptr);
+
+ if (nullptr == po_layer)
+ {
+ throw osrm::util::exception("Layer creation failed.");
+ }
+ TIMER_STOP(SCC_RUN_SETUP);
+ osrm::util::SimpleLogger().Write() << "shapefile setup took "
+ << TIMER_MSEC(SCC_RUN_SETUP) / 1000. << "s";
+
+ uint64_t total_network_length = 0;
+ percentage.reinit(graph->GetNumberOfNodes());
+ TIMER_START(SCC_OUTPUT);
+ for (const NodeID source : osrm::util::irange(0u, graph->GetNumberOfNodes()))
+ {
+ percentage.printIncrement();
+ for (const auto current_edge : graph->GetAdjacentEdgeRange(source))
+ {
+ const auto target = graph->GetTarget(current_edge);
+
+ if (source < target || SPECIAL_EDGEID == graph->FindEdge(target, source))
+ {
+ total_network_length +=
+ 100 * osrm::util::coordinate_calculation::greatCircleDistance(
+ coordinate_list[source], coordinate_list[target]);
+
+ BOOST_ASSERT(current_edge != SPECIAL_EDGEID);
+ BOOST_ASSERT(source != SPECIAL_NODEID);
+ BOOST_ASSERT(target != SPECIAL_NODEID);
+
+ const unsigned size_of_containing_component =
+ std::min(tarjan->get_component_size(tarjan->get_component_id(source)),
+ tarjan->get_component_size(tarjan->get_component_id(target)));
+
+ // edges that end on bollard nodes may actually be in two distinct components
+ if (size_of_containing_component < 1000)
+ {
+ OGRLineString line_string;
+ line_string.addPoint(
+ static_cast<double>(osrm::util::toFloating(coordinate_list[source].lon)),
+ static_cast<double>(osrm::util::toFloating(coordinate_list[source].lat)));
+ line_string.addPoint(
+ static_cast<double>(osrm::util::toFloating(coordinate_list[target].lon)),
+ static_cast<double>(osrm::util::toFloating(coordinate_list[target].lat)));
+
+ OGRFeature *po_feature = OGRFeature::CreateFeature(po_layer->GetLayerDefn());
+
+ po_feature->SetGeometry(&line_string);
+ if (OGRERR_NONE != po_layer->CreateFeature(po_feature))
+ {
+ throw osrm::util::exception("Failed to create feature in shapefile.");
+ }
+ OGRFeature::DestroyFeature(po_feature);
+ }
+ }
+ }
+ }
+ OGRSpatialReference::DestroySpatialReference(po_srs);
+ OGRDataSource::DestroyDataSource(po_datasource);
+ TIMER_STOP(SCC_OUTPUT);
+ osrm::util::SimpleLogger().Write()
+ << "generating output took: " << TIMER_MSEC(SCC_OUTPUT) / 1000. << "s";
+
+ osrm::util::SimpleLogger().Write()
+ << "total network distance: " << static_cast<uint64_t>(total_network_length / 100 / 1000.)
+ << " km";
+
+ osrm::util::SimpleLogger().Write() << "finished component analysis";
+ return EXIT_SUCCESS;
+}
+catch (const std::exception &e)
+{
+ osrm::util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+ return EXIT_FAILURE;
+}
diff --git a/src/tools/contract.cpp b/src/tools/contract.cpp
new file mode 100644
index 0000000..5bc65c5
--- /dev/null
+++ b/src/tools/contract.cpp
@@ -0,0 +1,159 @@
+#include "contractor/contractor.hpp"
+#include "contractor/contractor_config.hpp"
+#include "util/simple_logger.hpp"
+#include "util/version.hpp"
+
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+#include <boost/program_options/errors.hpp>
+
+#include <tbb/task_scheduler_init.h>
+
+#include <cstdlib>
+#include <exception>
+#include <new>
+#include <ostream>
+
+using namespace osrm;
+
+enum class return_code : unsigned
+{
+ ok,
+ fail,
+ exit
+};
+
+return_code parseArguments(int argc, char *argv[], contractor::ContractorConfig &contractor_config)
+{
+ // declare a group of options that will be allowed only on command line
+ boost::program_options::options_description generic_options("Options");
+ generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message");
+
+ // declare a group of options that will be allowed on command line
+ boost::program_options::options_description config_options("Configuration");
+ config_options.add_options()(
+ "threads,t",
+ boost::program_options::value<unsigned int>(&contractor_config.requested_num_threads)
+ ->default_value(tbb::task_scheduler_init::default_num_threads()),
+ "Number of threads to use")(
+ "core,k",
+ boost::program_options::value<double>(&contractor_config.core_factor)->default_value(1.0),
+ "Percentage of the graph (in vertices) to contract [0..1]")(
+ "segment-speed-file", boost::program_options::value<std::vector<std::string>>(
+ &contractor_config.segment_speed_lookup_paths)
+ ->composing(),
+ "Lookup files containing nodeA, nodeB, speed data to adjust edge weights")(
+ "level-cache,o", boost::program_options::value<bool>(&contractor_config.use_cached_priority)
+ ->default_value(false),
+ "Use .level file to retain the contaction level for each node from the last run.");
+
+ // hidden options, will be allowed on command line, but will not be shown to the user
+ boost::program_options::options_description hidden_options("Hidden options");
+ hidden_options.add_options()("input,i", boost::program_options::value<boost::filesystem::path>(
+ &contractor_config.osrm_input_path),
+ "Input file in .osm, .osm.bz2 or .osm.pbf format");
+
+ // positional option
+ boost::program_options::positional_options_description positional_options;
+ positional_options.add("input", 1);
+
+ // combine above options for parsing
+ boost::program_options::options_description cmdline_options;
+ cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+
+ boost::program_options::options_description visible_options(
+ "Usage: " + boost::filesystem::basename(argv[0]) + " <input.osrm> [options]");
+ visible_options.add(generic_options).add(config_options);
+
+ // parse command line options
+ boost::program_options::variables_map option_variables;
+ boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
+ .options(cmdline_options)
+ .positional(positional_options)
+ .run(),
+ option_variables);
+
+ if (option_variables.count("version"))
+ {
+ util::SimpleLogger().Write() << OSRM_VERSION;
+ return return_code::exit;
+ }
+
+ if (option_variables.count("help"))
+ {
+ util::SimpleLogger().Write() << visible_options;
+ return return_code::exit;
+ }
+
+ boost::program_options::notify(option_variables);
+
+ if (!option_variables.count("input"))
+ {
+ util::SimpleLogger().Write() << visible_options;
+ return return_code::fail;
+ }
+
+ return return_code::ok;
+}
+
+int main(int argc, char *argv[]) try
+{
+ util::LogPolicy::GetInstance().Unmute();
+ contractor::ContractorConfig contractor_config;
+
+ const return_code result = parseArguments(argc, argv, contractor_config);
+
+ if (return_code::fail == result)
+ {
+ return EXIT_FAILURE;
+ }
+
+ if (return_code::exit == result)
+ {
+ return EXIT_SUCCESS;
+ }
+
+ contractor_config.UseDefaultOutputNames();
+
+ if (1 > contractor_config.requested_num_threads)
+ {
+ util::SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
+ return EXIT_FAILURE;
+ }
+
+ const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
+
+ if (recommended_num_threads != contractor_config.requested_num_threads)
+ {
+ util::SimpleLogger().Write(logWARNING)
+ << "The recommended number of threads is " << recommended_num_threads
+ << "! This setting may have performance side-effects.";
+ }
+
+ if (!boost::filesystem::is_regular_file(contractor_config.osrm_input_path))
+ {
+ util::SimpleLogger().Write(logWARNING)
+ << "Input file " << contractor_config.osrm_input_path.string() << " not found!";
+ return EXIT_FAILURE;
+ }
+
+ util::SimpleLogger().Write() << "Input file: "
+ << contractor_config.osrm_input_path.filename().string();
+ util::SimpleLogger().Write() << "Threads: " << contractor_config.requested_num_threads;
+
+ tbb::task_scheduler_init init(contractor_config.requested_num_threads);
+
+ return contractor::Contractor(contractor_config).Run();
+}
+catch (const std::bad_alloc &e)
+{
+ util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+ util::SimpleLogger().Write(logWARNING)
+ << "Please provide more memory or consider using a larger swapfile";
+ return EXIT_FAILURE;
+}
+catch (const std::exception &e)
+{
+ util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+ return EXIT_FAILURE;
+}
diff --git a/src/tools/extract.cpp b/src/tools/extract.cpp
new file mode 100644
index 0000000..4c5fa4c
--- /dev/null
+++ b/src/tools/extract.cpp
@@ -0,0 +1,160 @@
+#include "extractor/extractor.hpp"
+#include "extractor/extractor_config.hpp"
+#include "util/simple_logger.hpp"
+#include "util/version.hpp"
+
+#include <tbb/task_scheduler_init.h>
+
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+
+#include <cstdlib>
+#include <exception>
+#include <new>
+
+using namespace osrm;
+
+enum class return_code : unsigned
+{
+ ok,
+ fail,
+ exit
+};
+
+return_code parseArguments(int argc, char *argv[], extractor::ExtractorConfig &extractor_config)
+{
+ // declare a group of options that will be allowed only on command line
+ boost::program_options::options_description generic_options("Options");
+ generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message");
+
+ // declare a group of options that will be allowed both on command line
+ boost::program_options::options_description config_options("Configuration");
+ config_options.add_options()(
+ "profile,p",
+ boost::program_options::value<boost::filesystem::path>(&extractor_config.profile_path)
+ ->default_value("profile.lua"),
+ "Path to LUA routing profile")(
+ "threads,t",
+ boost::program_options::value<unsigned int>(&extractor_config.requested_num_threads)
+ ->default_value(tbb::task_scheduler_init::default_num_threads()),
+ "Number of threads to use")(
+ "generate-edge-lookup",
+ boost::program_options::value<bool>(&extractor_config.generate_edge_lookup)
+ ->implicit_value(true)
+ ->default_value(false),
+ "Generate a lookup table for internal edge-expanded-edge IDs to OSM node pairs")(
+ "small-component-size",
+ boost::program_options::value<unsigned int>(&extractor_config.small_component_size)
+ ->default_value(1000),
+ "Number of nodes required before a strongly-connected-componennt is considered big "
+ "(affects nearest neighbor snapping)");
+
+ // hidden options, will be allowed on command line, but will not be
+ // shown to the user
+ boost::program_options::options_description hidden_options("Hidden options");
+ hidden_options.add_options()("input,i", boost::program_options::value<boost::filesystem::path>(
+ &extractor_config.input_path),
+ "Input file in .osm, .osm.bz2 or .osm.pbf format");
+
+ // positional option
+ boost::program_options::positional_options_description positional_options;
+ positional_options.add("input", 1);
+
+ // combine above options for parsing
+ boost::program_options::options_description cmdline_options;
+ cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+
+ boost::program_options::options_description visible_options(
+ boost::filesystem::basename(argv[0]) + " <input.osm/.osm.bz2/.osm.pbf> [options]");
+ visible_options.add(generic_options).add(config_options);
+
+ // parse command line options
+ try
+ {
+ boost::program_options::variables_map option_variables;
+ boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
+ .options(cmdline_options)
+ .positional(positional_options)
+ .run(),
+ option_variables);
+ if (option_variables.count("version"))
+ {
+ util::SimpleLogger().Write() << OSRM_VERSION;
+ return return_code::exit;
+ }
+
+ if (option_variables.count("help"))
+ {
+ util::SimpleLogger().Write() << visible_options;
+ return return_code::exit;
+ }
+
+ boost::program_options::notify(option_variables);
+
+ if (!option_variables.count("input"))
+ {
+ util::SimpleLogger().Write() << visible_options;
+ return return_code::exit;
+ }
+ }
+ catch (std::exception &e)
+ {
+ util::SimpleLogger().Write(logWARNING) << e.what();
+ return return_code::fail;
+ }
+
+ return return_code::ok;
+}
+
+int main(int argc, char *argv[]) try
+{
+ util::LogPolicy::GetInstance().Unmute();
+ extractor::ExtractorConfig extractor_config;
+
+ const auto result = parseArguments(argc, argv, extractor_config);
+
+ if (return_code::fail == result)
+ {
+ return EXIT_FAILURE;
+ }
+
+ if (return_code::exit == result)
+ {
+ return EXIT_SUCCESS;
+ }
+
+ extractor_config.UseDefaultOutputNames();
+
+ if (1 > extractor_config.requested_num_threads)
+ {
+ util::SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
+ return EXIT_FAILURE;
+ }
+
+ if (!boost::filesystem::is_regular_file(extractor_config.input_path))
+ {
+ util::SimpleLogger().Write(logWARNING)
+ << "Input file " << extractor_config.input_path.string() << " not found!";
+ return EXIT_FAILURE;
+ }
+
+ if (!boost::filesystem::is_regular_file(extractor_config.profile_path))
+ {
+ util::SimpleLogger().Write(logWARNING)
+ << "Profile " << extractor_config.profile_path.string() << " not found!";
+ return EXIT_FAILURE;
+ }
+ return extractor::Extractor(extractor_config).run();
+}
+catch (const std::bad_alloc &e)
+{
+ util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+ util::SimpleLogger().Write(logWARNING)
+ << "Please provide more memory or consider using a larger swapfile";
+ return EXIT_FAILURE;
+}
+catch (const std::exception &e)
+{
+ util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+ return EXIT_FAILURE;
+}
diff --git a/src/tools/io-benchmark.cpp b/src/tools/io-benchmark.cpp
new file mode 100644
index 0000000..0030740
--- /dev/null
+++ b/src/tools/io-benchmark.cpp
@@ -0,0 +1,325 @@
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+#include "util/timing_util.hpp"
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+#include <cmath>
+#include <cstdio>
+#include <fcntl.h>
+#ifdef __linux__
+#include <malloc.h>
+#endif
+
+#include <algorithm>
+#include <chrono>
+#include <iomanip>
+#include <numeric>
+#include <random>
+#include <vector>
+
+namespace osrm
+{
+namespace tools
+{
+
+const unsigned NUMBER_OF_ELEMENTS = 268435456;
+
+struct Statistics
+{
+ double min, max, med, mean, dev;
+};
+
+void runStatistics(std::vector<double> &timings_vector, Statistics &stats)
+{
+ std::sort(timings_vector.begin(), timings_vector.end());
+ stats.min = timings_vector.front();
+ stats.max = timings_vector.back();
+ stats.med = timings_vector[timings_vector.size() / 2];
+ double primary_sum = std::accumulate(timings_vector.begin(), timings_vector.end(), 0.0);
+ stats.mean = primary_sum / timings_vector.size();
+
+ double primary_sq_sum = std::inner_product(timings_vector.begin(), timings_vector.end(),
+ timings_vector.begin(), 0.0);
+ stats.dev = std::sqrt(primary_sq_sum / timings_vector.size() - (stats.mean * stats.mean));
+}
+}
+}
+
+boost::filesystem::path test_path;
+
+int main(int argc, char *argv[]) try
+{
+
+#ifdef __FreeBSD__
+ osrm::util::SimpleLogger().Write() << "Not supported on FreeBSD";
+ return 0;
+#endif
+#ifdef _WIN32
+ osrm::util::SimpleLogger().Write() << "Not supported on Windows";
+ return 0;
+#else
+
+ osrm::util::LogPolicy::GetInstance().Unmute();
+ if (1 == argc)
+ {
+ osrm::util::SimpleLogger().Write(logWARNING) << "usage: " << argv[0] << " /path/on/device";
+ return -1;
+ }
+
+ test_path = boost::filesystem::path(argv[1]);
+ test_path /= "osrm.tst";
+ osrm::util::SimpleLogger().Write(logDEBUG) << "temporary file: " << test_path.string();
+
+ // create files for testing
+ if (2 == argc)
+ {
+ // create file to test
+ if (boost::filesystem::exists(test_path))
+ {
+ throw osrm::util::exception("Data file already exists");
+ }
+
+ int *random_array = new int[osrm::tools::NUMBER_OF_ELEMENTS];
+ std::generate(random_array, random_array + osrm::tools::NUMBER_OF_ELEMENTS, std::rand);
+#ifdef __APPLE__
+ FILE *fd = fopen(test_path.string().c_str(), "w");
+ fcntl(fileno(fd), F_NOCACHE, 1);
+ fcntl(fileno(fd), F_RDAHEAD, 0);
+ TIMER_START(write_1gb);
+ write(fileno(fd), (char *)random_array, osrm::tools::NUMBER_OF_ELEMENTS * sizeof(unsigned));
+ TIMER_STOP(write_1gb);
+ fclose(fd);
+#endif
+#ifdef __linux__
+ int file_desc =
+ open(test_path.string().c_str(), O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, S_IRWXU);
+ if (-1 == file_desc)
+ {
+ throw osrm::util::exception("Could not open random data file");
+ }
+ TIMER_START(write_1gb);
+ int ret =
+ write(file_desc, random_array, osrm::tools::NUMBER_OF_ELEMENTS * sizeof(unsigned));
+ if (0 > ret)
+ {
+ throw osrm::util::exception("could not write random data file");
+ }
+ TIMER_STOP(write_1gb);
+ close(file_desc);
+#endif
+ delete[] random_array;
+ osrm::util::SimpleLogger().Write(logDEBUG) << "writing raw 1GB took "
+ << TIMER_SEC(write_1gb) << "s";
+ osrm::util::SimpleLogger().Write() << "raw write performance: " << std::setprecision(5)
+ << std::fixed << 1024 * 1024 / TIMER_SEC(write_1gb)
+ << "MB/sec";
+
+ osrm::util::SimpleLogger().Write(logDEBUG)
+ << "finished creation of random data. Flush disk cache now!";
+ }
+ else
+ {
+ // Run Non-Cached I/O benchmarks
+ if (!boost::filesystem::exists(test_path))
+ {
+ throw osrm::util::exception("data file does not exist");
+ }
+
+ // volatiles do not get optimized
+ osrm::tools::Statistics stats;
+
+#ifdef __APPLE__
+ volatile unsigned single_block[1024];
+ char *raw_array = new char[osrm::tools::NUMBER_OF_ELEMENTS * sizeof(unsigned)];
+ FILE *fd = fopen(test_path.string().c_str(), "r");
+ fcntl(fileno(fd), F_NOCACHE, 1);
+ fcntl(fileno(fd), F_RDAHEAD, 0);
+#endif
+#ifdef __linux__
+ char *single_block = (char *)memalign(512, 1024 * sizeof(unsigned));
+
+ int file_desc = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
+ if (-1 == file_desc)
+ {
+ osrm::util::SimpleLogger().Write(logDEBUG) << "opened, error: " << strerror(errno);
+ return -1;
+ }
+ char *raw_array = (char *)memalign(512, osrm::tools::NUMBER_OF_ELEMENTS * sizeof(unsigned));
+#endif
+ TIMER_START(read_1gb);
+#ifdef __APPLE__
+ read(fileno(fd), raw_array, osrm::tools::NUMBER_OF_ELEMENTS * sizeof(unsigned));
+ close(fileno(fd));
+ fd = fopen(test_path.string().c_str(), "r");
+#endif
+#ifdef __linux__
+ int ret = read(file_desc, raw_array, osrm::tools::NUMBER_OF_ELEMENTS * sizeof(unsigned));
+ osrm::util::SimpleLogger().Write(logDEBUG) << "read " << ret
+ << " bytes, error: " << strerror(errno);
+ close(file_desc);
+ file_desc = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
+ osrm::util::SimpleLogger().Write(logDEBUG) << "opened, error: " << strerror(errno);
+#endif
+ TIMER_STOP(read_1gb);
+
+ osrm::util::SimpleLogger().Write(logDEBUG) << "reading raw 1GB took " << TIMER_SEC(read_1gb)
+ << "s";
+ osrm::util::SimpleLogger().Write() << "raw read performance: " << std::setprecision(5)
+ << std::fixed << 1024 * 1024 / TIMER_SEC(read_1gb)
+ << "MB/sec";
+
+ std::vector<double> timing_results_raw_random;
+ osrm::util::SimpleLogger().Write(logDEBUG) << "running 1000 random I/Os of 4KB";
+
+#ifdef __APPLE__
+ fseek(fd, 0, SEEK_SET);
+#endif
+#ifdef __linux__
+ lseek(file_desc, 0, SEEK_SET);
+#endif
+ // make 1000 random access, time each I/O seperately
+ unsigned number_of_blocks = (osrm::tools::NUMBER_OF_ELEMENTS * sizeof(unsigned) - 1) / 4096;
+ std::random_device rd;
+ std::default_random_engine e1(rd());
+ std::uniform_int_distribution<unsigned> uniform_dist(0, number_of_blocks - 1);
+ for (unsigned i = 0; i < 1000; ++i)
+ {
+ unsigned block_to_read = uniform_dist(e1);
+ off_t current_offset = block_to_read * 4096;
+ TIMER_START(random_access);
+#ifdef __APPLE__
+ int ret1 = fseek(fd, current_offset, SEEK_SET);
+ int ret2 = read(fileno(fd), (char *)&single_block[0], 4096);
+#endif
+
+#ifdef __FreeBSD__
+ int ret1 = 0;
+ int ret2 = 0;
+#endif
+
+#ifdef __linux__
+ int ret1 = lseek(file_desc, current_offset, SEEK_SET);
+ int ret2 = read(file_desc, (char *)single_block, 4096);
+#endif
+ TIMER_STOP(random_access);
+ if (((off_t)-1) == ret1)
+ {
+ osrm::util::SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
+ osrm::util::SimpleLogger().Write(logWARNING) << "seek error " << strerror(errno);
+ throw osrm::util::exception("seek error");
+ }
+ if (-1 == ret2)
+ {
+ osrm::util::SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
+ osrm::util::SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
+ throw osrm::util::exception("read error");
+ }
+ timing_results_raw_random.push_back(TIMER_SEC(random_access));
+ }
+
+ // Do statistics
+ osrm::util::SimpleLogger().Write(logDEBUG) << "running raw random I/O statistics";
+ std::ofstream random_csv("random.csv", std::ios::trunc);
+ for (unsigned i = 0; i < timing_results_raw_random.size(); ++i)
+ {
+ random_csv << i << ", " << timing_results_raw_random[i] << std::endl;
+ }
+ osrm::tools::runStatistics(timing_results_raw_random, stats);
+
+ osrm::util::SimpleLogger().Write() << "raw random I/O: " << std::setprecision(5)
+ << std::fixed << "min: " << stats.min << "ms, "
+ << "mean: " << stats.mean << "ms, "
+ << "med: " << stats.med << "ms, "
+ << "max: " << stats.max << "ms, "
+ << "dev: " << stats.dev << "ms";
+
+ std::vector<double> timing_results_raw_seq;
+#ifdef __APPLE__
+ fseek(fd, 0, SEEK_SET);
+#endif
+#ifdef __linux__
+ lseek(file_desc, 0, SEEK_SET);
+#endif
+
+ // read every 100th block
+ for (unsigned i = 0; i < 1000; ++i)
+ {
+ off_t current_offset = i * 4096;
+ TIMER_START(read_every_100);
+#ifdef __APPLE__
+ int ret1 = fseek(fd, current_offset, SEEK_SET);
+ int ret2 = read(fileno(fd), (char *)&single_block, 4096);
+#endif
+
+#ifdef __FreeBSD__
+ int ret1 = 0;
+ int ret2 = 0;
+#endif
+
+#ifdef __linux__
+ int ret1 = lseek(file_desc, current_offset, SEEK_SET);
+
+ int ret2 = read(file_desc, (char *)single_block, 4096);
+#endif
+ TIMER_STOP(read_every_100);
+ if (((off_t)-1) == ret1)
+ {
+ osrm::util::SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
+ osrm::util::SimpleLogger().Write(logWARNING) << "seek error " << strerror(errno);
+ throw osrm::util::exception("seek error");
+ }
+ if (-1 == ret2)
+ {
+ osrm::util::SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
+ osrm::util::SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
+ throw osrm::util::exception("read error");
+ }
+ timing_results_raw_seq.push_back(TIMER_SEC(read_every_100));
+ }
+#ifdef __APPLE__
+ fclose(fd);
+ // free(single_element);
+ free(raw_array);
+// free(single_block);
+#endif
+#ifdef __linux__
+ close(file_desc);
+#endif
+ // Do statistics
+ osrm::util::SimpleLogger().Write(logDEBUG) << "running sequential I/O statistics";
+ // print simple statistics: min, max, median, variance
+ std::ofstream seq_csv("sequential.csv", std::ios::trunc);
+ for (unsigned i = 0; i < timing_results_raw_seq.size(); ++i)
+ {
+ seq_csv << i << ", " << timing_results_raw_seq[i] << std::endl;
+ }
+ osrm::tools::runStatistics(timing_results_raw_seq, stats);
+ osrm::util::SimpleLogger().Write() << "raw sequential I/O: " << std::setprecision(5)
+ << std::fixed << "min: " << stats.min << "ms, "
+ << "mean: " << stats.mean << "ms, "
+ << "med: " << stats.med << "ms, "
+ << "max: " << stats.max << "ms, "
+ << "dev: " << stats.dev << "ms";
+
+ if (boost::filesystem::exists(test_path))
+ {
+ boost::filesystem::remove(test_path);
+ osrm::util::SimpleLogger().Write(logDEBUG) << "removing temporary files";
+ }
+ }
+ return EXIT_SUCCESS;
+#endif
+}
+catch (const std::exception &e)
+{
+ osrm::util::SimpleLogger().Write(logWARNING) << "caught exception: " << e.what();
+ osrm::util::SimpleLogger().Write(logWARNING) << "cleaning up, and exiting";
+ if (boost::filesystem::exists(test_path))
+ {
+ boost::filesystem::remove(test_path);
+ osrm::util::SimpleLogger().Write(logWARNING) << "removing temporary files";
+ }
+ return EXIT_FAILURE;
+}
diff --git a/src/tools/routed.cpp b/src/tools/routed.cpp
new file mode 100644
index 0000000..6c49d4e
--- /dev/null
+++ b/src/tools/routed.cpp
@@ -0,0 +1,348 @@
+#include "server/server.hpp"
+#include "util/make_unique.hpp"
+#include "util/simple_logger.hpp"
+#include "util/version.hpp"
+
+#include "osrm/osrm.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/storage_config.hpp"
+
+#include <boost/any.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+
+#ifdef __linux__
+#include <sys/mman.h>
+#endif
+
+#include <cstdlib>
+
+#include <signal.h>
+
+#include <chrono>
+#include <future>
+#include <iostream>
+#include <new>
+#include <thread>
+#include <string>
+
+#ifdef _WIN32
+boost::function0<void> console_ctrl_function;
+
+BOOL WINAPI console_ctrl_handler(DWORD ctrl_type)
+{
+ switch (ctrl_type)
+ {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ case CTRL_CLOSE_EVENT:
+ case CTRL_SHUTDOWN_EVENT:
+ console_ctrl_function();
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+#endif
+
+using namespace osrm;
+
+const static unsigned INIT_OK_START_ENGINE = 0;
+const static unsigned INIT_OK_DO_NOT_START_ENGINE = 1;
+const static unsigned INIT_FAILED = -1;
+
+// generate boost::program_options object for the routing part
+inline unsigned
+generateServerProgramOptions(const int argc,
+ const char *argv[],
+ boost::filesystem::path &base_path,
+ std::string &ip_address,
+ int &ip_port,
+ int &requested_num_threads,
+ bool &use_shared_memory,
+ bool &trial,
+ int &max_locations_trip,
+ int &max_locations_viaroute,
+ int &max_locations_distance_table,
+ int &max_locations_map_matching)
+{
+ using boost::program_options::value;
+ using boost::filesystem::path;
+
+ // declare a group of options that will be allowed only on command line
+ boost::program_options::options_description generic_options("Options");
+ generic_options.add_options() //
+ ("version,v", "Show version")("help,h", "Show this help message") //
+ ("trial", value<bool>(&trial)->implicit_value(true), "Quit after initialization");
+
+ // declare a group of options that will be allowed on command line
+ boost::program_options::options_description config_options("Configuration");
+ config_options.add_options() //
+ ("ip,i", value<std::string>(&ip_address)->default_value("0.0.0.0"),
+ "IP address") //
+ ("port,p", value<int>(&ip_port)->default_value(5000),
+ "TCP/IP port") //
+ ("threads,t", value<int>(&requested_num_threads)->default_value(8),
+ "Number of threads to use") //
+ ("shared-memory,s",
+ value<bool>(&use_shared_memory)->implicit_value(true)->default_value(false),
+ "Load data from shared memory") //
+ ("max-viaroute-size", value<int>(&max_locations_viaroute)->default_value(500),
+ "Max. locations supported in viaroute query") //
+ ("max-trip-size", value<int>(&max_locations_trip)->default_value(100),
+ "Max. locations supported in trip query") //
+ ("max-table-size", value<int>(&max_locations_distance_table)->default_value(100),
+ "Max. locations supported in distance table query") //
+ ("max-matching-size", value<int>(&max_locations_map_matching)->default_value(100),
+ "Max. locations supported in map matching query");
+
+ // hidden options, will be allowed on command line, but will not be shown to the user
+ boost::program_options::options_description hidden_options("Hidden options");
+ hidden_options.add_options()("base,b", value<boost::filesystem::path>(&base_path),
+ "base path to .osrm file");
+
+ // positional option
+ boost::program_options::positional_options_description positional_options;
+ positional_options.add("base", 1);
+
+ // combine above options for parsing
+ boost::program_options::options_description cmdline_options;
+ cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+
+ boost::program_options::options_description visible_options(
+ boost::filesystem::path(argv[0]).stem().string() + " <base.osrm> [<options>]");
+ visible_options.add(generic_options).add(config_options);
+
+ // parse command line options
+ boost::program_options::variables_map option_variables;
+ boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
+ .options(cmdline_options)
+ .positional(positional_options)
+ .run(),
+ option_variables);
+
+ if (option_variables.count("version"))
+ {
+ util::SimpleLogger().Write() << OSRM_VERSION;
+ return INIT_OK_DO_NOT_START_ENGINE;
+ }
+
+ if (option_variables.count("help"))
+ {
+ util::SimpleLogger().Write() << visible_options;
+ return INIT_OK_DO_NOT_START_ENGINE;
+ }
+
+ boost::program_options::notify(option_variables);
+
+ if (!use_shared_memory && option_variables.count("base"))
+ {
+ return INIT_OK_START_ENGINE;
+ }
+ else if (use_shared_memory && !option_variables.count("base"))
+ {
+ return INIT_OK_START_ENGINE;
+ }
+ else if (use_shared_memory && option_variables.count("base"))
+ {
+ util::SimpleLogger().Write(logWARNING) << "Shared memory settings conflict with path settings.";
+ }
+
+ util::SimpleLogger().Write() << visible_options;
+ return INIT_OK_DO_NOT_START_ENGINE;
+}
+
+int main(int argc, const char *argv[]) try
+{
+ util::LogPolicy::GetInstance().Unmute();
+
+ bool trial_run = false;
+ std::string ip_address;
+ int ip_port, requested_thread_num;
+
+ EngineConfig config;
+ boost::filesystem::path base_path;
+ const unsigned init_result = generateServerProgramOptions(
+ argc, argv, base_path, ip_address, ip_port, requested_thread_num,
+ config.use_shared_memory, trial_run, config.max_locations_trip,
+ config.max_locations_viaroute, config.max_locations_distance_table,
+ config.max_locations_map_matching);
+ if (init_result == INIT_OK_DO_NOT_START_ENGINE)
+ {
+ return EXIT_SUCCESS;
+ }
+ if (init_result == INIT_FAILED)
+ {
+ return EXIT_FAILURE;
+ }
+ if (!base_path.empty())
+ {
+ config.storage_config = storage::StorageConfig(base_path);
+ }
+ if(!config.IsValid())
+ {
+ if (base_path.empty() != config.use_shared_memory)
+ {
+ util::SimpleLogger().Write(logWARNING) << "Path settings and shared memory conflicts.";
+ }
+ else
+ {
+ if(!boost::filesystem::is_regular_file(config.storage_config.ram_index_path))
+ {
+ util::SimpleLogger().Write(logWARNING) << config.storage_config.ram_index_path << " is not found";
+ }
+ if(!boost::filesystem::is_regular_file(config.storage_config.file_index_path))
+ {
+ util::SimpleLogger().Write(logWARNING) << config.storage_config.file_index_path << " is not found";
+ }
+ if(!boost::filesystem::is_regular_file(config.storage_config.hsgr_data_path))
+ {
+ util::SimpleLogger().Write(logWARNING) << config.storage_config.hsgr_data_path << " is not found";
+ }
+ if(!boost::filesystem::is_regular_file(config.storage_config.nodes_data_path))
+ {
+ util::SimpleLogger().Write(logWARNING) << config.storage_config.nodes_data_path << " is not found";
+ }
+ if(!boost::filesystem::is_regular_file(config.storage_config.edges_data_path))
+ {
+ util::SimpleLogger().Write(logWARNING) << config.storage_config.edges_data_path << " is not found";
+ }
+ if(!boost::filesystem::is_regular_file(config.storage_config.core_data_path))
+ {
+ util::SimpleLogger().Write(logWARNING) << config.storage_config.core_data_path << " is not found";
+ }
+ if(!boost::filesystem::is_regular_file(config.storage_config.geometries_path))
+ {
+ util::SimpleLogger().Write(logWARNING) << config.storage_config.geometries_path << " is not found";
+ }
+ if(!boost::filesystem::is_regular_file(config.storage_config.timestamp_path))
+ {
+ util::SimpleLogger().Write(logWARNING) << config.storage_config.timestamp_path << " is not found";
+ }
+ if(!boost::filesystem::is_regular_file(config.storage_config.datasource_names_path))
+ {
+ util::SimpleLogger().Write(logWARNING) << config.storage_config.datasource_names_path << " is not found";
+ }
+ if(!boost::filesystem::is_regular_file(config.storage_config.datasource_indexes_path))
+ {
+ util::SimpleLogger().Write(logWARNING) << config.storage_config.datasource_indexes_path << " is not found";
+ }
+ if(!boost::filesystem::is_regular_file(config.storage_config.names_data_path))
+ {
+ util::SimpleLogger().Write(logWARNING) << config.storage_config.names_data_path << " is not found";
+ }
+ if(!boost::filesystem::is_regular_file(config.storage_config.properties_path))
+ {
+ util::SimpleLogger().Write(logWARNING) << config.storage_config.properties_path << " is not found";
+ }
+ }
+ return EXIT_FAILURE;
+ }
+
+#ifdef __linux__
+ struct MemoryLocker final
+ {
+ explicit MemoryLocker(bool should_lock) : should_lock(should_lock)
+ {
+ if (should_lock && -1 == mlockall(MCL_CURRENT | MCL_FUTURE))
+ {
+ could_lock = false;
+ util::SimpleLogger().Write(logWARNING) << "memory could not be locked to RAM";
+ }
+ }
+ ~MemoryLocker()
+ {
+ if (should_lock && could_lock)
+ (void)munlockall();
+ }
+ bool should_lock = false, could_lock = true;
+ } memory_locker(config.use_shared_memory);
+#endif
+ util::SimpleLogger().Write() << "starting up engines, " << OSRM_VERSION;
+
+ if (config.use_shared_memory)
+ {
+ util::SimpleLogger().Write() << "Loading from shared memory";
+ }
+
+ util::SimpleLogger().Write() << "Threads: " << requested_thread_num;
+ util::SimpleLogger().Write() << "IP address: " << ip_address;
+ util::SimpleLogger().Write() << "IP port: " << ip_port;
+
+#ifndef _WIN32
+ int sig = 0;
+ sigset_t new_mask;
+ sigset_t old_mask;
+ sigfillset(&new_mask);
+ pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask);
+#endif
+
+ auto routing_server = server::Server::CreateServer(ip_address, ip_port, requested_thread_num);
+ auto service_handler = util::make_unique<server::ServiceHandler>(config);
+
+ routing_server->RegisterServiceHandler(std::move(service_handler));
+
+ if (trial_run)
+ {
+ util::SimpleLogger().Write() << "trial run, quitting after successful initialization";
+ }
+ else
+ {
+ std::packaged_task<int()> server_task([&]
+ {
+ routing_server->Run();
+ return 0;
+ });
+ auto future = server_task.get_future();
+ std::thread server_thread(std::move(server_task));
+
+#ifndef _WIN32
+ sigset_t wait_mask;
+ pthread_sigmask(SIG_SETMASK, &old_mask, nullptr);
+ sigemptyset(&wait_mask);
+ sigaddset(&wait_mask, SIGINT);
+ sigaddset(&wait_mask, SIGQUIT);
+ sigaddset(&wait_mask, SIGTERM);
+ pthread_sigmask(SIG_BLOCK, &wait_mask, nullptr);
+ util::SimpleLogger().Write() << "running and waiting for requests";
+ sigwait(&wait_mask, &sig);
+#else
+ // Set console control handler to allow server to be stopped.
+ console_ctrl_function = std::bind(&server::Server::Stop, routing_server);
+ SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
+ util::SimpleLogger().Write() << "running and waiting for requests";
+ routing_server->Run();
+#endif
+ util::SimpleLogger().Write() << "initiating shutdown";
+ routing_server->Stop();
+ util::SimpleLogger().Write() << "stopping threads";
+
+ auto status = future.wait_for(std::chrono::seconds(2));
+
+ if (status == std::future_status::ready)
+ {
+ server_thread.join();
+ }
+ else
+ {
+ util::SimpleLogger().Write(logWARNING) << "Didn't exit within 2 seconds. Hard abort!";
+ server_task.reset(); // just kill it
+ }
+ }
+
+ util::SimpleLogger().Write() << "freeing objects";
+ routing_server.reset();
+ util::SimpleLogger().Write() << "shutdown completed";
+}
+catch (const std::bad_alloc &e)
+{
+ util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+ util::SimpleLogger().Write(logWARNING)
+ << "Please provide more memory or consider using a larger swapfile";
+ return EXIT_FAILURE;
+}
+catch (const std::exception &e)
+{
+ util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+ return EXIT_FAILURE;
+}
diff --git a/src/tools/springclean.cpp b/src/tools/springclean.cpp
new file mode 100644
index 0000000..69a7cc1
--- /dev/null
+++ b/src/tools/springclean.cpp
@@ -0,0 +1,82 @@
+#include <cstdio>
+
+#include "storage/shared_memory.hpp"
+#include "storage/shared_datatype.hpp"
+#include "util/simple_logger.hpp"
+
+namespace osrm
+{
+namespace tools
+{
+
+// FIXME remove after folding back into datastore
+using namespace storage;
+
+void deleteRegion(const SharedDataType region)
+{
+ if (SharedMemory::RegionExists(region) && !SharedMemory::Remove(region))
+ {
+ const std::string name = [&]
+ {
+ switch (region)
+ {
+ case CURRENT_REGIONS:
+ return "CURRENT_REGIONS";
+ case LAYOUT_1:
+ return "LAYOUT_1";
+ case DATA_1:
+ return "DATA_1";
+ case LAYOUT_2:
+ return "LAYOUT_2";
+ case DATA_2:
+ return "DATA_2";
+ case LAYOUT_NONE:
+ return "LAYOUT_NONE";
+ default: // DATA_NONE:
+ return "DATA_NONE";
+ }
+ }();
+
+ util::SimpleLogger().Write(logWARNING) << "could not delete shared memory region " << name;
+ }
+}
+
+// find all existing shmem regions and remove them.
+void springclean()
+{
+ util::SimpleLogger().Write() << "spring-cleaning all shared memory regions";
+ deleteRegion(DATA_1);
+ deleteRegion(LAYOUT_1);
+ deleteRegion(DATA_2);
+ deleteRegion(LAYOUT_2);
+ deleteRegion(CURRENT_REGIONS);
+}
+}
+}
+
+int main() try
+{
+ osrm::util::LogPolicy::GetInstance().Unmute();
+ osrm::util::SimpleLogger().Write() << "Releasing all locks";
+ osrm::util::SimpleLogger().Write() << "ATTENTION! BE CAREFUL!";
+ osrm::util::SimpleLogger().Write() << "----------------------";
+ osrm::util::SimpleLogger().Write() << "This tool may put osrm-routed into an undefined state!";
+ osrm::util::SimpleLogger().Write()
+ << "Type 'Y' to acknowledge that you know what your are doing.";
+ osrm::util::SimpleLogger().Write() << "\n\nDo you want to purge all shared memory allocated "
+ << "by osrm-datastore? [type 'Y' to confirm]";
+
+ const auto letter = getchar();
+ if (letter != 'Y')
+ {
+ osrm::util::SimpleLogger().Write() << "aborted.";
+ return EXIT_SUCCESS;
+ }
+ osrm::tools::springclean();
+ return EXIT_SUCCESS;
+}
+catch (const std::exception &e)
+{
+ osrm::util::SimpleLogger().Write(logWARNING) << "[excpetion] " << e.what();
+ return EXIT_FAILURE;
+}
diff --git a/src/tools/store.cpp b/src/tools/store.cpp
new file mode 100644
index 0000000..7866cf3
--- /dev/null
+++ b/src/tools/store.cpp
@@ -0,0 +1,104 @@
+#include "storage/storage.hpp"
+#include "util/exception.hpp"
+#include "util/simple_logger.hpp"
+#include "util/typedefs.hpp"
+#include "util/version.hpp"
+
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+
+using namespace osrm;
+
+// generate boost::program_options object for the routing part
+bool generateDataStoreOptions(const int argc, const char *argv[], boost::filesystem::path& base_path)
+{
+ // declare a group of options that will be allowed only on command line
+ boost::program_options::options_description generic_options("Options");
+ generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
+ "springclean,s", "Remove all regions in shared memory");
+
+ // declare a group of options that will be allowed both on command line
+ // as well as in a config file
+ boost::program_options::options_description config_options("Configuration");
+
+ // hidden options, will be allowed on command line but will not be shown to the user
+ boost::program_options::options_description hidden_options("Hidden options");
+ hidden_options.add_options()(
+ "base,b", boost::program_options::value<boost::filesystem::path>(&base_path),
+ "base path to .osrm file");
+
+ // positional option
+ boost::program_options::positional_options_description positional_options;
+ positional_options.add("base", 1);
+
+ // combine above options for parsing
+ boost::program_options::options_description cmdline_options;
+ cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+
+ boost::program_options::options_description visible_options(
+ boost::filesystem::basename(argv[0]) + " [<options>] <configuration>");
+ visible_options.add(generic_options).add(config_options);
+
+ // print help options if no infile is specified
+ if (argc < 2)
+ {
+ util::SimpleLogger().Write() << visible_options;
+ return false;
+ }
+
+ // parse command line options
+ boost::program_options::variables_map option_variables;
+ boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
+ .options(cmdline_options)
+ .positional(positional_options)
+ .run(),
+ option_variables);
+
+ if (option_variables.count("version"))
+ {
+ util::SimpleLogger().Write() << OSRM_VERSION;
+ return false;
+ }
+
+ if (option_variables.count("help"))
+ {
+ util::SimpleLogger().Write() << visible_options;
+ return false;
+ }
+
+ boost::program_options::notify(option_variables);
+
+ return true;
+}
+
+int main(const int argc, const char *argv[]) try
+{
+ util::LogPolicy::GetInstance().Unmute();
+
+ boost::filesystem::path base_path;
+ if (!generateDataStoreOptions(argc, argv, base_path))
+ {
+ return EXIT_SUCCESS;
+ }
+ storage::StorageConfig config(base_path);
+ if (!config.IsValid())
+ {
+ util::SimpleLogger().Write(logWARNING) << "Invalid file path given!";
+ return EXIT_FAILURE;
+ }
+ storage::Storage storage(std::move(config));
+ return storage.Run();
+}
+catch (const std::bad_alloc &e)
+{
+ util::SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+ util::SimpleLogger().Write(logWARNING)
+ << "Please provide more memory or disable locking the virtual "
+ "address space (note: this makes OSRM swap, i.e. slow)";
+ return EXIT_FAILURE;
+}
+catch (const std::exception &e)
+{
+ util::SimpleLogger().Write(logWARNING) << "caught exception: " << e.what();
+ return EXIT_FAILURE;
+}
diff --git a/src/tools/unlock_all_mutexes.cpp b/src/tools/unlock_all_mutexes.cpp
new file mode 100644
index 0000000..2af8477
--- /dev/null
+++ b/src/tools/unlock_all_mutexes.cpp
@@ -0,0 +1,20 @@
+#include "util/simple_logger.hpp"
+#include "storage/shared_barriers.hpp"
+
+#include <iostream>
+
+int main() try
+{
+ osrm::util::LogPolicy::GetInstance().Unmute();
+ osrm::util::SimpleLogger().Write() << "Releasing all locks";
+ osrm::storage::SharedBarriers barrier;
+ barrier.pending_update_mutex.unlock();
+ barrier.query_mutex.unlock();
+ barrier.update_mutex.unlock();
+ return 0;
+}
+catch (const std::exception &e)
+{
+ osrm::util::SimpleLogger().Write(logWARNING) << "[excpetion] " << e.what();
+ return EXIT_FAILURE;
+}
diff --git a/src/util/assert.cpp b/src/util/assert.cpp
new file mode 100644
index 0000000..7051784
--- /dev/null
+++ b/src/util/assert.cpp
@@ -0,0 +1,29 @@
+#include "util/assert.hpp"
+
+#include <sstream>
+
+namespace
+{
+// We throw to guarantee for stack-unwinding and therefore our destructors being called.
+void assertion_failed_msg_helper(
+ char const *expr, char const *msg, char const *function, char const *file, long line)
+{
+ std::ostringstream fmt;
+ fmt << file << ":" << line << "\nin: " << function << ": " << expr << "\n" << msg;
+ throw osrm::util::assertionError{fmt.str().c_str()};
+}
+}
+
+// Boost.Assert only declares the following two functions and let's us define them here.
+namespace boost
+{
+void assertion_failed(char const *expr, char const *function, char const *file, long line)
+{
+ ::assertion_failed_msg_helper(expr, "", function, file, line);
+}
+void assertion_failed_msg(
+ char const *expr, char const *msg, char const *function, char const *file, long line)
+{
+ ::assertion_failed_msg_helper(expr, msg, function, file, line);
+}
+}
diff --git a/src/util/coordinate.cpp b/src/util/coordinate.cpp
new file mode 100644
index 0000000..9ccbf17
--- /dev/null
+++ b/src/util/coordinate.cpp
@@ -0,0 +1,100 @@
+#include "util/coordinate_calculation.hpp"
+
+#ifndef NDEBUG
+#include "util/simple_logger.hpp"
+#endif
+#include "osrm/coordinate.hpp"
+
+#ifndef NDEBUG
+#include <bitset>
+#endif
+#include <iostream>
+#include <iomanip>
+#include <limits>
+
+namespace osrm
+{
+namespace util
+{
+
+Coordinate::Coordinate()
+ : lon(std::numeric_limits<int>::min()), lat(std::numeric_limits<int>::min())
+{
+}
+
+Coordinate::Coordinate(const FloatCoordinate &other)
+ : Coordinate(toFixed(other.lon), toFixed(other.lat))
+{
+}
+
+Coordinate::Coordinate(const FloatLongitude lon_, const FloatLatitude lat_)
+ : Coordinate(toFixed(lon_), toFixed(lat_))
+{
+}
+
+Coordinate::Coordinate(const FixedLongitude lon_, const FixedLatitude lat_) : lon(lon_), lat(lat_)
+{
+}
+
+bool Coordinate::IsValid() const
+{
+ return !(lat > FixedLatitude(90 * COORDINATE_PRECISION) ||
+ lat < FixedLatitude(-90 * COORDINATE_PRECISION) ||
+ lon > FixedLongitude(180 * COORDINATE_PRECISION) ||
+ lon < FixedLongitude(-180 * COORDINATE_PRECISION));
+}
+
+FloatCoordinate::FloatCoordinate()
+ : lon(std::numeric_limits<double>::min()), lat(std::numeric_limits<double>::min())
+{
+}
+
+FloatCoordinate::FloatCoordinate(const Coordinate other)
+ : FloatCoordinate(toFloating(other.lon), toFloating(other.lat))
+{
+}
+
+FloatCoordinate::FloatCoordinate(const FixedLongitude lon_, const FixedLatitude lat_)
+ : FloatCoordinate(toFloating(lon_), toFloating(lat_))
+{
+}
+
+FloatCoordinate::FloatCoordinate(const FloatLongitude lon_, const FloatLatitude lat_) : lon(lon_), lat(lat_)
+{
+}
+
+bool FloatCoordinate::IsValid() const
+{
+ return !(lat > FloatLatitude(90) ||
+ lat < FloatLatitude(-90) ||
+ lon > FloatLongitude(180) ||
+ lon < FloatLongitude(-180));
+}
+
+
+bool operator==(const Coordinate lhs, const Coordinate rhs)
+{
+ return lhs.lat == rhs.lat && lhs.lon == rhs.lon;
+}
+bool operator==(const FloatCoordinate lhs, const FloatCoordinate rhs)
+{
+ return lhs.lat == rhs.lat && lhs.lon == rhs.lon;
+}
+
+bool operator!=(const Coordinate lhs, const Coordinate rhs) { return !(lhs == rhs); }
+bool operator!=(const FloatCoordinate lhs, const FloatCoordinate rhs) { return !(lhs == rhs); }
+
+std::ostream &operator<<(std::ostream &out, const Coordinate coordinate)
+{
+ out << std::setprecision(12) << "(lon:" << toFloating(coordinate.lon)
+ << ", lat:" << toFloating(coordinate.lat) << ")";
+ return out;
+}
+std::ostream &operator<<(std::ostream &out, const FloatCoordinate coordinate)
+{
+ out << std::setprecision(12) << "(lon:" << coordinate.lon
+ << ", lat:" << coordinate.lat << ")";
+ return out;
+}
+}
+}
diff --git a/src/util/coordinate_calculation.cpp b/src/util/coordinate_calculation.cpp
new file mode 100644
index 0000000..8ed69c9
--- /dev/null
+++ b/src/util/coordinate_calculation.cpp
@@ -0,0 +1,325 @@
+#include "util/coordinate.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/trigonometry_table.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cmath>
+
+#include <limits>
+#include <utility>
+
+namespace osrm
+{
+namespace util
+{
+
+namespace coordinate_calculation
+{
+
+// Does not project the coordinates!
+double squaredEuclideanDistance(const FloatCoordinate &lhs, const FloatCoordinate &rhs)
+{
+ const double dx = static_cast<double>(lhs.lon - rhs.lon);
+ const double dy = static_cast<double>(lhs.lat - rhs.lat);
+
+ return dx * dx + dy * dy;
+}
+
+double haversineDistance(const Coordinate coordinate_1, const Coordinate coordinate_2)
+{
+ auto lon1 = static_cast<int>(coordinate_1.lon);
+ auto lat1 = static_cast<int>(coordinate_1.lat);
+ auto lon2 = static_cast<int>(coordinate_2.lon);
+ auto lat2 = static_cast<int>(coordinate_2.lat);
+ BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
+ BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
+ BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
+ BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
+ const double lt1 = lat1 / COORDINATE_PRECISION;
+ const double ln1 = lon1 / COORDINATE_PRECISION;
+ const double lt2 = lat2 / COORDINATE_PRECISION;
+ const double ln2 = lon2 / COORDINATE_PRECISION;
+ const double dlat1 = lt1 * DEGREE_TO_RAD;
+
+ const double dlong1 = ln1 * DEGREE_TO_RAD;
+ const double dlat2 = lt2 * DEGREE_TO_RAD;
+ const double dlong2 = ln2 * DEGREE_TO_RAD;
+
+ const double dlong = dlong1 - dlong2;
+ const double dlat = dlat1 - dlat2;
+
+ const double aharv = std::pow(std::sin(dlat / 2.0), 2.0) +
+ std::cos(dlat1) * std::cos(dlat2) * std::pow(std::sin(dlong / 2.), 2);
+ const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
+ return EARTH_RADIUS * charv;
+}
+
+double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coordinate_2)
+{
+ auto lon1 = static_cast<int>(coordinate_1.lon);
+ auto lat1 = static_cast<int>(coordinate_1.lat);
+ auto lon2 = static_cast<int>(coordinate_2.lon);
+ auto lat2 = static_cast<int>(coordinate_2.lat);
+ BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
+ BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
+ BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
+ BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
+
+ const double float_lat1 = (lat1 / COORDINATE_PRECISION) * DEGREE_TO_RAD;
+ const double float_lon1 = (lon1 / COORDINATE_PRECISION) * DEGREE_TO_RAD;
+ const double float_lat2 = (lat2 / COORDINATE_PRECISION) * DEGREE_TO_RAD;
+ const double float_lon2 = (lon2 / COORDINATE_PRECISION) * DEGREE_TO_RAD;
+
+ const double x_value = (float_lon2 - float_lon1) * std::cos((float_lat1 + float_lat2) / 2.0);
+ const double y_value = float_lat2 - float_lat1;
+ return std::hypot(x_value, y_value) * EARTH_RADIUS;
+}
+
+std::pair<double, FloatCoordinate> projectPointOnSegment(const FloatCoordinate &source,
+ const FloatCoordinate &target,
+ const FloatCoordinate &coordinate)
+{
+ const FloatCoordinate slope_vector{target.lon - source.lon, target.lat - source.lat};
+ const FloatCoordinate rel_coordinate{coordinate.lon - source.lon, coordinate.lat - source.lat};
+ // dot product of two un-normed vectors
+ const auto unnormed_ratio = static_cast<double>(slope_vector.lon * rel_coordinate.lon) +
+ static_cast<double>(slope_vector.lat * rel_coordinate.lat);
+ // squared length of the slope vector
+ const auto squared_length = static_cast<double>(slope_vector.lon * slope_vector.lon) +
+ static_cast<double>(slope_vector.lat * slope_vector.lat);
+
+ if (squared_length < std::numeric_limits<double>::epsilon())
+ {
+ return {0, source};
+ }
+
+ const double normed_ratio = unnormed_ratio / squared_length;
+ double clamped_ratio = normed_ratio;
+ if (clamped_ratio > 1.)
+ {
+ clamped_ratio = 1.;
+ }
+ else if (clamped_ratio < 0.)
+ {
+ clamped_ratio = 0.;
+ }
+ return {clamped_ratio,
+ {
+ source.lon + slope_vector.lon * FloatLongitude(clamped_ratio),
+ source.lat + slope_vector.lat * FloatLatitude(clamped_ratio),
+ }};
+}
+
+double perpendicularDistance(const Coordinate segment_source,
+ const Coordinate segment_target,
+ const Coordinate query_location,
+ Coordinate &nearest_location,
+ double &ratio)
+{
+ using namespace coordinate_calculation;
+
+ BOOST_ASSERT(query_location.IsValid());
+
+ FloatCoordinate projected_nearest;
+ std::tie(ratio, projected_nearest) =
+ projectPointOnSegment(mercator::fromWGS84(segment_source), mercator::fromWGS84(segment_target), mercator::fromWGS84(query_location));
+ nearest_location = mercator::toWGS84(projected_nearest);
+
+ const double approximate_distance = greatCircleDistance(query_location, nearest_location);
+ BOOST_ASSERT(0.0 <= approximate_distance);
+ return approximate_distance;
+}
+
+double perpendicularDistance(const Coordinate source_coordinate,
+ const Coordinate target_coordinate,
+ const Coordinate query_location)
+{
+ double ratio;
+ Coordinate nearest_location;
+
+ return perpendicularDistance(source_coordinate, target_coordinate, query_location,
+ nearest_location, ratio);
+}
+
+Coordinate centroid(const Coordinate lhs, const Coordinate rhs)
+{
+ Coordinate centroid;
+ // The coordinates of the midpoints are given by:
+ // x = (x1 + x2) /2 and y = (y1 + y2) /2.
+ centroid.lon = (lhs.lon + rhs.lon) / FixedLongitude(2);
+ centroid.lat = (lhs.lat + rhs.lat) / FixedLatitude(2);
+ return centroid;
+}
+
+double degToRad(const double degree)
+{
+ using namespace boost::math::constants;
+ return degree * (pi<double>() / 180.0);
+}
+
+double radToDeg(const double radian)
+{
+ using namespace boost::math::constants;
+ return radian * (180.0 * (1. / pi<double>()));
+}
+
+double bearing(const Coordinate first_coordinate, const Coordinate second_coordinate)
+{
+ const double lon_diff =
+ static_cast<double>(toFloating(second_coordinate.lon - first_coordinate.lon));
+ const double lon_delta = degToRad(lon_diff);
+ const double lat1 = degToRad(static_cast<double>(toFloating(first_coordinate.lat)));
+ const double lat2 = degToRad(static_cast<double>(toFloating(second_coordinate.lat)));
+ const double y = std::sin(lon_delta) * std::cos(lat2);
+ const double x =
+ std::cos(lat1) * std::sin(lat2) - std::sin(lat1) * std::cos(lat2) * std::cos(lon_delta);
+ double result = radToDeg(std::atan2(y, x));
+ while (result < 0.0)
+ {
+ result += 360.0;
+ }
+
+ while (result >= 360.0)
+ {
+ result -= 360.0;
+ }
+ return result;
+}
+
+double computeAngle(const Coordinate first, const Coordinate second, const Coordinate third)
+{
+ using namespace boost::math::constants;
+ using namespace coordinate_calculation;
+
+ const double v1x = static_cast<double>(toFloating(first.lon - second.lon));
+ const double v1y =
+ mercator::latToY(toFloating(first.lat)) - mercator::latToY(toFloating(second.lat));
+ const double v2x = static_cast<double>(toFloating(third.lon - second.lon));
+ const double v2y =
+ mercator::latToY(toFloating(third.lat)) - mercator::latToY(toFloating(second.lat));
+
+ double angle = (atan2_lookup(v2y, v2x) - atan2_lookup(v1y, v1x)) * 180. / pi<double>();
+
+ while (angle < 0.)
+ {
+ angle += 360.;
+ }
+
+ return angle;
+}
+
+Coordinate interpolateLinear(double factor, const Coordinate from, const Coordinate to)
+{
+ BOOST_ASSERT(0 <= factor && factor <= 1.0);
+
+ FixedLongitude interpolated_lon(((1. - factor) * static_cast<std::int32_t>(from.lon)) +
+ (factor * static_cast<std::int32_t>(to.lon)));
+ FixedLatitude interpolated_lat(((1. - factor) * static_cast<std::int32_t>(from.lat)) +
+ (factor * static_cast<std::int32_t>(to.lat)));
+
+ return {std::move(interpolated_lon), std::move(interpolated_lat)};
+}
+
+namespace mercator
+{
+FloatLatitude yToLat(const double y)
+{
+ const auto clamped_y = std::max(-180., std::min(180., y));
+ const double normalized_lat =
+ RAD_TO_DEGREE * 2. * std::atan(std::exp(clamped_y * DEGREE_TO_RAD));
+
+ return FloatLatitude(normalized_lat - 90.);
+}
+
+double latToY(const FloatLatitude latitude)
+{
+ const double normalized_lat = 90. + static_cast<double>(latitude);
+
+ const double y = RAD_TO_DEGREE * std::log(std::tan(normalized_lat * DEGREE_TO_RAD * 0.5));
+ const auto clamped_y = std::max(-180., std::min(180., y));
+ return clamped_y;
+}
+
+FloatLatitude clamp(const FloatLatitude lat)
+{
+ return std::max(std::min(lat, FloatLatitude(detail::MAX_LATITUDE)),
+ FloatLatitude(-detail::MAX_LATITUDE));
+}
+
+FloatLongitude clamp(const FloatLongitude lon)
+{
+ return std::max(std::min(lon, FloatLongitude(detail::MAX_LONGITUDE)),
+ FloatLongitude(-detail::MAX_LONGITUDE));
+}
+
+inline void pixelToDegree(const double shift, double &x, double &y)
+{
+ const double b = shift / 2.0;
+ x = (x - b) / shift * 360.0;
+ // FIXME needs to be simplified
+ const double g = (y - b) / -(shift / (2 * M_PI)) / DEGREE_TO_RAD;
+ static_assert(DEGREE_TO_RAD / (2 * M_PI) - 1 / 360. < 0.0001, "");
+ y = static_cast<double>(util::coordinate_calculation::mercator::yToLat(g));
+}
+
+double degreeToPixel(FloatLongitude lon, unsigned zoom)
+{
+ const double shift = (1u << zoom) * TILE_SIZE;
+ const double b = shift / 2.0;
+ const double x = b * (1 + static_cast<double>(lon) / 180.0);
+ return x;
+}
+
+double degreeToPixel(FloatLatitude lat, unsigned zoom)
+{
+ const double shift = (1u << zoom) * TILE_SIZE;
+ const double b = shift / 2.0;
+ const double y = b * (1. - latToY(lat) / 180.);
+ return y;
+}
+
+FloatCoordinate fromWGS84(const FloatCoordinate &wgs84_coordinate)
+{
+ return {wgs84_coordinate.lon, FloatLatitude{coordinate_calculation::mercator::latToY(wgs84_coordinate.lat)}};
+}
+
+FloatCoordinate toWGS84(const FloatCoordinate &mercator_coordinate)
+{
+ return {mercator_coordinate.lon, coordinate_calculation::mercator::yToLat(static_cast<double>(mercator_coordinate.lat))};
+}
+
+// Converts a WMS tile coordinate (z,x,y) into a wgs bounding box
+void xyzToWGS84(
+ const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy)
+{
+ using util::coordinate_calculation::mercator::TILE_SIZE;
+
+ minx = x * TILE_SIZE;
+ miny = (y + 1.0) * TILE_SIZE;
+ maxx = (x + 1.0) * TILE_SIZE;
+ maxy = y * TILE_SIZE;
+ // 2^z * TILE_SIZE
+ const double shift = (1u << static_cast<unsigned>(z)) * TILE_SIZE;
+ pixelToDegree(shift, minx, miny);
+ pixelToDegree(shift, maxx, maxy);
+}
+
+// Converts a WMS tile coordinate (z,x,y) into a mercator bounding box
+void xyzToMercator(
+ const int x, const int y, const int z, double &minx, double &miny, double &maxx, double &maxy)
+{
+ using namespace util::coordinate_calculation::mercator;
+
+ xyzToWGS84(x, y, z, minx, miny, maxx, maxy);
+
+ minx = static_cast<double>(clamp(util::FloatLongitude(minx))) * DEGREE_TO_PX;
+ miny = latToY(clamp(util::FloatLatitude(miny))) * DEGREE_TO_PX;
+ maxx = static_cast<double>(clamp(util::FloatLongitude(maxx))) * DEGREE_TO_PX;
+ maxy = latToY(clamp(util::FloatLatitude(maxy))) * DEGREE_TO_PX;
+}
+
+} // ns mercato // ns mercatorr
+} // ns coordinate_calculation
+} // ns util
+} // ns osrm
diff --git a/src/util/exception.cpp b/src/util/exception.cpp
new file mode 100644
index 0000000..394d8c0
--- /dev/null
+++ b/src/util/exception.cpp
@@ -0,0 +1,21 @@
+#include "util/exception.hpp"
+
+// This function exists to 'anchor' the class, and stop the compiler from
+// copying vtable and RTTI info into every object file that includes
+// this header. (Caught by -Wweak-vtables under Clang.)
+
+// More information from the LLVM Coding Standards:
+// If a class is defined in a header file and has a vtable (either it has
+// virtual methods or it derives from classes with virtual methods), it must
+// always have at least one out-of-line virtual method in the class. Without
+// this, the compiler will copy the vtable and RTTI into every .o file that
+// #includes the header, bloating .o file sizes and increasing link times.
+
+namespace osrm
+{
+namespace util
+{
+
+void exception::anchor() const {}
+}
+}
diff --git a/src/util/fingerprint.cpp b/src/util/fingerprint.cpp
new file mode 100644
index 0000000..2764c7b
--- /dev/null
+++ b/src/util/fingerprint.cpp
@@ -0,0 +1,2 @@
+#include "util/fingerprint.hpp"
+#include "util/fingerprint_impl.hpp"
diff --git a/src/util/hilbert_value.cpp b/src/util/hilbert_value.cpp
new file mode 100644
index 0000000..a1505ee
--- /dev/null
+++ b/src/util/hilbert_value.cpp
@@ -0,0 +1,84 @@
+#include "util/hilbert_value.hpp"
+
+namespace osrm
+{
+namespace util
+{
+
+namespace
+{
+
+std::uint64_t bitInterleaving(const std::uint32_t longitude, const std::uint32_t latitude)
+{
+ std::uint64_t result = 0;
+ for (std::int8_t index = 31; index >= 0; --index)
+ {
+ result |= (latitude >> index) & 1;
+ result <<= 1;
+ result |= (longitude >> index) & 1;
+ if (0 != index)
+ {
+ result <<= 1;
+ }
+ }
+ return result;
+}
+
+void transposeCoordinate(std::uint32_t *x)
+{
+ std::uint32_t M = 1u << (32 - 1), P, Q, t;
+ int i;
+ // Inverse undo
+ for (Q = M; Q > 1; Q >>= 1)
+ {
+ P = Q - 1;
+ for (i = 0; i < 2; ++i)
+ {
+
+ const bool condition = (x[i] & Q);
+ if (condition)
+ {
+ x[0] ^= P; // invert
+ }
+ else
+ {
+ t = (x[0] ^ x[i]) & P;
+ x[0] ^= t;
+ x[i] ^= t;
+ }
+ } // exchange
+ }
+ // Gray encode
+ for (i = 1; i < 2; ++i)
+ {
+ x[i] ^= x[i - 1];
+ }
+ t = 0;
+ for (Q = M; Q > 1; Q >>= 1)
+ {
+ const bool condition = (x[2 - 1] & Q);
+ if (condition)
+ {
+ t ^= Q - 1;
+ }
+ } // check if this for loop is wrong
+ for (i = 0; i < 2; ++i)
+ {
+ x[i] ^= t;
+ }
+}
+} // anonymous ns
+
+std::uint64_t hilbertCode(const Coordinate coordinate)
+{
+ std::uint32_t location[2];
+ location[0] = static_cast<std::int32_t>(coordinate.lon) +
+ static_cast<std::int32_t>(180 * COORDINATE_PRECISION);
+ location[1] = static_cast<std::int32_t>(coordinate.lat) +
+ static_cast<std::int32_t>(90 * COORDINATE_PRECISION);
+
+ transposeCoordinate(location);
+ return bitInterleaving(location[0], location[1]);
+}
+}
+}
diff --git a/src/util/name_table.cpp b/src/util/name_table.cpp
new file mode 100644
index 0000000..e3d5cef
--- /dev/null
+++ b/src/util/name_table.cpp
@@ -0,0 +1,62 @@
+#include "util/name_table.hpp"
+#include "util/simple_logger.hpp"
+#include "util/exception.hpp"
+
+#include <algorithm>
+#include <limits>
+#include <fstream>
+
+#include <boost/filesystem/fstream.hpp>
+
+namespace osrm
+{
+namespace util
+{
+
+NameTable::NameTable(const std::string &filename)
+{
+ boost::filesystem::ifstream name_stream(filename, std::ios::binary);
+
+ if( !name_stream )
+ throw exception("Failed to open " + filename + " for reading.");
+
+ name_stream >> m_name_table;
+
+ unsigned number_of_chars = 0;
+ name_stream.read(reinterpret_cast<char *>(&number_of_chars), sizeof(number_of_chars));
+ if( !name_stream )
+ throw exception("Encountered invalid file, failed to read number of contained chars");
+
+ BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
+ m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
+ name_stream.read(reinterpret_cast<char *>(&m_names_char_list[0]),
+ number_of_chars * sizeof(m_names_char_list[0]));
+ if( !name_stream )
+ throw exception("Failed to read " + std::to_string(number_of_chars) + " characters from file.");
+
+ if (0 == m_names_char_list.size())
+ {
+ util::SimpleLogger().Write(logWARNING) << "list of street names is empty";
+ }
+}
+
+std::string NameTable::GetNameForID(const unsigned name_id) const
+{
+ if (std::numeric_limits<unsigned>::max() == name_id)
+ {
+ return "";
+ }
+ auto range = m_name_table.GetRange(name_id);
+
+ std::string result;
+ result.reserve(range.size());
+ if (range.begin() != range.end())
+ {
+ result.resize(range.back() - range.front() + 1);
+ std::copy(m_names_char_list.begin() + range.front(),
+ m_names_char_list.begin() + range.back() + 1, result.begin());
+ }
+ return result;
+}
+} // namespace util
+} // namespace osrm
diff --git a/util/simple_logger.cpp b/src/util/simple_logger.cpp
similarity index 61%
rename from util/simple_logger.cpp
rename to src/util/simple_logger.cpp
index e3f4f8e..13ee103 100644
--- a/util/simple_logger.cpp
+++ b/src/util/simple_logger.cpp
@@ -1,31 +1,4 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "simple_logger.hpp"
+#include "util/simple_logger.hpp"
#ifdef _MSC_VER
#include <io.h>
#define isatty _isatty
@@ -38,6 +11,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <mutex>
#include <string>
+namespace osrm
+{
+namespace util
+{
+
namespace
{
static const char COL_RESET[]{"\x1b[0m"};
@@ -119,3 +97,5 @@ SimpleLogger::~SimpleLogger()
}
}
}
+}
+}
diff --git a/taginfo.json b/taginfo.json
index 17a4f8f..4ef48de 100644
--- a/taginfo.json
+++ b/taginfo.json
@@ -6,13 +6,12 @@
"description": "High-performance routing engine for shortest paths in road networks.",
"project_url": "http://project-osrm.org",
"icon_url": "http://project-osrm.org/images/osrm_icon.png",
- "contact_name": "Dennis Luxen",
- "contact_email": "info at project-osrm.org"
+ "contact_name": "Patrick Niklaus",
+ "contact_email": "patrick at mapbox.com"
},
"tags": [
{
"key": "highway",
- "description": "Type of road.",
"object_types": [ "way" ]
},
{
@@ -22,6 +21,23 @@
},
{
"key": "oneway",
+ "value": "true",
+ "object_types": [ "way" ]
+ },
+ {
+ "key": "oneway",
+ "value": "1",
+ "object_types": [ "way" ]
+ },
+ {
+ "key": "oneway",
+ "value": "-1",
+ "object_types": [ "way" ]
+ },
+ {
+ "key": "oneway",
+ "value": "reversible",
+ "description": "is marked as non-routable because of time-dependence",
"object_types": [ "way" ]
},
{
@@ -38,10 +54,127 @@
"key": "status",
"description": "This is used by HOT."
},
- {
- "key": "access",
- "object_types": [ "way" ]
- },
+ {"key": "maxspeed:advisory"},
+ {"key": "maxspeed:advisory:forward"},
+ {"key": "maxspeed:advisory:backward"},
+ {"key": "bridge", "value": "movable", "description": "uses capacity and duration"},
+ {"key": "capacity:car", "description": "used for movable bridges"},
+ {"key": "side_road", "value": "yes", "description": "gets speed penalty"},
+ {"key": "side_road", "value": "rotary", "description": "gets speed penalty"},
+ {"key": "route", "object_types": ["way"]},
+ {"key": "highway", "value": "traffic_signals", "object_types": ["node"]},
+ {"key": "access", "value": "yes"},
+ {"key": "access", "value": "motorcar"},
+ {"key": "access", "value": "motor_vehicle"},
+ {"key": "access", "value": "vehicle"},
+ {"key": "access", "value": "permissive"},
+ {"key": "access", "value": "designated"},
+ {"key": "access", "value": "destination"},
+ {"key": "access", "value": "no"},
+ {"key": "access", "value": "private"},
+ {"key": "access", "value": "agricultural"},
+ {"key": "access", "value": "forestry"},
+ {"key": "access", "value": "emergency"},
+ {"key": "access", "value": "psv"},
+ {"key": "access", "value": "delivery"},
+ {"key": "maxspeed", "value": "urban"},
+ {"key": "maxspeed", "value": "rural"},
+ {"key": "maxspeed", "value": "trunk"},
+ {"key": "maxspeed", "value": "motorway"},
+ {"key": "maxspeed", "value": "ch:rural"},
+ {"key": "maxspeed", "value": "ch:trunk"},
+ {"key": "maxspeed", "value": "ch:motorway"},
+ {"key": "maxspeed", "value": "de:living_street"},
+ {"key": "maxspeed", "value": "ru:living_street"},
+ {"key": "maxspeed", "value": "ru:urban"},
+ {"key": "maxspeed", "value": "ua:urban"},
+ {"key": "maxspeed", "value": "at:rural"},
+ {"key": "maxspeed", "value": "de:rural"},
+ {"key": "maxspeed", "value": "at:trunk"},
+ {"key": "maxspeed", "value": "cz:trunk"},
+ {"key": "maxspeed", "value": "ro:trunk"},
+ {"key": "maxspeed", "value": "cz:motorway"},
+ {"key": "maxspeed", "value": "de:motorway"},
+ {"key": "maxspeed", "value": "ru:motorway"},
+ {"key": "maxspeed", "value": "gb:nsl_single"},
+ {"key": "maxspeed", "value": "gb:nsl_dual"},
+ {"key": "maxspeed", "value": "gb:motorway"},
+ {"key": "maxspeed", "value": "uk:nsl_single"},
+ {"key": "maxspeed", "value": "uk:nsl_dual"},
+ {"key": "maxspeed", "value": "uk:motorway"},
+ {"key": "smoothness", "value": "intermediate"},
+ {"key": "smoothness", "value": "bad"},
+ {"key": "smoothness", "value": "very_bad"},
+ {"key": "smoothness", "value": "horrible"},
+ {"key": "smoothness", "value": "very_horrible"},
+ {"key": "smoothness", "value": "impassable"},
+ {"key": "tracktype", "value": "grade1"},
+ {"key": "tracktype", "value": "grade2"},
+ {"key": "tracktype", "value": "grade3"},
+ {"key": "tracktype", "value": "grade4"},
+ {"key": "tracktype", "value": "grade5"},
+ {"key": "bollard", "value": "rising"},
+ {"key": "bollard", "description": "Non-rising bollards are barriers"},
+ {"key": "barrier", "value": "cattle_grid"},
+ {"key": "barrier", "value": "border_control"},
+ {"key": "barrier", "value": "checkpoint"},
+ {"key": "barrier", "value": "toll_booth"},
+ {"key": "barrier", "value": "sally_port"},
+ {"key": "barrier", "value": "gate"},
+ {"key": "barrier", "value": "lift_gate"},
+ {"key": "barrier", "value": "no"},
+ {"key": "barrier", "value": "entrance"},
+ {"key": "highway", "value": "motorway"},
+ {"key": "highway", "value": "motorway_link"},
+ {"key": "highway", "value": "trunk"},
+ {"key": "highway", "value": "trunk_link"},
+ {"key": "highway", "value": "primary"},
+ {"key": "highway", "value": "primary_link"},
+ {"key": "highway", "value": "secondary"},
+ {"key": "highway", "value": "secondary_link"},
+ {"key": "highway", "value": "tertiary"},
+ {"key": "highway", "value": "tertiary_link"},
+ {"key": "highway", "value": "unclassified"},
+ {"key": "highway", "value": "residential"},
+ {"key": "highway", "value": "living_street"},
+ {"key": "highway", "value": "service"},
+ {"key": "highway", "value": "ferry"},
+ {"key": "highway", "value": "movable"},
+ {"key": "highway", "value": "shuttle_train"},
+ {"key": "highway", "value": "default"},
+ {"key": "width", "description": "Penalties for narrow streets"},
+ {"key": "lanes", "description": "Penalties for shared single lane streets"},
+ {"key": "surface", "value": "asphalt"},
+ {"key": "surface", "value": "concrete"},
+ {"key": "surface", "value": "concrete:plates"},
+ {"key": "surface", "value": "concrete:lanes"},
+ {"key": "surface", "value": "paved"},
+ {"key": "surface", "value": "cement"},
+ {"key": "surface", "value": "compacted"},
+ {"key": "surface", "value": "fine_gravel"},
+ {"key": "surface", "value": "paving_stones"},
+ {"key": "surface", "value": "metal"},
+ {"key": "surface", "value": "bricks"},
+ {"key": "surface", "value": "grass"},
+ {"key": "surface", "value": "wood"},
+ {"key": "surface", "value": "sett"},
+ {"key": "surface", "value": "grass_paver"},
+ {"key": "surface", "value": "gravel"},
+ {"key": "surface", "value": "unpaved"},
+ {"key": "surface", "value": "ground"},
+ {"key": "surface", "value": "dirt"},
+ {"key": "surface", "value": "pebblestone"},
+ {"key": "surface", "value": "tartan"},
+ {"key": "surface", "value": "cobblestone"},
+ {"key": "surface", "value": "clay"},
+ {"key": "surface", "value": "earth"},
+ {"key": "surface", "value": "stone"},
+ {"key": "surface", "value": "rocky"},
+ {"key": "surface", "value": "sand"},
+ {"key": "surface", "value": "mud"},
+ {"key": "motorcar"},
+ {"key": "motor_vehicle"},
+ {"key": "vehicle"},
{
"key": "barrier"
},
diff --git a/test/data/Makefile b/test/data/Makefile
new file mode 100755
index 0000000..0ddda31
--- /dev/null
+++ b/test/data/Makefile
@@ -0,0 +1,29 @@
+MONACO_URL:=https://s3.amazonaws.com/mapbox/osrm/testing/monaco.osm.pbf
+TOOL_ROOT:=../../build
+PROFILE_ROOT:=../../profiles
+OSRM_EXTRACT:=$(TOOL_ROOT)/osrm-extract
+OSRM_CONTRACT:=$(TOOL_ROOT)/osrm-contract
+PROFILE:=$(PROFILE_ROOT)/car.lua
+
+all: monaco.osrm.hsgr
+
+clean:
+ rm monaco.*
+
+monaco.osm.pbf:
+ wget $(MONACO_URL) -O monaco.osm.pbf
+
+monaco.osrm: monaco.osm.pbf $(PROFILE) $(OSRM_EXTRACT)
+ @echo "Verifiyng data file integrity..."
+ md5sum -c data.md5sum
+ @echo "Running osrm-extract..."
+ $(OSRM_EXTRACT) monaco.osm.pbf -p $(PROFILE)
+
+monaco.osrm.hsgr: monaco.osrm $(PROFILE) $(OSRM_CONTRACT)
+ @echo "Running osrm-contract..."
+ $(OSRM_CONTRACT) monaco.osrm
+
+checksum:
+ md5sum monaco.osm.pbf > data.md5sum
+
+.PHONY: clean checksum
diff --git a/test/data/data.md5sum b/test/data/data.md5sum
new file mode 100644
index 0000000..47151b4
--- /dev/null
+++ b/test/data/data.md5sum
@@ -0,0 +1 @@
+2b8dd9343d5e615afc9c67bcc7028a63 monaco.osm.pbf
diff --git a/third_party/variant/.clang-format b/third_party/variant/.clang-format
new file mode 100644
index 0000000..c1aca2a
--- /dev/null
+++ b/third_party/variant/.clang-format
@@ -0,0 +1,89 @@
+---
+# Mapbox.Variant C/C+ style
+Language: Cpp
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: true
+ AfterControlStatement: true
+ AfterEnum: true
+ AfterFunction: true
+ AfterNamespace: false
+ AfterObjCDeclaration: true
+ AfterStruct: true
+ AfterUnion: true
+ BeforeCatch: true
+ BeforeElse: true
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+ColumnLimit: 0
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeCategories:
+ - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+ Priority: 2
+ - Regex: '^(<|"(gtest|isl|json)/)'
+ Priority: 3
+ - Regex: '.*'
+ Priority: 1
+IndentCaseLabels: false
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Left
+ReflowComments: true
+SortIncludes: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+TabWidth: 4
+UseTab: Never
+...
diff --git a/third_party/variant/.gitignore b/third_party/variant/.gitignore
index 984cc2f..a9bc860 100644
--- a/third_party/variant/.gitignore
+++ b/third_party/variant/.gitignore
@@ -3,3 +3,6 @@ out
profiling
build
deps
+*.gcda
+*.gcno
+.ycm_extra_conf.pyc
diff --git a/third_party/variant/.travis.yml b/third_party/variant/.travis.yml
index cd1e655..99d0b48 100644
--- a/third_party/variant/.travis.yml
+++ b/third_party/variant/.travis.yml
@@ -1,22 +1,127 @@
-language: cpp
+language: c
-# http://docs.travis-ci.com/user/multi-os/
-os:
- - linux
- - osx
+sudo: false
-compiler:
- - clang
- - gcc
+# Save common build configurations as shortcuts, so we can reference them later.
+addons_shortcuts:
+ addons_clang35: &clang35
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5', 'boost-latest' ]
+ packages: [ 'clang-3.5', 'libboost1.55-all-dev' ]
+ addons_clang36: &clang36
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6', 'boost-latest' ]
+ packages: [ 'clang-3.6', 'libboost1.55-all-dev' ]
+ addons_clang37: &clang37
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7', 'boost-latest' ]
+ packages: [ 'clang-3.7', 'libboost1.55-all-dev' ]
+ addons_clang38: &clang38
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise', 'boost-latest' ]
+ packages: [ 'clang-3.8', 'libboost1.55-all-dev']
+ addons_gcc47: &gcc47
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
+ packages: [ 'g++-4.7', 'libboost1.55-all-dev' ]
+ addons_gcc48: &gcc48
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
+ packages: [ 'g++-4.8', 'libboost1.55-all-dev' ]
+ addons_gcc49: &gcc49
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
+ packages: [ 'g++-4.9', 'libboost1.55-all-dev' ]
+ addons_gcc5: &gcc5
+ apt:
+ sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
+ packages: [ 'g++-5', 'libboost1.55-all-dev' ]
+
+matrix:
+ include:
+ - os: osx
+ osx_image: xcode6
+ compiler: clang
+ - os: osx
+ osx_image: xcode7
+ env: TEST_GYP_BUILD=True
+ compiler: clang
+ - os: linux
+ compiler: "clang35"
+ env: CXX=clang++-3.5
+ addons: *clang35
+ - os: linux
+ compiler: "clang36"
+ env: CXX=clang++-3.6
+ addons: *clang36
+ - os: linux
+ compiler: "clang37"
+ env: CXX=clang++-3.7 COVERAGE=True
+ addons: *clang37
+ - os: linux
+ compiler: "clang38"
+ env: CXX=clang++-3.8
+ addons: *clang38
+ - os: linux
+ compiler: "clang38"
+ env: CXX=clang++-3.8 CXX_STD=c++14
+ addons: *clang38
+ - os: linux
+ compiler: "gcc47"
+ env: CXX=g++-4.7
+ addons: *gcc47
+ - os: linux
+ compiler: "gcc48"
+ env: CXX=g++-4.8
+ addons: *gcc48
+ - os: linux
+ compiler: "gcc49"
+ env: CXX=g++-4.9
+ addons: *gcc49
+ - os: linux
+ compiler: "gcc49"
+ env: CXX=g++-4.9 CXX_STD=c++14
+ addons: *gcc49
+ - os: linux
+ compiler: "gcc5"
+ env: CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0"
+ addons: *gcc5
+ - os: linux
+ compiler: "gcc5"
+ env: CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=1"
+ addons: *gcc5
before_install:
- - true
+ - echo ${CXX}
+ - if [[ $(uname -s) == 'Linux' ]]; then
+ export PYTHONPATH=$(pwd)/.local/lib/python2.7/site-packages;
+ else
+ brew install boost;
+ export PYTHONPATH=$(pwd)/.local/lib/python/site-packages;
+ fi
+ - if [[ ${COVERAGE:-0} == 'True' ]]; then
+ PYTHONUSERBASE=$(pwd)/.local pip install --user cpp-coveralls;
+ fi
install:
- - true
-
-before_script:
- - true
+ - make test
+ - make bench
+ - if [[ $(uname -s) == 'Linux' ]]; then
+ make sizes /usr/include/boost/variant.hpp;
+ else
+ make sizes `brew --prefix`/include/boost/variant.hpp;
+ fi
+ - scripts/run_compilation_failure_tests.sh
+ - if [[ ${TEST_GYP_BUILD:-0} == 'True' ]]; then
+ make clean;
+ make gyp;
+ fi
script:
- - source "scripts/${TRAVIS_OS_NAME}.sh"
+ - if [[ ${COVERAGE:-0} == 'True' ]]; then
+ make clean;
+ make coverage;
+ ./out/cov-test;
+ cp unit*gc* test/;
+ ./.local/bin/cpp-coveralls -i optional.hpp -i recursive_wrapper.hpp -i variant.hpp -i variant_io.hpp --gcov-options '\-lp';
+ fi
diff --git a/third_party/variant/.ycm_extra_conf.py b/third_party/variant/.ycm_extra_conf.py
new file mode 100644
index 0000000..ba74668
--- /dev/null
+++ b/third_party/variant/.ycm_extra_conf.py
@@ -0,0 +1,40 @@
+#-----------------------------------------------------------------------------
+#
+# Configuration for YouCompleteMe Vim plugin
+#
+# http://valloric.github.io/YouCompleteMe/
+#
+#-----------------------------------------------------------------------------
+
+from os.path import realpath, dirname
+
+basedir = dirname(realpath(__file__))
+
+# some default flags
+# for more information install clang-3.2-doc package and
+# check UsersManual.html
+flags = [
+'-Werror',
+'-Wall',
+'-Wextra',
+'-pedantic',
+
+'-std=c++11',
+
+# '-x' and 'c++' also required
+# use 'c' for C projects
+'-x',
+'c++',
+
+# include third party libraries
+'-I.',
+]
+
+# youcompleteme is calling this function to get flags
+# You can also set database for flags. Check: JSONCompilationDatabase.html in
+# clang-3.2-doc package
+def FlagsForFile( filename ):
+ return {
+ 'flags': flags,
+ 'do_cache': True
+ }
diff --git a/third_party/variant/Jamroot b/third_party/variant/Jamroot
index aa21375..1e98cf5 100644
--- a/third_party/variant/Jamroot
+++ b/third_party/variant/Jamroot
@@ -1,3 +1,6 @@
+# Inofficial and incomplete build file using Boost build system.
+# You should use make unless you know what you are doing.
+
local BOOST_DIR = "/usr/local" ;
#using clang : : ;
@@ -15,7 +18,6 @@ exe variant-test
:
<include>$(BOOST_DIR)/include
<include>./
- <cxxflags>-std=c++11
#<define>SINGLE_THREADED
<variant>release:<cxxflags>-march=native
;
@@ -30,7 +32,6 @@ exe binary-visitor-test
:
<include>$(BOOST_DIR)/include
<include>./
- <cxxflags>-std=c++11
<variant>release:<cxxflags>-march=native
;
@@ -43,7 +44,6 @@ exe recursive-wrapper-test
:
<include>$(BOOST_DIR)/include
<include>./
- <cxxflags>-std=c++11
<variant>release:<cxxflags>-march=native
;
@@ -56,7 +56,6 @@ exe unique-ptr-test
:
<include>$(BOOST_DIR)/include
<include>./
- <cxxflags>-std=c++11
<variant>release:<cxxflags>-march=native
;
@@ -70,6 +69,5 @@ exe reference_wrapper_test
:
<include>$(BOOST_DIR)/include
<include>./
- <cxxflags>-std=c++11
<variant>release:<cxxflags>-march=native
;
diff --git a/third_party/variant/LICENSE_1_0.txt b/third_party/variant/LICENSE_1_0.txt
new file mode 100644
index 0000000..36b7cd9
--- /dev/null
+++ b/third_party/variant/LICENSE_1_0.txt
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/third_party/variant/Makefile b/third_party/variant/Makefile
index cae3d46..3665251 100644
--- a/third_party/variant/Makefile
+++ b/third_party/variant/Makefile
@@ -1,8 +1,11 @@
+
CXX := $(CXX)
+CXX_STD ?= c++11
+
BOOST_LIBS = -lboost_timer -lboost_system -lboost_chrono
-RELEASE_FLAGS = -O3 -DNDEBUG -finline-functions -march=native -DSINGLE_THREADED
+RELEASE_FLAGS = -O3 -DNDEBUG -march=native -DSINGLE_THREADED -fvisibility-inlines-hidden
DEBUG_FLAGS = -O0 -g -DDEBUG -fno-inline-functions
-COMMON_FLAGS = -Wall -Wsign-compare -Wsign-conversion -Wshadow -Wunused-parameter -pedantic -fvisibility-inlines-hidden -std=c++11
+COMMON_FLAGS = -Wall -pedantic -Wextra -Wsign-compare -Wsign-conversion -Wshadow -Wunused-parameter -std=$(CXX_STD)
CXXFLAGS := $(CXXFLAGS)
LDFLAGS := $(LDFLAGS)
@@ -33,23 +36,23 @@ gyp: ./deps/gyp
make V=1 -C ./out tests
./out/Release/tests
-out/bench-variant-debug: Makefile test/bench_variant.cpp variant.hpp
+out/bench-variant-debug: Makefile test/bench_variant.cpp variant.hpp recursive_wrapper.hpp
mkdir -p ./out
- $(CXX) -o out/bench-variant-debug test/bench_variant.cpp -I./ $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
+ $(CXX) -o out/bench-variant-debug test/bench_variant.cpp -I./ -pthreads $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
-out/bench-variant: Makefile test/bench_variant.cpp variant.hpp
+out/bench-variant: Makefile test/bench_variant.cpp variant.hpp recursive_wrapper.hpp
mkdir -p ./out
$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
-out/unique_ptr_test: Makefile test/unique_ptr_test.cpp variant.hpp
+out/unique_ptr_test: Makefile test/unique_ptr_test.cpp variant.hpp recursive_wrapper.hpp
mkdir -p ./out
$(CXX) -o out/unique_ptr_test test/unique_ptr_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
-out/recursive_wrapper_test: Makefile test/recursive_wrapper_test.cpp variant.hpp
+out/recursive_wrapper_test: Makefile test/recursive_wrapper_test.cpp variant.hpp recursive_wrapper.hpp
mkdir -p ./out
$(CXX) -o out/recursive_wrapper_test test/recursive_wrapper_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
-out/binary_visitor_test: Makefile test/binary_visitor_test.cpp variant.hpp
+out/binary_visitor_test: Makefile test/binary_visitor_test.cpp variant.hpp variant_io.hpp recursive_wrapper.hpp
mkdir -p ./out
$(CXX) -o out/binary_visitor_test test/binary_visitor_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
@@ -59,24 +62,30 @@ bench: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_w
./out/recursive_wrapper_test 100000
./out/binary_visitor_test 100000
-out/unit: Makefile test/unit.cpp test/optional_unit.cpp optional.hpp variant.hpp
+out/unit.o: Makefile test/unit.cpp
+ mkdir -p ./out
+ $(CXX) -c -o $@ test/unit.cpp -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS)
+
+out/%.o: test/t/%.cpp Makefile optional.hpp recursive_wrapper.hpp variant.hpp variant_io.hpp
+ mkdir -p ./out
+ $(CXX) -c -o $@ $< -I. -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS)
+
+out/unit: out/unit.o out/binary_visitor_1.o out/binary_visitor_2.o out/binary_visitor_3.o out/binary_visitor_4.o out/binary_visitor_5.o out/binary_visitor_6.o out/issue21.o out/mutating_visitor.o out/optional.o out/recursive_wrapper.o out/sizeof.o out/unary_visitor.o out/variant.o
mkdir -p ./out
- $(CXX) -o out/unit test/unit.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
- $(CXX) -o out/optional_unit test/optional_unit.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
+ $(CXX) -o $@ $^ $(LDFLAGS)
test: out/unit
./out/unit
- ./out/optional_unit
coverage:
mkdir -p ./out
- $(CXX) -o out/cov-test --coverage test/unit.cpp -I./ $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
+ $(CXX) -o out/cov-test --coverage test/unit.cpp test/t/*.cpp -I./ -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
-sizes: Makefile variant.hpp
+sizes: Makefile variant.hpp recursive_wrapper.hpp
mkdir -p ./out
- @$(CXX) -o ./out/variant_hello_world.out variant.hpp $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/variant_hello_world.out
+ @$(CXX) -o ./out/our_variant_hello_world.out variant.hpp $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/our_variant_hello_world.out
@$(CXX) -o ./out/boost_variant_hello_world.out $(RUN_ARGS) $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/boost_variant_hello_world.out
- @$(CXX) -o ./out/variant_hello_world ./test/variant_hello_world.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/variant_hello_world
+ @$(CXX) -o ./out/our_variant_hello_world ./test/our_variant_hello_world.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/our_variant_hello_world
@$(CXX) -o ./out/boost_variant_hello_world ./test/boost_variant_hello_world.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/boost_variant_hello_world
profile: out/bench-variant-debug
@@ -91,8 +100,9 @@ clean:
rm -f *gcov
rm -f test/unit.gc*
rm -f test/*gcov
+ rm -f *.gcda *.gcno
-pgo: out Makefile variant.hpp
+pgo: out Makefile variant.hpp recursive_wrapper.hpp
$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS) -pg -fprofile-generate
./test-variant 500000 >/dev/null 2>/dev/null
$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS) -fprofile-use
diff --git a/third_party/variant/README.md b/third_party/variant/README.md
index 791131d..24cdb57 100644
--- a/third_party/variant/README.md
+++ b/third_party/variant/README.md
@@ -4,11 +4,13 @@ An alternative to `boost::variant` for C++11.
[![Build Status](https://secure.travis-ci.org/mapbox/variant.svg)](https://travis-ci.org/mapbox/variant)
[![Build status](https://ci.appveyor.com/api/projects/status/v9tatx21j1k0fcgy)](https://ci.appveyor.com/project/Mapbox/variant)
-[![Coverage Status](https://coveralls.io/repos/mapbox/variant/badge.svg?branch=master)](https://coveralls.io/r/mapbox/variant?branch=master)
+[![Coverage Status](https://coveralls.io/repos/mapbox/variant/badge.svg?branch=master&service=github)](https://coveralls.io/r/mapbox/variant?branch=master)
-# Why use Mapbox Variant?
-Mapbox variant has the same speedy performance of `boost::variant` but is faster to compile, results in smaller binaries, and has no dependencies.
+## Why use Mapbox Variant?
+
+Mapbox variant has the same speedy performance of `boost::variant` but is
+faster to compile, results in smaller binaries, and has no dependencies.
For example on OS X 10.9 with clang++ and libc++:
@@ -18,49 +20,91 @@ Size of pre-compiled header (release / debug) | 2.8/2.8 MB | 12/15 MB
Size of simple program linking variant (release / debug) | 8/24 K | 12/40 K
Time to compile header | 185 ms | 675 ms
+(Numbers from an older version of Mapbox variant.)
+
+
+## Goals
+
+Mapbox `variant` has been a very valuable, lightweight alternative for apps
+that can use c++11 or c++14 but that do not want a boost dependency.
+Mapbox `variant` has also been useful in apps that do depend on boost, like
+mapnik, to help (slightly) with compile times and to majorly lessen dependence
+on boost in core headers. The original goal and near term goal is to maintain
+external API compatibility with `boost::variant` such that Mapbox `variant`
+can be a "drop in". At the same time the goal is to stay minimal: Only
+implement the features that are actually needed in existing software. So being
+an "incomplete" implementation is just fine.
+
+Currently Mapbox variant doesn't try to be API compatible with the upcoming
+variant standard, because the standard is not finished and it would be too much
+work. But we'll revisit this decision in the future if needed.
+
+If Mapbox variant is not for you, have a look at [these other
+implementations](doc/other_implementations.md).
-# Depends
+Want to know more about the upcoming standard? Have a look at our
+[overview](doc/standards_effort.md).
- - Compiler supporting `-std=c++11`
-Tested with
+## Depends
+
+ - Compiler supporting `-std=c++11` or `-std=c++14`
+
+Tested with:
- g++-4.7
- g++-4.8
- - clang++-3.4
+ - g++-4.9
+ - g++-5
- clang++-3.5
- - Visual C++ Compiler November 2013 CTP
- - Visual C++ Compiler 2014 CTP 4
+ - clang++-3.6
+ - clang++-3.7
+ - clang++-3.8
+ - Visual Studio 2015
-Note: get the "2013 Nov CTP" release at http://www.microsoft.com/en-us/download/details.aspx?id=41151 and the 2014 CTP at http://www.visualstudio.com/en-us/downloads/visual-studio-14-ctp-vs.aspx
+## Usage
-# Usage
+There is nothing to build, just include `variant.hpp` and
+`recursive_wrapper.hpp` in your project. Include `variant_io.hpp` if you need
+the `operator<<` overload for variant.
-There is nothing to build, just include `variant.hpp` and `recursive_wrapper.hpp` in your project.
-# Tests
+## Unit Tests
-The tests depend on:
+On Unix systems compile and run the unit tests with `make test`.
- - Boost headers (for benchmarking against `boost::variant`)
- - Boost built with `--with-timer` (used for benchmark timing)
+On Windows run `scripts/build-local.bat`.
-On Unix systems set your boost includes and libs locations and run `make test`:
- export LDFLAGS='-L/opt/boost/lib'
- export CXXFLAGS='-I/opt/boost/include'
- make test
+## Limitations
+
+* The `variant` can not hold references (something like `variant<int&>` is
+ not possible). You might want to try `std::reference_wrapper` instead.
+
+
+## Deprecations
+
+* The included implementation of `optional` is deprecated and will be removed
+ in a future version. See https://github.com/mapbox/variant/issues/64.
+* Old versions of the code needed visitors to derive from `static_visitor`.
+ This is not needed any more and marked as deprecated. The `static_visitor`
+ class will be removed in future versions.
+
-On windows do:
+## Benchmarks
- vcbuild
+The benchmarks depend on:
-## Benchmark
+ - Boost headers (for benchmarking against `boost::variant`)
+ - Boost built with `--with-timer` (used for benchmark timing)
-On Unix systems run the benchmark like:
+On Unix systems set your boost includes and libs locations and run `make test`:
+ export LDFLAGS='-L/opt/boost/lib'
+ export CXXFLAGS='-I/opt/boost/include'
make bench
+
## Check object sizes
make sizes /path/to/boost/variant.hpp
diff --git a/third_party/variant/doc/other_implementations.md b/third_party/variant/doc/other_implementations.md
new file mode 100644
index 0000000..a0d8b9b
--- /dev/null
+++ b/third_party/variant/doc/other_implementations.md
@@ -0,0 +1,15 @@
+
+# Other implementations of variant and optional
+
+These are some other implementations of `variant` and/or `optional` types.
+They are not necessarily compatible with this implementation. This is an
+incomplete list.
+
+* [Boost Variant](http://www.boost.org/doc/libs/1_59_0/doc/html/variant.html) and [Boost Optional](http://www.boost.org/doc/libs/1_59_0/libs/optional/doc/html/index.html)
+* [Eggs Variant](http://eggs-cpp.github.io/variant/) by [Agustín Bergé](http://talesofcpp.fusionfenix.com/)
+* [anthonyw/variant](https://bitbucket.org/anthonyw/variant) (implementation of P0110R0)
+* [JasonL9000/cppcon14](https://github.com/JasonL9000/cppcon14)
+* [tomilov/variant](https://github.com/tomilov/variant)
+* [akrzemi1/Optional](https://github.com/akrzemi1/Optional)
+* [mpark/variant](https://github.com/mpark/variant)
+
diff --git a/third_party/variant/doc/standards_effort.md b/third_party/variant/doc/standards_effort.md
new file mode 100644
index 0000000..d2df488
--- /dev/null
+++ b/third_party/variant/doc/standards_effort.md
@@ -0,0 +1,28 @@
+
+# Standards efforts
+
+A `variant` type is on planned for inclusion in the C++ Standard, probably in
+C++17. Current working papers are (list extracted from [2015 working group
+papers](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/)):
+
+* 2015-09-28: Variant design review. [P0086R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0086r0.pdf)
+* 2015-09-28: Variant: a type-safe union without undefined behavior (v2) [P0087R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0087r0.pdf)
+* 2015-09-27: Variant: a type-safe union that is rarely invalid (v5) [P0088R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0088r0.pdf)
+* 2015-09-24: Simply a Strong Variant [P0093R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0093r0.html)
+* 2015-09-24: Simply a Basic Variant [P0094R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0094r0.html)
+* 2015-09-24: The Case for a Language Based Variant [P0096R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0095r0.html)
+* 2015-09-25: Implementing the strong guarantee for variant<> assignment [P0110R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0110r0.html)
+* 2015-09-24: Homogeneous interface for variant, any and optional (Revision 1) [P0032R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0032r1.pdf)
+
+Last state can be seen from
+[The Variant Saga: A happy ending?](https://isocpp.org/blog/2015/11/the-variant-saga-a-happy-ending).
+
+The `optional` type is also on the way into the standard. The papers are:
+* 2013-10-03: A proposal to add a utility class to represent optional objects (Revision 5) [N3793](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3793.html)
+* 2014-01-18: Working Draft, Technical Specification on C++ Extensions for Library Fundamentals [N3848](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3848.html)
+
+## Older Papers
+
+* Older working drafts are: N4218 (rev 1), N4516 (rev 2), N4450 (rev 3), and [N4542](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4542.pdf) (rev 4). They have been split into P0086 (general design discussions) and P0087 and P0088 (containing two competing? specs).
+* 2015-07-28: Variant: Discriminated Union with Value Semantics [P0080R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0080r0.pdf) An alternative proposal to N4542.
+
diff --git a/third_party/variant/optional.hpp b/third_party/variant/optional.hpp
index 133e2c8..1185894 100644
--- a/third_party/variant/optional.hpp
+++ b/third_party/variant/optional.hpp
@@ -1,16 +1,18 @@
#ifndef MAPBOX_UTIL_OPTIONAL_HPP
#define MAPBOX_UTIL_OPTIONAL_HPP
+#pragma message("This implementation of optional is deprecated. See https://github.com/mapbox/variant/issues/64.")
+
#include <type_traits>
+#include <utility>
#include "variant.hpp"
-namespace mapbox
-{
-namespace util
-{
+namespace mapbox {
+namespace util {
-template <typename T> class optional
+template <typename T>
+class optional
{
static_assert(!std::is_reference<T>::value, "optional doesn't support references");
@@ -23,7 +25,7 @@ template <typename T> class optional
public:
optional() = default;
- optional(optional const &rhs)
+ optional(optional const& rhs)
{
if (this != &rhs)
{ // protect against invalid self-assignment
@@ -31,23 +33,23 @@ template <typename T> class optional
}
}
- optional(T const &v) { variant_ = v; }
+ optional(T const& v) { variant_ = v; }
explicit operator bool() const noexcept { return variant_.template is<T>(); }
- T const &get() const { return variant_.template get<T>(); }
- T &get() { return variant_.template get<T>(); }
+ T const& get() const { return variant_.template get<T>(); }
+ T& get() { return variant_.template get<T>(); }
- T const &operator*() const { return this->get(); }
+ T const& operator*() const { return this->get(); }
T operator*() { return this->get(); }
- optional &operator=(T const &v)
+ optional& operator=(T const& v)
{
variant_ = v;
return *this;
}
- optional &operator=(optional const &rhs)
+ optional& operator=(optional const& rhs)
{
if (this != &rhs)
{
@@ -56,14 +58,17 @@ template <typename T> class optional
return *this;
}
- template <typename... Args> void emplace(Args &&... args)
+ template <typename... Args>
+ void emplace(Args&&... args)
{
variant_ = T{std::forward<Args>(args)...};
}
void reset() { variant_ = none_type{}; }
-};
-}
-}
-#endif
+}; // class optional
+
+} // namespace util
+} // namespace mapbox
+
+#endif // MAPBOX_UTIL_OPTIONAL_HPP
diff --git a/third_party/variant/recursive_wrapper.hpp b/third_party/variant/recursive_wrapper.hpp
index 54b2763..4becdd6 100644
--- a/third_party/variant/recursive_wrapper.hpp
+++ b/third_party/variant/recursive_wrapper.hpp
@@ -1,44 +1,72 @@
-#ifndef MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
-#define MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
-
+#ifndef MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
+#define MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
+
+// Based on variant/recursive_wrapper.hpp from boost.
+//
+// Original license:
+//
+// Copyright (c) 2002-2003
+// Eric Friedman, Itay Maman
+//
+// 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)
+
+#include <cassert>
#include <utility>
-namespace mapbox { namespace util {
+namespace mapbox {
+namespace util {
template <typename T>
class recursive_wrapper
{
-public:
- using type = T;
-private:
T* p_;
-public:
+ void assign(T const& rhs)
+ {
+ this->get() = rhs;
+ }
+
+ public:
+ using type = T;
- ~recursive_wrapper();
- recursive_wrapper();
+ /**
+ * Default constructor default initializes the internally stored value.
+ * For POD types this means nothing is done and the storage is
+ * uninitialized.
+ *
+ * @throws std::bad_alloc if there is insufficient memory for an object
+ * of type T.
+ * @throws any exception thrown by the default constructur of T.
+ */
+ recursive_wrapper()
+ : p_(new T){};
- recursive_wrapper(recursive_wrapper const& operand);
- recursive_wrapper(T const& operand);
- recursive_wrapper(recursive_wrapper&& operand);
- recursive_wrapper(T&& operand);
+ ~recursive_wrapper() noexcept { delete p_; };
-private:
+ recursive_wrapper(recursive_wrapper const& operand)
+ : p_(new T(operand.get())) {}
- void assign(const T& rhs);
+ recursive_wrapper(T const& operand)
+ : p_(new T(operand)) {}
-public:
+ recursive_wrapper(recursive_wrapper&& operand)
+ : p_(new T(std::move(operand.get()))) {}
+
+ recursive_wrapper(T&& operand)
+ : p_(new T(std::move(operand))) {}
inline recursive_wrapper& operator=(recursive_wrapper const& rhs)
{
- assign( rhs.get() );
+ assign(rhs.get());
return *this;
}
inline recursive_wrapper& operator=(T const& rhs)
{
- assign( rhs );
+ assign(rhs);
return *this;
}
@@ -49,7 +77,6 @@ public:
p_ = temp;
}
-
recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept
{
swap(rhs);
@@ -62,66 +89,34 @@ public:
return *this;
}
+ T& get()
+ {
+ assert(p_);
+ return *get_pointer();
+ }
-public:
+ T const& get() const
+ {
+ assert(p_);
+ return *get_pointer();
+ }
- T& get() { return *get_pointer(); }
- const T& get() const { return *get_pointer(); }
T* get_pointer() { return p_; }
- const T* get_pointer() const { return p_; }
- operator T const&() const { return this->get(); }
- operator T&() { return this->get(); }
-};
-template <typename T>
-recursive_wrapper<T>::~recursive_wrapper()
-{
- delete p_;
-}
-
-template <typename T>
-recursive_wrapper<T>::recursive_wrapper()
- : p_(new T)
-{
-}
-
-template <typename T>
-recursive_wrapper<T>::recursive_wrapper(recursive_wrapper const& operand)
- : p_(new T( operand.get() ))
-{
-}
-
-template <typename T>
-recursive_wrapper<T>::recursive_wrapper(T const& operand)
- : p_(new T(operand))
-{
-}
+ const T* get_pointer() const { return p_; }
-template <typename T>
-recursive_wrapper<T>::recursive_wrapper(recursive_wrapper&& operand)
- : p_(operand.p_)
-{
- operand.p_ = nullptr;
-}
+ operator T const&() const { return this->get(); }
-template <typename T>
-recursive_wrapper<T>::recursive_wrapper(T&& operand)
- : p_(new T( std::move(operand) ))
-{
-}
+ operator T&() { return this->get(); }
-template <typename T>
-void recursive_wrapper<T>::assign(const T& rhs)
-{
- this->get() = rhs;
-}
+}; // class recursive_wrapper
template <typename T>
inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
{
lhs.swap(rhs);
}
+} // namespace util
+} // namespace mapbox
-}}
-
-#endif // MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
+#endif // MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
diff --git a/third_party/variant/scripts/build-appveyor.bat b/third_party/variant/scripts/build-appveyor.bat
index 9b9d7c8..bdee7ea 100644
--- a/third_party/variant/scripts/build-appveyor.bat
+++ b/third_party/variant/scripts/build-appveyor.bat
@@ -10,7 +10,7 @@ IF /I "%PLATFORM"=="x64" (
CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
)
-IF NOT EXIST deps\gyp git clone --depth 1 https://chromium.googlesource.com/external/gyp.git deps/gyp
+IF NOT EXIST deps\gyp git clone --quiet --depth 1 https://chromium.googlesource.com/external/gyp.git deps/gyp
CALL deps\gyp\gyp.bat variant.gyp --depth=. ^
-f msvs ^
diff --git a/third_party/variant/scripts/linux.sh b/third_party/variant/scripts/linux.sh
deleted file mode 100644
index f173db5..0000000
--- a/third_party/variant/scripts/linux.sh
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env bash
-
-set -e -u
-set -o pipefail
-
-# ppa for latest boost
-sudo add-apt-repository -y ppa:boost-latest/ppa
-# ppa for g++ 4.7 and 4.8
-sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
-sudo apt-get update -y
-
-# install boost headers and g++ upgrades
-sudo apt-get -y -qq install boost1.55 gcc-4.8 g++-4.8 gcc-4.7 g++-4.7
-
-if [[ "$CXX" == "clang++" ]]; then
- echo 'running tests against clang++'
- make test
- make bench
- make clean
-else
- # run tests against g++ 4.7
- export CXX="g++-4.7"; export CC="gcc-4.7"
- echo 'running tests against g++ 4.7'
- make test
- make bench
- make clean
-
- # run tests against g++ 4.8
- export CXX="g++-4.8"; export CC="gcc-4.8"
- echo 'running tests against g++ 4.8'
- make test
- make bench
- make clean
-
-fi
-
-# compare object sizes against boost::variant
-echo 'comparing object sizes to boost::variant'
-make sizes /usr/include/boost/variant.hpp
-make clean
-
-# test building with gyp
-echo 'testing build with gyp'
-make gyp
-
-# run coverage when using clang++
-if [[ $CXX == "clang++" ]]; then
- make clean
- make coverage
- git status
- ./out/cov-test
- cp unit*gc* test/
- sudo pip install cpp-coveralls
- coveralls -i variant.hpp -i recursive_wrapper.hpp --gcov-options '\-lp'
-fi
-
-# set strictness back to normal
-# to avoid tripping up travis
-set +e +u
diff --git a/third_party/variant/scripts/osx.sh b/third_party/variant/scripts/osx.sh
deleted file mode 100644
index 14149ca..0000000
--- a/third_party/variant/scripts/osx.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env bash
-
-set -e -u
-set -o pipefail
-
-# install boost headers
-brew unlink boost
-brew install boost
-
-# run tests
-make test
-make bench
-make clean
-
-# compare object sizes against boost::variant
-make sizes `brew --prefix`/include/boost/variant.hpp
-make clean
-
-# test building with gyp
-make gyp
\ No newline at end of file
diff --git a/third_party/variant/scripts/run_compilation_failure_tests.sh b/third_party/variant/scripts/run_compilation_failure_tests.sh
new file mode 100755
index 0000000..c2608fe
--- /dev/null
+++ b/third_party/variant/scripts/run_compilation_failure_tests.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+# Try to compile all programs in the test/compilation_failure directory.
+# Compilation must fail and the error message must match the pattern in the
+# corresponding .pattern file.
+#
+
+DIR="test/compilation_failure"
+CXX=${CXX:-clang++}
+
+if [ `uname -s` = "Darwin" ]; then
+ CXXFLAGS="$CXXFLAGS -stdlib=libc++"
+fi
+
+error_msg() {
+ if [ ! -z "$1" ]; then
+ printf 'output was:\n=======\n%s\n=======\n' "$1"
+ fi
+}
+
+exit_code=0
+for test_code in $DIR/*.cpp; do
+ name=`basename $test_code .cpp`
+
+ result=`${CXX} -std=c++11 -c -o /dev/null -I. ${CXXFLAGS} ${test_code} 2>&1`
+ status=$?
+
+ if [ $status = 1 ]; then
+ expected=`sed -n -e '/@EXPECTED/s/.*: \+//p' ${test_code}`
+ if echo $result | grep -q "$expected"; then
+ echo "$name [OK]"
+ else
+ echo "$name [FAILED - wrong error message]"
+ echo "Expected error message: $expected"
+ error_msg "$result"
+ exit_code=1
+ fi
+ elif [ $status = 0 ]; then
+ echo "$name [FAILED - compile was successful]"
+ error_msg "$result"
+ exit_code=1
+ else
+ echo "$name [FAILED - unknown error in compile]"
+ error_msg "$result"
+ exit_code=1
+ fi
+done
+
+exit ${exit_code}
+
diff --git a/third_party/variant/test/bench_variant.cpp b/third_party/variant/test/bench_variant.cpp
index 474e3c3..700dac7 100644
--- a/third_party/variant/test/bench_variant.cpp
+++ b/third_party/variant/test/bench_variant.cpp
@@ -1,10 +1,16 @@
+
+#include <algorithm>
+#include <cstdlib>
#include <iostream>
-#include <vector>
-#include <thread>
+#include <memory>
#include <string>
+#include <thread>
#include <utility>
-#include <boost/variant.hpp>
+#include <vector>
+
#include <boost/timer/timer.hpp>
+#include <boost/variant.hpp>
+
#include "variant.hpp"
#define TEXT_SHORT "Test"
@@ -23,7 +29,7 @@ struct Holder
std::vector<value_type> data;
template <typename T>
- void append_move(T && obj)
+ void append_move(T&& obj)
{
data.emplace_back(std::forward<T>(obj));
}
@@ -37,49 +43,48 @@ struct Holder
} // namespace test
-struct print : util::static_visitor<>
+struct print
{
template <typename T>
- void operator() (T const& val) const
+ void operator()(T const& val) const
{
std::cerr << val << ":" << typeid(T).name() << std::endl;
}
};
-
template <typename V>
struct dummy : boost::static_visitor<>
{
- dummy(V & v)
+ dummy(V& v)
: v_(v) {}
template <typename T>
- void operator() (T && val) const
+ void operator()(T&& val) const
{
v_ = std::move(val);
}
- V & v_;
+ V& v_;
};
template <typename V>
-struct dummy2 : util::static_visitor<>
+struct dummy2
{
- dummy2(V & v)
+ dummy2(V& v)
: v_(v) {}
template <typename T>
- void operator() (T && val) const
+ void operator()(T&& val) const
{
v_ = std::move(val);
}
- V & v_;
+ V& v_;
};
void run_boost_test(std::size_t runs)
{
test::Holder<boost::variant<int, double, std::string>> h;
h.data.reserve(runs);
- for (std::size_t i=0; i< runs; ++i)
+ for (std::size_t i = 0; i < runs; ++i)
{
h.append_move(std::string(TEXT_SHORT));
h.append_move(std::string(TEXT_LONG));
@@ -99,7 +104,7 @@ void run_variant_test(std::size_t runs)
{
test::Holder<util::variant<int, double, std::string>> h;
h.data.reserve(runs);
- for (std::size_t i=0; i< runs; ++i)
+ for (std::size_t i = 0; i < runs; ++i)
{
h.append_move(std::string(TEXT_SHORT));
h.append_move(std::string(TEXT_LONG));
@@ -111,13 +116,13 @@ void run_variant_test(std::size_t runs)
for (auto const& v2 : h.data)
{
dummy2<util::variant<int, double, std::string>> d(v);
- util::apply_visitor (d, v2);
+ util::apply_visitor(d, v2);
}
}
-int main (int argc, char** argv)
+int main(int argc, char** argv)
{
- if (argc!=2)
+ if (argc != 2)
{
std::cerr << "Usage:" << argv[0] << " <num-runs>" << std::endl;
return 1;
@@ -154,11 +159,11 @@ int main (int argc, char** argv)
thread_group tg;
std::cerr << "custom variant: ";
boost::timer::auto_cpu_timer timer;
- for (std::size_t i=0; i<THREADS; ++i)
+ for (std::size_t i = 0; i < THREADS; ++i)
{
tg.emplace_back(new std::thread(run_variant_test, NUM_RUNS));
}
- std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
+ std::for_each(tg.begin(), tg.end(), [](value_type& t) {if (t->joinable()) t->join(); });
}
{
@@ -167,15 +172,14 @@ int main (int argc, char** argv)
thread_group tg;
std::cerr << "boost variant: ";
boost::timer::auto_cpu_timer timer;
- for (std::size_t i=0; i<THREADS; ++i)
+ for (std::size_t i = 0; i < THREADS; ++i)
{
tg.emplace_back(new std::thread(run_boost_test, NUM_RUNS));
}
- std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
+ std::for_each(tg.begin(), tg.end(), [](value_type& t) {if (t->joinable()) t->join(); });
}
}
#endif
-
return EXIT_SUCCESS;
}
diff --git a/third_party/variant/test/binary_visitor_test.cpp b/third_party/variant/test/binary_visitor_test.cpp
index de2a30e..fa0f2ea 100644
--- a/third_party/variant/test/binary_visitor_test.cpp
+++ b/third_party/variant/test/binary_visitor_test.cpp
@@ -1,13 +1,14 @@
+
+#include <algorithm>
#include <cstdint>
+#include <cstdlib>
#include <iostream>
-#include <vector>
-#include <thread>
-#include <string>
#include <sstream>
-#include <utility>
+#include <string>
#include <type_traits>
-#include <boost/variant.hpp>
-#include <boost/timer/timer.hpp>
+#include <utility>
+#include <vector>
+
#include "variant.hpp"
#include "variant_io.hpp"
@@ -16,12 +17,14 @@ using namespace mapbox;
namespace test {
template <typename T>
-struct string_to_number {};
+struct string_to_number
+{
+};
template <>
struct string_to_number<double>
{
- double operator() (std::string const& str) const
+ double operator()(std::string const& str) const
{
return std::stod(str);
}
@@ -30,7 +33,7 @@ struct string_to_number<double>
template <>
struct string_to_number<std::int64_t>
{
- std::int64_t operator() (std::string const& str) const
+ std::int64_t operator()(std::string const& str) const
{
return std::stoll(str);
}
@@ -39,7 +42,7 @@ struct string_to_number<std::int64_t>
template <>
struct string_to_number<std::uint64_t>
{
- std::uint64_t operator() (std::string const& str) const
+ std::uint64_t operator()(std::string const& str) const
{
return std::stoull(str);
}
@@ -48,7 +51,7 @@ struct string_to_number<std::uint64_t>
template <>
struct string_to_number<bool>
{
- bool operator() (std::string const& str) const
+ bool operator()(std::string const& str) const
{
bool result;
std::istringstream(str) >> std::boolalpha >> result;
@@ -56,28 +59,28 @@ struct string_to_number<bool>
}
};
-struct javascript_equal_visitor : util::static_visitor<bool>
+struct javascript_equal_visitor
{
template <typename T>
- bool operator() (T lhs, T rhs) const
+ bool operator()(T lhs, T rhs) const
{
return lhs == rhs;
}
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
- bool operator() (T lhs, std::string const& rhs) const
+ bool operator()(T lhs, std::string const& rhs) const
{
return lhs == string_to_number<T>()(rhs);
}
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
- bool operator() (std::string const& lhs, T rhs) const
+ bool operator()(std::string const& lhs, T rhs) const
{
return string_to_number<T>()(lhs) == rhs;
}
template <typename T0, typename T1>
- bool operator() (T0 lhs, T1 rhs) const
+ bool operator()(T0 lhs, T1 rhs) const
{
return lhs == static_cast<T0>(rhs);
}
@@ -89,7 +92,7 @@ struct javascript_equal
javascript_equal(T const& lhs)
: lhs_(lhs) {}
- bool operator() (T const& rhs) const
+ bool operator()(T const& rhs) const
{
return util::apply_visitor(test::javascript_equal_visitor(), lhs_, rhs);
}
@@ -98,7 +101,7 @@ struct javascript_equal
} // namespace test
-int main (/*int argc, char** argv*/)
+int main()
{
typedef util::variant<bool, std::int64_t, std::uint64_t, double, std::string> variant_type;
variant_type v0(3.14159);
@@ -108,7 +111,6 @@ int main (/*int argc, char** argv*/)
std::cerr << v0 << " == " << v1 << " -> "
<< std::boolalpha << util::apply_visitor(test::javascript_equal_visitor(), v0, v1) << std::endl;
-
std::vector<variant_type> vec;
vec.emplace_back(std::string("1"));
diff --git a/third_party/variant/test/boost_variant_hello_world.cpp b/third_party/variant/test/boost_variant_hello_world.cpp
index 0d0925a..fdb200e 100644
--- a/third_party/variant/test/boost_variant_hello_world.cpp
+++ b/third_party/variant/test/boost_variant_hello_world.cpp
@@ -1,17 +1,18 @@
#include <boost/variant.hpp>
-#include <cstdint>
+
#include <stdexcept>
struct check : boost::static_visitor<>
{
template <typename T>
- void operator() (T const& val) const
+ void operator()(T const& val) const
{
if (val != 0) throw std::runtime_error("invalid");
}
};
-int main() {
+int main()
+{
typedef boost::variant<bool, int, double> variant_type;
variant_type v(0);
boost::apply_visitor(check(), v);
diff --git a/third_party/variant/test/catch.hpp b/third_party/variant/test/catch.hpp
deleted file mode 100644
index 057c82e..0000000
--- a/third_party/variant/test/catch.hpp
+++ /dev/null
@@ -1,8683 +0,0 @@
-/*
- * CATCH v1.0 build 45 (master branch)
- * Generated: 2014-05-19 18:22:42.461908
- * ----------------------------------------------------------
- * This file has been merged from multiple headers. Please don't edit it directly
- * Copyright (c) 2012 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
-
-#define TWOBLUECUBES_CATCH_HPP_INCLUDED
-
-#ifdef __clang__
-#pragma clang diagnostic ignored "-Wglobal-constructors"
-#pragma clang diagnostic ignored "-Wvariadic-macros"
-#pragma clang diagnostic ignored "-Wc99-extensions"
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wpadded"
-#pragma clang diagnostic ignored "-Wc++98-compat"
-#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
-#endif
-
-#ifdef CATCH_CONFIG_MAIN
-# define CATCH_CONFIG_RUNNER
-#endif
-
-#ifdef CATCH_CONFIG_RUNNER
-# ifndef CLARA_CONFIG_MAIN
-# define CLARA_CONFIG_MAIN_NOT_DEFINED
-# define CLARA_CONFIG_MAIN
-# endif
-#endif
-
-// #included from: internal/catch_notimplemented_exception.h
-#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
-
-// #included from: catch_common.h
-#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
-
-#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 )
-#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
-
-#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
-#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
-
-#include <sstream>
-#include <stdexcept>
-#include <algorithm>
-
-// #included from: catch_compiler_capabilities.h
-#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
-
-// Much of the following code is based on Boost (1.53)
-
-#ifdef __clang__
-
-# if __has_feature(cxx_nullptr)
-# define CATCH_CONFIG_CPP11_NULLPTR
-# endif
-
-# if __has_feature(cxx_noexcept)
-# define CATCH_CONFIG_CPP11_NOEXCEPT
-# endif
-
-#endif // __clang__
-
-////////////////////////////////////////////////////////////////////////////////
-// Borland
-#ifdef __BORLANDC__
-
-#if (__BORLANDC__ > 0x582 )
-//#define CATCH_CONFIG_SFINAE // Not confirmed
-#endif
-
-#endif // __BORLANDC__
-
-////////////////////////////////////////////////////////////////////////////////
-// EDG
-#ifdef __EDG_VERSION__
-
-#if (__EDG_VERSION__ > 238 )
-//#define CATCH_CONFIG_SFINAE // Not confirmed
-#endif
-
-#endif // __EDG_VERSION__
-
-////////////////////////////////////////////////////////////////////////////////
-// Digital Mars
-#ifdef __DMC__
-
-#if (__DMC__ > 0x840 )
-//#define CATCH_CONFIG_SFINAE // Not confirmed
-#endif
-
-#endif // __DMC__
-
-////////////////////////////////////////////////////////////////////////////////
-// GCC
-#ifdef __GNUC__
-
-#if __GNUC__ < 3
-
-#if (__GNUC_MINOR__ >= 96 )
-//#define CATCH_CONFIG_SFINAE
-#endif
-
-#elif __GNUC__ >= 3
-
-// #define CATCH_CONFIG_SFINAE // Taking this out completely for now
-
-#endif // __GNUC__ < 3
-
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) )
-
-#define CATCH_CONFIG_CPP11_NULLPTR
-#endif
-
-#endif // __GNUC__
-
-////////////////////////////////////////////////////////////////////////////////
-// Visual C++
-#ifdef _MSC_VER
-
-#if (_MSC_VER >= 1310 ) // (VC++ 7.0+)
-//#define CATCH_CONFIG_SFINAE // Not confirmed
-#endif
-
-#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 )
-
-#ifndef CATCH_CONFIG_NO_VARIADIC_MACROS
-#define CATCH_CONFIG_VARIADIC_MACROS
-#endif
-
-#endif
-
-////////////////////////////////////////////////////////////////////////////////
-// C++ language feature support
-
-// detect language version:
-#if (__cplusplus == 201103L)
-# define CATCH_CPP11
-# define CATCH_CPP11_OR_GREATER
-#elif (__cplusplus >= 201103L)
-# define CATCH_CPP11_OR_GREATER
-#endif
-
-// noexcept support:
-#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
-# define CATCH_NOEXCEPT noexcept
-# define CATCH_NOEXCEPT_IS(x) noexcept(x)
-#else
-# define CATCH_NOEXCEPT throw()
-# define CATCH_NOEXCEPT_IS(x)
-#endif
-
-namespace Catch {
-
- class NonCopyable {
- NonCopyable( NonCopyable const& );
- void operator = ( NonCopyable const& );
- protected:
- 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<typename ContainerT>
- inline 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<typename AssociativeContainerT>
- inline 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 endsWith( std::string const& s, std::string const& 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 );
-
- 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 );
- SourceLineInfo( SourceLineInfo const& other );
-# ifdef CATCH_CPP11_OR_GREATER
- SourceLineInfo( SourceLineInfo && ) = default;
- SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
- SourceLineInfo& operator = ( SourceLineInfo && ) = default;
-# endif
- bool empty() const;
- bool operator == ( SourceLineInfo const& other ) const;
-
- std::string file;
- std::size_t line;
- };
-
- 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; }
-
- void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
-
- // Use this in variadic streaming macros to allow
- // >> +StreamEndStop
- // as well as
- // >> stuff +StreamEndStop
- struct StreamEndStop {
- std::string operator+() {
- return std::string();
- }
- };
- template<typename T>
- T const& operator + ( T const& value, StreamEndStop ) {
- return value;
- }
-}
-
-#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
-#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
-
-#include <ostream>
-
-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;
- };
-
-} // end namespace Catch
-
-///////////////////////////////////////////////////////////////////////////////
-#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO )
-
-// #included from: internal/catch_context.h
-#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
-
-// #included from: catch_interfaces_generators.h
-#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
-
-#include <string>
-
-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<typename T>
- class Ptr {
- public:
- Ptr() : m_p( 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 = 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() { return m_p; }
- const T* get() const{ return m_p; }
- T& operator*() const { return *m_p; }
- T* operator->() const { return m_p; }
- bool operator !() const { return m_p == NULL; }
- operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); }
-
- private:
- T* m_p;
- };
-
- struct IShared : NonCopyable {
- virtual ~IShared();
- virtual void addRef() const = 0;
- virtual void release() const = 0;
- };
-
- template<typename T = IShared>
- 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
-
-#include <memory>
-#include <vector>
-#include <stdlib.h>
-
-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<IConfig const> getConfig() const = 0;
- };
-
- struct IMutableContext : IContext
- {
- virtual ~IMutableContext();
- virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
- virtual void setRunner( IRunner* runner ) = 0;
- virtual void setConfig( Ptr<IConfig const> 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
-
-#include <vector>
-
-namespace Catch {
-
- class TestSpec;
-
- struct ITestCase : IShared {
- virtual void invoke () const = 0;
- protected:
- virtual ~ITestCase();
- };
-
- class TestCase;
- struct IConfig;
-
- struct ITestCaseRegistry {
- virtual ~ITestCaseRegistry();
- virtual std::vector<TestCase> const& getAllTests() const = 0;
- virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases ) const = 0;
-
- };
-}
-
-namespace Catch {
-
-template<typename C>
-class MethodTestCase : public SharedImpl<ITestCase> {
-
-public:
- MethodTestCase( void (C::*method)() ) : m_method( method ) {}
-
- virtual void invoke() const {
- C obj;
- (obj.*m_method)();
- }
-
-private:
- virtual ~MethodTestCase() {}
-
- void (C::*m_method)();
-};
-
-typedef void(*TestFunction)();
-
-struct NameAndDesc {
- NameAndDesc( const char* _name = "", const char* _description= "" )
- : name( _name ), description( _description )
- {}
-
- const char* name;
- const char* description;
-};
-
-struct AutoReg {
-
- AutoReg( TestFunction function,
- SourceLineInfo const& lineInfo,
- NameAndDesc const& nameAndDesc );
-
- template<typename C>
- AutoReg( void (C::*method)(),
- char const* className,
- NameAndDesc const& nameAndDesc,
- SourceLineInfo const& lineInfo ) {
- registerTestCase( new MethodTestCase<C>( method ),
- className,
- nameAndDesc,
- lineInfo );
- }
-
- void registerTestCase( ITestCase* testCase,
- char const* className,
- NameAndDesc const& nameAndDesc,
- SourceLineInfo const& lineInfo );
-
- ~AutoReg();
-
-private:
- AutoReg( AutoReg const& );
- void operator= ( AutoReg const& );
-};
-
-} // end namespace Catch
-
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_TESTCASE( ... ) \
- static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
- namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
- static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )()
-
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
- namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); }
-
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\
- namespace{ \
- struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
- void test(); \
- }; \
- Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
- } \
- void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
-
-#else
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
- static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
- namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
- static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )()
-
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
- namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); }
-
- ///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
- namespace{ \
- struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
- void test(); \
- }; \
- Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
- } \
- void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
-
-#endif
-
-// #included from: internal/catch_capture.hpp
-#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
-
-// #included from: catch_expression_decomposer.hpp
-#define TWOBLUECUBES_CATCH_EXPRESSION_DECOMPOSER_HPP_INCLUDED
-
-// #included from: catch_expression_lhs.hpp
-#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
-
-// #included from: catch_expressionresult_builder.h
-#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_BUILDER_H_INCLUDED
-
-// #included from: catch_tostring.h
-#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
-
-// #included from: catch_sfinae.hpp
-#define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED
-
-// Try to detect if the current compiler supports SFINAE
-
-namespace Catch {
-
- struct TrueType {
- static const bool value = true;
- typedef void Enable;
- char sizer[1];
- };
- struct FalseType {
- static const bool value = false;
- typedef void Disable;
- char sizer[2];
- };
-
-#ifdef CATCH_CONFIG_SFINAE
-
- template<bool> struct NotABooleanExpression;
-
- template<bool c> struct If : NotABooleanExpression<c> {};
- template<> struct If<true> : TrueType {};
- template<> struct If<false> : FalseType {};
-
- template<int size> struct SizedIf;
- template<> struct SizedIf<sizeof(TrueType)> : TrueType {};
- template<> struct SizedIf<sizeof(FalseType)> : FalseType {};
-
-#endif // CATCH_CONFIG_SFINAE
-
-} // end namespace Catch
-
-#include <sstream>
-#include <iomanip>
-#include <limits>
-#include <vector>
-#include <cstddef>
-
-#ifdef __OBJC__
-// #included from: catch_objc_arc.hpp
-#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
-
-#import <Foundation/Foundation.h>
-
-#ifdef __has_feature
-#define CATCH_ARC_ENABLED __has_feature(objc_arc)
-#else
-#define CATCH_ARC_ENABLED 0
-#endif
-
-void arcSafeRelease( NSObject* obj );
-id performOptionalSelector( id obj, SEL sel );
-
-#if !CATCH_ARC_ENABLED
-inline void arcSafeRelease( NSObject* obj ) {
- [obj release];
-}
-inline id performOptionalSelector( id obj, SEL sel ) {
- if( [obj respondsToSelector: sel] )
- return [obj performSelector: sel];
- return nil;
-}
-#define CATCH_UNSAFE_UNRETAINED
-#define CATCH_ARC_STRONG
-#else
-inline void arcSafeRelease( NSObject* ){}
-inline id performOptionalSelector( id obj, SEL sel ) {
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
-#endif
- if( [obj respondsToSelector: sel] )
- return [obj performSelector: sel];
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
- return nil;
-}
-#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
-#define CATCH_ARC_STRONG __strong
-#endif
-
-#endif
-
-namespace Catch {
-namespace Detail {
-
-// SFINAE is currently disabled by default for all compilers.
-// If the non SFINAE version of IsStreamInsertable is ambiguous for you
-// and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE
-#ifdef CATCH_CONFIG_SFINAE
-
- template<typename T>
- class IsStreamInsertableHelper {
- template<int N> struct TrueIfSizeable : TrueType {};
-
- template<typename T2>
- static TrueIfSizeable<sizeof((*(std::ostream*)0) << *((T2 const*)0))> dummy(T2*);
- static FalseType dummy(...);
-
- public:
- typedef SizedIf<sizeof(dummy((T*)0))> type;
- };
-
- template<typename T>
- struct IsStreamInsertable : IsStreamInsertableHelper<T>::type {};
-
-#else
-
- struct BorgType {
- template<typename T> BorgType( T const& );
- };
-
- TrueType& testStreamable( std::ostream& );
- FalseType testStreamable( FalseType );
-
- FalseType operator<<( std::ostream const&, BorgType const& );
-
- template<typename T>
- struct IsStreamInsertable {
- static std::ostream &s;
- static T const&t;
- enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
- };
-
-#endif
-
- template<bool C>
- struct StringMakerBase {
- template<typename T>
- static std::string convert( T const& ) { return "{?}"; }
- };
-
- template<>
- struct StringMakerBase<true> {
- template<typename T>
- static std::string convert( T const& _value ) {
- std::ostringstream oss;
- oss << _value;
- return oss.str();
- }
- };
-
- struct Endianness {
- enum Arch { Big, Little };
-
- static Arch which() {
- union _{
- int asInt;
- char asChar[sizeof (int)];
- } u;
-
- u.asInt = 1;
- return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
- }
- };
-
- // Writes the raw memory into a string, considering endianness
- template<typename T>
- std::string rawMemoryToString( T value ) {
- union _ {
- T typedValue;
- unsigned char bytes[sizeof(T)];
- } u;
-
- u.typedValue = value;
-
- std::ostringstream oss;
- oss << "0x";
-
- int i = 0, end = sizeof(T), inc = 1;
- if( Endianness::which() == Endianness::Little ) {
- i = end-1;
- end = inc = -1;
- }
- for( ; i != end; i += inc )
- oss << std::hex << std::setw(2) << std::setfill('0') << (unsigned int)u.bytes[i];
- return oss.str();
- }
-
-} // end namespace Detail
-
-template<typename T>
-std::string toString( T const& value );
-
-template<typename T>
-struct StringMaker :
- Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
-
-template<typename T>
-struct StringMaker<T*> {
- template<typename U>
- static std::string convert( U* p ) {
- if( !p )
- return INTERNAL_CATCH_STRINGIFY( NULL );
- else
- return Detail::rawMemoryToString( p );
- }
-};
-
-template<typename R, typename C>
-struct StringMaker<R C::*> {
- static std::string convert( R C::* p ) {
- if( !p )
- return INTERNAL_CATCH_STRINGIFY( NULL );
- else
- return Detail::rawMemoryToString( p );
- }
-};
-
-namespace Detail {
- template<typename InputIterator>
- std::string rangeToString( InputIterator first, InputIterator last );
-}
-
-template<typename T, typename Allocator>
-struct StringMaker<std::vector<T, Allocator> > {
- static std::string convert( std::vector<T,Allocator> const& v ) {
- return Detail::rangeToString( v.begin(), v.end() );
- }
-};
-
-namespace Detail {
- template<typename T>
- std::string makeString( T const& value ) {
- return StringMaker<T>::convert( value );
- }
-} // end namespace Detail
-
-/// \brief converts any type to a string
-///
-/// The default template forwards on to ostringstream - except when an
-/// ostringstream overload does not exist - in which case it attempts to detect
-/// that and writes {?}.
-/// Overload (not specialise) this template for custom typs that you don't want
-/// to provide an ostream overload for.
-template<typename T>
-std::string toString( T const& value ) {
- return StringMaker<T>::convert( value );
-}
-
-// Built in overloads
-
-std::string toString( std::string const& value );
-std::string toString( std::wstring const& value );
-std::string toString( const char* const value );
-std::string toString( char* const value );
-std::string toString( int value );
-std::string toString( unsigned long value );
-std::string toString( unsigned int value );
-std::string toString( const double value );
-std::string toString( bool value );
-std::string toString( char value );
-std::string toString( signed char value );
-std::string toString( unsigned char value );
-
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
-std::string toString( std::nullptr_t );
-#endif
-
-#ifdef __OBJC__
- std::string toString( NSString const * const& nsstring );
- std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
- std::string toString( NSObject* const& nsObject );
-#endif
-
- namespace Detail {
- template<typename InputIterator>
- std::string rangeToString( InputIterator first, InputIterator last ) {
- std::ostringstream oss;
- oss << "{ ";
- if( first != last ) {
- oss << toString( *first );
- for( ++first ; first != last ; ++first ) {
- oss << ", " << toString( *first );
- }
- }
- oss << " }";
- return oss.str();
- }
-}
-
-} // end namespace Catch
-
-// #included from: catch_assertionresult.h
-#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
-
-#include <string>
-// #included from: catch_result_type.h
-#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
-
-namespace Catch {
-
- // ResultWas::OfType enum
- struct ResultWas { enum OfType {
- Unknown = -1,
- Ok = 0,
- Info = 1,
- Warning = 2,
-
- FailureBit = 0x10,
-
- ExpressionFailed = FailureBit | 1,
- ExplicitFailure = FailureBit | 2,
-
- Exception = 0x100 | FailureBit,
-
- ThrewException = Exception | 1,
- DidntThrowException = Exception | 2
-
- }; };
-
- inline bool isOk( ResultWas::OfType resultType ) {
- return ( resultType & ResultWas::FailureBit ) == 0;
- }
- inline bool isJustInfo( int flags ) {
- return flags == ResultWas::Info;
- }
-
- // ResultAction::Value enum
- struct ResultAction { enum Value {
- None,
- Failed = 1, // Failure - but no debug break if Debug bit not set
- Debug = 2, // If this bit is set, invoke the debugger
- Abort = 4 // Test run should abort
- }; };
-
- // ResultDisposition::Flags enum
- struct ResultDisposition { enum Flags {
- Normal = 0x00,
-
- ContinueOnFailure = 0x01, // Failures fail test, but execution continues
- NegateResult = 0x02, // Prefix expressiom with !
- SuppressFail = 0x04 // Failures are reported but do not fail the test
- }; };
-
- inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
- return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
- }
-
- inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
- inline bool shouldNegate( int flags ) { return ( flags & ResultDisposition::NegateResult ) != 0; }
- inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }
-
-} // end namespace Catch
-
-
-namespace Catch {
-
- struct AssertionInfo
- {
- AssertionInfo() {}
- AssertionInfo( std::string const& _macroName,
- SourceLineInfo const& _lineInfo,
- std::string const& _capturedExpression,
- ResultDisposition::Flags _resultDisposition );
-
- std::string macroName;
- SourceLineInfo lineInfo;
- std::string capturedExpression;
- ResultDisposition::Flags resultDisposition;
- };
-
- struct AssertionResultData
- {
- AssertionResultData() : resultType( ResultWas::Unknown ) {}
-
- std::string reconstructedExpression;
- std::string message;
- ResultWas::OfType resultType;
- };
-
- class AssertionResult {
- public:
- AssertionResult();
- AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
- ~AssertionResult();
-# ifdef CATCH_CPP11_OR_GREATER
- AssertionResult( AssertionResult const& ) = default;
- AssertionResult( AssertionResult && ) = default;
- AssertionResult& operator = ( AssertionResult const& ) = default;
- AssertionResult& operator = ( AssertionResult && ) = default;
-# endif
-
- bool isOk() const;
- bool succeeded() const;
- ResultWas::OfType getResultType() const;
- bool hasExpression() const;
- bool hasMessage() const;
- std::string getExpression() const;
- std::string getExpressionInMacro() const;
- bool hasExpandedExpression() const;
- std::string getExpandedExpression() const;
- std::string getMessage() const;
- SourceLineInfo getSourceInfo() const;
- std::string getTestMacroName() const;
-
- protected:
- AssertionInfo m_info;
- AssertionResultData m_resultData;
- };
-
-} // end namespace Catch
-
-// #included from: catch_evaluate.hpp
-#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
-#endif
-
-#include <cstddef>
-
-namespace Catch {
-namespace Internal {
-
- enum Operator {
- IsEqualTo,
- IsNotEqualTo,
- IsLessThan,
- IsGreaterThan,
- IsLessThanOrEqualTo,
- IsGreaterThanOrEqualTo
- };
-
- template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } };
- template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } };
- template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } };
- template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } };
- template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } };
- template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } };
- template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
-
- template<typename T>
- inline T& opCast(T const& t) { return const_cast<T&>(t); }
-
-// nullptr_t support based on pull request #154 from Konstantin Baumann
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
- inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; }
-#endif // CATCH_CONFIG_CPP11_NULLPTR
-
- // So the compare overloads can be operator agnostic we convey the operator as a template
- // enum, which is used to specialise an Evaluator for doing the comparison.
- template<typename T1, typename T2, Operator Op>
- class Evaluator{};
-
- template<typename T1, typename T2>
- struct Evaluator<T1, T2, IsEqualTo> {
- static bool evaluate( T1 const& lhs, T2 const& rhs) {
- return opCast( lhs ) == opCast( rhs );
- }
- };
- template<typename T1, typename T2>
- struct Evaluator<T1, T2, IsNotEqualTo> {
- static bool evaluate( T1 const& lhs, T2 const& rhs ) {
- return opCast( lhs ) != opCast( rhs );
- }
- };
- template<typename T1, typename T2>
- struct Evaluator<T1, T2, IsLessThan> {
- static bool evaluate( T1 const& lhs, T2 const& rhs ) {
- return opCast( lhs ) < opCast( rhs );
- }
- };
- template<typename T1, typename T2>
- struct Evaluator<T1, T2, IsGreaterThan> {
- static bool evaluate( T1 const& lhs, T2 const& rhs ) {
- return opCast( lhs ) > opCast( rhs );
- }
- };
- template<typename T1, typename T2>
- struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
- static bool evaluate( T1 const& lhs, T2 const& rhs ) {
- return opCast( lhs ) >= opCast( rhs );
- }
- };
- template<typename T1, typename T2>
- struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
- static bool evaluate( T1 const& lhs, T2 const& rhs ) {
- return opCast( lhs ) <= opCast( rhs );
- }
- };
-
- template<Operator Op, typename T1, typename T2>
- bool applyEvaluator( T1 const& lhs, T2 const& rhs ) {
- return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
- }
-
- // This level of indirection allows us to specialise for integer types
- // to avoid signed/ unsigned warnings
-
- // "base" overload
- template<Operator Op, typename T1, typename T2>
- bool compare( T1 const& lhs, T2 const& rhs ) {
- return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
- }
-
- // unsigned X to int
- template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
- return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
- }
- template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
- return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
- }
- template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
- return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
- }
-
- // unsigned X to long
- template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
- return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
- }
- template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
- return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
- }
- template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
- return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
- }
-
- // int to unsigned X
- template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
- }
- template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
- }
- template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
- }
-
- // long to unsigned X
- template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
- }
- template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
- }
- template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
- return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
- }
-
- // pointer to long (when comparing against NULL)
- template<Operator Op, typename T> bool compare( long lhs, T* rhs ) {
- return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
- }
- template<Operator Op, typename T> bool compare( T* lhs, long rhs ) {
- return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
- }
-
- // pointer to int (when comparing against NULL)
- template<Operator Op, typename T> bool compare( int lhs, T* rhs ) {
- return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
- }
- template<Operator Op, typename T> bool compare( T* lhs, int rhs ) {
- return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
- }
-
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
- // pointer to nullptr_t (when comparing against nullptr)
- template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
- return Evaluator<T*, T*, Op>::evaluate( NULL, rhs );
- }
- template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
- return Evaluator<T*, T*, Op>::evaluate( lhs, NULL );
- }
-#endif // CATCH_CONFIG_CPP11_NULLPTR
-
-} // end of namespace Internal
-} // end of namespace Catch
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-namespace Catch {
-
-struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
-
-// Wraps the (stringised versions of) the lhs, operator and rhs of an expression - as well as
-// the result of evaluating it. This is used to build an AssertionResult object
-class ExpressionResultBuilder {
-public:
-
- ExpressionResultBuilder( ResultWas::OfType resultType = ResultWas::Unknown );
- ExpressionResultBuilder( ExpressionResultBuilder const& other );
- ExpressionResultBuilder& operator=(ExpressionResultBuilder const& other );
-
- ExpressionResultBuilder& setResultType( ResultWas::OfType result );
- ExpressionResultBuilder& setResultType( bool result );
- ExpressionResultBuilder& setLhs( std::string const& lhs );
- ExpressionResultBuilder& setRhs( std::string const& rhs );
- ExpressionResultBuilder& setOp( std::string const& op );
-
- ExpressionResultBuilder& endExpression( ResultDisposition::Flags resultDisposition );
-
- template<typename T>
- ExpressionResultBuilder& operator << ( T const& value ) {
- m_stream << value;
- return *this;
- }
-
- std::string reconstructExpression( AssertionInfo const& info ) const;
-
- AssertionResult buildResult( AssertionInfo const& info ) const;
-
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
-
-private:
- AssertionResultData m_data;
- struct ExprComponents {
- ExprComponents() : shouldNegate( false ) {}
- bool shouldNegate;
- std::string lhs, rhs, op;
- } m_exprComponents;
- std::ostringstream m_stream;
-};
-
-} // end namespace Catch
-
-namespace Catch {
-
-// Wraps the LHS of an expression and captures the operator and RHS (if any) -
-// wrapping them all in an ExpressionResultBuilder object
-template<typename T>
-class ExpressionLhs {
- ExpressionLhs& operator = ( ExpressionLhs const& );
-# ifdef CATCH_CPP11_OR_GREATER
- ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
-# endif
-
-public:
- ExpressionLhs( T lhs ) : m_lhs( lhs ) {}
-# ifdef CATCH_CPP11_OR_GREATER
- ExpressionLhs( ExpressionLhs const& ) = default;
- ExpressionLhs( ExpressionLhs && ) = default;
-# endif
-
- template<typename RhsT>
- ExpressionResultBuilder& operator == ( RhsT const& rhs ) {
- return captureExpression<Internal::IsEqualTo>( rhs );
- }
-
- template<typename RhsT>
- ExpressionResultBuilder& operator != ( RhsT const& rhs ) {
- return captureExpression<Internal::IsNotEqualTo>( rhs );
- }
-
- template<typename RhsT>
- ExpressionResultBuilder& operator < ( RhsT const& rhs ) {
- return captureExpression<Internal::IsLessThan>( rhs );
- }
-
- template<typename RhsT>
- ExpressionResultBuilder& operator > ( RhsT const& rhs ) {
- return captureExpression<Internal::IsGreaterThan>( rhs );
- }
-
- template<typename RhsT>
- ExpressionResultBuilder& operator <= ( RhsT const& rhs ) {
- return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
- }
-
- template<typename RhsT>
- ExpressionResultBuilder& operator >= ( RhsT const& rhs ) {
- return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
- }
-
- ExpressionResultBuilder& operator == ( bool rhs ) {
- return captureExpression<Internal::IsEqualTo>( rhs );
- }
-
- ExpressionResultBuilder& operator != ( bool rhs ) {
- return captureExpression<Internal::IsNotEqualTo>( rhs );
- }
-
- ExpressionResultBuilder& endExpression( ResultDisposition::Flags resultDisposition ) {
- bool value = m_lhs ? true : false;
- return m_result
- .setLhs( Catch::toString( value ) )
- .setResultType( value )
- .endExpression( resultDisposition );
- }
-
- // Only simple binary expressions are allowed on the LHS.
- // If more complex compositions are required then place the sub expression in parentheses
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
-
-private:
- template<Internal::Operator Op, typename RhsT>
- ExpressionResultBuilder& captureExpression( RhsT const& rhs ) {
- return m_result
- .setResultType( Internal::compare<Op>( m_lhs, rhs ) )
- .setLhs( Catch::toString( m_lhs ) )
- .setRhs( Catch::toString( rhs ) )
- .setOp( Internal::OperatorTraits<Op>::getName() );
- }
-
-private:
- ExpressionResultBuilder m_result;
- T m_lhs;
-};
-
-} // end namespace Catch
-
-namespace Catch {
-
-// Captures the LHS of the expression and wraps it in an Expression Lhs object
-class ExpressionDecomposer {
-public:
-
- template<typename T>
- ExpressionLhs<T const&> operator->* ( T const& operand ) {
- return ExpressionLhs<T const&>( operand );
- }
-
- ExpressionLhs<bool> operator->* ( bool value ) {
- return ExpressionLhs<bool>( value );
- }
-};
-
-} // end namespace Catch
-
-// #included from: catch_message.h
-#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
- struct MessageInfo {
- MessageInfo( std::string const& _macroName,
- SourceLineInfo const& _lineInfo,
- ResultWas::OfType _type );
-
- std::string macroName;
- SourceLineInfo lineInfo;
- ResultWas::OfType type;
- std::string message;
- unsigned int sequence;
-
- bool operator == ( MessageInfo const& other ) const {
- return sequence == other.sequence;
- }
- bool operator < ( MessageInfo const& other ) const {
- return sequence < other.sequence;
- }
- private:
- static unsigned int globalCount;
- };
-
- struct MessageBuilder {
- MessageBuilder( std::string const& macroName,
- SourceLineInfo const& lineInfo,
- ResultWas::OfType type )
- : m_info( macroName, lineInfo, type )
- {}
-
- template<typename T>
- MessageBuilder& operator << ( T const& value ) {
- m_stream << value;
- return *this;
- }
-
- MessageInfo m_info;
- std::ostringstream m_stream;
- };
-
- class ScopedMessage {
- public:
- ScopedMessage( MessageBuilder const& builder );
- ~ScopedMessage();
-
- MessageInfo m_info;
- };
-
-} // end namespace Catch
-
-// #included from: catch_interfaces_capture.h
-#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
- class TestCase;
- class ExpressionResultBuilder;
- class AssertionResult;
- struct AssertionInfo;
- struct SectionInfo;
- struct MessageInfo;
- class ScopedMessageBuilder;
- struct Counts;
-
- struct IResultCapture {
-
- virtual ~IResultCapture();
-
- virtual void assertionEnded( AssertionResult const& result ) = 0;
- virtual bool sectionStarted( SectionInfo const& sectionInfo,
- Counts& assertions ) = 0;
- virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0;
- virtual void pushScopedMessage( MessageInfo const& message ) = 0;
- virtual void popScopedMessage( MessageInfo const& message ) = 0;
-
- virtual bool shouldDebugBreak() const = 0;
-
- virtual ResultAction::Value acceptExpression( ExpressionResultBuilder const& assertionResult, AssertionInfo const& assertionInfo ) = 0;
-
- virtual std::string getCurrentTestName() const = 0;
- virtual const AssertionResult* getLastResult() const = 0;
- };
-}
-
-// #included from: catch_debugger.h
-#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
-
-// #included from: catch_platform.h
-#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
-
-#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
-#define CATCH_PLATFORM_MAC
-#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
-#define CATCH_PLATFORM_IPHONE
-#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
-#define CATCH_PLATFORM_WINDOWS
-#endif
-
-#include <string>
-
-namespace Catch{
-
- bool isDebuggerActive();
- void writeToDebugConsole( std::string const& text );
-}
-
-#ifdef CATCH_PLATFORM_MAC
-
- // The following code snippet based on:
- // http://cocoawithlove.com/2008/03/break-into-debugger.html
- #ifdef DEBUG
- #if defined(__ppc64__) || defined(__ppc__)
- #define CATCH_BREAK_INTO_DEBUGGER() \
- if( Catch::isDebuggerActive() ) { \
- __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
- : : : "memory","r0","r3","r4" ); \
- }
- #else
- #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
- #endif
- #endif
-
-#elif defined(_MSC_VER)
- #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); }
-#elif defined(__MINGW32__)
- extern "C" __declspec(dllimport) void __stdcall DebugBreak();
- #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); }
-#endif
-
-#ifndef CATCH_BREAK_INTO_DEBUGGER
-#define CATCH_BREAK_INTO_DEBUGGER() Catch::isTrue( true );
-#endif
-
-// #included from: catch_interfaces_registry_hub.h
-#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
- class TestCase;
- struct ITestCaseRegistry;
- struct IExceptionTranslatorRegistry;
- struct IExceptionTranslator;
- struct IReporterRegistry;
- struct IReporterFactory;
-
- struct IRegistryHub {
- virtual ~IRegistryHub();
-
- virtual IReporterRegistry const& getReporterRegistry() const = 0;
- virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
- virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
- };
-
- struct IMutableRegistryHub {
- virtual ~IMutableRegistryHub();
- virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0;
- virtual void registerTest( TestCase const& testInfo ) = 0;
- virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
- };
-
- IRegistryHub& getRegistryHub();
- IMutableRegistryHub& getMutableRegistryHub();
- void cleanUp();
- std::string translateActiveException();
-
-}
-
-// #included from: catch_interfaces_config.h
-#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
-
-#include <iostream>
-#include <string>
-#include <vector>
-
-namespace Catch {
-
- struct Verbosity { enum Level {
- NoOutput = 0,
- Quiet,
- Normal
- }; };
-
- struct WarnAbout { enum What {
- Nothing = 0x00,
- NoAssertions = 0x01
- }; };
-
- struct ShowDurations { enum OrNot {
- DefaultForReporter,
- Always,
- Never
- }; };
-
- class TestSpec;
-
- struct IConfig : IShared {
-
- virtual ~IConfig();
-
- virtual bool allowThrows() const = 0;
- virtual std::ostream& stream() const = 0;
- virtual std::string name() const = 0;
- virtual bool includeSuccessfulResults() const = 0;
- virtual bool shouldDebugBreak() const = 0;
- virtual bool warnAboutMissingAssertions() const = 0;
- virtual int abortAfter() const = 0;
- virtual bool showInvisibles() const = 0;
- virtual ShowDurations::OrNot showDurations() const = 0;
- virtual TestSpec const& testSpec() const = 0;
- };
-}
-
-#include <ostream>
-
-namespace Catch {
-
- inline IResultCapture& getResultCapture() {
- return getCurrentContext().getResultCapture();
- }
-
- template<typename MatcherT>
- ExpressionResultBuilder expressionResultBuilderFromMatcher( MatcherT const& matcher,
- std::string const& matcherCallAsString ) {
- std::string matcherAsString = matcher.toString();
- if( matcherAsString == "{?}" )
- matcherAsString = matcherCallAsString;
- return ExpressionResultBuilder()
- .setRhs( matcherAsString )
- .setOp( "matches" );
- }
-
- template<typename MatcherT, typename ArgT>
- ExpressionResultBuilder expressionResultBuilderFromMatcher( MatcherT const& matcher,
- ArgT const& arg,
- std::string const& matcherCallAsString ) {
- return expressionResultBuilderFromMatcher( matcher, matcherCallAsString )
- .setLhs( Catch::toString( arg ) )
- .setResultType( matcher.match( arg ) );
- }
-
- template<typename MatcherT, typename ArgT>
- ExpressionResultBuilder expressionResultBuilderFromMatcher( MatcherT const& matcher,
- ArgT* arg,
- std::string const& matcherCallAsString ) {
- return expressionResultBuilderFromMatcher( matcher, matcherCallAsString )
- .setLhs( Catch::toString( arg ) )
- .setResultType( matcher.match( arg ) );
- }
-
-struct TestFailureException{};
-
-} // end namespace Catch
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_ACCEPT_EXPR( evaluatedExpr, resultDisposition, originalExpr ) \
- if( Catch::ResultAction::Value internal_catch_action = Catch::getResultCapture().acceptExpression( evaluatedExpr, __assertionInfo ) ) { \
- if( internal_catch_action & Catch::ResultAction::Debug ) CATCH_BREAK_INTO_DEBUGGER(); \
- if( internal_catch_action & Catch::ResultAction::Abort ) throw Catch::TestFailureException(); \
- if( !Catch::shouldContinueOnFailure( resultDisposition ) ) throw Catch::TestFailureException(); \
- Catch::isTrue( false && originalExpr ); \
- }
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
- do { \
- Catch::AssertionInfo __assertionInfo( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
- try { \
- INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionDecomposer()->*expr ).endExpression( resultDisposition ), resultDisposition, expr ); \
- } catch( Catch::TestFailureException& ) { \
- throw; \
- } catch( ... ) { \
- INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException(), \
- Catch::ResultDisposition::Normal, expr ); \
- } \
- } while( Catch::isTrue( false ) )
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
- INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
- if( Catch::getResultCapture().getLastResult()->succeeded() )
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \
- INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
- if( !Catch::getResultCapture().getLastResult()->succeeded() )
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \
- do { \
- Catch::AssertionInfo __assertionInfo( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
- try { \
- expr; \
- INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::Ok ), resultDisposition, false ); \
- } \
- catch( ... ) { \
- INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException(), resultDisposition, false ); \
- } \
-} while( Catch::isTrue( false ) )
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_THROWS_IMPL( expr, exceptionType, resultDisposition ) \
- try { \
- if( Catch::getCurrentContext().getConfig()->allowThrows() ) { \
- expr; \
- INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::DidntThrowException ), resultDisposition, false ); \
- } \
- } \
- catch( Catch::TestFailureException& ) { \
- throw; \
- } \
- catch( exceptionType ) { \
- INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( Catch::ResultWas::Ok ), resultDisposition, false ); \
- }
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_THROWS( expr, exceptionType, resultDisposition, macroName ) \
- do { \
- Catch::AssertionInfo __assertionInfo( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
- INTERNAL_CATCH_THROWS_IMPL( expr, exceptionType, resultDisposition ) \
- } while( Catch::isTrue( false ) )
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \
- do { \
- Catch::AssertionInfo __assertionInfo( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
- INTERNAL_CATCH_THROWS_IMPL( expr, exceptionType, resultDisposition ) \
- catch( ... ) { \
- INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException() ), \
- resultDisposition | Catch::ResultDisposition::ContinueOnFailure, false ); \
- } \
- } while( Catch::isTrue( false ) )
-
-///////////////////////////////////////////////////////////////////////////////
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
- #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \
- do { \
- Catch::AssertionInfo __assertionInfo( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
- INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( messageType ) << __VA_ARGS__ +::Catch::StreamEndStop(), resultDisposition, true ) \
- } while( Catch::isTrue( false ) )
-#else
- #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \
- do { \
- Catch::AssertionInfo __assertionInfo( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
- INTERNAL_CATCH_ACCEPT_EXPR( Catch::ExpressionResultBuilder( messageType ) << log, resultDisposition, true ) \
- } while( Catch::isTrue( false ) )
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_INFO( log, macroName ) \
- Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \
- do { \
- Catch::AssertionInfo __assertionInfo( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \
- try { \
- INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::expressionResultBuilderFromMatcher( ::Catch::Matchers::matcher, arg, #matcher ) ), resultDisposition, false ); \
- } catch( Catch::TestFailureException& ) { \
- throw; \
- } catch( ... ) { \
- INTERNAL_CATCH_ACCEPT_EXPR( ( Catch::ExpressionResultBuilder( Catch::ResultWas::ThrewException ) << Catch::translateActiveException() ), \
- resultDisposition | Catch::ResultDisposition::ContinueOnFailure, false ); \
- } \
- } while( Catch::isTrue( false ) )
-
-// #included from: internal/catch_section.h
-#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
-
-// #included from: catch_section_info.h
-#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
-
-namespace Catch {
-
- struct SectionInfo {
- SectionInfo( std::string const& _name,
- std::string const& _description,
- SourceLineInfo const& _lineInfo )
- : name( _name ),
- description( _description ),
- lineInfo( _lineInfo )
- {}
-
- std::string name;
- std::string description;
- SourceLineInfo lineInfo;
- };
-
-} // end namespace Catch
-
-// #included from: catch_totals.hpp
-#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
-
-#include <cstddef>
-
-namespace Catch {
-
- struct Counts {
- Counts() : passed( 0 ), failed( 0 ) {}
-
- Counts operator - ( Counts const& other ) const {
- Counts diff;
- diff.passed = passed - other.passed;
- diff.failed = failed - other.failed;
- return diff;
- }
- Counts& operator += ( Counts const& other ) {
- passed += other.passed;
- failed += other.failed;
- return *this;
- }
-
- std::size_t total() const {
- return passed + failed;
- }
-
- std::size_t passed;
- std::size_t failed;
- };
-
- struct Totals {
-
- Totals operator - ( Totals const& other ) const {
- Totals diff;
- diff.assertions = assertions - other.assertions;
- diff.testCases = testCases - other.testCases;
- return diff;
- }
-
- Totals delta( Totals const& prevTotals ) const {
- Totals diff = *this - prevTotals;
- if( diff.assertions.failed > 0 )
- ++diff.testCases.failed;
- else
- ++diff.testCases.passed;
- return diff;
- }
-
- Totals& operator += ( Totals const& other ) {
- assertions += other.assertions;
- testCases += other.testCases;
- return *this;
- }
-
- Counts assertions;
- Counts testCases;
- };
-}
-
-// #included from: catch_timer.h
-#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
-
-#ifdef CATCH_PLATFORM_WINDOWS
-typedef unsigned long long uint64_t;
-#else
-#include <stdint.h>
-#endif
-
-namespace Catch {
-
- class Timer {
- public:
- Timer() : m_ticks( 0 ) {}
- void start();
- unsigned int getElapsedNanoseconds() const;
- unsigned int getElapsedMilliseconds() const;
- double getElapsedSeconds() const;
-
- private:
- uint64_t m_ticks;
- };
-
-} // namespace Catch
-
-#include <string>
-
-namespace Catch {
-
- class Section {
- public:
- Section( SourceLineInfo const& lineInfo,
- std::string const& name,
- std::string const& description = "" );
- ~Section();
-# ifdef CATCH_CPP11_OR_GREATER
- Section( Section const& ) = default;
- Section( Section && ) = default;
- Section& operator = ( Section const& ) = default;
- Section& operator = ( Section && ) = default;
-# endif
-
- // This indicates whether the section should be executed or not
- operator bool();
-
- private:
-
- SectionInfo m_info;
-
- std::string m_name;
- Counts m_assertions;
- bool m_sectionIncluded;
- Timer m_timer;
- };
-
-} // end namespace Catch
-
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
- #define INTERNAL_CATCH_SECTION( ... ) \
- if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
-#else
- #define INTERNAL_CATCH_SECTION( name, desc ) \
- if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, name, desc ) )
-#endif
-
-// #included from: internal/catch_generators.hpp
-#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
-
-#include <iterator>
-#include <vector>
-#include <string>
-#include <stdlib.h>
-
-namespace Catch {
-
-template<typename T>
-struct IGenerator {
- virtual ~IGenerator() {}
- virtual T getValue( std::size_t index ) const = 0;
- virtual std::size_t size () const = 0;
-};
-
-template<typename T>
-class BetweenGenerator : public IGenerator<T> {
-public:
- BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
-
- virtual T getValue( std::size_t index ) const {
- return m_from+static_cast<int>( index );
- }
-
- virtual std::size_t size() const {
- return static_cast<std::size_t>( 1+m_to-m_from );
- }
-
-private:
-
- T m_from;
- T m_to;
-};
-
-template<typename T>
-class ValuesGenerator : public IGenerator<T> {
-public:
- ValuesGenerator(){}
-
- void add( T value ) {
- m_values.push_back( value );
- }
-
- virtual T getValue( std::size_t index ) const {
- return m_values[index];
- }
-
- virtual std::size_t size() const {
- return m_values.size();
- }
-
-private:
- std::vector<T> m_values;
-};
-
-template<typename T>
-class CompositeGenerator {
-public:
- CompositeGenerator() : m_totalSize( 0 ) {}
-
- // *** Move semantics, similar to auto_ptr ***
- CompositeGenerator( CompositeGenerator& other )
- : m_fileInfo( other.m_fileInfo ),
- m_totalSize( 0 )
- {
- move( other );
- }
-
- CompositeGenerator& setFileInfo( const char* fileInfo ) {
- m_fileInfo = fileInfo;
- return *this;
- }
-
- ~CompositeGenerator() {
- deleteAll( m_composed );
- }
-
- operator T () const {
- size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
-
- typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
- typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
- for( size_t index = 0; it != itEnd; ++it )
- {
- const IGenerator<T>* generator = *it;
- if( overallIndex >= index && overallIndex < index + generator->size() )
- {
- return generator->getValue( overallIndex-index );
- }
- index += generator->size();
- }
- CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
- return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
- }
-
- void add( const IGenerator<T>* generator ) {
- m_totalSize += generator->size();
- m_composed.push_back( generator );
- }
-
- CompositeGenerator& then( CompositeGenerator& other ) {
- move( other );
- return *this;
- }
-
- CompositeGenerator& then( T value ) {
- ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
- valuesGen->add( value );
- add( valuesGen );
- return *this;
- }
-
-private:
-
- void move( CompositeGenerator& other ) {
- std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) );
- m_totalSize += other.m_totalSize;
- other.m_composed.clear();
- }
-
- std::vector<const IGenerator<T>*> m_composed;
- std::string m_fileInfo;
- size_t m_totalSize;
-};
-
-namespace Generators
-{
- template<typename T>
- CompositeGenerator<T> between( T from, T to ) {
- CompositeGenerator<T> generators;
- generators.add( new BetweenGenerator<T>( from, to ) );
- return generators;
- }
-
- template<typename T>
- CompositeGenerator<T> values( T val1, T val2 ) {
- CompositeGenerator<T> generators;
- ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
- valuesGen->add( val1 );
- valuesGen->add( val2 );
- generators.add( valuesGen );
- return generators;
- }
-
- template<typename T>
- CompositeGenerator<T> values( T val1, T val2, T val3 ){
- CompositeGenerator<T> generators;
- ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
- valuesGen->add( val1 );
- valuesGen->add( val2 );
- valuesGen->add( val3 );
- generators.add( valuesGen );
- return generators;
- }
-
- template<typename T>
- CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
- CompositeGenerator<T> generators;
- ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
- valuesGen->add( val1 );
- valuesGen->add( val2 );
- valuesGen->add( val3 );
- valuesGen->add( val4 );
- generators.add( valuesGen );
- return generators;
- }
-
-} // end namespace Generators
-
-using namespace Generators;
-
-} // end namespace Catch
-
-#define INTERNAL_CATCH_LINESTR2( line ) #line
-#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
-
-#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
-
-// #included from: internal/catch_interfaces_exception.h
-#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
-
-#include <string>
-
-namespace Catch {
-
- typedef std::string(*exceptionTranslateFunction)();
-
- struct IExceptionTranslator {
- virtual ~IExceptionTranslator();
- virtual std::string translate() const = 0;
- };
-
- struct IExceptionTranslatorRegistry {
- virtual ~IExceptionTranslatorRegistry();
-
- virtual std::string translateActiveException() const = 0;
- };
-
- class ExceptionTranslatorRegistrar {
- template<typename T>
- class ExceptionTranslator : public IExceptionTranslator {
- public:
-
- ExceptionTranslator( std::string(*translateFunction)( T& ) )
- : m_translateFunction( translateFunction )
- {}
-
- virtual std::string translate() const {
- try {
- throw;
- }
- catch( T& ex ) {
- return m_translateFunction( ex );
- }
- }
-
- protected:
- std::string(*m_translateFunction)( T& );
- };
-
- public:
- template<typename T>
- ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
- getMutableRegistryHub().registerTranslator
- ( new ExceptionTranslator<T>( translateFunction ) );
- }
- };
-}
-
-///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \
- static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \
- namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\
- static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature )
-
-// #included from: internal/catch_approx.hpp
-#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
-
-#include <cmath>
-#include <limits>
-
-namespace Catch {
-namespace Detail {
-
- class Approx {
- public:
- explicit Approx ( double value )
- : m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
- m_scale( 1.0 ),
- m_value( value )
- {}
-
- Approx( Approx const& other )
- : m_epsilon( other.m_epsilon ),
- m_scale( other.m_scale ),
- m_value( other.m_value )
- {}
-
- static Approx custom() {
- return Approx( 0 );
- }
-
- Approx operator()( double value ) {
- Approx approx( value );
- approx.epsilon( m_epsilon );
- approx.scale( m_scale );
- return approx;
- }
-
- friend bool operator == ( double lhs, Approx const& rhs ) {
- // Thanks to Richard Harris for his help refining this formula
- return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
- }
-
- friend bool operator == ( Approx const& lhs, double rhs ) {
- return operator==( rhs, lhs );
- }
-
- friend bool operator != ( double lhs, Approx const& rhs ) {
- return !operator==( lhs, rhs );
- }
-
- friend bool operator != ( Approx const& lhs, double rhs ) {
- return !operator==( rhs, lhs );
- }
-
- Approx& epsilon( double newEpsilon ) {
- m_epsilon = newEpsilon;
- return *this;
- }
-
- Approx& scale( double newScale ) {
- m_scale = newScale;
- return *this;
- }
-
- std::string toString() const {
- std::ostringstream oss;
- oss << "Approx( " << Catch::toString( m_value ) << " )";
- return oss.str();
- }
-
- private:
- double m_epsilon;
- double m_scale;
- double m_value;
- };
-}
-
-template<>
-inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
- return value.toString();
-}
-
-} // end namespace Catch
-
-// #included from: internal/catch_matchers.hpp
-#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
-
-namespace Catch {
-namespace Matchers {
- namespace Impl {
-
- template<typename ExpressionT>
- struct Matcher : SharedImpl<IShared>
- {
- typedef ExpressionT ExpressionType;
-
- virtual ~Matcher() {}
- virtual Ptr<Matcher> clone() const = 0;
- virtual bool match( ExpressionT const& expr ) const = 0;
- virtual std::string toString() const = 0;
- };
-
- template<typename DerivedT, typename ExpressionT>
- struct MatcherImpl : Matcher<ExpressionT> {
-
- virtual Ptr<Matcher<ExpressionT> > clone() const {
- return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) );
- }
- };
-
- namespace Generic {
-
- template<typename ExpressionT>
- class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
- public:
-
- AllOf() {}
- AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {}
-
- AllOf& add( Matcher<ExpressionT> const& matcher ) {
- m_matchers.push_back( matcher.clone() );
- return *this;
- }
- virtual bool match( ExpressionT const& expr ) const
- {
- for( std::size_t i = 0; i < m_matchers.size(); ++i )
- if( !m_matchers[i]->match( expr ) )
- return false;
- return true;
- }
- virtual std::string toString() const {
- std::ostringstream oss;
- oss << "( ";
- for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
- if( i != 0 )
- oss << " and ";
- oss << m_matchers[i]->toString();
- }
- oss << " )";
- return oss.str();
- }
-
- private:
- std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
- };
-
- template<typename ExpressionT>
- class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> {
- public:
-
- AnyOf() {}
- AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {}
-
- AnyOf& add( Matcher<ExpressionT> const& matcher ) {
- m_matchers.push_back( matcher.clone() );
- return *this;
- }
- virtual bool match( ExpressionT const& expr ) const
- {
- for( std::size_t i = 0; i < m_matchers.size(); ++i )
- if( m_matchers[i]->match( expr ) )
- return true;
- return false;
- }
- virtual std::string toString() const {
- std::ostringstream oss;
- oss << "( ";
- for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
- if( i != 0 )
- oss << " or ";
- oss << m_matchers[i]->toString();
- }
- oss << " )";
- return oss.str();
- }
-
- private:
- std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
- };
-
- }
-
- namespace StdString {
-
- inline std::string makeString( std::string const& str ) { return str; }
- inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); }
-
- struct Equals : MatcherImpl<Equals, std::string> {
- Equals( std::string const& str ) : m_str( str ){}
- Equals( Equals const& other ) : m_str( other.m_str ){}
-
- virtual ~Equals();
-
- virtual bool match( std::string const& expr ) const {
- return m_str == expr;
- }
- virtual std::string toString() const {
- return "equals: \"" + m_str + "\"";
- }
-
- std::string m_str;
- };
-
- struct Contains : MatcherImpl<Contains, std::string> {
- Contains( std::string const& substr ) : m_substr( substr ){}
- Contains( Contains const& other ) : m_substr( other.m_substr ){}
-
- virtual ~Contains();
-
- virtual bool match( std::string const& expr ) const {
- return expr.find( m_substr ) != std::string::npos;
- }
- virtual std::string toString() const {
- return "contains: \"" + m_substr + "\"";
- }
-
- std::string m_substr;
- };
-
- struct StartsWith : MatcherImpl<StartsWith, std::string> {
- StartsWith( std::string const& substr ) : m_substr( substr ){}
- StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){}
-
- virtual ~StartsWith();
-
- virtual bool match( std::string const& expr ) const {
- return expr.find( m_substr ) == 0;
- }
- virtual std::string toString() const {
- return "starts with: \"" + m_substr + "\"";
- }
-
- std::string m_substr;
- };
-
- struct EndsWith : MatcherImpl<EndsWith, std::string> {
- EndsWith( std::string const& substr ) : m_substr( substr ){}
- EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){}
-
- virtual ~EndsWith();
-
- virtual bool match( std::string const& expr ) const {
- return expr.find( m_substr ) == expr.size() - m_substr.size();
- }
- virtual std::string toString() const {
- return "ends with: \"" + m_substr + "\"";
- }
-
- std::string m_substr;
- };
- } // namespace StdString
- } // namespace Impl
-
- // The following functions create the actual matcher objects.
- // This allows the types to be inferred
- template<typename ExpressionT>
- inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
- Impl::Matcher<ExpressionT> const& m2 ) {
- return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 );
- }
- template<typename ExpressionT>
- inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
- Impl::Matcher<ExpressionT> const& m2,
- Impl::Matcher<ExpressionT> const& m3 ) {
- return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
- }
- template<typename ExpressionT>
- inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
- Impl::Matcher<ExpressionT> const& m2 ) {
- return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 );
- }
- template<typename ExpressionT>
- inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
- Impl::Matcher<ExpressionT> const& m2,
- Impl::Matcher<ExpressionT> const& m3 ) {
- return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
- }
-
- inline Impl::StdString::Equals Equals( std::string const& str ) {
- return Impl::StdString::Equals( str );
- }
- inline Impl::StdString::Equals Equals( const char* str ) {
- return Impl::StdString::Equals( Impl::StdString::makeString( str ) );
- }
- inline Impl::StdString::Contains Contains( std::string const& substr ) {
- return Impl::StdString::Contains( substr );
- }
- inline Impl::StdString::Contains Contains( const char* substr ) {
- return Impl::StdString::Contains( Impl::StdString::makeString( substr ) );
- }
- inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) {
- return Impl::StdString::StartsWith( substr );
- }
- inline Impl::StdString::StartsWith StartsWith( const char* substr ) {
- return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) );
- }
- inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) {
- return Impl::StdString::EndsWith( substr );
- }
- inline Impl::StdString::EndsWith EndsWith( const char* substr ) {
- return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) );
- }
-
-} // namespace Matchers
-
-using namespace Matchers;
-
-} // namespace Catch
-
-// These files are included here so the single_include script doesn't put them
-// in the conditionally compiled sections
-// #included from: internal/catch_test_case_info.h
-#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
-
-#include <string>
-#include <set>
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
-
-namespace Catch {
-
- struct ITestCase;
-
- struct TestCaseInfo {
- TestCaseInfo( std::string const& _name,
- std::string const& _className,
- std::string const& _description,
- std::set<std::string> const& _tags,
- bool _isHidden,
- SourceLineInfo const& _lineInfo );
-
- TestCaseInfo( TestCaseInfo const& other );
-
- std::string name;
- std::string className;
- std::string description;
- std::set<std::string> tags;
- std::string tagsAsString;
- SourceLineInfo lineInfo;
- bool isHidden;
- bool throws;
- };
-
- class TestCase : public TestCaseInfo {
- public:
-
- TestCase( ITestCase* testCase, TestCaseInfo const& info );
- TestCase( TestCase const& other );
-
- TestCase withName( std::string const& _newName ) const;
-
- void invoke() const;
-
- TestCaseInfo const& getTestCaseInfo() const;
-
- bool isHidden() const;
- bool throws() const;
-
- void swap( TestCase& other );
- bool operator == ( TestCase const& other ) const;
- bool operator < ( TestCase const& other ) const;
- TestCase& operator = ( TestCase const& other );
-
- private:
- Ptr<ITestCase> test;
- };
-
- TestCase makeTestCase( ITestCase* testCase,
- std::string const& className,
- std::string const& name,
- std::string const& description,
- SourceLineInfo const& lineInfo );
-}
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-// #included from: internal/catch_interfaces_runner.h
-#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
-
-namespace Catch {
- class TestCase;
-
- struct IRunner {
- virtual ~IRunner();
- };
-}
-
-
-#ifdef __OBJC__
-// #included from: internal/catch_objc.hpp
-#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
-
-#import <objc/runtime.h>
-
-#include <string>
-
-// NB. Any general catch headers included here must be included
-// in catch.hpp first to make sure they are included by the single
-// header for non obj-usage
-
-///////////////////////////////////////////////////////////////////////////////
-// This protocol is really only here for (self) documenting purposes, since
-// all its methods are optional.
- at protocol OcFixture
-
- at optional
-
--(void) setUp;
--(void) tearDown;
-
- at end
-
-namespace Catch {
-
- class OcMethod : public SharedImpl<ITestCase> {
-
- public:
- OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
-
- virtual void invoke() const {
- id obj = [[m_cls alloc] init];
-
- performOptionalSelector( obj, @selector(setUp) );
- performOptionalSelector( obj, m_sel );
- performOptionalSelector( obj, @selector(tearDown) );
-
- arcSafeRelease( obj );
- }
- private:
- virtual ~OcMethod() {}
-
- Class m_cls;
- SEL m_sel;
- };
-
- namespace Detail{
-
- inline std::string getAnnotation( Class cls,
- std::string const& annotationName,
- std::string const& testCaseName ) {
- NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
- SEL sel = NSSelectorFromString( selStr );
- arcSafeRelease( selStr );
- id value = performOptionalSelector( cls, sel );
- if( value )
- return [(NSString*)value UTF8String];
- return "";
- }
- }
-
- inline size_t registerTestMethods() {
- size_t noTestMethods = 0;
- int noClasses = objc_getClassList( NULL, 0 );
-
- Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
- objc_getClassList( classes, noClasses );
-
- for( int c = 0; c < noClasses; c++ ) {
- Class cls = classes[c];
- {
- u_int count;
- Method* methods = class_copyMethodList( cls, &count );
- for( u_int m = 0; m < count ; m++ ) {
- SEL selector = method_getName(methods[m]);
- std::string methodName = sel_getName(selector);
- if( startsWith( methodName, "Catch_TestCase_" ) ) {
- std::string testCaseName = methodName.substr( 15 );
- std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
- std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
- const char* className = class_getName( cls );
-
- getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) );
- noTestMethods++;
- }
- }
- free(methods);
- }
- }
- return noTestMethods;
- }
-
- namespace Matchers {
- namespace Impl {
- namespace NSStringMatchers {
-
- template<typename MatcherT>
- struct StringHolder : MatcherImpl<MatcherT, NSString*>{
- StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
- StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
- StringHolder() {
- arcSafeRelease( m_substr );
- }
-
- NSString* m_substr;
- };
-
- struct Equals : StringHolder<Equals> {
- Equals( NSString* substr ) : StringHolder( substr ){}
-
- virtual bool match( ExpressionType const& str ) const {
- return (str != nil || m_substr == nil ) &&
- [str isEqualToString:m_substr];
- }
-
- virtual std::string toString() const {
- return "equals string: \"" + Catch::toString( m_substr ) + "\"";
- }
- };
-
- struct Contains : StringHolder<Contains> {
- Contains( NSString* substr ) : StringHolder( substr ){}
-
- virtual bool match( ExpressionType const& str ) const {
- return (str != nil || m_substr == nil ) &&
- [str rangeOfString:m_substr].location != NSNotFound;
- }
-
- virtual std::string toString() const {
- return "contains string: \"" + Catch::toString( m_substr ) + "\"";
- }
- };
-
- struct StartsWith : StringHolder<StartsWith> {
- StartsWith( NSString* substr ) : StringHolder( substr ){}
-
- virtual bool match( ExpressionType const& str ) const {
- return (str != nil || m_substr == nil ) &&
- [str rangeOfString:m_substr].location == 0;
- }
-
- virtual std::string toString() const {
- return "starts with: \"" + Catch::toString( m_substr ) + "\"";
- }
- };
- struct EndsWith : StringHolder<EndsWith> {
- EndsWith( NSString* substr ) : StringHolder( substr ){}
-
- virtual bool match( ExpressionType const& str ) const {
- return (str != nil || m_substr == nil ) &&
- [str rangeOfString:m_substr].location == [str length] - [m_substr length];
- }
-
- virtual std::string toString() const {
- return "ends with: \"" + Catch::toString( m_substr ) + "\"";
- }
- };
-
- } // namespace NSStringMatchers
- } // namespace Impl
-
- inline Impl::NSStringMatchers::Equals
- Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
-
- inline Impl::NSStringMatchers::Contains
- Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
-
- inline Impl::NSStringMatchers::StartsWith
- StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
-
- inline Impl::NSStringMatchers::EndsWith
- EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
-
- } // namespace Matchers
-
- using namespace Matchers;
-
-} // namespace Catch
-
-///////////////////////////////////////////////////////////////////////////////
-#define OC_TEST_CASE( name, desc )\
-+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
-{\
-return @ name; \
-}\
-+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
-{ \
-return @ desc; \
-} \
--(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
-
-#endif
-
-#ifdef CATCH_CONFIG_RUNNER
-// #included from: internal/catch_impl.hpp
-#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
-
-// Collect all the implementation files together here
-// These are the equivalent of what would usually be cpp files
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wweak-vtables"
-#endif
-
-// #included from: catch_runner.hpp
-#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
-
-// #included from: internal/catch_commandline.hpp
-#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
-
-// #included from: catch_config.hpp
-#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
-
-// #included from: catch_test_spec_parser.hpp
-#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
-
-// #included from: catch_test_spec.hpp
-#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
-
-#include <string>
-#include <vector>
-
-namespace Catch {
-
- class TestSpec {
- struct Pattern : SharedImpl<> {
- virtual ~Pattern();
- virtual bool matches( TestCaseInfo const& testCase ) const = 0;
- };
- class NamePattern : public Pattern {
- enum WildcardPosition {
- NoWildcard = 0,
- WildcardAtStart = 1,
- WildcardAtEnd = 2,
- WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
- };
-
- public:
- NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) {
- if( startsWith( m_name, "*" ) ) {
- m_name = m_name.substr( 1 );
- m_wildcard = WildcardAtStart;
- }
- if( endsWith( m_name, "*" ) ) {
- m_name = m_name.substr( 0, m_name.size()-1 );
- m_wildcard = (WildcardPosition)( m_wildcard | WildcardAtEnd );
- }
- }
- virtual ~NamePattern();
- virtual bool matches( TestCaseInfo const& testCase ) const {
- switch( m_wildcard ) {
- case NoWildcard:
- return m_name == toLower( testCase.name );
- case WildcardAtStart:
- return endsWith( toLower( testCase.name ), m_name );
- case WildcardAtEnd:
- return startsWith( toLower( testCase.name ), m_name );
- case WildcardAtBothEnds:
- return contains( toLower( testCase.name ), m_name );
- }
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunreachable-code"
-#endif
- throw std::logic_error( "Unknown enum" );
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
- }
- private:
- std::string m_name;
- WildcardPosition m_wildcard;
- };
- class TagPattern : public Pattern {
- public:
- TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
- virtual ~TagPattern();
- virtual bool matches( TestCaseInfo const& testCase ) const {
- return testCase.tags.find( m_tag ) != testCase.tags.end();
- }
- private:
- std::string m_tag;
- };
- class ExcludedPattern : public Pattern {
- public:
- ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
- virtual ~ExcludedPattern();
- virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
- private:
- Ptr<Pattern> m_underlyingPattern;
- };
-
- struct Filter {
- std::vector<Ptr<Pattern> > m_patterns;
-
- bool matches( TestCaseInfo const& testCase ) const {
- // All patterns in a filter must match for the filter to be a match
- for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it )
- if( !(*it)->matches( testCase ) )
- return false;
- return true;
- }
- };
-
- public:
- bool hasFilters() const {
- return !m_filters.empty();
- }
- bool matches( TestCaseInfo const& testCase ) const {
- // A TestSpec matches if any filter matches
- for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it )
- if( it->matches( testCase ) )
- return true;
- return false;
- }
-
- private:
- std::vector<Filter> m_filters;
-
- friend class TestSpecParser;
- };
-}
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-namespace Catch {
-
- class TestSpecParser {
- enum Mode{ None, Name, QuotedName, Tag };
- Mode m_mode;
- bool m_exclusion;
- std::size_t m_start, m_pos;
- std::string m_arg;
- TestSpec::Filter m_currentFilter;
- TestSpec m_testSpec;
-
- public:
- TestSpecParser parse( std::string const& arg ) {
- m_mode = None;
- m_exclusion = false;
- m_start = std::string::npos;
- m_arg = arg;
- for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
- visitChar( m_arg[m_pos] );
- if( m_mode == Name )
- addPattern<TestSpec::NamePattern>();
- addFilter();
- return *this;
- }
- TestSpec testSpec() {
- return m_testSpec;
- }
- private:
- void visitChar( char c ) {
- if( m_mode == None ) {
- switch( c ) {
- case ' ': return;
- case '~': m_exclusion = true; return;
- case '[': return startNewMode( Tag, ++m_pos );
- case '"': return startNewMode( QuotedName, ++m_pos );
- default: startNewMode( Name, m_pos ); break;
- }
- }
- if( m_mode == Name ) {
- if( c == ',' ) {
- addPattern<TestSpec::NamePattern>();
- addFilter();
- }
- else if( c == '[' ) {
- if( subString() == "exclude:" )
- m_exclusion = true;
- else
- addPattern<TestSpec::NamePattern>();
- startNewMode( Tag, ++m_pos );
- }
- }
- else if( m_mode == QuotedName && c == '"' )
- addPattern<TestSpec::NamePattern>();
- else if( m_mode == Tag && c == ']' )
- addPattern<TestSpec::TagPattern>();
- }
- void startNewMode( Mode mode, std::size_t start ) {
- m_mode = mode;
- m_start = start;
- }
- std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
- template<typename T>
- void addPattern() {
- std::string token = subString();
- if( startsWith( token, "exclude:" ) ) {
- m_exclusion = true;
- token = token.substr( 8 );
- }
- if( !token.empty() ) {
- Ptr<TestSpec::Pattern> pattern = new T( token );
- if( m_exclusion )
- pattern = new TestSpec::ExcludedPattern( pattern );
- m_currentFilter.m_patterns.push_back( pattern );
- }
- m_exclusion = false;
- m_mode = None;
- }
- void addFilter() {
- if( !m_currentFilter.m_patterns.empty() ) {
- m_testSpec.m_filters.push_back( m_currentFilter );
- m_currentFilter = TestSpec::Filter();
- }
- }
- };
- inline TestSpec parseTestSpec( std::string const& arg ) {
- return TestSpecParser().parse( arg ).testSpec();
- }
-
-} // namespace Catch
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-// #included from: catch_stream.h
-#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
-
-#include <streambuf>
-
-#ifdef __clang__
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
-
-namespace Catch {
-
- class Stream {
- public:
- Stream();
- Stream( std::streambuf* _streamBuf, bool _isOwned );
- void release();
-
- std::streambuf* streamBuf;
-
- private:
- bool isOwned;
- };
-}
-
-#include <memory>
-#include <vector>
-#include <string>
-#include <iostream>
-
-#ifndef CATCH_CONFIG_CONSOLE_WIDTH
-#define CATCH_CONFIG_CONSOLE_WIDTH 80
-#endif
-
-namespace Catch {
-
- struct ConfigData {
-
- ConfigData()
- : listTests( false ),
- listTags( false ),
- listReporters( false ),
- listTestNamesOnly( false ),
- showSuccessfulTests( false ),
- shouldDebugBreak( false ),
- noThrow( false ),
- showHelp( false ),
- showInvisibles( false ),
- abortAfter( -1 ),
- verbosity( Verbosity::Normal ),
- warnings( WarnAbout::Nothing ),
- showDurations( ShowDurations::DefaultForReporter )
- {}
-
- bool listTests;
- bool listTags;
- bool listReporters;
- bool listTestNamesOnly;
-
- bool showSuccessfulTests;
- bool shouldDebugBreak;
- bool noThrow;
- bool showHelp;
- bool showInvisibles;
-
- int abortAfter;
-
- Verbosity::Level verbosity;
- WarnAbout::What warnings;
- ShowDurations::OrNot showDurations;
-
- std::string reporterName;
- std::string outputFilename;
- std::string name;
- std::string processName;
-
- std::vector<std::string> testsOrTags;
- };
-
- class Config : public SharedImpl<IConfig> {
- private:
- Config( Config const& other );
- Config& operator = ( Config const& other );
- virtual void dummy();
- public:
-
- Config()
- : m_os( std::cout.rdbuf() )
- {}
-
- Config( ConfigData const& data )
- : m_data( data ),
- m_os( std::cout.rdbuf() )
- {
- if( !data.testsOrTags.empty() ) {
- TestSpecParser parser;
- for( std::size_t i = 0; i < data.testsOrTags.size(); ++i )
- parser.parse( data.testsOrTags[i] );
- m_testSpec = parser.testSpec();
- }
- }
-
- virtual ~Config() {
- m_os.rdbuf( std::cout.rdbuf() );
- m_stream.release();
- }
-
- void setFilename( std::string const& filename ) {
- m_data.outputFilename = filename;
- }
-
- std::string const& getFilename() const {
- return m_data.outputFilename ;
- }
-
- bool listTests() const { return m_data.listTests; }
- bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
- bool listTags() const { return m_data.listTags; }
- bool listReporters() const { return m_data.listReporters; }
-
- std::string getProcessName() const { return m_data.processName; }
-
- bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
-
- void setStreamBuf( std::streambuf* buf ) {
- m_os.rdbuf( buf ? buf : std::cout.rdbuf() );
- }
-
- void useStream( std::string const& streamName ) {
- Stream stream = createStream( streamName );
- setStreamBuf( stream.streamBuf );
- m_stream.release();
- m_stream = stream;
- }
-
- std::string getReporterName() const { return m_data.reporterName; }
-
- int abortAfter() const { return m_data.abortAfter; }
-
- TestSpec const& testSpec() const { return m_testSpec; }
-
- bool showHelp() const { return m_data.showHelp; }
- bool showInvisibles() const { return m_data.showInvisibles; }
-
- // IConfig interface
- virtual bool allowThrows() const { return !m_data.noThrow; }
- virtual std::ostream& stream() const { return m_os; }
- virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
- virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
- virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
- virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
-
- private:
- ConfigData m_data;
-
- Stream m_stream;
- mutable std::ostream m_os;
- TestSpec m_testSpec;
- };
-
-} // end namespace Catch
-
-// #included from: catch_clara.h
-#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED
-
-// Use Catch's value for console width (store Clara's off to the side, if present)
-#ifdef CLARA_CONFIG_CONSOLE_WIDTH
-#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
-#undef CLARA_CONFIG_CONSOLE_WIDTH
-#endif
-#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
-
-// Declare Clara inside the Catch namespace
-#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
-// #included from: ../external/clara.h
-
-// Only use header guard if we are not using an outer namespace
-#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
-
-#ifndef STITCH_CLARA_OPEN_NAMESPACE
-#define TWOBLUECUBES_CLARA_H_INCLUDED
-#define STITCH_CLARA_OPEN_NAMESPACE
-#define STITCH_CLARA_CLOSE_NAMESPACE
-#else
-#define STITCH_CLARA_CLOSE_NAMESPACE }
-#endif
-
-#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
-
-// ----------- #included from tbc_text_format.h -----------
-
-// Only use header guard if we are not using an outer namespace
-#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE)
-#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-#define TBC_TEXT_FORMAT_H_INCLUDED
-#endif
-
-#include <string>
-#include <vector>
-#include <sstream>
-
-// Use optional outer namespace
-#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
-#endif
-
-namespace Tbc {
-
-#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
- const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
-#else
- const unsigned int consoleWidth = 80;
-#endif
-
- struct TextAttributes {
- TextAttributes()
- : initialIndent( std::string::npos ),
- indent( 0 ),
- width( consoleWidth-1 ),
- tabChar( '\t' )
- {}
-
- TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; }
- TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; }
- TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; }
- TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; }
-
- std::size_t initialIndent; // indent of first line, or npos
- std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
- std::size_t width; // maximum width of text, including indent. Longer text will wrap
- char tabChar; // If this char is seen the indent is changed to current pos
- };
-
- class Text {
- public:
- Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
- : attr( _attr )
- {
- std::string wrappableChars = " [({.,/|\\-";
- std::size_t indent = _attr.initialIndent != std::string::npos
- ? _attr.initialIndent
- : _attr.indent;
- std::string remainder = _str;
-
- while( !remainder.empty() ) {
- if( lines.size() >= 1000 ) {
- lines.push_back( "... message truncated due to excessive size" );
- return;
- }
- std::size_t tabPos = std::string::npos;
- std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
- std::size_t pos = remainder.find_first_of( '\n' );
- if( pos <= width ) {
- width = pos;
- }
- pos = remainder.find_last_of( _attr.tabChar, width );
- if( pos != std::string::npos ) {
- tabPos = pos;
- if( remainder[width] == '\n' )
- width--;
- remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
- }
-
- if( width == remainder.size() ) {
- spliceLine( indent, remainder, width );
- }
- else if( remainder[width] == '\n' ) {
- spliceLine( indent, remainder, width );
- if( width <= 1 || remainder.size() != 1 )
- remainder = remainder.substr( 1 );
- indent = _attr.indent;
- }
- else {
- pos = remainder.find_last_of( wrappableChars, width );
- if( pos != std::string::npos && pos > 0 ) {
- spliceLine( indent, remainder, pos );
- if( remainder[0] == ' ' )
- remainder = remainder.substr( 1 );
- }
- else {
- spliceLine( indent, remainder, width-1 );
- lines.back() += "-";
- }
- if( lines.size() == 1 )
- indent = _attr.indent;
- if( tabPos != std::string::npos )
- indent += tabPos;
- }
- }
- }
-
- void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
- lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
- _remainder = _remainder.substr( _pos );
- }
-
- typedef std::vector<std::string>::const_iterator const_iterator;
-
- const_iterator begin() const { return lines.begin(); }
- const_iterator end() const { return lines.end(); }
- std::string const& last() const { return lines.back(); }
- std::size_t size() const { return lines.size(); }
- std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
- std::string toString() const {
- std::ostringstream oss;
- oss << *this;
- return oss.str();
- }
-
- inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
- for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
- it != itEnd; ++it ) {
- if( it != _text.begin() )
- _stream << "\n";
- _stream << *it;
- }
- return _stream;
- }
-
- private:
- std::string str;
- TextAttributes attr;
- std::vector<std::string> lines;
- };
-
-} // end namespace Tbc
-
-#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-} // end outer namespace
-#endif
-
-#endif // TBC_TEXT_FORMAT_H_INCLUDED
-
-// ----------- end of #include from tbc_text_format.h -----------
-// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h
-
-#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
-
-#include <map>
-#include <algorithm>
-#include <stdexcept>
-#include <memory>
-
-// Use optional outer namespace
-#ifdef STITCH_CLARA_OPEN_NAMESPACE
-STITCH_CLARA_OPEN_NAMESPACE
-#endif
-
-namespace Clara {
-
- struct UnpositionalTag {};
-
- extern UnpositionalTag _;
-
-#ifdef CLARA_CONFIG_MAIN
- UnpositionalTag _;
-#endif
-
- namespace Detail {
-
-#ifdef CLARA_CONSOLE_WIDTH
- const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
-#else
- const unsigned int consoleWidth = 80;
-#endif
-
- using namespace Tbc;
-
- inline bool startsWith( std::string const& str, std::string const& prefix ) {
- return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix;
- }
-
- template<typename T> struct RemoveConstRef{ typedef T type; };
- template<typename T> struct RemoveConstRef<T&>{ typedef T type; };
- template<typename T> struct RemoveConstRef<T const&>{ typedef T type; };
- template<typename T> struct RemoveConstRef<T const>{ typedef T type; };
-
- template<typename T> struct IsBool { static const bool value = false; };
- template<> struct IsBool<bool> { static const bool value = true; };
-
- template<typename T>
- void convertInto( std::string const& _source, T& _dest ) {
- std::stringstream ss;
- ss << _source;
- ss >> _dest;
- if( ss.fail() )
- throw std::runtime_error( "Unable to convert " + _source + " to destination type" );
- }
- inline void convertInto( std::string const& _source, std::string& _dest ) {
- _dest = _source;
- }
- inline void convertInto( std::string const& _source, bool& _dest ) {
- std::string sourceLC = _source;
- std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower );
- if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" )
- _dest = true;
- else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" )
- _dest = false;
- else
- throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" );
- }
- inline void convertInto( bool _source, bool& _dest ) {
- _dest = _source;
- }
- template<typename T>
- inline void convertInto( bool, T& ) {
- throw std::runtime_error( "Invalid conversion" );
- }
-
- template<typename ConfigT>
- struct IArgFunction {
- virtual ~IArgFunction() {}
-# ifdef CATCH_CPP11_OR_GREATER
- IArgFunction() = default;
- IArgFunction( IArgFunction const& ) = default;
-# endif
- virtual void set( ConfigT& config, std::string const& value ) const = 0;
- virtual void setFlag( ConfigT& config ) const = 0;
- virtual bool takesArg() const = 0;
- virtual IArgFunction* clone() const = 0;
- };
-
- template<typename ConfigT>
- class BoundArgFunction {
- public:
- BoundArgFunction() : functionObj( NULL ) {}
- BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
- BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {}
- BoundArgFunction& operator = ( BoundArgFunction const& other ) {
- IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL;
- delete functionObj;
- functionObj = newFunctionObj;
- return *this;
- }
- ~BoundArgFunction() { delete functionObj; }
-
- void set( ConfigT& config, std::string const& value ) const {
- functionObj->set( config, value );
- }
- void setFlag( ConfigT& config ) const {
- functionObj->setFlag( config );
- }
- bool takesArg() const { return functionObj->takesArg(); }
-
- bool isSet() const {
- return functionObj != NULL;
- }
- private:
- IArgFunction<ConfigT>* functionObj;
- };
-
- template<typename C>
- struct NullBinder : IArgFunction<C>{
- virtual void set( C&, std::string const& ) const {}
- virtual void setFlag( C& ) const {}
- virtual bool takesArg() const { return true; }
- virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
- };
-
- template<typename C, typename M>
- struct BoundDataMember : IArgFunction<C>{
- BoundDataMember( M C::* _member ) : member( _member ) {}
- virtual void set( C& p, std::string const& stringValue ) const {
- convertInto( stringValue, p.*member );
- }
- virtual void setFlag( C& p ) const {
- convertInto( true, p.*member );
- }
- virtual bool takesArg() const { return !IsBool<M>::value; }
- virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
- M C::* member;
- };
- template<typename C, typename M>
- struct BoundUnaryMethod : IArgFunction<C>{
- BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {}
- virtual void set( C& p, std::string const& stringValue ) const {
- typename RemoveConstRef<M>::type value;
- convertInto( stringValue, value );
- (p.*member)( value );
- }
- virtual void setFlag( C& p ) const {
- typename RemoveConstRef<M>::type value;
- convertInto( true, value );
- (p.*member)( value );
- }
- virtual bool takesArg() const { return !IsBool<M>::value; }
- virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
- void (C::*member)( M );
- };
- template<typename C>
- struct BoundNullaryMethod : IArgFunction<C>{
- BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {}
- virtual void set( C& p, std::string const& stringValue ) const {
- bool value;
- convertInto( stringValue, value );
- if( value )
- (p.*member)();
- }
- virtual void setFlag( C& p ) const {
- (p.*member)();
- }
- virtual bool takesArg() const { return false; }
- virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
- void (C::*member)();
- };
-
- template<typename C>
- struct BoundUnaryFunction : IArgFunction<C>{
- BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {}
- virtual void set( C& obj, std::string const& stringValue ) const {
- bool value;
- convertInto( stringValue, value );
- if( value )
- function( obj );
- }
- virtual void setFlag( C& p ) const {
- function( p );
- }
- virtual bool takesArg() const { return false; }
- virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
- void (*function)( C& );
- };
-
- template<typename C, typename T>
- struct BoundBinaryFunction : IArgFunction<C>{
- BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {}
- virtual void set( C& obj, std::string const& stringValue ) const {
- typename RemoveConstRef<T>::type value;
- convertInto( stringValue, value );
- function( obj, value );
- }
- virtual void setFlag( C& obj ) const {
- typename RemoveConstRef<T>::type value;
- convertInto( true, value );
- function( obj, value );
- }
- virtual bool takesArg() const { return !IsBool<T>::value; }
- virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
- void (*function)( C&, T );
- };
-
- } // namespace Detail
-
- struct Parser {
- Parser() : separators( " \t=:" ) {}
-
- struct Token {
- enum Type { Positional, ShortOpt, LongOpt };
- Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {}
- Type type;
- std::string data;
- };
-
- void parseIntoTokens( int argc, char const * const * argv, std::vector<Parser::Token>& tokens ) const {
- const std::string doubleDash = "--";
- for( int i = 1; i < argc && argv[i] != doubleDash; ++i )
- parseIntoTokens( argv[i] , tokens);
- }
- void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const {
- while( !arg.empty() ) {
- Parser::Token token( Parser::Token::Positional, arg );
- arg = "";
- if( token.data[0] == '-' ) {
- if( token.data.size() > 1 && token.data[1] == '-' ) {
- token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) );
- }
- else {
- token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) );
- if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) {
- arg = "-" + token.data.substr( 1 );
- token.data = token.data.substr( 0, 1 );
- }
- }
- }
- if( token.type != Parser::Token::Positional ) {
- std::size_t pos = token.data.find_first_of( separators );
- if( pos != std::string::npos ) {
- arg = token.data.substr( pos+1 );
- token.data = token.data.substr( 0, pos );
- }
- }
- tokens.push_back( token );
- }
- }
- std::string separators;
- };
-
- template<typename ConfigT>
- struct CommonArgProperties {
- CommonArgProperties() {}
- CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {}
-
- Detail::BoundArgFunction<ConfigT> boundField;
- std::string description;
- std::string detail;
- std::string placeholder; // Only value if boundField takes an arg
-
- bool takesArg() const {
- return !placeholder.empty();
- }
- void validate() const {
- if( !boundField.isSet() )
- throw std::logic_error( "option not bound" );
- }
- };
- struct OptionArgProperties {
- std::vector<std::string> shortNames;
- std::string longName;
-
- bool hasShortName( std::string const& shortName ) const {
- return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end();
- }
- bool hasLongName( std::string const& _longName ) const {
- return _longName == longName;
- }
- };
- struct PositionalArgProperties {
- PositionalArgProperties() : position( -1 ) {}
- int position; // -1 means non-positional (floating)
-
- bool isFixedPositional() const {
- return position != -1;
- }
- };
-
- template<typename ConfigT>
- class CommandLine {
-
- struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties {
- Arg() {}
- Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {}
-
- using CommonArgProperties<ConfigT>::placeholder; // !TBD
-
- std::string dbgName() const {
- if( !longName.empty() )
- return "--" + longName;
- if( !shortNames.empty() )
- return "-" + shortNames[0];
- return "positional args";
- }
- std::string commands() const {
- std::ostringstream oss;
- bool first = true;
- std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end();
- for(; it != itEnd; ++it ) {
- if( first )
- first = false;
- else
- oss << ", ";
- oss << "-" << *it;
- }
- if( !longName.empty() ) {
- if( !first )
- oss << ", ";
- oss << "--" << longName;
- }
- if( !placeholder.empty() )
- oss << " <" << placeholder << ">";
- return oss.str();
- }
- };
-
- // NOTE: std::auto_ptr is deprecated in c++11/c++0x
-#if defined(__cplusplus) && __cplusplus > 199711L
- typedef std::unique_ptr<Arg> ArgAutoPtr;
-#else
- typedef std::auto_ptr<Arg> ArgAutoPtr;
-#endif
-
- friend void addOptName( Arg& arg, std::string const& optName )
- {
- if( optName.empty() )
- return;
- if( Detail::startsWith( optName, "--" ) ) {
- if( !arg.longName.empty() )
- throw std::logic_error( "Only one long opt may be specified. '"
- + arg.longName
- + "' already specified, now attempting to add '"
- + optName + "'" );
- arg.longName = optName.substr( 2 );
- }
- else if( Detail::startsWith( optName, "-" ) )
- arg.shortNames.push_back( optName.substr( 1 ) );
- else
- throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" );
- }
- friend void setPositionalArg( Arg& arg, int position )
- {
- arg.position = position;
- }
-
- class ArgBuilder {
- public:
- ArgBuilder( Arg* arg ) : m_arg( arg ) {}
-
- // Bind a non-boolean data member (requires placeholder string)
- template<typename C, typename M>
- void bind( M C::* field, std::string const& placeholder ) {
- m_arg->boundField = new Detail::BoundDataMember<C,M>( field );
- m_arg->placeholder = placeholder;
- }
- // Bind a boolean data member (no placeholder required)
- template<typename C>
- void bind( bool C::* field ) {
- m_arg->boundField = new Detail::BoundDataMember<C,bool>( field );
- }
-
- // Bind a method taking a single, non-boolean argument (requires a placeholder string)
- template<typename C, typename M>
- void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) {
- m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod );
- m_arg->placeholder = placeholder;
- }
-
- // Bind a method taking a single, boolean argument (no placeholder string required)
- template<typename C>
- void bind( void (C::* unaryMethod)( bool ) ) {
- m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod );
- }
-
- // Bind a method that takes no arguments (will be called if opt is present)
- template<typename C>
- void bind( void (C::* nullaryMethod)() ) {
- m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod );
- }
-
- // Bind a free function taking a single argument - the object to operate on (no placeholder string required)
- template<typename C>
- void bind( void (* unaryFunction)( C& ) ) {
- m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction );
- }
-
- // Bind a free function taking a single argument - the object to operate on (requires a placeholder string)
- template<typename C, typename T>
- void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) {
- m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction );
- m_arg->placeholder = placeholder;
- }
-
- ArgBuilder& describe( std::string const& description ) {
- m_arg->description = description;
- return *this;
- }
- ArgBuilder& detail( std::string const& detail ) {
- m_arg->detail = detail;
- return *this;
- }
-
- protected:
- Arg* m_arg;
- };
-
- class OptBuilder : public ArgBuilder {
- public:
- OptBuilder( Arg* arg ) : ArgBuilder( arg ) {}
- OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {}
-
- OptBuilder& operator[]( std::string const& optName ) {
- addOptName( *ArgBuilder::m_arg, optName );
- return *this;
- }
- };
-
- public:
-
- CommandLine()
- : m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
- m_highestSpecifiedArgPosition( 0 ),
- m_throwOnUnrecognisedTokens( false )
- {}
- CommandLine( CommandLine const& other )
- : m_boundProcessName( other.m_boundProcessName ),
- m_options ( other.m_options ),
- m_positionalArgs( other.m_positionalArgs ),
- m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ),
- m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
- {
- if( other.m_floatingArg.get() )
- m_floatingArg = ArgAutoPtr( new Arg( *other.m_floatingArg ) );
- }
-
- CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
- m_throwOnUnrecognisedTokens = shouldThrow;
- return *this;
- }
-
- OptBuilder operator[]( std::string const& optName ) {
- m_options.push_back( Arg() );
- addOptName( m_options.back(), optName );
- OptBuilder builder( &m_options.back() );
- return builder;
- }
-
- ArgBuilder operator[]( int position ) {
- m_positionalArgs.insert( std::make_pair( position, Arg() ) );
- if( position > m_highestSpecifiedArgPosition )
- m_highestSpecifiedArgPosition = position;
- setPositionalArg( m_positionalArgs[position], position );
- ArgBuilder builder( &m_positionalArgs[position] );
- return builder;
- }
-
- // Invoke this with the _ instance
- ArgBuilder operator[]( UnpositionalTag ) {
- if( m_floatingArg.get() )
- throw std::logic_error( "Only one unpositional argument can be added" );
- m_floatingArg = ArgAutoPtr( new Arg() );
- ArgBuilder builder( m_floatingArg.get() );
- return builder;
- }
-
- template<typename C, typename M>
- void bindProcessName( M C::* field ) {
- m_boundProcessName = new Detail::BoundDataMember<C,M>( field );
- }
- template<typename C, typename M>
- void bindProcessName( void (C::*_unaryMethod)( M ) ) {
- m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod );
- }
-
- void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const {
- typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it;
- std::size_t maxWidth = 0;
- for( it = itBegin; it != itEnd; ++it )
- maxWidth = (std::max)( maxWidth, it->commands().size() );
-
- for( it = itBegin; it != itEnd; ++it ) {
- Detail::Text usage( it->commands(), Detail::TextAttributes()
- .setWidth( maxWidth+indent )
- .setIndent( indent ) );
- Detail::Text desc( it->description, Detail::TextAttributes()
- .setWidth( width - maxWidth - 3 ) );
-
- for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) {
- std::string usageCol = i < usage.size() ? usage[i] : "";
- os << usageCol;
-
- if( i < desc.size() && !desc[i].empty() )
- os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' )
- << desc[i];
- os << "\n";
- }
- }
- }
- std::string optUsage() const {
- std::ostringstream oss;
- optUsage( oss );
- return oss.str();
- }
-
- void argSynopsis( std::ostream& os ) const {
- for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) {
- if( i > 1 )
- os << " ";
- typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i );
- if( it != m_positionalArgs.end() )
- os << "<" << it->second.placeholder << ">";
- else if( m_floatingArg.get() )
- os << "<" << m_floatingArg->placeholder << ">";
- else
- throw std::logic_error( "non consecutive positional arguments with no floating args" );
- }
- // !TBD No indication of mandatory args
- if( m_floatingArg.get() ) {
- if( m_highestSpecifiedArgPosition > 1 )
- os << " ";
- os << "[<" << m_floatingArg->placeholder << "> ...]";
- }
- }
- std::string argSynopsis() const {
- std::ostringstream oss;
- argSynopsis( oss );
- return oss.str();
- }
-
- void usage( std::ostream& os, std::string const& procName ) const {
- validate();
- os << "usage:\n " << procName << " ";
- argSynopsis( os );
- if( !m_options.empty() ) {
- os << " [options]\n\nwhere options are: \n";
- optUsage( os, 2 );
- }
- os << "\n";
- }
- std::string usage( std::string const& procName ) const {
- std::ostringstream oss;
- usage( oss, procName );
- return oss.str();
- }
-
- ConfigT parse( int argc, char const * const * argv ) const {
- ConfigT config;
- parseInto( argc, argv, config );
- return config;
- }
-
- std::vector<Parser::Token> parseInto( int argc, char const * const * argv, ConfigT& config ) const {
- std::string processName = argv[0];
- std::size_t lastSlash = processName.find_last_of( "/\\" );
- if( lastSlash != std::string::npos )
- processName = processName.substr( lastSlash+1 );
- m_boundProcessName.set( config, processName );
- std::vector<Parser::Token> tokens;
- Parser parser;
- parser.parseIntoTokens( argc, argv, tokens );
- return populate( tokens, config );
- }
-
- std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
- validate();
- std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config );
- unusedTokens = populateFixedArgs( unusedTokens, config );
- unusedTokens = populateFloatingArgs( unusedTokens, config );
- return unusedTokens;
- }
-
- std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
- std::vector<Parser::Token> unusedTokens;
- std::vector<std::string> errors;
- for( std::size_t i = 0; i < tokens.size(); ++i ) {
- Parser::Token const& token = tokens[i];
- typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
- for(; it != itEnd; ++it ) {
- Arg const& arg = *it;
-
- try {
- if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) ||
- ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) {
- if( arg.takesArg() ) {
- if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional )
- errors.push_back( "Expected argument to option: " + token.data );
- else
- arg.boundField.set( config, tokens[++i].data );
- }
- else {
- arg.boundField.setFlag( config );
- }
- break;
- }
- }
- catch( std::exception& ex ) {
- errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" );
- }
- }
- if( it == itEnd ) {
- if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
- unusedTokens.push_back( token );
- else if( m_throwOnUnrecognisedTokens )
- errors.push_back( "unrecognised option: " + token.data );
- }
- }
- if( !errors.empty() ) {
- std::ostringstream oss;
- for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
- it != itEnd;
- ++it ) {
- if( it != errors.begin() )
- oss << "\n";
- oss << *it;
- }
- throw std::runtime_error( oss.str() );
- }
- return unusedTokens;
- }
- std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
- std::vector<Parser::Token> unusedTokens;
- int position = 1;
- for( std::size_t i = 0; i < tokens.size(); ++i ) {
- Parser::Token const& token = tokens[i];
- typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position );
- if( it != m_positionalArgs.end() )
- it->second.boundField.set( config, token.data );
- else
- unusedTokens.push_back( token );
- if( token.type == Parser::Token::Positional )
- position++;
- }
- return unusedTokens;
- }
- std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
- if( !m_floatingArg.get() )
- return tokens;
- std::vector<Parser::Token> unusedTokens;
- for( std::size_t i = 0; i < tokens.size(); ++i ) {
- Parser::Token const& token = tokens[i];
- if( token.type == Parser::Token::Positional )
- m_floatingArg->boundField.set( config, token.data );
- else
- unusedTokens.push_back( token );
- }
- return unusedTokens;
- }
-
- void validate() const
- {
- if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() )
- throw std::logic_error( "No options or arguments specified" );
-
- for( typename std::vector<Arg>::const_iterator it = m_options.begin(),
- itEnd = m_options.end();
- it != itEnd; ++it )
- it->validate();
- }
-
- private:
- Detail::BoundArgFunction<ConfigT> m_boundProcessName;
- std::vector<Arg> m_options;
- std::map<int, Arg> m_positionalArgs;
- ArgAutoPtr m_floatingArg;
- int m_highestSpecifiedArgPosition;
- bool m_throwOnUnrecognisedTokens;
- };
-
-} // end namespace Clara
-
-STITCH_CLARA_CLOSE_NAMESPACE
-#undef STITCH_CLARA_OPEN_NAMESPACE
-#undef STITCH_CLARA_CLOSE_NAMESPACE
-
-#endif // TWOBLUECUBES_CLARA_H_INCLUDED
-#undef STITCH_CLARA_OPEN_NAMESPACE
-
-// Restore Clara's value for console width, if present
-#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
-#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
-#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
-#endif
-
-#include <fstream>
-
-namespace Catch {
-
- inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; }
- inline void abortAfterX( ConfigData& config, int x ) {
- if( x < 1 )
- throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" );
- config.abortAfter = x;
- }
- inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
-
- inline void addWarning( ConfigData& config, std::string const& _warning ) {
- if( _warning == "NoAssertions" )
- config.warnings = (WarnAbout::What)( config.warnings | WarnAbout::NoAssertions );
- else
- throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" );
-
- }
- inline void setVerbosity( ConfigData& config, int level ) {
- // !TBD: accept strings?
- config.verbosity = (Verbosity::Level)level;
- }
- inline void setShowDurations( ConfigData& config, bool _showDurations ) {
- config.showDurations = _showDurations
- ? ShowDurations::Always
- : ShowDurations::Never;
- }
- inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
- std::ifstream f( _filename.c_str() );
- if( !f.is_open() )
- throw std::domain_error( "Unable to load input file: " + _filename );
-
- std::string line;
- while( std::getline( f, line ) ) {
- line = trim(line);
- if( !line.empty() && !startsWith( line, "#" ) )
- addTestOrTags( config, "\"" + line + "\"" );
- }
- }
-
- inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
-
- using namespace Clara;
- CommandLine<ConfigData> cli;
-
- cli.bindProcessName( &ConfigData::processName );
-
- cli["-?"]["-h"]["--help"]
- .describe( "display usage information" )
- .bind( &ConfigData::showHelp );
-
- cli["-l"]["--list-tests"]
- .describe( "list all/matching test cases" )
- .bind( &ConfigData::listTests );
-
- cli["-t"]["--list-tags"]
- .describe( "list all/matching tags" )
- .bind( &ConfigData::listTags );
-
- cli["-s"]["--success"]
- .describe( "include successful tests in output" )
- .bind( &ConfigData::showSuccessfulTests );
-
- cli["-b"]["--break"]
- .describe( "break into debugger on failure" )
- .bind( &ConfigData::shouldDebugBreak );
-
- cli["-e"]["--nothrow"]
- .describe( "skip exception tests" )
- .bind( &ConfigData::noThrow );
-
- cli["-i"]["--invisibles"]
- .describe( "show invisibles (tabs, newlines)" )
- .bind( &ConfigData::showInvisibles );
-
- cli["-o"]["--out"]
- .describe( "output filename" )
- .bind( &ConfigData::outputFilename, "filename" );
-
- cli["-r"]["--reporter"]
-// .placeholder( "name[:filename]" )
- .describe( "reporter to use (defaults to console)" )
- .bind( &ConfigData::reporterName, "name" );
-
- cli["-n"]["--name"]
- .describe( "suite name" )
- .bind( &ConfigData::name, "name" );
-
- cli["-a"]["--abort"]
- .describe( "abort at first failure" )
- .bind( &abortAfterFirst );
-
- cli["-x"]["--abortx"]
- .describe( "abort after x failures" )
- .bind( &abortAfterX, "no. failures" );
-
- cli["-w"]["--warn"]
- .describe( "enable warnings" )
- .bind( &addWarning, "warning name" );
-
-// - needs updating if reinstated
-// cli.into( &setVerbosity )
-// .describe( "level of verbosity (0=no output)" )
-// .shortOpt( "v")
-// .longOpt( "verbosity" )
-// .placeholder( "level" );
-
- cli[_]
- .describe( "which test or tests to use" )
- .bind( &addTestOrTags, "test name, pattern or tags" );
-
- cli["-d"]["--durations"]
- .describe( "show test durations" )
- .bind( &setShowDurations, "yes/no" );
-
- cli["-f"]["--input-file"]
- .describe( "load test names to run from a file" )
- .bind( &loadTestNamesFromFile, "filename" );
-
- // Less common commands which don't have a short form
- cli["--list-test-names-only"]
- .describe( "list all/matching test cases names only" )
- .bind( &ConfigData::listTestNamesOnly );
-
- cli["--list-reporters"]
- .describe( "list all reporters" )
- .bind( &ConfigData::listReporters );
-
- return cli;
- }
-
-} // end namespace Catch
-
-// #included from: internal/catch_list.hpp
-#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
-
-// #included from: catch_text.h
-#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED
-
-#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
-
-#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch
-// #included from: ../external/tbc_text_format.h
-// Only use header guard if we are not using an outer namespace
-#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
-# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
-# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
-# endif
-# else
-# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
-# endif
-#endif
-#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
-#include <string>
-#include <vector>
-#include <sstream>
-
-// Use optional outer namespace
-#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
-#endif
-
-namespace Tbc {
-
-#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
- const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
-#else
- const unsigned int consoleWidth = 80;
-#endif
-
- struct TextAttributes {
- TextAttributes()
- : initialIndent( std::string::npos ),
- indent( 0 ),
- width( consoleWidth-1 ),
- tabChar( '\t' )
- {}
-
- TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; }
- TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; }
- TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; }
- TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; }
-
- std::size_t initialIndent; // indent of first line, or npos
- std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
- std::size_t width; // maximum width of text, including indent. Longer text will wrap
- char tabChar; // If this char is seen the indent is changed to current pos
- };
-
- class Text {
- public:
- Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
- : attr( _attr )
- {
- std::string wrappableChars = " [({.,/|\\-";
- std::size_t indent = _attr.initialIndent != std::string::npos
- ? _attr.initialIndent
- : _attr.indent;
- std::string remainder = _str;
-
- while( !remainder.empty() ) {
- if( lines.size() >= 1000 ) {
- lines.push_back( "... message truncated due to excessive size" );
- return;
- }
- std::size_t tabPos = std::string::npos;
- std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
- std::size_t pos = remainder.find_first_of( '\n' );
- if( pos <= width ) {
- width = pos;
- }
- pos = remainder.find_last_of( _attr.tabChar, width );
- if( pos != std::string::npos ) {
- tabPos = pos;
- if( remainder[width] == '\n' )
- width--;
- remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
- }
-
- if( width == remainder.size() ) {
- spliceLine( indent, remainder, width );
- }
- else if( remainder[width] == '\n' ) {
- spliceLine( indent, remainder, width );
- if( width <= 1 || remainder.size() != 1 )
- remainder = remainder.substr( 1 );
- indent = _attr.indent;
- }
- else {
- pos = remainder.find_last_of( wrappableChars, width );
- if( pos != std::string::npos && pos > 0 ) {
- spliceLine( indent, remainder, pos );
- if( remainder[0] == ' ' )
- remainder = remainder.substr( 1 );
- }
- else {
- spliceLine( indent, remainder, width-1 );
- lines.back() += "-";
- }
- if( lines.size() == 1 )
- indent = _attr.indent;
- if( tabPos != std::string::npos )
- indent += tabPos;
- }
- }
- }
-
- void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
- lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
- _remainder = _remainder.substr( _pos );
- }
-
- typedef std::vector<std::string>::const_iterator const_iterator;
-
- const_iterator begin() const { return lines.begin(); }
- const_iterator end() const { return lines.end(); }
- std::string const& last() const { return lines.back(); }
- std::size_t size() const { return lines.size(); }
- std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
- std::string toString() const {
- std::ostringstream oss;
- oss << *this;
- return oss.str();
- }
-
- inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
- for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
- it != itEnd; ++it ) {
- if( it != _text.begin() )
- _stream << "\n";
- _stream << *it;
- }
- return _stream;
- }
-
- private:
- std::string str;
- TextAttributes attr;
- std::vector<std::string> lines;
- };
-
-} // end namespace Tbc
-
-#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-} // end outer namespace
-#endif
-
-#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
-#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
-
-namespace Catch {
- using Tbc::Text;
- using Tbc::TextAttributes;
-}
-
-// #included from: catch_console_colour.hpp
-#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
-
-namespace Catch {
-
- namespace Detail {
- struct IColourImpl;
- }
-
- struct Colour {
- enum Code {
- None = 0,
-
- White,
- Red,
- Green,
- Blue,
- Cyan,
- Yellow,
- Grey,
-
- Bright = 0x10,
-
- BrightRed = Bright | Red,
- BrightGreen = Bright | Green,
- LightGrey = Bright | Grey,
- BrightWhite = Bright | White,
-
- // By intention
- FileName = LightGrey,
- ResultError = BrightRed,
- ResultSuccess = BrightGreen,
-
- Error = BrightRed,
- Success = Green,
-
- OriginalExpression = Cyan,
- ReconstructedExpression = Yellow,
-
- SecondaryText = LightGrey,
- Headers = White
- };
-
- // Use constructed object for RAII guard
- Colour( Code _colourCode );
- ~Colour();
-
- // Use static method for one-shot changes
- static void use( Code _colourCode );
-
- private:
- static Detail::IColourImpl* impl();
- };
-
-} // end namespace Catch
-
-// #included from: catch_interfaces_reporter.h
-#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
-
-// #included from: catch_option.hpp
-#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
-
-namespace Catch {
-
- // An optional type
- template<typename T>
- class Option {
- public:
- Option() : nullableValue( NULL ) {}
- Option( T const& _value )
- : nullableValue( new( storage ) T( _value ) )
- {}
- Option( Option const& _other )
- : nullableValue( _other ? new( storage ) T( *_other ) : NULL )
- {}
-
- ~Option() {
- reset();
- }
-
- Option& operator= ( Option const& _other ) {
- if( &_other != this ) {
- reset();
- if( _other )
- nullableValue = new( storage ) T( *_other );
- }
- return *this;
- }
- Option& operator = ( T const& _value ) {
- reset();
- nullableValue = new( storage ) T( _value );
- return *this;
- }
-
- void reset() {
- if( nullableValue )
- nullableValue->~T();
- nullableValue = NULL;
- }
-
- T& operator*() { return *nullableValue; }
- T const& operator*() const { return *nullableValue; }
- T* operator->() { return nullableValue; }
- const T* operator->() const { return nullableValue; }
-
- T valueOr( T const& defaultValue ) const {
- return nullableValue ? *nullableValue : defaultValue;
- }
-
- bool some() const { return nullableValue != NULL; }
- bool none() const { return nullableValue == NULL; }
-
- bool operator !() const { return nullableValue == NULL; }
- operator SafeBool::type() const {
- return SafeBool::makeSafe( some() );
- }
-
- private:
- T* nullableValue;
- char storage[sizeof(T)];
- };
-
-} // end namespace Catch
-
-#include <string>
-#include <ostream>
-#include <map>
-#include <assert.h>
-
-namespace Catch
-{
- struct ReporterConfig {
- explicit ReporterConfig( Ptr<IConfig> const& _fullConfig )
- : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
-
- ReporterConfig( Ptr<IConfig> const& _fullConfig, std::ostream& _stream )
- : m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
-
- std::ostream& stream() const { return *m_stream; }
- Ptr<IConfig> fullConfig() const { return m_fullConfig; }
-
- private:
- std::ostream* m_stream;
- Ptr<IConfig> m_fullConfig;
- };
-
- struct ReporterPreferences {
- ReporterPreferences()
- : shouldRedirectStdOut( false )
- {}
-
- bool shouldRedirectStdOut;
- };
-
- template<typename T>
- struct LazyStat : Option<T> {
- LazyStat() : used( false ) {}
- LazyStat& operator=( T const& _value ) {
- Option<T>::operator=( _value );
- used = false;
- return *this;
- }
- void reset() {
- Option<T>::reset();
- used = false;
- }
- bool used;
- };
-
- struct TestRunInfo {
- TestRunInfo( std::string const& _name ) : name( _name ) {}
- std::string name;
- };
- struct GroupInfo {
- GroupInfo( std::string const& _name,
- std::size_t _groupIndex,
- std::size_t _groupsCount )
- : name( _name ),
- groupIndex( _groupIndex ),
- groupsCounts( _groupsCount )
- {}
-
- std::string name;
- std::size_t groupIndex;
- std::size_t groupsCounts;
- };
-
- struct AssertionStats {
- AssertionStats( AssertionResult const& _assertionResult,
- std::vector<MessageInfo> const& _infoMessages,
- Totals const& _totals )
- : assertionResult( _assertionResult ),
- infoMessages( _infoMessages ),
- totals( _totals )
- {
- if( assertionResult.hasMessage() ) {
- // Copy message into messages list.
- // !TBD This should have been done earlier, somewhere
- MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
- builder << assertionResult.getMessage();
- builder.m_info.message = builder.m_stream.str();
-
- infoMessages.push_back( builder.m_info );
- }
- }
- virtual ~AssertionStats();
-
-# ifdef CATCH_CPP11_OR_GREATER
- AssertionStats( AssertionStats const& ) = default;
- AssertionStats( AssertionStats && ) = default;
- AssertionStats& operator = ( AssertionStats const& ) = default;
- AssertionStats& operator = ( AssertionStats && ) = default;
-# endif
-
- AssertionResult assertionResult;
- std::vector<MessageInfo> infoMessages;
- Totals totals;
- };
-
- struct SectionStats {
- SectionStats( SectionInfo const& _sectionInfo,
- Counts const& _assertions,
- double _durationInSeconds,
- bool _missingAssertions )
- : sectionInfo( _sectionInfo ),
- assertions( _assertions ),
- durationInSeconds( _durationInSeconds ),
- missingAssertions( _missingAssertions )
- {}
- virtual ~SectionStats();
-# ifdef CATCH_CPP11_OR_GREATER
- SectionStats( SectionStats const& ) = default;
- SectionStats( SectionStats && ) = default;
- SectionStats& operator = ( SectionStats const& ) = default;
- SectionStats& operator = ( SectionStats && ) = default;
-# endif
-
- SectionInfo sectionInfo;
- Counts assertions;
- double durationInSeconds;
- bool missingAssertions;
- };
-
- struct TestCaseStats {
- TestCaseStats( TestCaseInfo const& _testInfo,
- Totals const& _totals,
- std::string const& _stdOut,
- std::string const& _stdErr,
- bool _aborting )
- : testInfo( _testInfo ),
- totals( _totals ),
- stdOut( _stdOut ),
- stdErr( _stdErr ),
- aborting( _aborting )
- {}
- virtual ~TestCaseStats();
-
-# ifdef CATCH_CPP11_OR_GREATER
- TestCaseStats( TestCaseStats const& ) = default;
- TestCaseStats( TestCaseStats && ) = default;
- TestCaseStats& operator = ( TestCaseStats const& ) = default;
- TestCaseStats& operator = ( TestCaseStats && ) = default;
-# endif
-
- TestCaseInfo testInfo;
- Totals totals;
- std::string stdOut;
- std::string stdErr;
- bool aborting;
- };
-
- struct TestGroupStats {
- TestGroupStats( GroupInfo const& _groupInfo,
- Totals const& _totals,
- bool _aborting )
- : groupInfo( _groupInfo ),
- totals( _totals ),
- aborting( _aborting )
- {}
- TestGroupStats( GroupInfo const& _groupInfo )
- : groupInfo( _groupInfo ),
- aborting( false )
- {}
- virtual ~TestGroupStats();
-
-# ifdef CATCH_CPP11_OR_GREATER
- TestGroupStats( TestGroupStats const& ) = default;
- TestGroupStats( TestGroupStats && ) = default;
- TestGroupStats& operator = ( TestGroupStats const& ) = default;
- TestGroupStats& operator = ( TestGroupStats && ) = default;
-# endif
-
- GroupInfo groupInfo;
- Totals totals;
- bool aborting;
- };
-
- struct TestRunStats {
- TestRunStats( TestRunInfo const& _runInfo,
- Totals const& _totals,
- bool _aborting )
- : runInfo( _runInfo ),
- totals( _totals ),
- aborting( _aborting )
- {}
- virtual ~TestRunStats();
-
-# ifndef CATCH_CPP11_OR_GREATER
- TestRunStats( TestRunStats const& _other )
- : runInfo( _other.runInfo ),
- totals( _other.totals ),
- aborting( _other.aborting )
- {}
-# else
- TestRunStats( TestRunStats const& ) = default;
- TestRunStats( TestRunStats && ) = default;
- TestRunStats& operator = ( TestRunStats const& ) = default;
- TestRunStats& operator = ( TestRunStats && ) = default;
-# endif
-
- TestRunInfo runInfo;
- Totals totals;
- bool aborting;
- };
-
- struct IStreamingReporter : IShared {
- virtual ~IStreamingReporter();
-
- // Implementing class must also provide the following static method:
- // static std::string getDescription();
-
- virtual ReporterPreferences getPreferences() const = 0;
-
- virtual void noMatchingTestCases( std::string const& spec ) = 0;
-
- virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
- virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
-
- virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
- virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
-
- virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
-
- virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
- virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
- virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
- virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
- virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
- };
-
- struct IReporterFactory {
- virtual ~IReporterFactory();
- virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
- virtual std::string getDescription() const = 0;
- };
-
- struct IReporterRegistry {
- typedef std::map<std::string, IReporterFactory*> FactoryMap;
-
- virtual ~IReporterRegistry();
- virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const = 0;
- virtual FactoryMap const& getFactories() const = 0;
- };
-
-}
-
-#include <limits>
-#include <algorithm>
-
-namespace Catch {
-
- inline std::size_t listTests( Config const& config ) {
-
- TestSpec testSpec = config.testSpec();
- if( config.testSpec().hasFilters() )
- std::cout << "Matching test cases:\n";
- else {
- std::cout << "All available test cases:\n";
- testSpec = TestSpecParser().parse( "*" ).testSpec();
- }
-
- std::size_t matchedTests = 0;
- TextAttributes nameAttr, tagsAttr;
- nameAttr.setInitialIndent( 2 ).setIndent( 4 );
- tagsAttr.setIndent( 6 );
-
- std::vector<TestCase> matchedTestCases;
- getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
- for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
- it != itEnd;
- ++it ) {
- matchedTests++;
- TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
- Colour::Code colour = testCaseInfo.isHidden
- ? Colour::SecondaryText
- : Colour::None;
- Colour colourGuard( colour );
-
- std::cout << Text( testCaseInfo.name, nameAttr ) << std::endl;
- if( !testCaseInfo.tags.empty() )
- std::cout << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
- }
-
- if( !config.testSpec().hasFilters() )
- std::cout << pluralise( matchedTests, "test case" ) << "\n" << std::endl;
- else
- std::cout << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl;
- return matchedTests;
- }
-
- inline std::size_t listTestsNamesOnly( Config const& config ) {
- TestSpec testSpec = config.testSpec();
- if( !config.testSpec().hasFilters() )
- testSpec = TestSpecParser().parse( "*" ).testSpec();
- std::size_t matchedTests = 0;
- std::vector<TestCase> matchedTestCases;
- getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
- for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
- it != itEnd;
- ++it ) {
- matchedTests++;
- TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
- std::cout << testCaseInfo.name << std::endl;
- }
- return matchedTests;
- }
-
- inline std::size_t listTags( Config const& config ) {
- TestSpec testSpec = config.testSpec();
- if( config.testSpec().hasFilters() )
- std::cout << "Tags for matching test cases:\n";
- else {
- std::cout << "All available tags:\n";
- testSpec = TestSpecParser().parse( "*" ).testSpec();
- }
-
- std::map<std::string, int> tagCounts;
-
- std::vector<TestCase> matchedTestCases;
- getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
- for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
- it != itEnd;
- ++it ) {
- for( std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(),
- tagItEnd = it->getTestCaseInfo().tags.end();
- tagIt != tagItEnd;
- ++tagIt ) {
- std::string tagName = *tagIt;
- std::map<std::string, int>::iterator countIt = tagCounts.find( tagName );
- if( countIt == tagCounts.end() )
- tagCounts.insert( std::make_pair( tagName, 1 ) );
- else
- countIt->second++;
- }
- }
-
- for( std::map<std::string, int>::const_iterator countIt = tagCounts.begin(),
- countItEnd = tagCounts.end();
- countIt != countItEnd;
- ++countIt ) {
- std::ostringstream oss;
- oss << " " << countIt->second << " ";
- Text wrapper( "[" + countIt->first + "]", TextAttributes()
- .setInitialIndent( 0 )
- .setIndent( oss.str().size() )
- .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
- std::cout << oss.str() << wrapper << "\n";
- }
- std::cout << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl;
- return tagCounts.size();
- }
-
- inline std::size_t listReporters( Config const& /*config*/ ) {
- std::cout << "Available reports:\n";
- IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
- IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
- std::size_t maxNameLen = 0;
- for(it = itBegin; it != itEnd; ++it )
- maxNameLen = (std::max)( maxNameLen, it->first.size() );
-
- for(it = itBegin; it != itEnd; ++it ) {
- Text wrapper( it->second->getDescription(), TextAttributes()
- .setInitialIndent( 0 )
- .setIndent( 7+maxNameLen )
- .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
- std::cout << " "
- << it->first
- << ":"
- << std::string( maxNameLen - it->first.size() + 2, ' ' )
- << wrapper << "\n";
- }
- std::cout << std::endl;
- return factories.size();
- }
-
- inline Option<std::size_t> list( Config const& config ) {
- Option<std::size_t> listedCount;
- if( config.listTests() )
- listedCount = listedCount.valueOr(0) + listTests( config );
- if( config.listTestNamesOnly() )
- listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
- if( config.listTags() )
- listedCount = listedCount.valueOr(0) + listTags( config );
- if( config.listReporters() )
- listedCount = listedCount.valueOr(0) + listReporters( config );
- return listedCount;
- }
-
-} // end namespace Catch
-
-// #included from: internal/catch_runner_impl.hpp
-#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
-
-// #included from: catch_test_case_tracker.hpp
-#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
-
-#include <map>
-#include <string>
-#include <assert.h>
-
-namespace Catch {
-namespace SectionTracking {
-
- class TrackedSection {
-
- typedef std::map<std::string, TrackedSection> TrackedSections;
-
- public:
- enum RunState {
- NotStarted,
- Executing,
- ExecutingChildren,
- Completed
- };
-
- TrackedSection( std::string const& name, TrackedSection* parent )
- : m_name( name ), m_runState( NotStarted ), m_parent( parent )
- {}
-
- RunState runState() const { return m_runState; }
-
- TrackedSection* findChild( std::string const& childName ) {
- TrackedSections::iterator it = m_children.find( childName );
- return it != m_children.end()
- ? &it->second
- : NULL;
- }
- TrackedSection* acquireChild( std::string const& childName ) {
- if( TrackedSection* child = findChild( childName ) )
- return child;
- m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) );
- return findChild( childName );
- }
- void enter() {
- if( m_runState == NotStarted )
- m_runState = Executing;
- }
- void leave() {
- for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end();
- it != itEnd;
- ++it )
- if( it->second.runState() != Completed ) {
- m_runState = ExecutingChildren;
- return;
- }
- m_runState = Completed;
- }
- TrackedSection* getParent() {
- return m_parent;
- }
- bool hasChildren() const {
- return !m_children.empty();
- }
-
- private:
- std::string m_name;
- RunState m_runState;
- TrackedSections m_children;
- TrackedSection* m_parent;
-
- };
-
- class TestCaseTracker {
- public:
- TestCaseTracker( std::string const& testCaseName )
- : m_testCase( testCaseName, NULL ),
- m_currentSection( &m_testCase ),
- m_completedASectionThisRun( false )
- {}
-
- bool enterSection( std::string const& name ) {
- TrackedSection* child = m_currentSection->acquireChild( name );
- if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed )
- return false;
-
- m_currentSection = child;
- m_currentSection->enter();
- return true;
- }
- void leaveSection() {
- m_currentSection->leave();
- m_currentSection = m_currentSection->getParent();
- assert( m_currentSection != NULL );
- m_completedASectionThisRun = true;
- }
-
- bool currentSectionHasChildren() const {
- return m_currentSection->hasChildren();
- }
- bool isCompleted() const {
- return m_testCase.runState() == TrackedSection::Completed;
- }
-
- class Guard {
- public:
- Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) {
- m_tracker.enterTestCase();
- }
- ~Guard() {
- m_tracker.leaveTestCase();
- }
- private:
- Guard( Guard const& );
- void operator = ( Guard const& );
- TestCaseTracker& m_tracker;
- };
-
- private:
- void enterTestCase() {
- m_currentSection = &m_testCase;
- m_completedASectionThisRun = false;
- m_testCase.enter();
- }
- void leaveTestCase() {
- m_testCase.leave();
- }
-
- TrackedSection m_testCase;
- TrackedSection* m_currentSection;
- bool m_completedASectionThisRun;
- };
-
-} // namespace SectionTracking
-
-using SectionTracking::TestCaseTracker;
-
-} // namespace Catch
-
-#include <set>
-#include <string>
-
-namespace Catch {
-
- class StreamRedirect {
-
- public:
- StreamRedirect( std::ostream& stream, std::string& targetString )
- : m_stream( stream ),
- m_prevBuf( stream.rdbuf() ),
- m_targetString( targetString )
- {
- stream.rdbuf( m_oss.rdbuf() );
- }
-
- ~StreamRedirect() {
- m_targetString += m_oss.str();
- m_stream.rdbuf( m_prevBuf );
- }
-
- private:
- std::ostream& m_stream;
- std::streambuf* m_prevBuf;
- std::ostringstream m_oss;
- std::string& m_targetString;
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- class RunContext : public IResultCapture, public IRunner {
-
- RunContext( RunContext const& );
- void operator =( RunContext const& );
-
- public:
-
- explicit RunContext( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> const& reporter )
- : m_runInfo( config->name() ),
- m_context( getCurrentMutableContext() ),
- m_activeTestCase( NULL ),
- m_config( config ),
- m_reporter( reporter ),
- m_prevRunner( &m_context.getRunner() ),
- m_prevResultCapture( &m_context.getResultCapture() ),
- m_prevConfig( m_context.getConfig() )
- {
- m_context.setRunner( this );
- m_context.setConfig( m_config );
- m_context.setResultCapture( this );
- m_reporter->testRunStarting( m_runInfo );
- }
-
- virtual ~RunContext() {
- m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
- m_context.setRunner( m_prevRunner );
- m_context.setConfig( NULL );
- m_context.setResultCapture( m_prevResultCapture );
- m_context.setConfig( m_prevConfig );
- }
-
- void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
- m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) );
- }
- void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) {
- m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) );
- }
-
- Totals runTest( TestCase const& testCase ) {
- Totals prevTotals = m_totals;
-
- std::string redirectedCout;
- std::string redirectedCerr;
-
- TestCaseInfo testInfo = testCase.getTestCaseInfo();
-
- m_reporter->testCaseStarting( testInfo );
-
- m_activeTestCase = &testCase;
- m_testCaseTracker = TestCaseTracker( testInfo.name );
-
- do {
- do {
- runCurrentTest( redirectedCout, redirectedCerr );
- }
- while( !m_testCaseTracker->isCompleted() && !aborting() );
- }
- while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
-
- Totals deltaTotals = m_totals.delta( prevTotals );
- m_totals.testCases += deltaTotals.testCases;
- m_reporter->testCaseEnded( TestCaseStats( testInfo,
- deltaTotals,
- redirectedCout,
- redirectedCerr,
- aborting() ) );
-
- m_activeTestCase = NULL;
- m_testCaseTracker.reset();
-
- return deltaTotals;
- }
-
- Ptr<IConfig const> config() const {
- return m_config;
- }
-
- private: // IResultCapture
-
- virtual ResultAction::Value acceptExpression( ExpressionResultBuilder const& assertionResult, AssertionInfo const& assertionInfo ) {
- m_lastAssertionInfo = assertionInfo;
- return actOnCurrentResult( assertionResult.buildResult( assertionInfo ) );
- }
-
- virtual void assertionEnded( AssertionResult const& result ) {
- if( result.getResultType() == ResultWas::Ok ) {
- m_totals.assertions.passed++;
- }
- else if( !result.isOk() ) {
- m_totals.assertions.failed++;
- }
-
- if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) )
- m_messages.clear();
-
- // Reset working state
- m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
- }
-
- virtual bool sectionStarted (
- SectionInfo const& sectionInfo,
- Counts& assertions
- )
- {
- std::ostringstream oss;
- oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
-
- if( !m_testCaseTracker->enterSection( oss.str() ) )
- return false;
-
- m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
-
- m_reporter->sectionStarting( sectionInfo );
-
- assertions = m_totals.assertions;
-
- return true;
- }
- bool testForMissingAssertions( Counts& assertions ) {
- if( assertions.total() != 0 ||
- !m_config->warnAboutMissingAssertions() ||
- m_testCaseTracker->currentSectionHasChildren() )
- return false;
- m_totals.assertions.failed++;
- assertions.failed++;
- return true;
- }
-
- virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) {
- if( std::uncaught_exception() ) {
- m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) );
- return;
- }
-
- Counts assertions = m_totals.assertions - prevAssertions;
- bool missingAssertions = testForMissingAssertions( assertions );
-
- m_testCaseTracker->leaveSection();
-
- m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) );
- m_messages.clear();
- }
-
- virtual void pushScopedMessage( MessageInfo const& message ) {
- m_messages.push_back( message );
- }
-
- virtual void popScopedMessage( MessageInfo const& message ) {
- m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() );
- }
-
- virtual bool shouldDebugBreak() const {
- return m_config->shouldDebugBreak();
- }
-
- virtual std::string getCurrentTestName() const {
- return m_activeTestCase
- ? m_activeTestCase->getTestCaseInfo().name
- : "";
- }
-
- virtual const AssertionResult* getLastResult() const {
- return &m_lastResult;
- }
-
- public:
- // !TBD We need to do this another way!
- bool aborting() const {
- return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() );
- }
-
- private:
-
- ResultAction::Value actOnCurrentResult( AssertionResult const& result ) {
- m_lastResult = result;
- assertionEnded( m_lastResult );
-
- ResultAction::Value action = ResultAction::None;
-
- if( !m_lastResult.isOk() ) {
- action = ResultAction::Failed;
- if( shouldDebugBreak() )
- action = (ResultAction::Value)( action | ResultAction::Debug );
- if( aborting() )
- action = (ResultAction::Value)( action | ResultAction::Abort );
- }
- return action;
- }
-
- void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
- TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
- SectionInfo testCaseSection( testCaseInfo.name, testCaseInfo.description, testCaseInfo.lineInfo );
- m_reporter->sectionStarting( testCaseSection );
- Counts prevAssertions = m_totals.assertions;
- double duration = 0;
- try {
- m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
- TestCaseTracker::Guard guard( *m_testCaseTracker );
-
- Timer timer;
- timer.start();
- if( m_reporter->getPreferences().shouldRedirectStdOut ) {
- StreamRedirect coutRedir( std::cout, redirectedCout );
- StreamRedirect cerrRedir( std::cerr, redirectedCerr );
- m_activeTestCase->invoke();
- }
- else {
- m_activeTestCase->invoke();
- }
- duration = timer.getElapsedSeconds();
- }
- catch( TestFailureException& ) {
- // This just means the test was aborted due to failure
- }
- catch(...) {
- ExpressionResultBuilder exResult( ResultWas::ThrewException );
- exResult << translateActiveException();
- actOnCurrentResult( exResult.buildResult( m_lastAssertionInfo ) );
- }
- // If sections ended prematurely due to an exception we stored their
- // infos here so we can tear them down outside the unwind process.
- for( std::vector<UnfinishedSections>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
- itEnd = m_unfinishedSections.rend();
- it != itEnd;
- ++it )
- sectionEnded( it->info, it->prevAssertions, it->durationInSeconds );
- m_unfinishedSections.clear();
- m_messages.clear();
-
- Counts assertions = m_totals.assertions - prevAssertions;
- bool missingAssertions = testForMissingAssertions( assertions );
-
- SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
- m_reporter->sectionEnded( testCaseSectionStats );
- }
-
- private:
- struct UnfinishedSections {
- UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds )
- : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
- {}
-
- SectionInfo info;
- Counts prevAssertions;
- double durationInSeconds;
- };
-
- TestRunInfo m_runInfo;
- IMutableContext& m_context;
- TestCase const* m_activeTestCase;
- Option<TestCaseTracker> m_testCaseTracker;
- AssertionResult m_lastResult;
-
- Ptr<IConfig const> m_config;
- Totals m_totals;
- Ptr<IStreamingReporter> m_reporter;
- std::vector<MessageInfo> m_messages;
- IRunner* m_prevRunner;
- IResultCapture* m_prevResultCapture;
- Ptr<IConfig const> m_prevConfig;
- AssertionInfo m_lastAssertionInfo;
- std::vector<UnfinishedSections> m_unfinishedSections;
- };
-
-} // end namespace Catch
-
-// #included from: internal/catch_version.h
-#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED
-
-namespace Catch {
-
- // Versioning information
- struct Version {
- Version( unsigned int _majorVersion,
- unsigned int _minorVersion,
- unsigned int _buildNumber,
- char const* const _branchName )
- : majorVersion( _majorVersion ),
- minorVersion( _minorVersion ),
- buildNumber( _buildNumber ),
- branchName( _branchName )
- {}
-
- unsigned int const majorVersion;
- unsigned int const minorVersion;
- unsigned int const buildNumber;
- char const* const branchName;
-
- private:
- void operator=( Version const& );
- };
-
- extern Version libraryVersion;
-}
-
-#include <fstream>
-#include <stdlib.h>
-#include <limits>
-
-namespace Catch {
-
- class Runner {
-
- public:
- Runner( Ptr<Config> const& config )
- : m_config( config )
- {
- openStream();
- makeReporter();
- }
-
- Totals runTests() {
-
- RunContext context( m_config.get(), m_reporter );
-
- Totals totals;
-
- context.testGroupStarting( "", 1, 1 ); // deprecated?
-
- TestSpec testSpec = m_config->testSpec();
- if( !testSpec.hasFilters() )
- testSpec = TestSpecParser().parse( "~[.]" ).testSpec(); // All not hidden tests
-
- std::vector<TestCase> testCases;
- getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases );
-
- int testsRunForGroup = 0;
- for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
- it != itEnd;
- ++it ) {
- testsRunForGroup++;
- if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) {
-
- if( context.aborting() )
- break;
-
- totals += context.runTest( *it );
- m_testsAlreadyRun.insert( *it );
- }
- }
- context.testGroupEnded( "", totals, 1, 1 );
- return totals;
- }
-
- private:
- void openStream() {
- // Open output file, if specified
- if( !m_config->getFilename().empty() ) {
- m_ofs.open( m_config->getFilename().c_str() );
- if( m_ofs.fail() ) {
- std::ostringstream oss;
- oss << "Unable to open file: '" << m_config->getFilename() << "'";
- throw std::domain_error( oss.str() );
- }
- m_config->setStreamBuf( m_ofs.rdbuf() );
- }
- }
- void makeReporter() {
- std::string reporterName = m_config->getReporterName().empty()
- ? "console"
- : m_config->getReporterName();
-
- m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() );
- if( !m_reporter ) {
- std::ostringstream oss;
- oss << "No reporter registered with name: '" << reporterName << "'";
- throw std::domain_error( oss.str() );
- }
- }
-
- private:
- Ptr<Config> m_config;
- std::ofstream m_ofs;
- Ptr<IStreamingReporter> m_reporter;
- std::set<TestCase> m_testsAlreadyRun;
- };
-
- class Session {
- static bool alreadyInstantiated;
-
- public:
-
- struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; };
-
- Session()
- : m_cli( makeCommandLineParser() ) {
- if( alreadyInstantiated ) {
- std::string msg = "Only one instance of Catch::Session can ever be used";
- std::cerr << msg << std::endl;
- throw std::logic_error( msg );
- }
- alreadyInstantiated = true;
- }
- ~Session() {
- Catch::cleanUp();
- }
-
- void showHelp( std::string const& processName ) {
- std::cout << "\nCatch v" << libraryVersion.majorVersion << "."
- << libraryVersion.minorVersion << " build "
- << libraryVersion.buildNumber;
- if( libraryVersion.branchName != std::string( "master" ) )
- std::cout << " (" << libraryVersion.branchName << " branch)";
- std::cout << "\n";
-
- m_cli.usage( std::cout, processName );
- std::cout << "For more detail usage please see the project docs\n" << std::endl;
- }
-
- int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
- try {
- m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
- m_unusedTokens = m_cli.parseInto( argc, argv, m_configData );
- if( m_configData.showHelp )
- showHelp( m_configData.processName );
- m_config.reset();
- }
- catch( std::exception& ex ) {
- {
- Colour colourGuard( Colour::Red );
- std::cerr << "\nError(s) in input:\n"
- << Text( ex.what(), TextAttributes().setIndent(2) )
- << "\n\n";
- }
- m_cli.usage( std::cout, m_configData.processName );
- return (std::numeric_limits<int>::max)();
- }
- return 0;
- }
-
- void useConfigData( ConfigData const& _configData ) {
- m_configData = _configData;
- m_config.reset();
- }
-
- int run( int argc, char* const argv[] ) {
-
- int returnCode = applyCommandLine( argc, argv );
- if( returnCode == 0 )
- returnCode = run();
- return returnCode;
- }
-
- int run() {
- if( m_configData.showHelp )
- return 0;
-
- try
- {
- config(); // Force config to be constructed
- Runner runner( m_config );
-
- // Handle list request
- if( Option<std::size_t> listed = list( config() ) )
- return static_cast<int>( *listed );
-
- return static_cast<int>( runner.runTests().assertions.failed );
- }
- catch( std::exception& ex ) {
- std::cerr << ex.what() << std::endl;
- return (std::numeric_limits<int>::max)();
- }
- }
-
- Clara::CommandLine<ConfigData> const& cli() const {
- return m_cli;
- }
- std::vector<Clara::Parser::Token> const& unusedTokens() const {
- return m_unusedTokens;
- }
- ConfigData& configData() {
- return m_configData;
- }
- Config& config() {
- if( !m_config )
- m_config = new Config( m_configData );
- return *m_config;
- }
-
- private:
- Clara::CommandLine<ConfigData> m_cli;
- std::vector<Clara::Parser::Token> m_unusedTokens;
- ConfigData m_configData;
- Ptr<Config> m_config;
- };
-
- bool Session::alreadyInstantiated = false;
-
-} // end namespace Catch
-
-// #included from: catch_registry_hub.hpp
-#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
-
-// #included from: catch_test_case_registry_impl.hpp
-#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
-
-#include <vector>
-#include <set>
-#include <sstream>
-#include <iostream>
-
-namespace Catch {
-
- class TestRegistry : public ITestCaseRegistry {
- public:
- TestRegistry() : m_unnamedCount( 0 ) {}
- virtual ~TestRegistry();
-
- virtual void registerTest( TestCase const& testCase ) {
- std::string name = testCase.getTestCaseInfo().name;
- if( name == "" ) {
- std::ostringstream oss;
- oss << "Anonymous test case " << ++m_unnamedCount;
- return registerTest( testCase.withName( oss.str() ) );
- }
-
- if( m_functions.find( testCase ) == m_functions.end() ) {
- m_functions.insert( testCase );
- m_functionsInOrder.push_back( testCase );
- if( !testCase.isHidden() )
- m_nonHiddenFunctions.push_back( testCase );
- }
- else {
- TestCase const& prev = *m_functions.find( testCase );
- {
- Colour colourGuard( Colour::Red );
- std::cerr << "error: TEST_CASE( \"" << name << "\" ) already defined.\n"
- << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n"
- << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl;
- }
- exit(1);
- }
- }
-
- virtual std::vector<TestCase> const& getAllTests() const {
- return m_functionsInOrder;
- }
-
- virtual std::vector<TestCase> const& getAllNonHiddenTests() const {
- return m_nonHiddenFunctions;
- }
-
- virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases ) const {
- for( std::vector<TestCase>::const_iterator it = m_functionsInOrder.begin(),
- itEnd = m_functionsInOrder.end();
- it != itEnd;
- ++it ) {
- if( testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ) )
- matchingTestCases.push_back( *it );
- }
- }
-
- private:
-
- std::set<TestCase> m_functions;
- std::vector<TestCase> m_functionsInOrder;
- std::vector<TestCase> m_nonHiddenFunctions;
- size_t m_unnamedCount;
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- class FreeFunctionTestCase : public SharedImpl<ITestCase> {
- public:
-
- FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {}
-
- virtual void invoke() const {
- m_fun();
- }
-
- private:
- virtual ~FreeFunctionTestCase();
-
- TestFunction m_fun;
- };
-
- inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
- std::string className = classOrQualifiedMethodName;
- if( startsWith( className, "&" ) )
- {
- std::size_t lastColons = className.rfind( "::" );
- std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
- if( penultimateColons == std::string::npos )
- penultimateColons = 1;
- className = className.substr( penultimateColons, lastColons-penultimateColons );
- }
- return className;
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
- AutoReg::AutoReg( TestFunction function,
- SourceLineInfo const& lineInfo,
- NameAndDesc const& nameAndDesc ) {
- registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo );
- }
-
- AutoReg::~AutoReg() {}
-
- void AutoReg::registerTestCase( ITestCase* testCase,
- char const* classOrQualifiedMethodName,
- NameAndDesc const& nameAndDesc,
- SourceLineInfo const& lineInfo ) {
-
- getMutableRegistryHub().registerTest
- ( makeTestCase( testCase,
- extractClassName( classOrQualifiedMethodName ),
- nameAndDesc.name,
- nameAndDesc.description,
- lineInfo ) );
- }
-
-} // end namespace Catch
-
-// #included from: catch_reporter_registry.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
-
-#include <map>
-
-namespace Catch {
-
- class ReporterRegistry : public IReporterRegistry {
-
- public:
-
- virtual ~ReporterRegistry() {
- deleteAllValues( m_factories );
- }
-
- virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const {
- FactoryMap::const_iterator it = m_factories.find( name );
- if( it == m_factories.end() )
- return NULL;
- return it->second->create( ReporterConfig( config ) );
- }
-
- void registerReporter( std::string const& name, IReporterFactory* factory ) {
- m_factories.insert( std::make_pair( name, factory ) );
- }
-
- FactoryMap const& getFactories() const {
- return m_factories;
- }
-
- private:
- FactoryMap m_factories;
- };
-}
-
-// #included from: catch_exception_translator_registry.hpp
-#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
-
-#ifdef __OBJC__
-#import "Foundation/Foundation.h"
-#endif
-
-namespace Catch {
-
- class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
- public:
- ~ExceptionTranslatorRegistry() {
- deleteAll( m_translators );
- }
-
- virtual void registerTranslator( const IExceptionTranslator* translator ) {
- m_translators.push_back( translator );
- }
-
- virtual std::string translateActiveException() const {
- try {
-#ifdef __OBJC__
- // In Objective-C try objective-c exceptions first
- @try {
- throw;
- }
- @catch (NSException *exception) {
- return toString( [exception description] );
- }
-#else
- throw;
-#endif
- }
- catch( std::exception& ex ) {
- return ex.what();
- }
- catch( std::string& msg ) {
- return msg;
- }
- catch( const char* msg ) {
- return msg;
- }
- catch(...) {
- return tryTranslators( m_translators.begin() );
- }
- }
-
- std::string tryTranslators( std::vector<const IExceptionTranslator*>::const_iterator it ) const {
- if( it == m_translators.end() )
- return "Unknown exception";
-
- try {
- return (*it)->translate();
- }
- catch(...) {
- return tryTranslators( it+1 );
- }
- }
-
- private:
- std::vector<const IExceptionTranslator*> m_translators;
- };
-}
-
-namespace Catch {
-
- namespace {
-
- class RegistryHub : public IRegistryHub, public IMutableRegistryHub {
-
- RegistryHub( RegistryHub const& );
- void operator=( RegistryHub const& );
-
- public: // IRegistryHub
- RegistryHub() {
- }
- virtual IReporterRegistry const& getReporterRegistry() const {
- return m_reporterRegistry;
- }
- virtual ITestCaseRegistry const& getTestCaseRegistry() const {
- return m_testCaseRegistry;
- }
- virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() {
- return m_exceptionTranslatorRegistry;
- }
-
- public: // IMutableRegistryHub
- virtual void registerReporter( std::string const& name, IReporterFactory* factory ) {
- m_reporterRegistry.registerReporter( name, factory );
- }
- virtual void registerTest( TestCase const& testInfo ) {
- m_testCaseRegistry.registerTest( testInfo );
- }
- virtual void registerTranslator( const IExceptionTranslator* translator ) {
- m_exceptionTranslatorRegistry.registerTranslator( translator );
- }
-
- private:
- TestRegistry m_testCaseRegistry;
- ReporterRegistry m_reporterRegistry;
- ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
- };
-
- // Single, global, instance
- inline RegistryHub*& getTheRegistryHub() {
- static RegistryHub* theRegistryHub = NULL;
- if( !theRegistryHub )
- theRegistryHub = new RegistryHub();
- return theRegistryHub;
- }
- }
-
- IRegistryHub& getRegistryHub() {
- return *getTheRegistryHub();
- }
- IMutableRegistryHub& getMutableRegistryHub() {
- return *getTheRegistryHub();
- }
- void cleanUp() {
- delete getTheRegistryHub();
- getTheRegistryHub() = NULL;
- cleanUpContext();
- }
- std::string translateActiveException() {
- return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
- }
-
-} // end namespace Catch
-
-// #included from: catch_notimplemented_exception.hpp
-#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
-
-#include <ostream>
-
-namespace Catch {
-
- NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo )
- : m_lineInfo( lineInfo ) {
- std::ostringstream oss;
- oss << lineInfo << ": function ";
- oss << "not implemented";
- m_what = oss.str();
- }
-
- const char* NotImplementedException::what() const CATCH_NOEXCEPT {
- return m_what.c_str();
- }
-
-} // end namespace Catch
-
-// #included from: catch_context_impl.hpp
-#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
-
-// #included from: catch_stream.hpp
-#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
-
-// #included from: catch_streambuf.h
-#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
-
-#include <streambuf>
-
-namespace Catch {
-
- class StreamBufBase : public std::streambuf {
- public:
- virtual ~StreamBufBase() CATCH_NOEXCEPT;
- };
-}
-
-#include <stdexcept>
-#include <cstdio>
-
-namespace Catch {
-
- template<typename WriterF, size_t bufferSize=256>
- class StreamBufImpl : public StreamBufBase {
- char data[bufferSize];
- WriterF m_writer;
-
- public:
- StreamBufImpl() {
- setp( data, data + sizeof(data) );
- }
-
- ~StreamBufImpl() CATCH_NOEXCEPT {
- sync();
- }
-
- private:
- int overflow( int c ) {
- sync();
-
- if( c != EOF ) {
- if( pbase() == epptr() )
- m_writer( std::string( 1, static_cast<char>( c ) ) );
- else
- sputc( static_cast<char>( c ) );
- }
- return 0;
- }
-
- int sync() {
- if( pbase() != pptr() ) {
- m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
- setp( pbase(), epptr() );
- }
- return 0;
- }
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- struct OutputDebugWriter {
-
- void operator()( std::string const&str ) {
- writeToDebugConsole( str );
- }
- };
-
- Stream::Stream()
- : streamBuf( NULL ), isOwned( false )
- {}
-
- Stream::Stream( std::streambuf* _streamBuf, bool _isOwned )
- : streamBuf( _streamBuf ), isOwned( _isOwned )
- {}
-
- void Stream::release() {
- if( isOwned ) {
- delete streamBuf;
- streamBuf = NULL;
- isOwned = false;
- }
- }
-}
-
-namespace Catch {
-
- class Context : public IMutableContext {
-
- Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {}
- Context( Context const& );
- void operator=( Context const& );
-
- public: // IContext
- virtual IResultCapture& getResultCapture() {
- return *m_resultCapture;
- }
- virtual IRunner& getRunner() {
- return *m_runner;
- }
- virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) {
- return getGeneratorsForCurrentTest()
- .getGeneratorInfo( fileInfo, totalSize )
- .getCurrentIndex();
- }
- virtual bool advanceGeneratorsForCurrentTest() {
- IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
- return generators && generators->moveNext();
- }
-
- virtual Ptr<IConfig const> getConfig() const {
- return m_config;
- }
-
- public: // IMutableContext
- virtual void setResultCapture( IResultCapture* resultCapture ) {
- m_resultCapture = resultCapture;
- }
- virtual void setRunner( IRunner* runner ) {
- m_runner = runner;
- }
- virtual void setConfig( Ptr<IConfig const> const& config ) {
- m_config = config;
- }
-
- friend IMutableContext& getCurrentMutableContext();
-
- private:
- IGeneratorsForTest* findGeneratorsForCurrentTest() {
- std::string testName = getResultCapture().getCurrentTestName();
-
- std::map<std::string, IGeneratorsForTest*>::const_iterator it =
- m_generatorsByTestName.find( testName );
- return it != m_generatorsByTestName.end()
- ? it->second
- : NULL;
- }
-
- IGeneratorsForTest& getGeneratorsForCurrentTest() {
- IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
- if( !generators ) {
- std::string testName = getResultCapture().getCurrentTestName();
- generators = createGeneratorsForTest();
- m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
- }
- return *generators;
- }
-
- private:
- Ptr<IConfig const> m_config;
- IRunner* m_runner;
- IResultCapture* m_resultCapture;
- std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
- };
-
- namespace {
- Context* currentContext = NULL;
- }
- IMutableContext& getCurrentMutableContext() {
- if( !currentContext )
- currentContext = new Context();
- return *currentContext;
- }
- IContext& getCurrentContext() {
- return getCurrentMutableContext();
- }
-
- Stream createStream( std::string const& streamName ) {
- if( streamName == "stdout" ) return Stream( std::cout.rdbuf(), false );
- if( streamName == "stderr" ) return Stream( std::cerr.rdbuf(), false );
- if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true );
-
- throw std::domain_error( "Unknown stream: " + streamName );
- }
-
- void cleanUpContext() {
- delete currentContext;
- currentContext = NULL;
- }
-}
-
-// #included from: catch_console_colour_impl.hpp
-#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
-
-namespace Catch { namespace Detail {
- struct IColourImpl {
- virtual ~IColourImpl() {}
- virtual void use( Colour::Code _colourCode ) = 0;
- };
-}}
-
-#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
-
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-
-#ifdef __AFXDLL
-#include <AfxWin.h>
-#else
-#include <windows.h>
-#endif
-
-namespace Catch {
-namespace {
-
- class Win32ColourImpl : public Detail::IColourImpl {
- public:
- Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
- {
- CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
- GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
- originalAttributes = csbiInfo.wAttributes;
- }
-
- virtual void use( Colour::Code _colourCode ) {
- switch( _colourCode ) {
- case Colour::None: return setTextAttribute( originalAttributes );
- case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
- case Colour::Red: return setTextAttribute( FOREGROUND_RED );
- case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );
- case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE );
- case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
- case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
- case Colour::Grey: return setTextAttribute( 0 );
-
- case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY );
- case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
- case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
- case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
-
- case Colour::Bright: throw std::logic_error( "not a colour" );
- }
- }
-
- private:
- void setTextAttribute( WORD _textAttribute ) {
- SetConsoleTextAttribute( stdoutHandle, _textAttribute );
- }
- HANDLE stdoutHandle;
- WORD originalAttributes;
- };
-
- inline bool shouldUseColourForPlatform() {
- return true;
- }
-
- static Detail::IColourImpl* platformColourInstance() {
- static Win32ColourImpl s_instance;
- return &s_instance;
- }
-
-} // end anon namespace
-} // end namespace Catch
-
-#else // Not Windows - assumed to be POSIX compatible //////////////////////////
-
-#include <unistd.h>
-
-namespace Catch {
-namespace {
-
- // use POSIX/ ANSI console terminal codes
- // Thanks to Adam Strzelecki for original contribution
- // (http://github.com/nanoant)
- // https://github.com/philsquared/Catch/pull/131
- class PosixColourImpl : public Detail::IColourImpl {
- public:
- virtual void use( Colour::Code _colourCode ) {
- switch( _colourCode ) {
- case Colour::None:
- case Colour::White: return setColour( "[0m" );
- case Colour::Red: return setColour( "[0;31m" );
- case Colour::Green: return setColour( "[0;32m" );
- case Colour::Blue: return setColour( "[0:34m" );
- case Colour::Cyan: return setColour( "[0;36m" );
- case Colour::Yellow: return setColour( "[0;33m" );
- case Colour::Grey: return setColour( "[1;30m" );
-
- case Colour::LightGrey: return setColour( "[0;37m" );
- case Colour::BrightRed: return setColour( "[1;31m" );
- case Colour::BrightGreen: return setColour( "[1;32m" );
- case Colour::BrightWhite: return setColour( "[1;37m" );
-
- case Colour::Bright: throw std::logic_error( "not a colour" );
- }
- }
- private:
- void setColour( const char* _escapeCode ) {
- std::cout << '\033' << _escapeCode;
- }
- };
-
- inline bool shouldUseColourForPlatform() {
- return isatty(STDOUT_FILENO);
- }
-
- static Detail::IColourImpl* platformColourInstance() {
- static PosixColourImpl s_instance;
- return &s_instance;
- }
-
-} // end anon namespace
-} // end namespace Catch
-
-#endif // not Windows
-
-namespace Catch {
-
- namespace {
- struct NoColourImpl : Detail::IColourImpl {
- void use( Colour::Code ) {}
-
- static IColourImpl* instance() {
- static NoColourImpl s_instance;
- return &s_instance;
- }
- };
- static bool shouldUseColour() {
- return shouldUseColourForPlatform() && !isDebuggerActive();
- }
- }
-
- Colour::Colour( Code _colourCode ){ use( _colourCode ); }
- Colour::~Colour(){ use( None ); }
- void Colour::use( Code _colourCode ) {
- impl()->use( _colourCode );
- }
-
- Detail::IColourImpl* Colour::impl() {
- return shouldUseColour()
- ? platformColourInstance()
- : NoColourImpl::instance();
- }
-
-} // end namespace Catch
-
-// #included from: catch_generators_impl.hpp
-#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
-
-#include <vector>
-#include <string>
-#include <map>
-
-namespace Catch {
-
- struct GeneratorInfo : IGeneratorInfo {
-
- GeneratorInfo( std::size_t size )
- : m_size( size ),
- m_currentIndex( 0 )
- {}
-
- bool moveNext() {
- if( ++m_currentIndex == m_size ) {
- m_currentIndex = 0;
- return false;
- }
- return true;
- }
-
- std::size_t getCurrentIndex() const {
- return m_currentIndex;
- }
-
- std::size_t m_size;
- std::size_t m_currentIndex;
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- class GeneratorsForTest : public IGeneratorsForTest {
-
- public:
- ~GeneratorsForTest() {
- deleteAll( m_generatorsInOrder );
- }
-
- IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) {
- std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
- if( it == m_generatorsByName.end() ) {
- IGeneratorInfo* info = new GeneratorInfo( size );
- m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
- m_generatorsInOrder.push_back( info );
- return *info;
- }
- return *it->second;
- }
-
- bool moveNext() {
- std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
- std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
- for(; it != itEnd; ++it ) {
- if( (*it)->moveNext() )
- return true;
- }
- return false;
- }
-
- private:
- std::map<std::string, IGeneratorInfo*> m_generatorsByName;
- std::vector<IGeneratorInfo*> m_generatorsInOrder;
- };
-
- IGeneratorsForTest* createGeneratorsForTest()
- {
- return new GeneratorsForTest();
- }
-
-} // end namespace Catch
-
-// #included from: catch_assertionresult.hpp
-#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
-
-namespace Catch {
-
- AssertionInfo::AssertionInfo( std::string const& _macroName,
- SourceLineInfo const& _lineInfo,
- std::string const& _capturedExpression,
- ResultDisposition::Flags _resultDisposition )
- : macroName( _macroName ),
- lineInfo( _lineInfo ),
- capturedExpression( _capturedExpression ),
- resultDisposition( _resultDisposition )
- {}
-
- AssertionResult::AssertionResult() {}
-
- AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
- : m_info( info ),
- m_resultData( data )
- {}
-
- AssertionResult::~AssertionResult() {}
-
- // Result was a success
- bool AssertionResult::succeeded() const {
- return Catch::isOk( m_resultData.resultType );
- }
-
- // Result was a success, or failure is suppressed
- bool AssertionResult::isOk() const {
- return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
- }
-
- ResultWas::OfType AssertionResult::getResultType() const {
- return m_resultData.resultType;
- }
-
- bool AssertionResult::hasExpression() const {
- return !m_info.capturedExpression.empty();
- }
-
- bool AssertionResult::hasMessage() const {
- return !m_resultData.message.empty();
- }
-
- std::string AssertionResult::getExpression() const {
- if( shouldNegate( m_info.resultDisposition ) )
- return "!" + m_info.capturedExpression;
- else
- return m_info.capturedExpression;
- }
- std::string AssertionResult::getExpressionInMacro() const {
- if( m_info.macroName.empty() )
- return m_info.capturedExpression;
- else
- return m_info.macroName + "( " + m_info.capturedExpression + " )";
- }
-
- bool AssertionResult::hasExpandedExpression() const {
- return hasExpression() && getExpandedExpression() != getExpression();
- }
-
- std::string AssertionResult::getExpandedExpression() const {
- return m_resultData.reconstructedExpression;
- }
-
- std::string AssertionResult::getMessage() const {
- return m_resultData.message;
- }
- SourceLineInfo AssertionResult::getSourceInfo() const {
- return m_info.lineInfo;
- }
-
- std::string AssertionResult::getTestMacroName() const {
- return m_info.macroName;
- }
-
-} // end namespace Catch
-
-// #included from: catch_expressionresult_builder.hpp
-#define TWOBLUECUBES_CATCH_EXPRESSIONRESULT_BUILDER_HPP_INCLUDED
-
-#include <assert.h>
-
-namespace Catch {
-
- ExpressionResultBuilder::ExpressionResultBuilder( ResultWas::OfType resultType ) {
- m_data.resultType = resultType;
- }
- ExpressionResultBuilder::ExpressionResultBuilder( ExpressionResultBuilder const& other )
- : m_data( other.m_data ),
- m_exprComponents( other.m_exprComponents )
- {
- m_stream << other.m_stream.str();
- }
- ExpressionResultBuilder& ExpressionResultBuilder::operator=(ExpressionResultBuilder const& other ) {
- m_data = other.m_data;
- m_exprComponents = other.m_exprComponents;
- m_stream.str("");
- m_stream << other.m_stream.str();
- return *this;
- }
- ExpressionResultBuilder& ExpressionResultBuilder::setResultType( ResultWas::OfType result ) {
- m_data.resultType = result;
- return *this;
- }
- ExpressionResultBuilder& ExpressionResultBuilder::setResultType( bool result ) {
- m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
- return *this;
- }
- ExpressionResultBuilder& ExpressionResultBuilder::endExpression( ResultDisposition::Flags resultDisposition ) {
- m_exprComponents.shouldNegate = shouldNegate( resultDisposition );
- return *this;
- }
- ExpressionResultBuilder& ExpressionResultBuilder::setLhs( std::string const& lhs ) {
- m_exprComponents.lhs = lhs;
- return *this;
- }
- ExpressionResultBuilder& ExpressionResultBuilder::setRhs( std::string const& rhs ) {
- m_exprComponents.rhs = rhs;
- return *this;
- }
- ExpressionResultBuilder& ExpressionResultBuilder::setOp( std::string const& op ) {
- m_exprComponents.op = op;
- return *this;
- }
- AssertionResult ExpressionResultBuilder::buildResult( AssertionInfo const& info ) const
- {
- assert( m_data.resultType != ResultWas::Unknown );
-
- AssertionResultData data = m_data;
-
- // Flip bool results if shouldNegate is set
- if( m_exprComponents.shouldNegate && data.resultType == ResultWas::Ok )
- data.resultType = ResultWas::ExpressionFailed;
- else if( m_exprComponents.shouldNegate && data.resultType == ResultWas::ExpressionFailed )
- data.resultType = ResultWas::Ok;
-
- data.message = m_stream.str();
- data.reconstructedExpression = reconstructExpression( info );
- if( m_exprComponents.shouldNegate ) {
- if( m_exprComponents.op == "" )
- data.reconstructedExpression = "!" + data.reconstructedExpression;
- else
- data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
- }
- return AssertionResult( info, data );
- }
- std::string ExpressionResultBuilder::reconstructExpression( AssertionInfo const& info ) const {
- if( m_exprComponents.op == "" )
- return m_exprComponents.lhs.empty() ? info.capturedExpression : m_exprComponents.op + m_exprComponents.lhs;
- else if( m_exprComponents.op == "matches" )
- return m_exprComponents.lhs + " " + m_exprComponents.rhs;
- else if( m_exprComponents.op != "!" ) {
- if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
- m_exprComponents.lhs.find("\n") == std::string::npos &&
- m_exprComponents.rhs.find("\n") == std::string::npos )
- return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
- else
- return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
- }
- else
- return "{can't expand - use " + info.macroName + "_FALSE( " + info.capturedExpression.substr(1) + " ) instead of " + info.macroName + "( " + info.capturedExpression + " ) for better diagnostics}";
- }
-
-} // end namespace Catch
-
-// #included from: catch_test_case_info.hpp
-#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
-
-namespace Catch {
-
- inline bool isSpecialTag( std::string const& tag ) {
- return tag == "." ||
- tag == "hide" ||
- tag == "!hide" ||
- tag == "!throws";
- }
- inline bool isReservedTag( std::string const& tag ) {
- return !isSpecialTag( tag ) && tag.size() > 0 && !isalnum( tag[0] );
- }
- inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
- if( isReservedTag( tag ) ) {
- {
- Colour colourGuard( Colour::Red );
- std::cerr
- << "Tag name [" << tag << "] not allowed.\n"
- << "Tag names starting with non alpha-numeric characters are reserved\n";
- }
- {
- Colour colourGuard( Colour::FileName );
- std::cerr << _lineInfo << std::endl;
- }
- exit(1);
- }
- }
-
- TestCase makeTestCase( ITestCase* _testCase,
- std::string const& _className,
- std::string const& _name,
- std::string const& _descOrTags,
- SourceLineInfo const& _lineInfo )
- {
- bool isHidden( startsWith( _name, "./" ) ); // Legacy support
-
- // Parse out tags
- std::set<std::string> tags;
- std::string desc, tag;
- bool inTag = false;
- for( std::size_t i = 0; i < _descOrTags.size(); ++i ) {
- char c = _descOrTags[i];
- if( !inTag ) {
- if( c == '[' )
- inTag = true;
- else
- desc += c;
- }
- else {
- if( c == ']' ) {
- enforceNotReservedTag( tag, _lineInfo );
-
- inTag = false;
- if( tag == "hide" || tag == "." ) {
- tags.insert( "hide" );
- tags.insert( "." );
- isHidden = true;
- }
- else {
- tags.insert( tag );
- }
- tag.clear();
- }
- else
- tag += c;
- }
- }
- TestCaseInfo info( _name, _className, desc, tags, isHidden, _lineInfo );
- return TestCase( _testCase, info );
- }
-
- TestCaseInfo::TestCaseInfo( std::string const& _name,
- std::string const& _className,
- std::string const& _description,
- std::set<std::string> const& _tags,
- bool _isHidden,
- SourceLineInfo const& _lineInfo )
- : name( _name ),
- className( _className ),
- description( _description ),
- tags( _tags ),
- lineInfo( _lineInfo ),
- isHidden( _isHidden ),
- throws( false )
- {
- std::ostringstream oss;
- for( std::set<std::string>::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) {
- oss << "[" << *it << "]";
- if( *it == "!throws" )
- throws = true;
- }
- tagsAsString = oss.str();
- }
-
- TestCaseInfo::TestCaseInfo( TestCaseInfo const& other )
- : name( other.name ),
- className( other.className ),
- description( other.description ),
- tags( other.tags ),
- tagsAsString( other.tagsAsString ),
- lineInfo( other.lineInfo ),
- isHidden( other.isHidden ),
- throws( other.throws )
- {}
-
- TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
-
- TestCase::TestCase( TestCase const& other )
- : TestCaseInfo( other ),
- test( other.test )
- {}
-
- TestCase TestCase::withName( std::string const& _newName ) const {
- TestCase other( *this );
- other.name = _newName;
- return other;
- }
-
- void TestCase::invoke() const {
- test->invoke();
- }
-
- bool TestCase::isHidden() const {
- return TestCaseInfo::isHidden;
- }
- bool TestCase::throws() const {
- return TestCaseInfo::throws;
- }
-
- void TestCase::swap( TestCase& other ) {
- test.swap( other.test );
- className.swap( other.className );
- name.swap( other.name );
- description.swap( other.description );
- std::swap( lineInfo, other.lineInfo );
- }
-
- bool TestCase::operator == ( TestCase const& other ) const {
- return test.get() == other.test.get() &&
- name == other.name &&
- className == other.className;
- }
-
- bool TestCase::operator < ( TestCase const& other ) const {
- return name < other.name;
- }
- TestCase& TestCase::operator = ( TestCase const& other ) {
- TestCase temp( other );
- swap( temp );
- return *this;
- }
-
- TestCaseInfo const& TestCase::getTestCaseInfo() const
- {
- return *this;
- }
-
-} // end namespace Catch
-
-// #included from: catch_version.hpp
-#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED
-
-namespace Catch {
-
- // These numbers are maintained by a script
- Version libraryVersion( 1, 0, 45, "master" );
-}
-
-// #included from: catch_message.hpp
-#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
-
-namespace Catch {
-
- MessageInfo::MessageInfo( std::string const& _macroName,
- SourceLineInfo const& _lineInfo,
- ResultWas::OfType _type )
- : macroName( _macroName ),
- lineInfo( _lineInfo ),
- type( _type ),
- sequence( ++globalCount )
- {}
-
- // This may need protecting if threading support is added
- unsigned int MessageInfo::globalCount = 0;
-
- ////////////////////////////////////////////////////////////////////////////
-
- ScopedMessage::ScopedMessage( MessageBuilder const& builder )
- : m_info( builder.m_info )
- {
- m_info.message = builder.m_stream.str();
- getResultCapture().pushScopedMessage( m_info );
- }
- ScopedMessage::~ScopedMessage() {
- getResultCapture().popScopedMessage( m_info );
- }
-
-} // end namespace Catch
-
-// #included from: catch_legacy_reporter_adapter.hpp
-#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
-
-// #included from: catch_legacy_reporter_adapter.h
-#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
-
-namespace Catch
-{
- // Deprecated
- struct IReporter : IShared {
- virtual ~IReporter();
-
- virtual bool shouldRedirectStdout() const = 0;
-
- virtual void StartTesting() = 0;
- virtual void EndTesting( Totals const& totals ) = 0;
- virtual void StartGroup( std::string const& groupName ) = 0;
- virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
- virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
- virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
- virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
- virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
- virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
- virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
- virtual void Aborted() = 0;
- virtual void Result( AssertionResult const& result ) = 0;
- };
-
- class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
- {
- public:
- LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter );
- virtual ~LegacyReporterAdapter();
-
- virtual ReporterPreferences getPreferences() const;
- virtual void noMatchingTestCases( std::string const& );
- virtual void testRunStarting( TestRunInfo const& );
- virtual void testGroupStarting( GroupInfo const& groupInfo );
- virtual void testCaseStarting( TestCaseInfo const& testInfo );
- virtual void sectionStarting( SectionInfo const& sectionInfo );
- virtual void assertionStarting( AssertionInfo const& );
- virtual bool assertionEnded( AssertionStats const& assertionStats );
- virtual void sectionEnded( SectionStats const& sectionStats );
- virtual void testCaseEnded( TestCaseStats const& testCaseStats );
- virtual void testGroupEnded( TestGroupStats const& testGroupStats );
- virtual void testRunEnded( TestRunStats const& testRunStats );
-
- private:
- Ptr<IReporter> m_legacyReporter;
- };
-}
-
-namespace Catch
-{
- LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter )
- : m_legacyReporter( legacyReporter )
- {}
- LegacyReporterAdapter::~LegacyReporterAdapter() {}
-
- ReporterPreferences LegacyReporterAdapter::getPreferences() const {
- ReporterPreferences prefs;
- prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
- return prefs;
- }
-
- void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {}
- void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) {
- m_legacyReporter->StartTesting();
- }
- void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) {
- m_legacyReporter->StartGroup( groupInfo.name );
- }
- void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) {
- m_legacyReporter->StartTestCase( testInfo );
- }
- void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) {
- m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description );
- }
- void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) {
- // Not on legacy interface
- }
-
- bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) {
- if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
- for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
- it != itEnd;
- ++it ) {
- if( it->type == ResultWas::Info ) {
- ExpressionResultBuilder expressionBuilder( it->type );
- expressionBuilder << it->message;
- AssertionInfo info( it->macroName, it->lineInfo, "", ResultDisposition::Normal );
- AssertionResult result = expressionBuilder.buildResult( info );
- m_legacyReporter->Result( result );
- }
- }
- }
- m_legacyReporter->Result( assertionStats.assertionResult );
- return true;
- }
- void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) {
- if( sectionStats.missingAssertions )
- m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name );
- m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions );
- }
- void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) {
- m_legacyReporter->EndTestCase
- ( testCaseStats.testInfo,
- testCaseStats.totals,
- testCaseStats.stdOut,
- testCaseStats.stdErr );
- }
- void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) {
- if( testGroupStats.aborting )
- m_legacyReporter->Aborted();
- m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals );
- }
- void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
- m_legacyReporter->EndTesting( testRunStats.totals );
- }
-}
-
-// #included from: catch_timer.hpp
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wc++11-long-long"
-#endif
-
-#ifdef CATCH_PLATFORM_WINDOWS
-#include <windows.h>
-#else
-#include <sys/time.h>
-#endif
-
-namespace Catch {
-
- namespace {
-#ifdef CATCH_PLATFORM_WINDOWS
- uint64_t getCurrentTicks() {
- static uint64_t hz=0, hzo=0;
- if (!hz) {
- QueryPerformanceFrequency((LARGE_INTEGER*)&hz);
- QueryPerformanceCounter((LARGE_INTEGER*)&hzo);
- }
- uint64_t t;
- QueryPerformanceCounter((LARGE_INTEGER*)&t);
- return ((t-hzo)*1000000)/hz;
- }
-#else
- uint64_t getCurrentTicks() {
- timeval t;
- gettimeofday(&t,NULL);
- return (uint64_t)t.tv_sec * 1000000ull + (uint64_t)t.tv_usec;
- }
-#endif
- }
-
- void Timer::start() {
- m_ticks = getCurrentTicks();
- }
- unsigned int Timer::getElapsedNanoseconds() const {
- return (unsigned int)(getCurrentTicks() - m_ticks);
- }
- unsigned int Timer::getElapsedMilliseconds() const {
- return (unsigned int)((getCurrentTicks() - m_ticks)/1000);
- }
- double Timer::getElapsedSeconds() const {
- return (getCurrentTicks() - m_ticks)/1000000.0;
- }
-
-} // namespace Catch
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-// #included from: catch_common.hpp
-#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
-
-namespace Catch {
-
- bool startsWith( std::string const& s, std::string const& prefix ) {
- return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
- }
- bool endsWith( std::string const& s, std::string const& suffix ) {
- return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
- }
- bool contains( std::string const& s, std::string const& infix ) {
- return s.find( infix ) != std::string::npos;
- }
- void toLowerInPlace( std::string& s ) {
- std::transform( s.begin(), s.end(), s.begin(), ::tolower );
- }
- std::string toLower( std::string const& s ) {
- std::string lc = s;
- toLowerInPlace( lc );
- return lc;
- }
- std::string trim( std::string const& str ) {
- static char const* whitespaceChars = "\n\r\t ";
- std::string::size_type start = str.find_first_not_of( whitespaceChars );
- std::string::size_type end = str.find_last_not_of( whitespaceChars );
-
- return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
- }
-
- pluralise::pluralise( std::size_t count, std::string const& label )
- : m_count( count ),
- m_label( label )
- {}
-
- std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
- os << pluraliser.m_count << " " << pluraliser.m_label;
- if( pluraliser.m_count != 1 )
- os << "s";
- return os;
- }
-
- SourceLineInfo::SourceLineInfo() : line( 0 ){}
- SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
- : file( _file ),
- line( _line )
- {}
- SourceLineInfo::SourceLineInfo( SourceLineInfo const& other )
- : file( other.file ),
- line( other.line )
- {}
- bool SourceLineInfo::empty() const {
- return file.empty();
- }
- bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
- return line == other.line && file == other.file;
- }
-
- std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
-#ifndef __GNUG__
- os << info.file << "(" << info.line << ")";
-#else
- os << info.file << ":" << info.line;
-#endif
- return os;
- }
-
- void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
- std::ostringstream oss;
- oss << locationInfo << ": Internal Catch error: '" << message << "'";
- if( isTrue( true ))
- throw std::logic_error( oss.str() );
- }
-}
-
-// #included from: catch_section.hpp
-#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
-
-namespace Catch {
-
- Section::Section( SourceLineInfo const& lineInfo,
- std::string const& name,
- std::string const& description )
- : m_info( name, description, lineInfo ),
- m_sectionIncluded( getCurrentContext().getResultCapture().sectionStarted( m_info, m_assertions ) )
- {
- m_timer.start();
- }
-
- Section::~Section() {
- if( m_sectionIncluded )
- getCurrentContext().getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
- }
-
- // This indicates whether the section should be executed or not
- Section::operator bool() {
- return m_sectionIncluded;
- }
-
-} // end namespace Catch
-
-// #included from: catch_debugger.hpp
-#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
-
-#include <iostream>
-
-#ifdef CATCH_PLATFORM_MAC
-
- #include <assert.h>
- #include <stdbool.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <sys/sysctl.h>
-
- namespace Catch{
-
- // The following function is taken directly from the following technical note:
- // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
-
- // Returns true if the current process is being debugged (either
- // running under the debugger or has a debugger attached post facto).
- bool isDebuggerActive(){
-
- int mib[4];
- struct kinfo_proc info;
- size_t size;
-
- // Initialize the flags so that, if sysctl fails for some bizarre
- // reason, we get a predictable result.
-
- info.kp_proc.p_flag = 0;
-
- // Initialize mib, which tells sysctl the info we want, in this case
- // we're looking for information about a specific process ID.
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_PID;
- mib[3] = getpid();
-
- // Call sysctl.
-
- size = sizeof(info);
- if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) {
- std::cerr << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
- return false;
- }
-
- // We're being debugged if the P_TRACED flag is set.
-
- return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
- }
- } // namespace Catch
-
-#elif defined(_MSC_VER)
- extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
- namespace Catch {
- bool isDebuggerActive() {
- return IsDebuggerPresent() != 0;
- }
- }
-#elif defined(__MINGW32__)
- extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
- namespace Catch {
- bool isDebuggerActive() {
- return IsDebuggerPresent() != 0;
- }
- }
-#else
- namespace Catch {
- inline bool isDebuggerActive() { return false; }
- }
-#endif // Platform
-
-#ifdef CATCH_PLATFORM_WINDOWS
- extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
- namespace Catch {
- void writeToDebugConsole( std::string const& text ) {
- ::OutputDebugStringA( text.c_str() );
- }
- }
-#else
- namespace Catch {
- void writeToDebugConsole( std::string const& text ) {
- // !TBD: Need a version for Mac/ XCode and other IDEs
- std::cout << text;
- }
- }
-#endif // Platform
-
-// #included from: catch_tostring.hpp
-#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
-
-namespace Catch {
-
-std::string toString( std::string const& value ) {
- std::string s = value;
- if( getCurrentContext().getConfig()->showInvisibles() ) {
- for(size_t i = 0; i < s.size(); ++i ) {
- std::string subs;
- switch( s[i] ) {
- case '\n': subs = "\\n"; break;
- case '\t': subs = "\\t"; break;
- default: break;
- }
- if( !subs.empty() ) {
- s = s.substr( 0, i ) + subs + s.substr( i+1 );
- ++i;
- }
- }
- }
- return "\"" + s + "\"";
-}
-std::string toString( std::wstring const& value ) {
-
- std::string s;
- s.reserve( value.size() );
- for(size_t i = 0; i < value.size(); ++i )
- s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?';
- return toString( s );
-}
-
-std::string toString( const char* const value ) {
- return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" );
-}
-
-std::string toString( char* const value ) {
- return Catch::toString( static_cast<const char*>( value ) );
-}
-
-std::string toString( int value ) {
- std::ostringstream oss;
- oss << value;
- return oss.str();
-}
-
-std::string toString( unsigned long value ) {
- std::ostringstream oss;
- if( value > 8192 )
- oss << "0x" << std::hex << value;
- else
- oss << value;
- return oss.str();
-}
-
-std::string toString( unsigned int value ) {
- return toString( static_cast<unsigned long>( value ) );
-}
-
-std::string toString( const double value ) {
- std::ostringstream oss;
- oss << std::setprecision( 10 )
- << std::fixed
- << value;
- std::string d = oss.str();
- std::size_t i = d.find_last_not_of( '0' );
- if( i != std::string::npos && i != d.size()-1 ) {
- if( d[i] == '.' )
- i++;
- d = d.substr( 0, i+1 );
- }
- return d;
-}
-
-std::string toString( bool value ) {
- return value ? "true" : "false";
-}
-
-std::string toString( char value ) {
- return value < ' '
- ? toString( static_cast<unsigned int>( value ) )
- : Detail::makeString( value );
-}
-
-std::string toString( signed char value ) {
- return toString( static_cast<char>( value ) );
-}
-
-std::string toString( unsigned char value ) {
- return toString( static_cast<char>( value ) );
-}
-
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
-std::string toString( std::nullptr_t ) {
- return "nullptr";
-}
-#endif
-
-#ifdef __OBJC__
- std::string toString( NSString const * const& nsstring ) {
- if( !nsstring )
- return "nil";
- return std::string( "@\"" ) + [nsstring UTF8String] + "\"";
- }
- std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) {
- if( !nsstring )
- return "nil";
- return std::string( "@\"" ) + [nsstring UTF8String] + "\"";
- }
- std::string toString( NSObject* const& nsObject ) {
- return toString( [nsObject description] );
- }
-#endif
-
-} // end namespace Catch
-
-// #included from: ../reporters/catch_reporter_xml.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
-
-// #included from: catch_reporter_bases.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
-
-namespace Catch {
-
- struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
-
- StreamingReporterBase( ReporterConfig const& _config )
- : m_config( _config.fullConfig() ),
- stream( _config.stream() )
- {}
-
- virtual ~StreamingReporterBase();
-
- virtual void noMatchingTestCases( std::string const& ) {}
-
- virtual void testRunStarting( TestRunInfo const& _testRunInfo ) {
- currentTestRunInfo = _testRunInfo;
- }
- virtual void testGroupStarting( GroupInfo const& _groupInfo ) {
- currentGroupInfo = _groupInfo;
- }
-
- virtual void testCaseStarting( TestCaseInfo const& _testInfo ) {
- currentTestCaseInfo = _testInfo;
- }
- virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
- m_sectionStack.push_back( _sectionInfo );
- }
-
- virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) {
- m_sectionStack.pop_back();
- }
- virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
- currentTestCaseInfo.reset();
- assert( m_sectionStack.empty() );
- }
- virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) {
- currentGroupInfo.reset();
- }
- virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) {
- currentTestCaseInfo.reset();
- currentGroupInfo.reset();
- currentTestRunInfo.reset();
- }
-
- Ptr<IConfig> m_config;
- std::ostream& stream;
-
- LazyStat<TestRunInfo> currentTestRunInfo;
- LazyStat<GroupInfo> currentGroupInfo;
- LazyStat<TestCaseInfo> currentTestCaseInfo;
-
- std::vector<SectionInfo> m_sectionStack;
- };
-
- struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
- template<typename T, typename ChildNodeT>
- struct Node : SharedImpl<> {
- explicit Node( T const& _value ) : value( _value ) {}
- virtual ~Node() {}
-
- typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
- T value;
- ChildNodes children;
- };
- struct SectionNode : SharedImpl<> {
- explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
- virtual ~SectionNode();
-
- bool operator == ( SectionNode const& other ) const {
- return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
- }
- bool operator == ( Ptr<SectionNode> const& other ) const {
- return operator==( *other );
- }
-
- SectionStats stats;
- typedef std::vector<Ptr<SectionNode> > ChildSections;
- typedef std::vector<AssertionStats> Assertions;
- ChildSections childSections;
- Assertions assertions;
- std::string stdOut;
- std::string stdErr;
- };
-
- struct BySectionInfo {
- BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
- bool operator() ( Ptr<SectionNode> const& node ) const {
- return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
- }
- private:
- BySectionInfo& operator=( BySectionInfo const& other ); // = delete;
-
- SectionInfo const& m_other;
- };
-
- typedef Node<TestCaseStats, SectionNode> TestCaseNode;
- typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
- typedef Node<TestRunStats, TestGroupNode> TestRunNode;
-
- CumulativeReporterBase( ReporterConfig const& _config )
- : m_config( _config.fullConfig() ),
- stream( _config.stream() )
- {}
- ~CumulativeReporterBase();
-
- virtual void testRunStarting( TestRunInfo const& ) {}
- virtual void testGroupStarting( GroupInfo const& ) {}
-
- virtual void testCaseStarting( TestCaseInfo const& ) {}
-
- virtual void sectionStarting( SectionInfo const& sectionInfo ) {
- SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
- Ptr<SectionNode> node;
- if( m_sectionStack.empty() ) {
- if( !m_rootSection )
- m_rootSection = new SectionNode( incompleteStats );
- node = m_rootSection;
- }
- else {
- SectionNode& parentNode = *m_sectionStack.back();
- SectionNode::ChildSections::const_iterator it =
- std::find_if( parentNode.childSections.begin(),
- parentNode.childSections.end(),
- BySectionInfo( sectionInfo ) );
- if( it == parentNode.childSections.end() ) {
- node = new SectionNode( incompleteStats );
- parentNode.childSections.push_back( node );
- }
- else
- node = *it;
- }
- m_sectionStack.push_back( node );
- m_deepestSection = node;
- }
-
- virtual void assertionStarting( AssertionInfo const& ) {}
-
- virtual bool assertionEnded( AssertionStats const& assertionStats ) {
- assert( !m_sectionStack.empty() );
- SectionNode& sectionNode = *m_sectionStack.back();
- sectionNode.assertions.push_back( assertionStats );
- return true;
- }
- virtual void sectionEnded( SectionStats const& sectionStats ) {
- assert( !m_sectionStack.empty() );
- SectionNode& node = *m_sectionStack.back();
- node.stats = sectionStats;
- m_sectionStack.pop_back();
- }
- virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
- Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
- assert( m_sectionStack.size() == 0 );
- node->children.push_back( m_rootSection );
- m_testCases.push_back( node );
- m_rootSection.reset();
-
- assert( m_deepestSection );
- m_deepestSection->stdOut = testCaseStats.stdOut;
- m_deepestSection->stdErr = testCaseStats.stdErr;
- }
- virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
- Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
- node->children.swap( m_testCases );
- m_testGroups.push_back( node );
- }
- virtual void testRunEnded( TestRunStats const& testRunStats ) {
- Ptr<TestRunNode> node = new TestRunNode( testRunStats );
- node->children.swap( m_testGroups );
- m_testRuns.push_back( node );
- testRunEndedCumulative();
- }
- virtual void testRunEndedCumulative() = 0;
-
- Ptr<IConfig> m_config;
- std::ostream& stream;
- std::vector<AssertionStats> m_assertions;
- std::vector<std::vector<Ptr<SectionNode> > > m_sections;
- std::vector<Ptr<TestCaseNode> > m_testCases;
- std::vector<Ptr<TestGroupNode> > m_testGroups;
-
- std::vector<Ptr<TestRunNode> > m_testRuns;
-
- Ptr<SectionNode> m_rootSection;
- Ptr<SectionNode> m_deepestSection;
- std::vector<Ptr<SectionNode> > m_sectionStack;
-
- };
-
-} // end namespace Catch
-
-// #included from: ../internal/catch_reporter_registrars.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
-
-namespace Catch {
-
- template<typename T>
- class LegacyReporterRegistrar {
-
- class ReporterFactory : public IReporterFactory {
- virtual IStreamingReporter* create( ReporterConfig const& config ) const {
- return new LegacyReporterAdapter( new T( config ) );
- }
-
- virtual std::string getDescription() const {
- return T::getDescription();
- }
- };
-
- public:
-
- LegacyReporterRegistrar( std::string const& name ) {
- getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
- }
- };
-
- template<typename T>
- class ReporterRegistrar {
-
- class ReporterFactory : public IReporterFactory {
-
- // *** Please Note ***:
- // - If you end up here looking at a compiler error because it's trying to register
- // your custom reporter class be aware that the native reporter interface has changed
- // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
- // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
- // However please consider updating to the new interface as the old one is now
- // deprecated and will probably be removed quite soon!
- // Please contact me via github if you have any questions at all about this.
- // In fact, ideally, please contact me anyway to let me know you've hit this - as I have
- // no idea who is actually using custom reporters at all (possibly no-one!).
- // The new interface is designed to minimise exposure to interface changes in the future.
- virtual IStreamingReporter* create( ReporterConfig const& config ) const {
- return new T( config );
- }
-
- virtual std::string getDescription() const {
- return T::getDescription();
- }
- };
-
- public:
-
- ReporterRegistrar( std::string const& name ) {
- getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
- }
- };
-}
-
-#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
- namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
-#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
- namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
-
-// #included from: ../internal/catch_xmlwriter.hpp
-#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
-
-#include <sstream>
-#include <iostream>
-#include <string>
-#include <vector>
-
-namespace Catch {
-
- class XmlWriter {
- public:
-
- class ScopedElement {
- public:
- ScopedElement( XmlWriter* writer )
- : m_writer( writer )
- {}
-
- ScopedElement( ScopedElement const& other )
- : m_writer( other.m_writer ){
- other.m_writer = NULL;
- }
-
- ~ScopedElement() {
- if( m_writer )
- m_writer->endElement();
- }
-
- ScopedElement& writeText( std::string const& text, bool indent = true ) {
- m_writer->writeText( text, indent );
- return *this;
- }
-
- template<typename T>
- ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
- m_writer->writeAttribute( name, attribute );
- return *this;
- }
-
- private:
- mutable XmlWriter* m_writer;
- };
-
- XmlWriter()
- : m_tagIsOpen( false ),
- m_needsNewline( false ),
- m_os( &std::cout )
- {}
-
- XmlWriter( std::ostream& os )
- : m_tagIsOpen( false ),
- m_needsNewline( false ),
- m_os( &os )
- {}
-
- ~XmlWriter() {
- while( !m_tags.empty() )
- endElement();
- }
-
-# ifndef CATCH_CPP11_OR_GREATER
- XmlWriter& operator = ( XmlWriter const& other ) {
- XmlWriter temp( other );
- swap( temp );
- return *this;
- }
-# else
- XmlWriter( XmlWriter const& ) = default;
- XmlWriter( XmlWriter && ) = default;
- XmlWriter& operator = ( XmlWriter const& ) = default;
- XmlWriter& operator = ( XmlWriter && ) = default;
-# endif
-
- void swap( XmlWriter& other ) {
- std::swap( m_tagIsOpen, other.m_tagIsOpen );
- std::swap( m_needsNewline, other.m_needsNewline );
- std::swap( m_tags, other.m_tags );
- std::swap( m_indent, other.m_indent );
- std::swap( m_os, other.m_os );
- }
-
- XmlWriter& startElement( std::string const& name ) {
- ensureTagClosed();
- newlineIfNecessary();
- stream() << m_indent << "<" << name;
- m_tags.push_back( name );
- m_indent += " ";
- m_tagIsOpen = true;
- return *this;
- }
-
- ScopedElement scopedElement( std::string const& name ) {
- ScopedElement scoped( this );
- startElement( name );
- return scoped;
- }
-
- XmlWriter& endElement() {
- newlineIfNecessary();
- m_indent = m_indent.substr( 0, m_indent.size()-2 );
- if( m_tagIsOpen ) {
- stream() << "/>\n";
- m_tagIsOpen = false;
- }
- else {
- stream() << m_indent << "</" << m_tags.back() << ">\n";
- }
- m_tags.pop_back();
- return *this;
- }
-
- XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
- if( !name.empty() && !attribute.empty() ) {
- stream() << " " << name << "=\"";
- writeEncodedText( attribute );
- stream() << "\"";
- }
- return *this;
- }
-
- XmlWriter& writeAttribute( std::string const& name, bool attribute ) {
- stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\"";
- return *this;
- }
-
- template<typename T>
- XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
- if( !name.empty() )
- stream() << " " << name << "=\"" << attribute << "\"";
- return *this;
- }
-
- XmlWriter& writeText( std::string const& text, bool indent = true ) {
- if( !text.empty() ){
- bool tagWasOpen = m_tagIsOpen;
- ensureTagClosed();
- if( tagWasOpen && indent )
- stream() << m_indent;
- writeEncodedText( text );
- m_needsNewline = true;
- }
- return *this;
- }
-
- XmlWriter& writeComment( std::string const& text ) {
- ensureTagClosed();
- stream() << m_indent << "<!--" << text << "-->";
- m_needsNewline = true;
- return *this;
- }
-
- XmlWriter& writeBlankLine() {
- ensureTagClosed();
- stream() << "\n";
- return *this;
- }
-
- private:
-
- std::ostream& stream() {
- return *m_os;
- }
-
- void ensureTagClosed() {
- if( m_tagIsOpen ) {
- stream() << ">\n";
- m_tagIsOpen = false;
- }
- }
-
- void newlineIfNecessary() {
- if( m_needsNewline ) {
- stream() << "\n";
- m_needsNewline = false;
- }
- }
-
- void writeEncodedText( std::string const& text ) {
- static const char* charsToEncode = "<&\"";
- std::string mtext = text;
- std::string::size_type pos = mtext.find_first_of( charsToEncode );
- while( pos != std::string::npos ) {
- stream() << mtext.substr( 0, pos );
-
- switch( mtext[pos] ) {
- case '<':
- stream() << "<";
- break;
- case '&':
- stream() << "&";
- break;
- case '\"':
- stream() << """;
- break;
- }
- mtext = mtext.substr( pos+1 );
- pos = mtext.find_first_of( charsToEncode );
- }
- stream() << mtext;
- }
-
- bool m_tagIsOpen;
- bool m_needsNewline;
- std::vector<std::string> m_tags;
- std::string m_indent;
- std::ostream* m_os;
- };
-
-}
-namespace Catch {
- class XmlReporter : public SharedImpl<IReporter> {
- public:
- XmlReporter( ReporterConfig const& config ) : m_config( config ), m_sectionDepth( 0 ) {}
-
- static std::string getDescription() {
- return "Reports test results as an XML document";
- }
- virtual ~XmlReporter();
-
- private: // IReporter
-
- virtual bool shouldRedirectStdout() const {
- return true;
- }
-
- virtual void StartTesting() {
- m_xml = XmlWriter( m_config.stream() );
- m_xml.startElement( "Catch" );
- if( !m_config.fullConfig()->name().empty() )
- m_xml.writeAttribute( "name", m_config.fullConfig()->name() );
- }
-
- virtual void EndTesting( const Totals& totals ) {
- m_xml.scopedElement( "OverallResults" )
- .writeAttribute( "successes", totals.assertions.passed )
- .writeAttribute( "failures", totals.assertions.failed );
- m_xml.endElement();
- }
-
- virtual void StartGroup( const std::string& groupName ) {
- m_xml.startElement( "Group" )
- .writeAttribute( "name", groupName );
- }
-
- virtual void EndGroup( const std::string&, const Totals& totals ) {
- m_xml.scopedElement( "OverallResults" )
- .writeAttribute( "successes", totals.assertions.passed )
- .writeAttribute( "failures", totals.assertions.failed );
- m_xml.endElement();
- }
-
- virtual void StartSection( const std::string& sectionName, const std::string& description ) {
- if( m_sectionDepth++ > 0 ) {
- m_xml.startElement( "Section" )
- .writeAttribute( "name", trim( sectionName ) )
- .writeAttribute( "description", description );
- }
- }
- virtual void NoAssertionsInSection( const std::string& ) {}
- virtual void NoAssertionsInTestCase( const std::string& ) {}
-
- virtual void EndSection( const std::string& /*sectionName*/, const Counts& assertions ) {
- if( --m_sectionDepth > 0 ) {
- m_xml.scopedElement( "OverallResults" )
- .writeAttribute( "successes", assertions.passed )
- .writeAttribute( "failures", assertions.failed );
- m_xml.endElement();
- }
- }
-
- virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) {
- m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
- m_currentTestSuccess = true;
- }
-
- virtual void Result( const Catch::AssertionResult& assertionResult ) {
- if( !m_config.fullConfig()->includeSuccessfulResults() && assertionResult.getResultType() == ResultWas::Ok )
- return;
-
- if( assertionResult.hasExpression() ) {
- m_xml.startElement( "Expression" )
- .writeAttribute( "success", assertionResult.succeeded() )
- .writeAttribute( "filename", assertionResult.getSourceInfo().file )
- .writeAttribute( "line", assertionResult.getSourceInfo().line );
-
- m_xml.scopedElement( "Original" )
- .writeText( assertionResult.getExpression() );
- m_xml.scopedElement( "Expanded" )
- .writeText( assertionResult.getExpandedExpression() );
- m_currentTestSuccess &= assertionResult.succeeded();
- }
-
- switch( assertionResult.getResultType() ) {
- case ResultWas::ThrewException:
- m_xml.scopedElement( "Exception" )
- .writeAttribute( "filename", assertionResult.getSourceInfo().file )
- .writeAttribute( "line", assertionResult.getSourceInfo().line )
- .writeText( assertionResult.getMessage() );
- m_currentTestSuccess = false;
- break;
- case ResultWas::Info:
- m_xml.scopedElement( "Info" )
- .writeText( assertionResult.getMessage() );
- break;
- case ResultWas::Warning:
- m_xml.scopedElement( "Warning" )
- .writeText( assertionResult.getMessage() );
- break;
- case ResultWas::ExplicitFailure:
- m_xml.scopedElement( "Failure" )
- .writeText( assertionResult.getMessage() );
- m_currentTestSuccess = false;
- break;
- case ResultWas::Unknown:
- case ResultWas::Ok:
- case ResultWas::FailureBit:
- case ResultWas::ExpressionFailed:
- case ResultWas::Exception:
- case ResultWas::DidntThrowException:
- break;
- }
- if( assertionResult.hasExpression() )
- m_xml.endElement();
- }
-
- virtual void Aborted() {
- // !TBD
- }
-
- virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) {
- m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess );
- m_xml.endElement();
- }
-
- private:
- ReporterConfig m_config;
- bool m_currentTestSuccess;
- XmlWriter m_xml;
- int m_sectionDepth;
- };
-
-} // end namespace Catch
-
-// #included from: ../reporters/catch_reporter_junit.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
-
-#include <assert.h>
-
-namespace Catch {
-
- class JunitReporter : public CumulativeReporterBase {
- public:
- JunitReporter( ReporterConfig const& _config )
- : CumulativeReporterBase( _config ),
- xml( _config.stream() )
- {}
-
- ~JunitReporter();
-
- static std::string getDescription() {
- return "Reports test results in an XML format that looks like Ant's junitreport target";
- }
-
- virtual void noMatchingTestCases( std::string const& /*spec*/ ) {}
-
- virtual ReporterPreferences getPreferences() const {
- ReporterPreferences prefs;
- prefs.shouldRedirectStdOut = true;
- return prefs;
- }
-
- virtual void testRunStarting( TestRunInfo const& runInfo ) {
- CumulativeReporterBase::testRunStarting( runInfo );
- xml.startElement( "testsuites" );
- }
-
- virtual void testGroupStarting( GroupInfo const& groupInfo ) {
- suiteTimer.start();
- stdOutForSuite.str("");
- stdErrForSuite.str("");
- unexpectedExceptions = 0;
- CumulativeReporterBase::testGroupStarting( groupInfo );
- }
-
- virtual bool assertionEnded( AssertionStats const& assertionStats ) {
- if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException )
- unexpectedExceptions++;
- return CumulativeReporterBase::assertionEnded( assertionStats );
- }
-
- virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
- stdOutForSuite << testCaseStats.stdOut;
- stdErrForSuite << testCaseStats.stdErr;
- CumulativeReporterBase::testCaseEnded( testCaseStats );
- }
-
- virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
- double suiteTime = suiteTimer.getElapsedSeconds();
- CumulativeReporterBase::testGroupEnded( testGroupStats );
- writeGroup( *m_testGroups.back(), suiteTime );
- }
-
- virtual void testRunEndedCumulative() {
- xml.endElement();
- }
-
- void writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
- XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
- TestGroupStats const& stats = groupNode.value;
- xml.writeAttribute( "name", stats.groupInfo.name );
- xml.writeAttribute( "errors", unexpectedExceptions );
- xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
- xml.writeAttribute( "tests", stats.totals.assertions.total() );
- xml.writeAttribute( "hostname", "tbd" ); // !TBD
- if( m_config->showDurations() == ShowDurations::Never )
- xml.writeAttribute( "time", "" );
- else
- xml.writeAttribute( "time", suiteTime );
- xml.writeAttribute( "timestamp", "tbd" ); // !TBD
-
- // Write test cases
- for( TestGroupNode::ChildNodes::const_iterator
- it = groupNode.children.begin(), itEnd = groupNode.children.end();
- it != itEnd;
- ++it )
- writeTestCase( **it );
-
- xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false );
- xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false );
- }
-
- void writeTestCase( TestCaseNode const& testCaseNode ) {
- TestCaseStats const& stats = testCaseNode.value;
-
- // All test cases have exactly one section - which represents the
- // test case itself. That section may have 0-n nested sections
- assert( testCaseNode.children.size() == 1 );
- SectionNode const& rootSection = *testCaseNode.children.front();
-
- std::string className = stats.testInfo.className;
-
- if( className.empty() ) {
- if( rootSection.childSections.empty() )
- className = "global";
- }
- writeSection( className, "", rootSection );
- }
-
- void writeSection( std::string const& className,
- std::string const& rootName,
- SectionNode const& sectionNode ) {
- std::string name = trim( sectionNode.stats.sectionInfo.name );
- if( !rootName.empty() )
- name = rootName + "/" + name;
-
- if( !sectionNode.assertions.empty() ||
- !sectionNode.stdOut.empty() ||
- !sectionNode.stdErr.empty() ) {
- XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
- if( className.empty() ) {
- xml.writeAttribute( "classname", name );
- xml.writeAttribute( "name", "root" );
- }
- else {
- xml.writeAttribute( "classname", className );
- xml.writeAttribute( "name", name );
- }
- xml.writeAttribute( "time", toString( sectionNode.stats.durationInSeconds ) );
-
- writeAssertions( sectionNode );
-
- if( !sectionNode.stdOut.empty() )
- xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
- if( !sectionNode.stdErr.empty() )
- xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
- }
- for( SectionNode::ChildSections::const_iterator
- it = sectionNode.childSections.begin(),
- itEnd = sectionNode.childSections.end();
- it != itEnd;
- ++it )
- if( className.empty() )
- writeSection( name, "", **it );
- else
- writeSection( className, name, **it );
- }
-
- void writeAssertions( SectionNode const& sectionNode ) {
- for( SectionNode::Assertions::const_iterator
- it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end();
- it != itEnd;
- ++it )
- writeAssertion( *it );
- }
- void writeAssertion( AssertionStats const& stats ) {
- AssertionResult const& result = stats.assertionResult;
- if( !result.isOk() ) {
- std::string elementName;
- switch( result.getResultType() ) {
- case ResultWas::ThrewException:
- elementName = "error";
- break;
- case ResultWas::ExplicitFailure:
- elementName = "failure";
- break;
- case ResultWas::ExpressionFailed:
- elementName = "failure";
- break;
- case ResultWas::DidntThrowException:
- elementName = "failure";
- break;
-
- // We should never see these here:
- case ResultWas::Info:
- case ResultWas::Warning:
- case ResultWas::Ok:
- case ResultWas::Unknown:
- case ResultWas::FailureBit:
- case ResultWas::Exception:
- elementName = "internalError";
- break;
- }
-
- XmlWriter::ScopedElement e = xml.scopedElement( elementName );
-
- xml.writeAttribute( "message", result.getExpandedExpression() );
- xml.writeAttribute( "type", result.getTestMacroName() );
-
- std::ostringstream oss;
- if( !result.getMessage().empty() )
- oss << result.getMessage() << "\n";
- for( std::vector<MessageInfo>::const_iterator
- it = stats.infoMessages.begin(),
- itEnd = stats.infoMessages.end();
- it != itEnd;
- ++it )
- if( it->type == ResultWas::Info )
- oss << it->message << "\n";
-
- oss << "at " << result.getSourceInfo();
- xml.writeText( oss.str(), false );
- }
- }
-
- XmlWriter xml;
- Timer suiteTimer;
- std::ostringstream stdOutForSuite;
- std::ostringstream stdErrForSuite;
- unsigned int unexpectedExceptions;
- };
-
- INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
-
-} // end namespace Catch
-
-// #included from: ../reporters/catch_reporter_console.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
-
-#include <cstring>
-
-namespace Catch {
-
- struct ConsoleReporter : StreamingReporterBase {
- ConsoleReporter( ReporterConfig const& _config )
- : StreamingReporterBase( _config ),
- m_headerPrinted( false ),
- m_atLeastOneTestCasePrinted( false )
- {}
-
- virtual ~ConsoleReporter();
- static std::string getDescription() {
- return "Reports test results as plain lines of text";
- }
- virtual ReporterPreferences getPreferences() const {
- ReporterPreferences prefs;
- prefs.shouldRedirectStdOut = false;
- return prefs;
- }
-
- virtual void noMatchingTestCases( std::string const& spec ) {
- stream << "No test cases matched '" << spec << "'" << std::endl;
- }
-
- virtual void assertionStarting( AssertionInfo const& ) {
- }
-
- virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
- AssertionResult const& result = _assertionStats.assertionResult;
-
- bool printInfoMessages = true;
-
- // Drop out if result was successful and we're not printing those
- if( !m_config->includeSuccessfulResults() && result.isOk() ) {
- if( result.getResultType() != ResultWas::Warning )
- return false;
- printInfoMessages = false;
- }
-
- lazyPrint();
-
- AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
- printer.print();
- stream << std::endl;
- return true;
- }
-
- virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
- m_headerPrinted = false;
- StreamingReporterBase::sectionStarting( _sectionInfo );
- }
- virtual void sectionEnded( SectionStats const& _sectionStats ) {
- if( _sectionStats.missingAssertions ) {
- lazyPrint();
- Colour colour( Colour::ResultError );
- if( m_sectionStack.size() > 1 )
- stream << "\nNo assertions in section";
- else
- stream << "\nNo assertions in test case";
- stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
- }
- if( m_headerPrinted ) {
- if( m_config->showDurations() == ShowDurations::Always )
- stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
- m_headerPrinted = false;
- }
- else {
- if( m_config->showDurations() == ShowDurations::Always )
- stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
- }
- StreamingReporterBase::sectionEnded( _sectionStats );
- }
-
- virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) {
- StreamingReporterBase::testCaseEnded( _testCaseStats );
- m_headerPrinted = false;
- }
- virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) {
- if( currentGroupInfo.used ) {
- printSummaryDivider();
- stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
- printTotals( _testGroupStats.totals );
- stream << "\n" << std::endl;
- }
- StreamingReporterBase::testGroupEnded( _testGroupStats );
- }
- virtual void testRunEnded( TestRunStats const& _testRunStats ) {
- if( m_atLeastOneTestCasePrinted )
- printTotalsDivider();
- printTotals( _testRunStats.totals );
- stream << "\n" << std::endl;
- StreamingReporterBase::testRunEnded( _testRunStats );
- }
-
- private:
-
- class AssertionPrinter {
- void operator= ( AssertionPrinter const& );
- public:
- AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
- : stream( _stream ),
- stats( _stats ),
- result( _stats.assertionResult ),
- colour( Colour::None ),
- message( result.getMessage() ),
- messages( _stats.infoMessages ),
- printInfoMessages( _printInfoMessages )
- {
- switch( result.getResultType() ) {
- case ResultWas::Ok:
- colour = Colour::Success;
- passOrFail = "PASSED";
- //if( result.hasMessage() )
- if( _stats.infoMessages.size() == 1 )
- messageLabel = "with message";
- if( _stats.infoMessages.size() > 1 )
- messageLabel = "with messages";
- break;
- case ResultWas::ExpressionFailed:
- if( result.isOk() ) {
- colour = Colour::Success;
- passOrFail = "FAILED - but was ok";
- }
- else {
- colour = Colour::Error;
- passOrFail = "FAILED";
- }
- if( _stats.infoMessages.size() == 1 )
- messageLabel = "with message";
- if( _stats.infoMessages.size() > 1 )
- messageLabel = "with messages";
- break;
- case ResultWas::ThrewException:
- colour = Colour::Error;
- passOrFail = "FAILED";
- messageLabel = "due to unexpected exception with message";
- break;
- case ResultWas::DidntThrowException:
- colour = Colour::Error;
- passOrFail = "FAILED";
- messageLabel = "because no exception was thrown where one was expected";
- break;
- case ResultWas::Info:
- messageLabel = "info";
- break;
- case ResultWas::Warning:
- messageLabel = "warning";
- break;
- case ResultWas::ExplicitFailure:
- passOrFail = "FAILED";
- colour = Colour::Error;
- if( _stats.infoMessages.size() == 1 )
- messageLabel = "explicitly with message";
- if( _stats.infoMessages.size() > 1 )
- messageLabel = "explicitly with messages";
- break;
- // These cases are here to prevent compiler warnings
- case ResultWas::Unknown:
- case ResultWas::FailureBit:
- case ResultWas::Exception:
- passOrFail = "** internal error **";
- colour = Colour::Error;
- break;
- }
- }
-
- void print() const {
- printSourceInfo();
- if( stats.totals.assertions.total() > 0 ) {
- if( result.isOk() )
- stream << "\n";
- printResultType();
- printOriginalExpression();
- printReconstructedExpression();
- }
- else {
- stream << "\n";
- }
- printMessage();
- }
-
- private:
- void printResultType() const {
- if( !passOrFail.empty() ) {
- Colour colourGuard( colour );
- stream << passOrFail << ":\n";
- }
- }
- void printOriginalExpression() const {
- if( result.hasExpression() ) {
- Colour colourGuard( Colour::OriginalExpression );
- stream << " ";
- stream << result.getExpressionInMacro();
- stream << "\n";
- }
- }
- void printReconstructedExpression() const {
- if( result.hasExpandedExpression() ) {
- stream << "with expansion:\n";
- Colour colourGuard( Colour::ReconstructedExpression );
- stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n";
- }
- }
- void printMessage() const {
- if( !messageLabel.empty() )
- stream << messageLabel << ":" << "\n";
- for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
- it != itEnd;
- ++it ) {
- // If this assertion is a warning ignore any INFO messages
- if( printInfoMessages || it->type != ResultWas::Info )
- stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n";
- }
- }
- void printSourceInfo() const {
- Colour colourGuard( Colour::FileName );
- stream << result.getSourceInfo() << ": ";
- }
-
- std::ostream& stream;
- AssertionStats const& stats;
- AssertionResult const& result;
- Colour::Code colour;
- std::string passOrFail;
- std::string messageLabel;
- std::string message;
- std::vector<MessageInfo> messages;
- bool printInfoMessages;
- };
-
- void lazyPrint() {
-
- if( !currentTestRunInfo.used )
- lazyPrintRunInfo();
- if( !currentGroupInfo.used )
- lazyPrintGroupInfo();
-
- if( !m_headerPrinted ) {
- printTestCaseAndSectionHeader();
- m_headerPrinted = true;
- }
- m_atLeastOneTestCasePrinted = true;
- }
- void lazyPrintRunInfo() {
- stream << "\n" << getLineOfChars<'~'>() << "\n";
- Colour colour( Colour::SecondaryText );
- stream << currentTestRunInfo->name
- << " is a Catch v" << libraryVersion.majorVersion << "."
- << libraryVersion.minorVersion << " b"
- << libraryVersion.buildNumber;
- if( libraryVersion.branchName != std::string( "master" ) )
- stream << " (" << libraryVersion.branchName << ")";
- stream << " host application.\n"
- << "Run with -? for options\n\n";
-
- currentTestRunInfo.used = true;
- }
- void lazyPrintGroupInfo() {
- if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) {
- printClosedHeader( "Group: " + currentGroupInfo->name );
- currentGroupInfo.used = true;
- }
- }
- void printTestCaseAndSectionHeader() {
- assert( !m_sectionStack.empty() );
- printOpenHeader( currentTestCaseInfo->name );
-
- if( m_sectionStack.size() > 1 ) {
- Colour colourGuard( Colour::Headers );
-
- std::vector<SectionInfo>::const_iterator
- it = m_sectionStack.begin()+1, // Skip first section (test case)
- itEnd = m_sectionStack.end();
- for( ; it != itEnd; ++it )
- printHeaderString( it->name, 2 );
- }
-
- SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
-
- if( !lineInfo.empty() ){
- stream << getLineOfChars<'-'>() << "\n";
- Colour colourGuard( Colour::FileName );
- stream << lineInfo << "\n";
- }
- stream << getLineOfChars<'.'>() << "\n" << std::endl;
- }
-
- void printClosedHeader( std::string const& _name ) {
- printOpenHeader( _name );
- stream << getLineOfChars<'.'>() << "\n";
- }
- void printOpenHeader( std::string const& _name ) {
- stream << getLineOfChars<'-'>() << "\n";
- {
- Colour colourGuard( Colour::Headers );
- printHeaderString( _name );
- }
- }
-
- // if string has a : in first line will set indent to follow it on
- // subsequent lines
- void printHeaderString( std::string const& _string, std::size_t indent = 0 ) {
- std::size_t i = _string.find( ": " );
- if( i != std::string::npos )
- i+=2;
- else
- i = 0;
- stream << Text( _string, TextAttributes()
- .setIndent( indent+i)
- .setInitialIndent( indent ) ) << "\n";
- }
-
- void printTotals( const Totals& totals ) {
- if( totals.testCases.total() == 0 ) {
- stream << "No tests ran";
- }
- else if( totals.assertions.total() == 0 ) {
- Colour colour( Colour::Yellow );
- printCounts( "test case", totals.testCases );
- stream << " (no assertions)";
- }
- else if( totals.assertions.failed ) {
- Colour colour( Colour::ResultError );
- printCounts( "test case", totals.testCases );
- if( totals.testCases.failed > 0 ) {
- stream << " (";
- printCounts( "assertion", totals.assertions );
- stream << ")";
- }
- }
- else {
- Colour colour( Colour::ResultSuccess );
- stream << "All tests passed ("
- << pluralise( totals.assertions.passed, "assertion" ) << " in "
- << pluralise( totals.testCases.passed, "test case" ) << ")";
- }
- }
- void printCounts( std::string const& label, Counts const& counts ) {
- if( counts.total() == 1 ) {
- stream << "1 " << label << " - ";
- if( counts.failed )
- stream << "failed";
- else
- stream << "passed";
- }
- else {
- stream << counts.total() << " " << label << "s ";
- if( counts.passed ) {
- if( counts.failed )
- stream << "- " << counts.failed << " failed";
- else if( counts.passed == 2 )
- stream << "- both passed";
- else
- stream << "- all passed";
- }
- else {
- if( counts.failed == 2 )
- stream << "- both failed";
- else
- stream << "- all failed";
- }
- }
- }
-
- void printTotalsDivider() {
- stream << getLineOfChars<'='>() << "\n";
- }
- void printSummaryDivider() {
- stream << getLineOfChars<'-'>() << "\n";
- }
- template<char C>
- static char const* getLineOfChars() {
- static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
- if( !*line ) {
- memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
- line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
- }
- return line;
- }
-
- private:
- bool m_headerPrinted;
- bool m_atLeastOneTestCasePrinted;
- };
-
- INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter )
-
-} // end namespace Catch
-
-// #included from: ../reporters/catch_reporter_compact.hpp
-#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED
-
-namespace Catch {
-
- struct CompactReporter : StreamingReporterBase {
-
- CompactReporter( ReporterConfig const& _config )
- : StreamingReporterBase( _config )
- {}
-
- virtual ~CompactReporter();
-
- static std::string getDescription() {
- return "Reports test results on a single line, suitable for IDEs";
- }
-
- virtual ReporterPreferences getPreferences() const {
- ReporterPreferences prefs;
- prefs.shouldRedirectStdOut = false;
- return prefs;
- }
-
- virtual void noMatchingTestCases( std::string const& spec ) {
- stream << "No test cases matched '" << spec << "'" << std::endl;
- }
-
- virtual void assertionStarting( AssertionInfo const& ) {
- }
-
- virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
- AssertionResult const& result = _assertionStats.assertionResult;
-
- bool printInfoMessages = true;
-
- // Drop out if result was successful and we're not printing those
- if( !m_config->includeSuccessfulResults() && result.isOk() ) {
- if( result.getResultType() != ResultWas::Warning )
- return false;
- printInfoMessages = false;
- }
-
- AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
- printer.print();
-
- stream << std::endl;
- return true;
- }
-
- virtual void testRunEnded( TestRunStats const& _testRunStats ) {
- printTotals( _testRunStats.totals );
- stream << "\n" << std::endl;
- StreamingReporterBase::testRunEnded( _testRunStats );
- }
-
- private:
- class AssertionPrinter {
- void operator= ( AssertionPrinter const& );
- public:
- AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
- : stream( _stream )
- , stats( _stats )
- , result( _stats.assertionResult )
- , messages( _stats.infoMessages )
- , itMessage( _stats.infoMessages.begin() )
- , printInfoMessages( _printInfoMessages )
- {}
-
- void print() {
- printSourceInfo();
-
- itMessage = messages.begin();
-
- switch( result.getResultType() ) {
- case ResultWas::Ok:
- printResultType( Colour::ResultSuccess, passedString() );
- printOriginalExpression();
- printReconstructedExpression();
- if ( ! result.hasExpression() )
- printRemainingMessages( Colour::None );
- else
- printRemainingMessages();
- break;
- case ResultWas::ExpressionFailed:
- if( result.isOk() )
- printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) );
- else
- printResultType( Colour::Error, failedString() );
- printOriginalExpression();
- printReconstructedExpression();
- printRemainingMessages();
- break;
- case ResultWas::ThrewException:
- printResultType( Colour::Error, failedString() );
- printIssue( "unexpected exception with message:" );
- printMessage();
- printExpressionWas();
- printRemainingMessages();
- break;
- case ResultWas::DidntThrowException:
- printResultType( Colour::Error, failedString() );
- printIssue( "expected exception, got none" );
- printExpressionWas();
- printRemainingMessages();
- break;
- case ResultWas::Info:
- printResultType( Colour::None, "info" );
- printMessage();
- printRemainingMessages();
- break;
- case ResultWas::Warning:
- printResultType( Colour::None, "warning" );
- printMessage();
- printRemainingMessages();
- break;
- case ResultWas::ExplicitFailure:
- printResultType( Colour::Error, failedString() );
- printIssue( "explicitly" );
- printRemainingMessages( Colour::None );
- break;
- // These cases are here to prevent compiler warnings
- case ResultWas::Unknown:
- case ResultWas::FailureBit:
- case ResultWas::Exception:
- printResultType( Colour::Error, "** internal error **" );
- break;
- }
- }
-
- private:
- // Colour::LightGrey
-
- static Colour dimColour() { return Colour::FileName; }
-
-#ifdef CATCH_PLATFORM_MAC
- static const char* failedString() { return "FAILED"; }
- static const char* passedString() { return "PASSED"; }
-#else
- static const char* failedString() { return "failed"; }
- static const char* passedString() { return "passed"; }
-#endif
-
- void printSourceInfo() const {
- Colour colourGuard( Colour::FileName );
- stream << result.getSourceInfo() << ":";
- }
-
- void printResultType( Colour colour, std::string passOrFail ) const {
- if( !passOrFail.empty() ) {
- {
- Colour colourGuard( colour );
- stream << " " << passOrFail;
- }
- stream << ":";
- }
- }
-
- void printIssue( std::string issue ) const {
- stream << " " << issue;
- }
-
- void printExpressionWas() {
- if( result.hasExpression() ) {
- stream << ";";
- {
- Colour colour( dimColour() );
- stream << " expression was:";
- }
- printOriginalExpression();
- }
- }
-
- void printOriginalExpression() const {
- if( result.hasExpression() ) {
- stream << " " << result.getExpression();
- }
- }
-
- void printReconstructedExpression() const {
- if( result.hasExpandedExpression() ) {
- {
- Colour colour( dimColour() );
- stream << " for: ";
- }
- stream << result.getExpandedExpression();
- }
- }
-
- void printMessage() {
- if ( itMessage != messages.end() ) {
- stream << " '" << itMessage->message << "'";
- ++itMessage;
- }
- }
-
- void printRemainingMessages( Colour colour = dimColour() ) {
- if ( itMessage == messages.end() )
- return;
-
- // using messages.end() directly yields compilation error:
- std::vector<MessageInfo>::const_iterator itEnd = messages.end();
- const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
-
- {
- Colour colourGuard( colour );
- stream << " with " << pluralise( N, "message" ) << ":";
- }
-
- for(; itMessage != itEnd; ) {
- // If this assertion is a warning ignore any INFO messages
- if( printInfoMessages || itMessage->type != ResultWas::Info ) {
- stream << " '" << itMessage->message << "'";
- if ( ++itMessage != itEnd ) {
- Colour colourGuard( dimColour() );
- stream << " and";
- }
- }
- }
- }
-
- private:
- std::ostream& stream;
- AssertionStats const& stats;
- AssertionResult const& result;
- std::vector<MessageInfo> messages;
- std::vector<MessageInfo>::const_iterator itMessage;
- bool printInfoMessages;
- };
-
- // Colour, message variants:
- // - white: No tests ran.
- // - red: Failed [both/all] N test cases, failed [both/all] M assertions.
- // - white: Passed [both/all] N test cases (no assertions).
- // - red: Failed N tests cases, failed M assertions.
- // - green: Passed [both/all] N tests cases with M assertions.
-
- std::string bothOrAll( std::size_t count ) const {
- return count == 1 ? "" : count == 2 ? "both " : "all " ;
- }
-
- void printTotals( const Totals& totals ) const {
- if( totals.testCases.total() == 0 ) {
- stream << "No tests ran.";
- }
- else if( totals.testCases.failed == totals.testCases.total() ) {
- Colour colour( Colour::ResultError );
- const std::string qualify_assertions_failed =
- totals.assertions.failed == totals.assertions.total() ?
- bothOrAll( totals.assertions.failed ) : "";
- stream <<
- "Failed " << bothOrAll( totals.testCases.failed )
- << pluralise( totals.testCases.failed, "test case" ) << ", "
- "failed " << qualify_assertions_failed <<
- pluralise( totals.assertions.failed, "assertion" ) << ".";
- }
- else if( totals.assertions.total() == 0 ) {
- stream <<
- "Passed " << bothOrAll( totals.testCases.total() )
- << pluralise( totals.testCases.total(), "test case" )
- << " (no assertions).";
- }
- else if( totals.assertions.failed ) {
- Colour colour( Colour::ResultError );
- stream <<
- "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", "
- "failed " << pluralise( totals.assertions.failed, "assertion" ) << ".";
- }
- else {
- Colour colour( Colour::ResultSuccess );
- stream <<
- "Passed " << bothOrAll( totals.testCases.passed )
- << pluralise( totals.testCases.passed, "test case" ) <<
- " with " << pluralise( totals.assertions.passed, "assertion" ) << ".";
- }
- }
- };
-
- INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter )
-
-} // end namespace Catch
-
-namespace Catch {
- NonCopyable::~NonCopyable() {}
- IShared::~IShared() {}
- StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
- IContext::~IContext() {}
- IResultCapture::~IResultCapture() {}
- ITestCase::~ITestCase() {}
- ITestCaseRegistry::~ITestCaseRegistry() {}
- IRegistryHub::~IRegistryHub() {}
- IMutableRegistryHub::~IMutableRegistryHub() {}
- IExceptionTranslator::~IExceptionTranslator() {}
- IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
- IReporter::~IReporter() {}
- IReporterFactory::~IReporterFactory() {}
- IReporterRegistry::~IReporterRegistry() {}
- IStreamingReporter::~IStreamingReporter() {}
- AssertionStats::~AssertionStats() {}
- SectionStats::~SectionStats() {}
- TestCaseStats::~TestCaseStats() {}
- TestGroupStats::~TestGroupStats() {}
- TestRunStats::~TestRunStats() {}
- CumulativeReporterBase::SectionNode::~SectionNode() {}
- CumulativeReporterBase::~CumulativeReporterBase() {}
-
- StreamingReporterBase::~StreamingReporterBase() {}
- ConsoleReporter::~ConsoleReporter() {}
- CompactReporter::~CompactReporter() {}
- IRunner::~IRunner() {}
- IMutableContext::~IMutableContext() {}
- IConfig::~IConfig() {}
- XmlReporter::~XmlReporter() {}
- JunitReporter::~JunitReporter() {}
- TestRegistry::~TestRegistry() {}
- FreeFunctionTestCase::~FreeFunctionTestCase() {}
- IGeneratorInfo::~IGeneratorInfo() {}
- IGeneratorsForTest::~IGeneratorsForTest() {}
- TestSpec::Pattern::~Pattern() {}
- TestSpec::NamePattern::~NamePattern() {}
- TestSpec::TagPattern::~TagPattern() {}
- TestSpec::ExcludedPattern::~ExcludedPattern() {}
-
- Matchers::Impl::StdString::Equals::~Equals() {}
- Matchers::Impl::StdString::Contains::~Contains() {}
- Matchers::Impl::StdString::StartsWith::~StartsWith() {}
- Matchers::Impl::StdString::EndsWith::~EndsWith() {}
-
- void Config::dummy() {}
-
- INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter )
-}
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-#endif
-
-#ifdef CATCH_CONFIG_MAIN
-// #included from: internal/catch_default_main.hpp
-#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
-
-#ifndef __OBJC__
-
-// Standard C/C++ main entry point
-int main (int argc, char * const argv[]) {
- return Catch::Session().run( argc, argv );
-}
-
-#else // __OBJC__
-
-// Objective-C entry point
-int main (int argc, char * const argv[]) {
-#if !CATCH_ARC_ENABLED
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-#endif
-
- Catch::registerTestMethods();
- int result = Catch::Session().run( argc, (char* const*)argv );
-
-#if !CATCH_ARC_ENABLED
- [pool drain];
-#endif
-
- return result;
-}
-
-#endif // __OBJC__
-
-#endif
-
-#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
-# undef CLARA_CONFIG_MAIN
-#endif
-
-//////
-
-// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
-#ifdef CATCH_CONFIG_PREFIX_ALL
-
-#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" )
-#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::NegateResult, "CATCH_REQUIRE_FALSE" )
-
-#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" )
-#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" )
-#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" )
-
-#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" )
-#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::NegateResult, "CATCH_CHECK_FALSE" )
-#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" )
-#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" )
-#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" )
-
-#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" )
-#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" )
-#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" )
-
-#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" )
-#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" )
-
-#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
-#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg )
-#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
-#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
-#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
-
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
- #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
- #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
- #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
- #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
- #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ )
- #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ )
-#else
- #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
- #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
- #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
- #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
- #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg )
- #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg )
-#endif
-#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
-
-#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
-#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
-
-#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
-
-// "BDD-style" convenience wrappers
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
-#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
-#else
-#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags )
-#endif
-#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" )
-#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" )
-#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" )
-#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" )
-#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" )
-
-// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
-#else
-
-#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
-#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::NegateResult, "REQUIRE_FALSE" )
-
-#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., Catch::ResultDisposition::Normal, "REQUIRE_THROWS" )
-#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" )
-#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" )
-
-#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" )
-#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::NegateResult, "CHECK_FALSE" )
-#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" )
-#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" )
-#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" )
-
-#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, ..., Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" )
-#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" )
-#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" )
-
-#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" )
-#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" )
-
-#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
-#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg )
-#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
-#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
-#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
-
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
- #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
- #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
- #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
- #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
- #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ )
- #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ )
-#else
- #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
- #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
- #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
- #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
- #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg )
- #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg )
-#endif
-#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
-
-#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
-#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
-
-#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
-
-#endif
-
-#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
-
-// "BDD-style" convenience wrappers
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
-#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
-#else
-#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags )
-#endif
-#define GIVEN( desc ) SECTION( " Given: " desc, "" )
-#define WHEN( desc ) SECTION( " When: " desc, "" )
-#define AND_WHEN( desc ) SECTION( "And when: " desc, "" )
-#define THEN( desc ) SECTION( " Then: " desc, "" )
-#define AND_THEN( desc ) SECTION( " And: " desc, "" )
-
-using Catch::Detail::Approx;
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
-
diff --git a/third_party/variant/test/compilation_failure/default_constructor.cpp b/third_party/variant/test/compilation_failure/default_constructor.cpp
new file mode 100644
index 0000000..c75a8c1
--- /dev/null
+++ b/third_party/variant/test/compilation_failure/default_constructor.cpp
@@ -0,0 +1,22 @@
+
+// @EXPECTED: First type in variant must be default constructible to allow default construction of variant
+
+#include <variant.hpp>
+
+// Checks that the first type in a variant must be default constructible to
+// make the variant default constructible.
+
+struct no_def_constructor
+{
+
+ int value;
+
+ no_def_constructor() = delete;
+
+ no_def_constructor(int v) : value(v) {}
+};
+
+int main()
+{
+ mapbox::util::variant<no_def_constructor> x;
+}
diff --git a/third_party/variant/test/compilation_failure/empty_typelist.cpp b/third_party/variant/test/compilation_failure/empty_typelist.cpp
new file mode 100644
index 0000000..69a631c
--- /dev/null
+++ b/third_party/variant/test/compilation_failure/empty_typelist.cpp
@@ -0,0 +1,11 @@
+
+// @EXPECTED: Template parameter type list of variant can not be empty
+
+#include <variant.hpp>
+
+// Empty type list should not work.
+
+int main()
+{
+ mapbox::util::variant<> x;
+}
diff --git a/third_party/variant/test/compilation_failure/equality.cpp b/third_party/variant/test/compilation_failure/equality.cpp
new file mode 100644
index 0000000..b99a308
--- /dev/null
+++ b/third_party/variant/test/compilation_failure/equality.cpp
@@ -0,0 +1,11 @@
+
+// @EXPECTED:
+
+#include <variant.hpp>
+
+int main()
+{
+ mapbox::util::variant<int> x;
+ mapbox::util::variant<double> y;
+ x == y;
+}
diff --git a/third_party/variant/test/compilation_failure/get_type.cpp b/third_party/variant/test/compilation_failure/get_type.cpp
new file mode 100644
index 0000000..5123eb1
--- /dev/null
+++ b/third_party/variant/test/compilation_failure/get_type.cpp
@@ -0,0 +1,10 @@
+
+// @EXPECTED: enable_if
+
+#include <variant.hpp>
+
+int main()
+{
+ mapbox::util::variant<int, double> x;
+ x.get<std::string>();
+}
diff --git a/third_party/variant/test/compilation_failure/is_type.cpp b/third_party/variant/test/compilation_failure/is_type.cpp
new file mode 100644
index 0000000..a79638e
--- /dev/null
+++ b/third_party/variant/test/compilation_failure/is_type.cpp
@@ -0,0 +1,10 @@
+
+// @EXPECTED: invalid type in T in `is<T>()` for this variant
+
+#include <variant.hpp>
+
+int main()
+{
+ mapbox::util::variant<int, double> x;
+ x.is<std::string>();
+}
diff --git a/third_party/variant/test/compilation_failure/mutating_visitor_on_const.cpp b/third_party/variant/test/compilation_failure/mutating_visitor_on_const.cpp
new file mode 100644
index 0000000..ee77b56
--- /dev/null
+++ b/third_party/variant/test/compilation_failure/mutating_visitor_on_const.cpp
@@ -0,0 +1,24 @@
+
+// @EXPECTED: const int
+
+#include <variant.hpp>
+
+struct mutating_visitor
+{
+ mutating_visitor(int val)
+ : val_(val) {}
+
+ void operator()(int& val) const
+ {
+ val = val_;
+ }
+
+ int val_;
+};
+
+int main()
+{
+ const mapbox::util::variant<int> var(123);
+ const mutating_visitor visitor(456);
+ mapbox::util::apply_visitor(visitor, var);
+}
diff --git a/third_party/variant/test/compilation_failure/no-reference.cpp b/third_party/variant/test/compilation_failure/no-reference.cpp
new file mode 100644
index 0000000..17123ce
--- /dev/null
+++ b/third_party/variant/test/compilation_failure/no-reference.cpp
@@ -0,0 +1,9 @@
+
+// @EXPECTED: Variant can not hold reference types
+
+#include <variant.hpp>
+
+int main()
+{
+ mapbox::util::variant<double, int&, long> x{mapbox::util::no_init()};
+}
diff --git a/third_party/variant/test/include/catch.hpp b/third_party/variant/test/include/catch.hpp
new file mode 100644
index 0000000..dd6e3ed
--- /dev/null
+++ b/third_party/variant/test/include/catch.hpp
@@ -0,0 +1,11613 @@
+/*
+ * Catch v1.3.2
+ * Generated: 2015-12-28 15:07:07.166291
+ * ----------------------------------------------------------
+ * This file has been merged from multiple headers. Please don't edit it directly
+ * Copyright (c) 2012 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
+
+#define TWOBLUECUBES_CATCH_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang system_header
+#elif defined __GNUC__
+#pragma GCC system_header
+#endif
+
+// #included from: internal/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 push
+#pragma GCC diagnostic ignored "-Wpadded"
+#endif
+#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
+#define CATCH_IMPL
+#endif
+
+#ifdef CATCH_IMPL
+#ifndef CLARA_CONFIG_MAIN
+#define CLARA_CONFIG_MAIN_NOT_DEFINED
+#define CLARA_CONFIG_MAIN
+#endif
+#endif
+
+// #included from: internal/catch_notimplemented_exception.h
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
+
+// #included from: catch_common.h
+#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
+
+#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)
+#define INTERNAL_CATCH_UNIQUE_NAME(name) INTERNAL_CATCH_UNIQUE_NAME_LINE(name, __LINE__)
+
+#define INTERNAL_CATCH_STRINGIFY2(expr) #expr
+#define INTERNAL_CATCH_STRINGIFY(expr) INTERNAL_CATCH_STRINGIFY2(expr)
+
+#include <algorithm>
+#include <sstream>
+#include <stdexcept>
+
+// #included from: catch_compiler_capabilities.h
+#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
+
+// Detect a number of compiler features - mostly C++11/14 conformance - 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_OR_GREATER : Is C++11 supported?
+
+// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
+
+// ****************
+// Note to maintainers: if new toggles are added please document them
+// in configuration.md, too
+// ****************
+
+// In general each macro has a _NO_<feature name> form
+// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) 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 __clang__
+
+#if __has_feature(cxx_nullptr)
+#define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+#if __has_feature(cxx_noexcept)
+#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#endif
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// 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 (_MSC_VER >= 1600)
+#define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#if (_MSC_VER >= 1900) // (VC++ 13 (VS2015))
+#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#endif
+
+#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
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// C++ language feature support
+
+// catch all support for C++11
+#if defined(__cplusplus) && __cplusplus >= 201103L
+
+#define 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
+
+#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
+#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_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_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_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
+#define CATCH_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+// noexcept support:
+#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
+#define CATCH_NOEXCEPT noexcept
+#define CATCH_NOEXCEPT_IS(x) noexcept(x)
+#else
+#define CATCH_NOEXCEPT throw()
+#define CATCH_NOEXCEPT_IS(x)
+#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<T>
+#else
+#define CATCH_AUTO_PTR(T) std::auto_ptr<T>
+#endif
+
+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() {}
+ 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 <typename ContainerT>
+inline 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 <typename AssociativeContainerT>
+inline 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 endsWith(std::string const& s, std::string const& 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);
+ SourceLineInfo(SourceLineInfo const& other);
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ 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;
+
+ std::string file;
+ std::size_t line;
+};
+
+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();
+
+// Use this in variadic streaming macros to allow
+// >> +StreamEndStop
+// as well as
+// >> stuff +StreamEndStop
+struct StreamEndStop
+{
+ std::string operator+()
+ {
+ return std::string();
+ }
+};
+template <typename T>
+T const& operator+(T const& value, StreamEndStop)
+{
+ return value;
+}
+}
+
+#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo(__FILE__, static_cast<std::size_t>(__LINE__))
+#define CATCH_INTERNAL_ERROR(msg) ::Catch::throwLogicError(msg, CATCH_INTERNAL_LINEINFO);
+
+#include <ostream>
+
+namespace Catch {
+
+class NotImplementedException : public std::exception
+{
+ public:
+ NotImplementedException(SourceLineInfo const& lineInfo);
+ NotImplementedException(NotImplementedException const&) {}
+
+ virtual ~NotImplementedException() CATCH_NOEXCEPT {}
+
+ virtual const char* what() const CATCH_NOEXCEPT;
+
+ private:
+ std::string m_what;
+ SourceLineInfo m_lineInfo;
+};
+
+} // end namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException(CATCH_INTERNAL_LINEINFO)
+
+// #included from: internal/catch_context.h
+#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
+
+// #included from: catch_interfaces_generators.h
+#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
+
+#include <string>
+
+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 <typename T>
+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 <typename T = IShared>
+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
+
+#include <memory>
+#include <stdlib.h>
+#include <vector>
+
+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<IConfig const> getConfig() const = 0;
+};
+
+struct IMutableContext : IContext
+{
+ virtual ~IMutableContext();
+ virtual void setResultCapture(IResultCapture* resultCapture) = 0;
+ virtual void setRunner(IRunner* runner) = 0;
+ virtual void setConfig(Ptr<IConfig const> 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
+
+#include <vector>
+
+namespace Catch {
+
+class TestSpec;
+
+struct ITestCase : IShared
+{
+ virtual void invoke() const = 0;
+
+ protected:
+ virtual ~ITestCase();
+};
+
+class TestCase;
+struct IConfig;
+
+struct ITestCaseRegistry
+{
+ virtual ~ITestCaseRegistry();
+ virtual std::vector<TestCase> const& getAllTests() const = 0;
+ virtual std::vector<TestCase> const& getAllTestsSorted(IConfig const& config) const = 0;
+};
+
+bool matchTest(TestCase const& testCase, TestSpec const& testSpec, IConfig const& config);
+std::vector<TestCase> filterTests(std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config);
+std::vector<TestCase> const& getAllTestCasesSorted(IConfig const& config);
+}
+
+namespace Catch {
+
+template <typename C>
+class MethodTestCase : public SharedImpl<ITestCase>
+{
+
+ public:
+ MethodTestCase(void (C::*method)()) : m_method(method) {}
+
+ virtual void invoke() const
+ {
+ C obj;
+ (obj.*m_method)();
+ }
+
+ private:
+ virtual ~MethodTestCase() {}
+
+ void (C::*m_method)();
+};
+
+typedef void (*TestFunction)();
+
+struct NameAndDesc
+{
+ NameAndDesc(const char* _name = "", const char* _description = "")
+ : name(_name), description(_description)
+ {
+ }
+
+ const char* name;
+ const char* description;
+};
+
+void registerTestCase(ITestCase* testCase,
+ char const* className,
+ NameAndDesc const& nameAndDesc,
+ SourceLineInfo const& lineInfo);
+
+struct AutoReg
+{
+
+ AutoReg(TestFunction function,
+ SourceLineInfo const& lineInfo,
+ NameAndDesc const& nameAndDesc);
+
+ template <typename C>
+ AutoReg(void (C::*method)(),
+ char const* className,
+ NameAndDesc const& nameAndDesc,
+ SourceLineInfo const& lineInfo)
+ {
+
+ registerTestCase(new MethodTestCase<C>(method),
+ className,
+ nameAndDesc,
+ lineInfo);
+ }
+
+ ~AutoReg();
+
+ private:
+ AutoReg(AutoReg const&);
+ void operator=(AutoReg const&);
+};
+
+void registerTestCaseFunction(TestFunction function,
+ SourceLineInfo const& lineInfo,
+ NameAndDesc const& nameAndDesc);
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TESTCASE(...) \
+ static void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)(); \
+ namespace { \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(__VA_ARGS__)); \
+ } \
+ static void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)()
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_METHOD_AS_TEST_CASE(QualifiedMethod, ...) \
+ namespace { \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc(__VA_ARGS__), CATCH_INTERNAL_LINEINFO); \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST_CASE_METHOD(ClassName, ...) \
+ namespace { \
+ struct INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____) : ClassName \
+ { \
+ void test(); \
+ }; \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)::test, #ClassName, Catch::NameAndDesc(__VA_ARGS__), CATCH_INTERNAL_LINEINFO); \
+ } \
+ void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)::test()
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_REGISTER_TESTCASE(Function, ...) \
+ Catch::AutoReg(Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(__VA_ARGS__));
+
+#else
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TESTCASE(Name, Desc) \
+ static void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)(); \
+ namespace { \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(Name, Desc)); \
+ } \
+ static void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)()
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_METHOD_AS_TEST_CASE(QualifiedMethod, Name, Desc) \
+ namespace { \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc(Name, Desc), CATCH_INTERNAL_LINEINFO); \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST_CASE_METHOD(ClassName, TestName, Desc) \
+ namespace { \
+ struct INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____) : ClassName \
+ { \
+ void test(); \
+ }; \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME(autoRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)::test, #ClassName, Catch::NameAndDesc(TestName, Desc), CATCH_INTERNAL_LINEINFO); \
+ } \
+ void INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____T_E_S_T____)::test()
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_REGISTER_TESTCASE(Function, Name, Desc) \
+ Catch::AutoReg(Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc(Name, Desc));
+#endif
+
+// #included from: internal/catch_capture.hpp
+#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
+
+// #included from: catch_result_builder.h
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
+
+// #included from: catch_result_type.h
+#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
+
+namespace Catch {
+
+// ResultWas::OfType enum
+struct ResultWas
+{
+ enum OfType
+ {
+ Unknown = -1,
+ Ok = 0,
+ Info = 1,
+ Warning = 2,
+
+ FailureBit = 0x10,
+
+ ExpressionFailed = FailureBit | 1,
+ ExplicitFailure = FailureBit | 2,
+
+ Exception = 0x100 | FailureBit,
+
+ ThrewException = Exception | 1,
+ DidntThrowException = Exception | 2,
+
+ FatalErrorCondition = 0x200 | FailureBit
+
+ };
+};
+
+inline bool isOk(ResultWas::OfType resultType)
+{
+ return (resultType & ResultWas::FailureBit) == 0;
+}
+inline bool isJustInfo(int flags)
+{
+ return flags == ResultWas::Info;
+}
+
+// ResultDisposition::Flags enum
+struct ResultDisposition
+{
+ enum Flags
+ {
+ Normal = 0x01,
+
+ ContinueOnFailure = 0x02, // Failures fail test, but execution continues
+ FalseTest = 0x04, // Prefix expression with !
+ SuppressFail = 0x08 // Failures are reported but do not fail the test
+ };
+};
+
+inline ResultDisposition::Flags operator|(ResultDisposition::Flags lhs, ResultDisposition::Flags rhs)
+{
+ return static_cast<ResultDisposition::Flags>(static_cast<int>(lhs) | static_cast<int>(rhs));
+}
+
+inline bool shouldContinueOnFailure(int flags) { return (flags & ResultDisposition::ContinueOnFailure) != 0; }
+inline bool isFalseTest(int flags) { return (flags & ResultDisposition::FalseTest) != 0; }
+inline bool shouldSuppressFailure(int flags) { return (flags & ResultDisposition::SuppressFail) != 0; }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.h
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+struct AssertionInfo
+{
+ AssertionInfo() {}
+ AssertionInfo(std::string const& _macroName,
+ SourceLineInfo const& _lineInfo,
+ std::string const& _capturedExpression,
+ ResultDisposition::Flags _resultDisposition);
+
+ std::string macroName;
+ SourceLineInfo lineInfo;
+ std::string capturedExpression;
+ ResultDisposition::Flags resultDisposition;
+};
+
+struct AssertionResultData
+{
+ AssertionResultData() : resultType(ResultWas::Unknown) {}
+
+ std::string reconstructedExpression;
+ std::string message;
+ ResultWas::OfType resultType;
+};
+
+class AssertionResult
+{
+ public:
+ AssertionResult();
+ AssertionResult(AssertionInfo const& info, AssertionResultData const& data);
+ ~AssertionResult();
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ AssertionResult(AssertionResult const&) = default;
+ AssertionResult(AssertionResult&&) = default;
+ AssertionResult& operator=(AssertionResult const&) = default;
+ AssertionResult& operator=(AssertionResult&&) = default;
+#endif
+
+ bool isOk() const;
+ bool succeeded() const;
+ ResultWas::OfType getResultType() const;
+ bool hasExpression() const;
+ bool hasMessage() const;
+ std::string getExpression() const;
+ std::string getExpressionInMacro() const;
+ bool hasExpandedExpression() const;
+ std::string getExpandedExpression() const;
+ std::string getMessage() const;
+ SourceLineInfo getSourceInfo() const;
+ std::string getTestMacroName() const;
+
+ protected:
+ AssertionInfo m_info;
+ AssertionResultData m_resultData;
+};
+
+} // end namespace Catch
+
+// #included from: catch_matchers.hpp
+#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+namespace Impl {
+
+namespace Generic {
+template <typename ExpressionT>
+class AllOf;
+template <typename ExpressionT>
+class AnyOf;
+template <typename ExpressionT>
+class Not;
+}
+
+template <typename ExpressionT>
+struct Matcher : SharedImpl<IShared>
+{
+ typedef ExpressionT ExpressionType;
+
+ virtual ~Matcher() {}
+ virtual Ptr<Matcher> clone() const = 0;
+ virtual bool match(ExpressionT const& expr) const = 0;
+ virtual std::string toString() const = 0;
+
+ Generic::AllOf<ExpressionT> operator&&(Matcher<ExpressionT> const& other) const;
+ Generic::AnyOf<ExpressionT> operator||(Matcher<ExpressionT> const& other) const;
+ Generic::Not<ExpressionT> operator!() const;
+};
+
+template <typename DerivedT, typename ExpressionT>
+struct MatcherImpl : Matcher<ExpressionT>
+{
+
+ virtual Ptr<Matcher<ExpressionT>> clone() const
+ {
+ return Ptr<Matcher<ExpressionT>>(new DerivedT(static_cast<DerivedT const&>(*this)));
+ }
+};
+
+namespace Generic {
+template <typename ExpressionT>
+class Not : public MatcherImpl<Not<ExpressionT>, ExpressionT>
+{
+ public:
+ explicit Not(Matcher<ExpressionT> const& matcher) : m_matcher(matcher.clone()) {}
+ Not(Not const& other) : m_matcher(other.m_matcher) {}
+
+ virtual bool match(ExpressionT const& expr) const CATCH_OVERRIDE
+ {
+ return !m_matcher->match(expr);
+ }
+
+ virtual std::string toString() const CATCH_OVERRIDE
+ {
+ return "not " + m_matcher->toString();
+ }
+
+ private:
+ Ptr<Matcher<ExpressionT>> m_matcher;
+};
+
+template <typename ExpressionT>
+class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT>
+{
+ public:
+ AllOf() {}
+ AllOf(AllOf const& other) : m_matchers(other.m_matchers) {}
+
+ AllOf& add(Matcher<ExpressionT> const& matcher)
+ {
+ m_matchers.push_back(matcher.clone());
+ return *this;
+ }
+ virtual bool match(ExpressionT const& expr) const
+ {
+ for (std::size_t i = 0; i < m_matchers.size(); ++i)
+ if (!m_matchers[i]->match(expr))
+ return false;
+ return true;
+ }
+ virtual std::string toString() const
+ {
+ std::ostringstream oss;
+ oss << "( ";
+ for (std::size_t i = 0; i < m_matchers.size(); ++i)
+ {
+ if (i != 0)
+ oss << " and ";
+ oss << m_matchers[i]->toString();
+ }
+ oss << " )";
+ return oss.str();
+ }
+
+ AllOf operator&&(Matcher<ExpressionT> const& other) const
+ {
+ AllOf allOfExpr(*this);
+ allOfExpr.add(other);
+ return allOfExpr;
+ }
+
+ private:
+ std::vector<Ptr<Matcher<ExpressionT>>> m_matchers;
+};
+
+template <typename ExpressionT>
+class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT>
+{
+ public:
+ AnyOf() {}
+ AnyOf(AnyOf const& other) : m_matchers(other.m_matchers) {}
+
+ AnyOf& add(Matcher<ExpressionT> const& matcher)
+ {
+ m_matchers.push_back(matcher.clone());
+ return *this;
+ }
+ virtual bool match(ExpressionT const& expr) const
+ {
+ for (std::size_t i = 0; i < m_matchers.size(); ++i)
+ if (m_matchers[i]->match(expr))
+ return true;
+ return false;
+ }
+ virtual std::string toString() const
+ {
+ std::ostringstream oss;
+ oss << "( ";
+ for (std::size_t i = 0; i < m_matchers.size(); ++i)
+ {
+ if (i != 0)
+ oss << " or ";
+ oss << m_matchers[i]->toString();
+ }
+ oss << " )";
+ return oss.str();
+ }
+
+ AnyOf operator||(Matcher<ExpressionT> const& other) const
+ {
+ AnyOf anyOfExpr(*this);
+ anyOfExpr.add(other);
+ return anyOfExpr;
+ }
+
+ private:
+ std::vector<Ptr<Matcher<ExpressionT>>> m_matchers;
+};
+
+} // namespace Generic
+
+template <typename ExpressionT>
+Generic::AllOf<ExpressionT> Matcher<ExpressionT>::operator&&(Matcher<ExpressionT> const& other) const
+{
+ Generic::AllOf<ExpressionT> allOfExpr;
+ allOfExpr.add(*this);
+ allOfExpr.add(other);
+ return allOfExpr;
+}
+
+template <typename ExpressionT>
+Generic::AnyOf<ExpressionT> Matcher<ExpressionT>::operator||(Matcher<ExpressionT> const& other) const
+{
+ Generic::AnyOf<ExpressionT> anyOfExpr;
+ anyOfExpr.add(*this);
+ anyOfExpr.add(other);
+ return anyOfExpr;
+}
+
+template <typename ExpressionT>
+Generic::Not<ExpressionT> Matcher<ExpressionT>::operator!() const
+{
+ return Generic::Not<ExpressionT>(*this);
+}
+
+namespace StdString {
+
+inline std::string makeString(std::string const& str) { return str; }
+inline std::string makeString(const char* str) { return str ? std::string(str) : std::string(); }
+
+struct CasedString
+{
+ CasedString(std::string const& str, CaseSensitive::Choice caseSensitivity)
+ : m_caseSensitivity(caseSensitivity),
+ m_str(adjustString(str))
+ {
+ }
+ std::string adjustString(std::string const& str) const
+ {
+ return m_caseSensitivity == CaseSensitive::No
+ ? toLower(str)
+ : str;
+ }
+ std::string toStringSuffix() const
+ {
+ return m_caseSensitivity == CaseSensitive::No
+ ? " (case insensitive)"
+ : "";
+ }
+ CaseSensitive::Choice m_caseSensitivity;
+ std::string m_str;
+};
+
+struct Equals : MatcherImpl<Equals, std::string>
+{
+ Equals(std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+ : m_data(str, caseSensitivity)
+ {
+ }
+ Equals(Equals const& other) : m_data(other.m_data) {}
+
+ virtual ~Equals();
+
+ virtual bool match(std::string const& expr) const
+ {
+ return m_data.m_str == m_data.adjustString(expr);
+ ;
+ }
+ virtual std::string toString() const
+ {
+ return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+ }
+
+ CasedString m_data;
+};
+
+struct Contains : MatcherImpl<Contains, std::string>
+{
+ Contains(std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+ : m_data(substr, caseSensitivity) {}
+ Contains(Contains const& other) : m_data(other.m_data) {}
+
+ virtual ~Contains();
+
+ virtual bool match(std::string const& expr) const
+ {
+ return m_data.adjustString(expr).find(m_data.m_str) != std::string::npos;
+ }
+ virtual std::string toString() const
+ {
+ return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+ }
+
+ CasedString m_data;
+};
+
+struct StartsWith : MatcherImpl<StartsWith, std::string>
+{
+ StartsWith(std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+ : m_data(substr, caseSensitivity) {}
+
+ StartsWith(StartsWith const& other) : m_data(other.m_data) {}
+
+ virtual ~StartsWith();
+
+ virtual bool match(std::string const& expr) const
+ {
+ return m_data.adjustString(expr).find(m_data.m_str) == 0;
+ }
+ virtual std::string toString() const
+ {
+ return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+ }
+
+ CasedString m_data;
+};
+
+struct EndsWith : MatcherImpl<EndsWith, std::string>
+{
+ EndsWith(std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+ : m_data(substr, caseSensitivity) {}
+ EndsWith(EndsWith const& other) : m_data(other.m_data) {}
+
+ virtual ~EndsWith();
+
+ virtual bool match(std::string const& expr) const
+ {
+ return m_data.adjustString(expr).find(m_data.m_str) == expr.size() - m_data.m_str.size();
+ }
+ virtual std::string toString() const
+ {
+ return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+ }
+
+ CasedString m_data;
+};
+} // namespace StdString
+} // namespace Impl
+
+// The following functions create the actual matcher objects.
+// This allows the types to be inferred
+template <typename ExpressionT>
+inline Impl::Generic::Not<ExpressionT> Not(Impl::Matcher<ExpressionT> const& m)
+{
+ return Impl::Generic::Not<ExpressionT>(m);
+}
+
+template <typename ExpressionT>
+inline Impl::Generic::AllOf<ExpressionT> AllOf(Impl::Matcher<ExpressionT> const& m1,
+ Impl::Matcher<ExpressionT> const& m2)
+{
+ return Impl::Generic::AllOf<ExpressionT>().add(m1).add(m2);
+}
+template <typename ExpressionT>
+inline Impl::Generic::AllOf<ExpressionT> AllOf(Impl::Matcher<ExpressionT> const& m1,
+ Impl::Matcher<ExpressionT> const& m2,
+ Impl::Matcher<ExpressionT> const& m3)
+{
+ return Impl::Generic::AllOf<ExpressionT>().add(m1).add(m2).add(m3);
+}
+template <typename ExpressionT>
+inline Impl::Generic::AnyOf<ExpressionT> AnyOf(Impl::Matcher<ExpressionT> const& m1,
+ Impl::Matcher<ExpressionT> const& m2)
+{
+ return Impl::Generic::AnyOf<ExpressionT>().add(m1).add(m2);
+}
+template <typename ExpressionT>
+inline Impl::Generic::AnyOf<ExpressionT> AnyOf(Impl::Matcher<ExpressionT> const& m1,
+ Impl::Matcher<ExpressionT> const& m2,
+ Impl::Matcher<ExpressionT> const& m3)
+{
+ return Impl::Generic::AnyOf<ExpressionT>().add(m1).add(m2).add(m3);
+}
+
+inline Impl::StdString::Equals Equals(std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+{
+ return Impl::StdString::Equals(str, caseSensitivity);
+}
+inline Impl::StdString::Equals Equals(const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+{
+ return Impl::StdString::Equals(Impl::StdString::makeString(str), caseSensitivity);
+}
+inline Impl::StdString::Contains Contains(std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+{
+ return Impl::StdString::Contains(substr, caseSensitivity);
+}
+inline Impl::StdString::Contains Contains(const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
+{
+ return Impl::StdString::Contains(Impl::StdString::makeString(substr), caseSensitivity);
+}
+inline Impl::StdString::StartsWith StartsWith(std::string const& substr)
+{
+ return Impl::StdString::StartsWith(substr);
+}
+inline Impl::StdString::StartsWith StartsWith(const char* substr)
+{
+ return Impl::StdString::StartsWith(Impl::StdString::makeString(substr));
+}
+inline Impl::StdString::EndsWith EndsWith(std::string const& substr)
+{
+ return Impl::StdString::EndsWith(substr);
+}
+inline Impl::StdString::EndsWith EndsWith(const char* substr)
+{
+ return Impl::StdString::EndsWith(Impl::StdString::makeString(substr));
+}
+
+} // namespace Matchers
+
+using namespace Matchers;
+
+} // namespace Catch
+
+namespace Catch {
+
+struct TestFailureException
+{
+};
+
+template <typename T>
+class ExpressionLhs;
+
+struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
+
+struct CopyableStream
+{
+ CopyableStream() {}
+ CopyableStream(CopyableStream const& other)
+ {
+ oss << other.oss.str();
+ }
+ CopyableStream& operator=(CopyableStream const& other)
+ {
+ oss.str("");
+ oss << other.oss.str();
+ return *this;
+ }
+ std::ostringstream oss;
+};
+
+class ResultBuilder
+{
+ public:
+ ResultBuilder(char const* macroName,
+ SourceLineInfo const& lineInfo,
+ char const* capturedExpression,
+ ResultDisposition::Flags resultDisposition,
+ char const* secondArg = "");
+
+ template <typename T>
+ ExpressionLhs<T const&> operator<=(T const& operand);
+ ExpressionLhs<bool> operator<=(bool value);
+
+ template <typename T>
+ ResultBuilder& operator<<(T const& value)
+ {
+ m_stream.oss << value;
+ return *this;
+ }
+
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator&&(RhsT const&);
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator||(RhsT const&);
+
+ ResultBuilder& setResultType(ResultWas::OfType result);
+ ResultBuilder& setResultType(bool result);
+ ResultBuilder& setLhs(std::string const& lhs);
+ ResultBuilder& setRhs(std::string const& rhs);
+ ResultBuilder& setOp(std::string const& op);
+
+ void endExpression();
+
+ std::string reconstructExpression() const;
+ AssertionResult build() const;
+
+ void useActiveException(ResultDisposition::Flags resultDisposition = ResultDisposition::Normal);
+ void captureResult(ResultWas::OfType resultType);
+ void captureExpression();
+ void captureExpectedException(std::string const& expectedMessage);
+ void captureExpectedException(Matchers::Impl::Matcher<std::string> const& matcher);
+ void handleResult(AssertionResult const& result);
+ void react();
+ bool shouldDebugBreak() const;
+ bool allowThrows() const;
+
+ private:
+ AssertionInfo m_assertionInfo;
+ AssertionResultData m_data;
+ struct ExprComponents
+ {
+ ExprComponents() : testFalse(false) {}
+ bool testFalse;
+ std::string lhs, rhs, op;
+ } m_exprComponents;
+ CopyableStream m_stream;
+
+ bool m_shouldDebugBreak;
+ bool m_shouldThrow;
+};
+
+} // namespace Catch
+
+// Include after due to circular dependency:
+// #included from: catch_expression_lhs.hpp
+#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
+
+// #included from: catch_evaluate.hpp
+#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4389) // '==' : signed/unsigned mismatch
+#endif
+
+#include <cstddef>
+
+namespace Catch {
+namespace Internal {
+
+enum Operator
+{
+ IsEqualTo,
+ IsNotEqualTo,
+ IsLessThan,
+ IsGreaterThan,
+ IsLessThanOrEqualTo,
+ IsGreaterThanOrEqualTo
+};
+
+template <Operator Op>
+struct OperatorTraits
+{
+ static const char* getName() { return "*error*"; }
+};
+template <>
+struct OperatorTraits<IsEqualTo>
+{
+ static const char* getName() { return "=="; }
+};
+template <>
+struct OperatorTraits<IsNotEqualTo>
+{
+ static const char* getName() { return "!="; }
+};
+template <>
+struct OperatorTraits<IsLessThan>
+{
+ static const char* getName() { return "<"; }
+};
+template <>
+struct OperatorTraits<IsGreaterThan>
+{
+ static const char* getName() { return ">"; }
+};
+template <>
+struct OperatorTraits<IsLessThanOrEqualTo>
+{
+ static const char* getName() { return "<="; }
+};
+template <>
+struct OperatorTraits<IsGreaterThanOrEqualTo>
+{
+ static const char* getName() { return ">="; }
+};
+
+template <typename T>
+inline T& opCast(T const& t)
+{
+ return const_cast<T&>(t);
+}
+
+// nullptr_t support based on pull request #154 from Konstantin Baumann
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+inline std::nullptr_t opCast(std::nullptr_t)
+{
+ return nullptr;
+}
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+// So the compare overloads can be operator agnostic we convey the operator as a template
+// enum, which is used to specialise an Evaluator for doing the comparison.
+template <typename T1, typename T2, Operator Op>
+class Evaluator
+{
+};
+
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsEqualTo>
+{
+ static bool evaluate(T1 const& lhs, T2 const& rhs)
+ {
+ return opCast(lhs) == opCast(rhs);
+ }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsNotEqualTo>
+{
+ static bool evaluate(T1 const& lhs, T2 const& rhs)
+ {
+ return opCast(lhs) != opCast(rhs);
+ }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsLessThan>
+{
+ static bool evaluate(T1 const& lhs, T2 const& rhs)
+ {
+ return opCast(lhs) < opCast(rhs);
+ }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsGreaterThan>
+{
+ static bool evaluate(T1 const& lhs, T2 const& rhs)
+ {
+ return opCast(lhs) > opCast(rhs);
+ }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsGreaterThanOrEqualTo>
+{
+ static bool evaluate(T1 const& lhs, T2 const& rhs)
+ {
+ return opCast(lhs) >= opCast(rhs);
+ }
+};
+template <typename T1, typename T2>
+struct Evaluator<T1, T2, IsLessThanOrEqualTo>
+{
+ static bool evaluate(T1 const& lhs, T2 const& rhs)
+ {
+ return opCast(lhs) <= opCast(rhs);
+ }
+};
+
+template <Operator Op, typename T1, typename T2>
+bool applyEvaluator(T1 const& lhs, T2 const& rhs)
+{
+ return Evaluator<T1, T2, Op>::evaluate(lhs, rhs);
+}
+
+// This level of indirection allows us to specialise for integer types
+// to avoid signed/ unsigned warnings
+
+// "base" overload
+template <Operator Op, typename T1, typename T2>
+bool compare(T1 const& lhs, T2 const& rhs)
+{
+ return Evaluator<T1, T2, Op>::evaluate(lhs, rhs);
+}
+
+// unsigned X to int
+template <Operator Op>
+bool compare(unsigned int lhs, int rhs)
+{
+ return applyEvaluator<Op>(lhs, static_cast<unsigned int>(rhs));
+}
+template <Operator Op>
+bool compare(unsigned long lhs, int rhs)
+{
+ return applyEvaluator<Op>(lhs, static_cast<unsigned int>(rhs));
+}
+template <Operator Op>
+bool compare(unsigned char lhs, int rhs)
+{
+ return applyEvaluator<Op>(lhs, static_cast<unsigned int>(rhs));
+}
+
+// unsigned X to long
+template <Operator Op>
+bool compare(unsigned int lhs, long rhs)
+{
+ return applyEvaluator<Op>(lhs, static_cast<unsigned long>(rhs));
+}
+template <Operator Op>
+bool compare(unsigned long lhs, long rhs)
+{
+ return applyEvaluator<Op>(lhs, static_cast<unsigned long>(rhs));
+}
+template <Operator Op>
+bool compare(unsigned char lhs, long rhs)
+{
+ return applyEvaluator<Op>(lhs, static_cast<unsigned long>(rhs));
+}
+
+// int to unsigned X
+template <Operator Op>
+bool compare(int lhs, unsigned int rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned int>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(int lhs, unsigned long rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned int>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(int lhs, unsigned char rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned int>(lhs), rhs);
+}
+
+// long to unsigned X
+template <Operator Op>
+bool compare(long lhs, unsigned int rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long lhs, unsigned long rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long lhs, unsigned char rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+
+// pointer to long (when comparing against NULL)
+template <Operator Op, typename T>
+bool compare(long lhs, T* rhs)
+{
+ return Evaluator<T*, T*, Op>::evaluate(reinterpret_cast<T*>(lhs), rhs);
+}
+template <Operator Op, typename T>
+bool compare(T* lhs, long rhs)
+{
+ return Evaluator<T*, T*, Op>::evaluate(lhs, reinterpret_cast<T*>(rhs));
+}
+
+// pointer to int (when comparing against NULL)
+template <Operator Op, typename T>
+bool compare(int lhs, T* rhs)
+{
+ return Evaluator<T*, T*, Op>::evaluate(reinterpret_cast<T*>(lhs), rhs);
+}
+template <Operator Op, typename T>
+bool compare(T* lhs, int rhs)
+{
+ return Evaluator<T*, T*, Op>::evaluate(lhs, reinterpret_cast<T*>(rhs));
+}
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+// long long to unsigned X
+template <Operator Op>
+bool compare(long long lhs, unsigned int rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long long lhs, unsigned long rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long long lhs, unsigned long long rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(long long lhs, unsigned char rhs)
+{
+ return applyEvaluator<Op>(static_cast<unsigned long>(lhs), rhs);
+}
+
+// unsigned long long to X
+template <Operator Op>
+bool compare(unsigned long long lhs, int rhs)
+{
+ return applyEvaluator<Op>(static_cast<long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(unsigned long long lhs, long rhs)
+{
+ return applyEvaluator<Op>(static_cast<long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(unsigned long long lhs, long long rhs)
+{
+ return applyEvaluator<Op>(static_cast<long>(lhs), rhs);
+}
+template <Operator Op>
+bool compare(unsigned long long lhs, char rhs)
+{
+ return applyEvaluator<Op>(static_cast<long>(lhs), rhs);
+}
+
+// pointer to long long (when comparing against NULL)
+template <Operator Op, typename T>
+bool compare(long long lhs, T* rhs)
+{
+ return Evaluator<T*, T*, Op>::evaluate(reinterpret_cast<T*>(lhs), rhs);
+}
+template <Operator Op, typename T>
+bool compare(T* lhs, long long rhs)
+{
+ return Evaluator<T*, T*, Op>::evaluate(lhs, reinterpret_cast<T*>(rhs));
+}
+#endif // CATCH_CONFIG_CPP11_LONG_LONG
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+// pointer to nullptr_t (when comparing against nullptr)
+template <Operator Op, typename T>
+bool compare(std::nullptr_t, T* rhs)
+{
+ return Evaluator<T*, T*, Op>::evaluate(nullptr, rhs);
+}
+template <Operator Op, typename T>
+bool compare(T* lhs, std::nullptr_t)
+{
+ return Evaluator<T*, T*, Op>::evaluate(lhs, nullptr);
+}
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+} // end of namespace Internal
+} // end of namespace Catch
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// #included from: catch_tostring.h
+#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
+
+#include <cstddef>
+#include <iomanip>
+#include <limits>
+#include <sstream>
+#include <vector>
+
+#ifdef __OBJC__
+// #included from: catch_objc_arc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
+
+#import <Foundation/Foundation.h>
+
+#ifdef __has_feature
+#define CATCH_ARC_ENABLED __has_feature(objc_arc)
+#else
+#define CATCH_ARC_ENABLED 0
+#endif
+
+void arcSafeRelease(NSObject* obj);
+id performOptionalSelector(id obj, SEL sel);
+
+#if !CATCH_ARC_ENABLED
+inline void arcSafeRelease(NSObject* obj)
+{
+ [obj release];
+}
+inline id performOptionalSelector(id obj, SEL sel)
+{
+ if ([obj respondsToSelector:sel])
+ return [obj performSelector:sel];
+ return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED
+#define CATCH_ARC_STRONG
+#else
+inline void arcSafeRelease(NSObject*)
+{
+}
+inline id performOptionalSelector(id obj, SEL sel)
+{
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+#endif
+ if ([obj respondsToSelector:sel])
+ return [obj performSelector:sel];
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+ return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
+#define CATCH_ARC_STRONG __strong
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+#include <tuple>
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_IS_ENUM
+#include <type_traits>
+#endif
+
+namespace Catch {
+
+// Why we're here.
+template <typename T>
+std::string toString(T const& value);
+
+// Built in overloads
+
+std::string toString(std::string const& value);
+std::string toString(std::wstring const& value);
+std::string toString(const char* const value);
+std::string toString(char* const value);
+std::string toString(const wchar_t* const value);
+std::string toString(wchar_t* const value);
+std::string toString(int value);
+std::string toString(unsigned long value);
+std::string toString(unsigned int value);
+std::string toString(const double value);
+std::string toString(const float value);
+std::string toString(bool value);
+std::string toString(char value);
+std::string toString(signed char value);
+std::string toString(unsigned char value);
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+std::string toString(long long value);
+std::string toString(unsigned long long value);
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString(std::nullptr_t);
+#endif
+
+#ifdef __OBJC__
+std::string toString(NSString const* const& nsstring);
+std::string toString(NSString* CATCH_ARC_STRONG const& nsstring);
+std::string toString(NSObject* const& nsObject);
+#endif
+
+namespace Detail {
+
+extern const std::string unprintableString;
+
+struct BorgType
+{
+ template <typename T>
+ BorgType(T const&);
+};
+
+struct TrueType
+{
+ char sizer[1];
+};
+struct FalseType
+{
+ char sizer[2];
+};
+
+TrueType& testStreamable(std::ostream&);
+FalseType testStreamable(FalseType);
+
+FalseType operator<<(std::ostream const&, BorgType const&);
+
+template <typename T>
+struct IsStreamInsertable
+{
+ static std::ostream& s;
+ static T const& t;
+ enum
+ {
+ value = sizeof(testStreamable(s << t)) == sizeof(TrueType)
+ };
+};
+
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+template <typename T,
+ bool IsEnum = std::is_enum<T>::value>
+struct EnumStringMaker
+{
+ static std::string convert(T const&) { return unprintableString; }
+};
+
+template <typename T>
+struct EnumStringMaker<T, true>
+{
+ static std::string convert(T const& v)
+ {
+ return ::Catch::toString(
+ static_cast<typename std::underlying_type<T>::type>(v));
+ }
+};
+#endif
+template <bool C>
+struct StringMakerBase
+{
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+ template <typename T>
+ static std::string convert(T const& v)
+ {
+ return EnumStringMaker<T>::convert(v);
+ }
+#else
+ template <typename T>
+ static std::string convert(T const&)
+ {
+ return unprintableString;
+ }
+#endif
+};
+
+template <>
+struct StringMakerBase<true>
+{
+ template <typename T>
+ static std::string convert(T const& _value)
+ {
+ std::ostringstream oss;
+ oss << _value;
+ return oss.str();
+ }
+};
+
+std::string rawMemoryToString(const void* object, std::size_t size);
+
+template <typename T>
+inline std::string rawMemoryToString(const T& object)
+{
+ return rawMemoryToString(&object, sizeof(object));
+}
+
+} // end namespace Detail
+
+template <typename T>
+struct StringMaker : Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value>
+{
+};
+
+template <typename T>
+struct StringMaker<T*>
+{
+ template <typename U>
+ static std::string convert(U* p)
+ {
+ if (!p)
+ return "NULL";
+ else
+ return Detail::rawMemoryToString(p);
+ }
+};
+
+template <typename R, typename C>
+struct StringMaker<R C::*>
+{
+ static std::string convert(R C::*p)
+ {
+ if (!p)
+ return "NULL";
+ else
+ return Detail::rawMemoryToString(p);
+ }
+};
+
+namespace Detail {
+template <typename InputIterator>
+std::string rangeToString(InputIterator first, InputIterator last);
+}
+
+//template<typename T, typename Allocator>
+//struct StringMaker<std::vector<T, Allocator> > {
+// static std::string convert( std::vector<T,Allocator> const& v ) {
+// return Detail::rangeToString( v.begin(), v.end() );
+// }
+//};
+
+template <typename T, typename Allocator>
+std::string toString(std::vector<T, Allocator> const& v)
+{
+ return Detail::rangeToString(v.begin(), v.end());
+}
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+
+// toString for tuples
+namespace TupleDetail {
+template <
+ typename Tuple,
+ std::size_t N = 0,
+ bool = (N < std::tuple_size<Tuple>::value)>
+struct ElementPrinter
+{
+ static void print(const Tuple& tuple, std::ostream& os)
+ {
+ os << (N ? ", " : " ")
+ << Catch::toString(std::get<N>(tuple));
+ ElementPrinter<Tuple, N + 1>::print(tuple, os);
+ }
+};
+
+template <
+ typename Tuple,
+ std::size_t N>
+struct ElementPrinter<Tuple, N, false>
+{
+ static void print(const Tuple&, std::ostream&) {}
+};
+}
+
+template <typename... Types>
+struct StringMaker<std::tuple<Types...>>
+{
+
+ static std::string convert(const std::tuple<Types...>& tuple)
+ {
+ std::ostringstream os;
+ os << '{';
+ TupleDetail::ElementPrinter<std::tuple<Types...>>::print(tuple, os);
+ os << " }";
+ return os.str();
+ }
+};
+#endif // CATCH_CONFIG_CPP11_TUPLE
+
+namespace Detail {
+template <typename T>
+std::string makeString(T const& value)
+{
+ return StringMaker<T>::convert(value);
+}
+} // end namespace Detail
+
+/// \brief converts any type to a string
+///
+/// The default template forwards on to ostringstream - except when an
+/// ostringstream overload does not exist - in which case it attempts to detect
+/// that and writes {?}.
+/// Overload (not specialise) this template for custom typs that you don't want
+/// to provide an ostream overload for.
+template <typename T>
+std::string toString(T const& value)
+{
+ return StringMaker<T>::convert(value);
+}
+
+namespace Detail {
+template <typename InputIterator>
+std::string rangeToString(InputIterator first, InputIterator last)
+{
+ std::ostringstream oss;
+ oss << "{ ";
+ if (first != last)
+ {
+ oss << Catch::toString(*first);
+ for (++first; first != last; ++first)
+ oss << ", " << Catch::toString(*first);
+ }
+ oss << " }";
+ return oss.str();
+}
+}
+
+} // end namespace Catch
+
+namespace Catch {
+
+// Wraps the LHS of an expression and captures the operator and RHS (if any) -
+// wrapping them all in a ResultBuilder object
+template <typename T>
+class ExpressionLhs
+{
+ ExpressionLhs& operator=(ExpressionLhs const&);
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ ExpressionLhs& operator=(ExpressionLhs&&) = delete;
+#endif
+
+ public:
+ ExpressionLhs(ResultBuilder& rb, T lhs) : m_rb(rb), m_lhs(lhs) {}
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ ExpressionLhs(ExpressionLhs const&) = default;
+ ExpressionLhs(ExpressionLhs&&) = default;
+#endif
+
+ template <typename RhsT>
+ ResultBuilder& operator==(RhsT const& rhs)
+ {
+ return captureExpression<Internal::IsEqualTo>(rhs);
+ }
+
+ template <typename RhsT>
+ ResultBuilder& operator!=(RhsT const& rhs)
+ {
+ return captureExpression<Internal::IsNotEqualTo>(rhs);
+ }
+
+ template <typename RhsT>
+ ResultBuilder& operator<(RhsT const& rhs)
+ {
+ return captureExpression<Internal::IsLessThan>(rhs);
+ }
+
+ template <typename RhsT>
+ ResultBuilder& operator>(RhsT const& rhs)
+ {
+ return captureExpression<Internal::IsGreaterThan>(rhs);
+ }
+
+ template <typename RhsT>
+ ResultBuilder& operator<=(RhsT const& rhs)
+ {
+ return captureExpression<Internal::IsLessThanOrEqualTo>(rhs);
+ }
+
+ template <typename RhsT>
+ ResultBuilder& operator>=(RhsT const& rhs)
+ {
+ return captureExpression<Internal::IsGreaterThanOrEqualTo>(rhs);
+ }
+
+ ResultBuilder& operator==(bool rhs)
+ {
+ return captureExpression<Internal::IsEqualTo>(rhs);
+ }
+
+ ResultBuilder& operator!=(bool rhs)
+ {
+ return captureExpression<Internal::IsNotEqualTo>(rhs);
+ }
+
+ void endExpression()
+ {
+ bool value = m_lhs ? true : false;
+ m_rb
+ .setLhs(Catch::toString(value))
+ .setResultType(value)
+ .endExpression();
+ }
+
+ // Only simple binary expressions are allowed on the LHS.
+ // If more complex compositions are required then place the sub expression in parentheses
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator+(RhsT const&);
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator-(RhsT const&);
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator/(RhsT const&);
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator*(RhsT const&);
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator&&(RhsT const&);
+ template <typename RhsT>
+ STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator||(RhsT const&);
+
+ private:
+ template <Internal::Operator Op, typename RhsT>
+ ResultBuilder& captureExpression(RhsT const& rhs)
+ {
+ return m_rb
+ .setResultType(Internal::compare<Op>(m_lhs, rhs))
+ .setLhs(Catch::toString(m_lhs))
+ .setRhs(Catch::toString(rhs))
+ .setOp(Internal::OperatorTraits<Op>::getName());
+ }
+
+ private:
+ ResultBuilder& m_rb;
+ T m_lhs;
+};
+
+} // end namespace Catch
+
+namespace Catch {
+
+template <typename T>
+inline ExpressionLhs<T const&> ResultBuilder::operator<=(T const& operand)
+{
+ return ExpressionLhs<T const&>(*this, operand);
+}
+
+inline ExpressionLhs<bool> ResultBuilder::operator<=(bool value)
+{
+ return ExpressionLhs<bool>(*this, value);
+}
+
+} // namespace Catch
+
+// #included from: catch_message.h
+#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+struct MessageInfo
+{
+ MessageInfo(std::string const& _macroName,
+ SourceLineInfo const& _lineInfo,
+ ResultWas::OfType _type);
+
+ std::string macroName;
+ SourceLineInfo lineInfo;
+ ResultWas::OfType type;
+ std::string message;
+ unsigned int sequence;
+
+ bool operator==(MessageInfo const& other) const
+ {
+ return sequence == other.sequence;
+ }
+ bool operator<(MessageInfo const& other) const
+ {
+ return sequence < other.sequence;
+ }
+
+ private:
+ static unsigned int globalCount;
+};
+
+struct MessageBuilder
+{
+ MessageBuilder(std::string const& macroName,
+ SourceLineInfo const& lineInfo,
+ ResultWas::OfType type)
+ : m_info(macroName, lineInfo, type)
+ {
+ }
+
+ template <typename T>
+ MessageBuilder& operator<<(T const& value)
+ {
+ m_stream << value;
+ return *this;
+ }
+
+ MessageInfo m_info;
+ std::ostringstream m_stream;
+};
+
+class ScopedMessage
+{
+ public:
+ ScopedMessage(MessageBuilder const& builder);
+ ScopedMessage(ScopedMessage const& other);
+ ~ScopedMessage();
+
+ MessageInfo m_info;
+};
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_capture.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+class TestCase;
+class AssertionResult;
+struct AssertionInfo;
+struct SectionInfo;
+struct SectionEndInfo;
+struct MessageInfo;
+class ScopedMessageBuilder;
+struct Counts;
+
+struct IResultCapture
+{
+
+ virtual ~IResultCapture();
+
+ virtual void assertionEnded(AssertionResult const& result) = 0;
+ virtual bool sectionStarted(SectionInfo const& sectionInfo,
+ Counts& assertions) = 0;
+ virtual void sectionEnded(SectionEndInfo const& endInfo) = 0;
+ virtual void sectionEndedEarly(SectionEndInfo const& endInfo) = 0;
+ virtual void pushScopedMessage(MessageInfo const& message) = 0;
+ virtual void popScopedMessage(MessageInfo const& message) = 0;
+
+ virtual std::string getCurrentTestName() const = 0;
+ virtual const AssertionResult* getLastResult() const = 0;
+
+ virtual void handleFatalErrorCondition(std::string const& message) = 0;
+};
+
+IResultCapture& getResultCapture();
+}
+
+// #included from: catch_debugger.h
+#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
+
+// #included from: catch_platform.h
+#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
+
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+#define CATCH_PLATFORM_MAC
+#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+#define CATCH_PLATFORM_IPHONE
+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+#define CATCH_PLATFORM_WINDOWS
+#endif
+
+#include <string>
+
+namespace Catch {
+
+bool isDebuggerActive();
+void writeToDebugConsole(std::string const& text);
+}
+
+#ifdef CATCH_PLATFORM_MAC
+
+// The following code snippet based on:
+// http://cocoawithlove.com/2008/03/break-into-debugger.html
+#ifdef DEBUG
+#if defined(__ppc64__) || defined(__ppc__)
+#define CATCH_BREAK_INTO_DEBUGGER() \
+ if (Catch::isDebuggerActive()) \
+ { \
+ __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
+ : \
+ : \
+ : "memory", "r0", "r3", "r4"); \
+ }
+#else
+#define CATCH_BREAK_INTO_DEBUGGER() \
+ if (Catch::isDebuggerActive()) \
+ { \
+ __asm__("int $3\n" \
+ : \
+ :); \
+ }
+#endif
+#endif
+
+#elif defined(_MSC_VER)
+#define CATCH_BREAK_INTO_DEBUGGER() \
+ if (Catch::isDebuggerActive()) \
+ { \
+ __debugbreak(); \
+ }
+#elif defined(__MINGW32__)
+extern "C" __declspec(dllimport) void __stdcall DebugBreak();
+#define CATCH_BREAK_INTO_DEBUGGER() \
+ if (Catch::isDebuggerActive()) \
+ { \
+ DebugBreak(); \
+ }
+#endif
+
+#ifndef CATCH_BREAK_INTO_DEBUGGER
+#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
+#endif
+
+// #included from: catch_interfaces_runner.h
+#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
+
+namespace Catch {
+class TestCase;
+
+struct IRunner
+{
+ virtual ~IRunner();
+ virtual bool aborting() const = 0;
+};
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// In the event of a failure works out if the debugger needs to be invoked
+// and/or an exception thrown and takes appropriate action.
+// This needs to be done as a macro so the debugger will stop in the user
+// source code rather than in Catch library code
+#define INTERNAL_CATCH_REACT(resultBuilder) \
+ if (resultBuilder.shouldDebugBreak()) CATCH_BREAK_INTO_DEBUGGER(); \
+ resultBuilder.react();
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST(expr, resultDisposition, macroName) \
+ do \
+ { \
+ Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition); \
+ try \
+ { \
+ (__catchResult <= expr).endExpression(); \
+ } \
+ catch (...) \
+ { \
+ __catchResult.useActiveException(Catch::ResultDisposition::Normal); \
+ } \
+ INTERNAL_CATCH_REACT(__catchResult) \
+ } while (Catch::isTrue(false && (expr))) // expr here is never evaluated at runtime but it forces the compiler to give it a look
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_IF(expr, resultDisposition, macroName) \
+ INTERNAL_CATCH_TEST(expr, resultDisposition, macroName); \
+ if (Catch::getResultCapture().getLastResult()->succeeded())
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_ELSE(expr, resultDisposition, macroName) \
+ INTERNAL_CATCH_TEST(expr, resultDisposition, macroName); \
+ if (!Catch::getResultCapture().getLastResult()->succeeded())
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_NO_THROW(expr, resultDisposition, macroName) \
+ do \
+ { \
+ Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition); \
+ try \
+ { \
+ expr; \
+ __catchResult.captureResult(Catch::ResultWas::Ok); \
+ } \
+ catch (...) \
+ { \
+ __catchResult.useActiveException(resultDisposition); \
+ } \
+ INTERNAL_CATCH_REACT(__catchResult) \
+ } while (Catch::alwaysFalse())
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS(expr, resultDisposition, matcher, macroName) \
+ do \
+ { \
+ Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher); \
+ if (__catchResult.allowThrows()) \
+ try \
+ { \
+ expr; \
+ __catchResult.captureResult(Catch::ResultWas::DidntThrowException); \
+ } \
+ catch (...) \
+ { \
+ __catchResult.captureExpectedException(matcher); \
+ } \
+ else \
+ __catchResult.captureResult(Catch::ResultWas::Ok); \
+ INTERNAL_CATCH_REACT(__catchResult) \
+ } while (Catch::alwaysFalse())
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_AS(expr, exceptionType, resultDisposition, macroName) \
+ do \
+ { \
+ Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition); \
+ if (__catchResult.allowThrows()) \
+ try \
+ { \
+ expr; \
+ __catchResult.captureResult(Catch::ResultWas::DidntThrowException); \
+ } \
+ catch (exceptionType) \
+ { \
+ __catchResult.captureResult(Catch::ResultWas::Ok); \
+ } \
+ catch (...) \
+ { \
+ __catchResult.useActiveException(resultDisposition); \
+ } \
+ else \
+ __catchResult.captureResult(Catch::ResultWas::Ok); \
+ INTERNAL_CATCH_REACT(__catchResult) \
+ } while (Catch::alwaysFalse())
+
+///////////////////////////////////////////////////////////////////////////////
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define INTERNAL_CATCH_MSG(messageType, resultDisposition, macroName, ...) \
+ do \
+ { \
+ Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition); \
+ __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
+ __catchResult.captureResult(messageType); \
+ INTERNAL_CATCH_REACT(__catchResult) \
+ } while (Catch::alwaysFalse())
+#else
+#define INTERNAL_CATCH_MSG(messageType, resultDisposition, macroName, log) \
+ do \
+ { \
+ Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition); \
+ __catchResult << log + ::Catch::StreamEndStop(); \
+ __catchResult.captureResult(messageType); \
+ INTERNAL_CATCH_REACT(__catchResult) \
+ } while (Catch::alwaysFalse())
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_INFO(log, macroName) \
+ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME(scopedMessage) = Catch::MessageBuilder(macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info) << log;
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CHECK_THAT(arg, matcher, resultDisposition, macroName) \
+ do \
+ { \
+ Catch::ResultBuilder __catchResult(macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition); \
+ try \
+ { \
+ std::string matcherAsString = (matcher).toString(); \
+ __catchResult \
+ .setLhs(Catch::toString(arg)) \
+ .setRhs(matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString) \
+ .setOp("matches") \
+ .setResultType((matcher).match(arg)); \
+ __catchResult.captureExpression(); \
+ } \
+ catch (...) \
+ { \
+ __catchResult.useActiveException(resultDisposition | Catch::ResultDisposition::ContinueOnFailure); \
+ } \
+ INTERNAL_CATCH_REACT(__catchResult) \
+ } while (Catch::alwaysFalse())
+
+// #included from: internal/catch_section.h
+#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
+
+// #included from: catch_section_info.h
+#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
+
+// #included from: catch_totals.hpp
+#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
+
+#include <cstddef>
+
+namespace Catch {
+
+struct Counts
+{
+ Counts() : passed(0), failed(0), failedButOk(0) {}
+
+ Counts operator-(Counts const& other) const
+ {
+ Counts diff;
+ diff.passed = passed - other.passed;
+ diff.failed = failed - other.failed;
+ diff.failedButOk = failedButOk - other.failedButOk;
+ return diff;
+ }
+ Counts& operator+=(Counts const& other)
+ {
+ passed += other.passed;
+ failed += other.failed;
+ failedButOk += other.failedButOk;
+ return *this;
+ }
+
+ std::size_t total() const
+ {
+ return passed + failed + failedButOk;
+ }
+ bool allPassed() const
+ {
+ return failed == 0 && failedButOk == 0;
+ }
+ bool allOk() const
+ {
+ return failed == 0;
+ }
+
+ std::size_t passed;
+ std::size_t failed;
+ std::size_t failedButOk;
+};
+
+struct Totals
+{
+
+ Totals operator-(Totals const& other) const
+ {
+ Totals diff;
+ diff.assertions = assertions - other.assertions;
+ diff.testCases = testCases - other.testCases;
+ return diff;
+ }
+
+ Totals delta(Totals const& prevTotals) const
+ {
+ Totals diff = *this - prevTotals;
+ if (diff.assertions.failed > 0)
+ ++diff.testCases.failed;
+ else if (diff.assertions.failedButOk > 0)
+ ++diff.testCases.failedButOk;
+ else
+ ++diff.testCases.passed;
+ return diff;
+ }
+
+ Totals& operator+=(Totals const& other)
+ {
+ assertions += other.assertions;
+ testCases += other.testCases;
+ return *this;
+ }
+
+ Counts assertions;
+ Counts testCases;
+};
+}
+
+namespace Catch {
+
+struct SectionInfo
+{
+ SectionInfo(SourceLineInfo const& _lineInfo,
+ std::string const& _name,
+ std::string const& _description = std::string());
+
+ std::string name;
+ std::string description;
+ SourceLineInfo lineInfo;
+};
+
+struct SectionEndInfo
+{
+ SectionEndInfo(SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds)
+ : sectionInfo(_sectionInfo), prevAssertions(_prevAssertions), durationInSeconds(_durationInSeconds)
+ {
+ }
+
+ SectionInfo sectionInfo;
+ Counts prevAssertions;
+ double durationInSeconds;
+};
+
+} // end namespace Catch
+
+// #included from: catch_timer.h
+#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
+
+#ifdef CATCH_PLATFORM_WINDOWS
+typedef unsigned long long uint64_t;
+#else
+#include <stdint.h>
+#endif
+
+namespace Catch {
+
+class Timer
+{
+ public:
+ Timer() : m_ticks(0) {}
+ void start();
+ unsigned int getElapsedMicroseconds() const;
+ unsigned int getElapsedMilliseconds() const;
+ double getElapsedSeconds() const;
+
+ private:
+ uint64_t m_ticks;
+};
+
+} // namespace Catch
+
+#include <string>
+
+namespace Catch {
+
+class Section : NonCopyable
+{
+ public:
+ Section(SectionInfo const& info);
+ ~Section();
+
+ // This indicates whether the section should be executed or not
+ operator bool() const;
+
+ private:
+ SectionInfo m_info;
+
+ std::string m_name;
+ Counts m_assertions;
+ bool m_sectionIncluded;
+ Timer m_timer;
+};
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define INTERNAL_CATCH_SECTION(...) \
+ if (Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME(catch_internal_Section) = Catch::SectionInfo(CATCH_INTERNAL_LINEINFO, __VA_ARGS__))
+#else
+#define INTERNAL_CATCH_SECTION(name, desc) \
+ if (Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME(catch_internal_Section) = Catch::SectionInfo(CATCH_INTERNAL_LINEINFO, name, desc))
+#endif
+
+// #included from: internal/catch_generators.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
+
+#include <iterator>
+#include <stdlib.h>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+template <typename T>
+struct IGenerator
+{
+ virtual ~IGenerator() {}
+ virtual T getValue(std::size_t index) const = 0;
+ virtual std::size_t size() const = 0;
+};
+
+template <typename T>
+class BetweenGenerator : public IGenerator<T>
+{
+ public:
+ BetweenGenerator(T from, T to) : m_from(from), m_to(to) {}
+
+ virtual T getValue(std::size_t index) const
+ {
+ return m_from + static_cast<int>(index);
+ }
+
+ virtual std::size_t size() const
+ {
+ return static_cast<std::size_t>(1 + m_to - m_from);
+ }
+
+ private:
+ T m_from;
+ T m_to;
+};
+
+template <typename T>
+class ValuesGenerator : public IGenerator<T>
+{
+ public:
+ ValuesGenerator() {}
+
+ void add(T value)
+ {
+ m_values.push_back(value);
+ }
+
+ virtual T getValue(std::size_t index) const
+ {
+ return m_values[index];
+ }
+
+ virtual std::size_t size() const
+ {
+ return m_values.size();
+ }
+
+ private:
+ std::vector<T> m_values;
+};
+
+template <typename T>
+class CompositeGenerator
+{
+ public:
+ CompositeGenerator() : m_totalSize(0) {}
+
+ // *** Move semantics, similar to auto_ptr ***
+ CompositeGenerator(CompositeGenerator& other)
+ : m_fileInfo(other.m_fileInfo),
+ m_totalSize(0)
+ {
+ move(other);
+ }
+
+ CompositeGenerator& setFileInfo(const char* fileInfo)
+ {
+ m_fileInfo = fileInfo;
+ return *this;
+ }
+
+ ~CompositeGenerator()
+ {
+ deleteAll(m_composed);
+ }
+
+ operator T() const
+ {
+ size_t overallIndex = getCurrentContext().getGeneratorIndex(m_fileInfo, m_totalSize);
+
+ typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
+ typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
+ for (size_t index = 0; it != itEnd; ++it)
+ {
+ const IGenerator<T>* generator = *it;
+ if (overallIndex >= index && overallIndex < index + generator->size())
+ {
+ return generator->getValue(overallIndex - index);
+ }
+ index += generator->size();
+ }
+ CATCH_INTERNAL_ERROR("Indexed past end of generated range");
+ return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
+ }
+
+ void add(const IGenerator<T>* generator)
+ {
+ m_totalSize += generator->size();
+ m_composed.push_back(generator);
+ }
+
+ CompositeGenerator& then(CompositeGenerator& other)
+ {
+ move(other);
+ return *this;
+ }
+
+ CompositeGenerator& then(T value)
+ {
+ ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+ valuesGen->add(value);
+ add(valuesGen);
+ return *this;
+ }
+
+ private:
+ void move(CompositeGenerator& other)
+ {
+ std::copy(other.m_composed.begin(), other.m_composed.end(), std::back_inserter(m_composed));
+ m_totalSize += other.m_totalSize;
+ other.m_composed.clear();
+ }
+
+ std::vector<const IGenerator<T>*> m_composed;
+ std::string m_fileInfo;
+ size_t m_totalSize;
+};
+
+namespace Generators {
+template <typename T>
+CompositeGenerator<T> between(T from, T to)
+{
+ CompositeGenerator<T> generators;
+ generators.add(new BetweenGenerator<T>(from, to));
+ return generators;
+}
+
+template <typename T>
+CompositeGenerator<T> values(T val1, T val2)
+{
+ CompositeGenerator<T> generators;
+ ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+ valuesGen->add(val1);
+ valuesGen->add(val2);
+ generators.add(valuesGen);
+ return generators;
+}
+
+template <typename T>
+CompositeGenerator<T> values(T val1, T val2, T val3)
+{
+ CompositeGenerator<T> generators;
+ ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+ valuesGen->add(val1);
+ valuesGen->add(val2);
+ valuesGen->add(val3);
+ generators.add(valuesGen);
+ return generators;
+}
+
+template <typename T>
+CompositeGenerator<T> values(T val1, T val2, T val3, T val4)
+{
+ CompositeGenerator<T> generators;
+ ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+ valuesGen->add(val1);
+ valuesGen->add(val2);
+ valuesGen->add(val3);
+ valuesGen->add(val4);
+ generators.add(valuesGen);
+ return generators;
+}
+
+} // end namespace Generators
+
+using namespace Generators;
+
+} // end namespace Catch
+
+#define INTERNAL_CATCH_LINESTR2(line) #line
+#define INTERNAL_CATCH_LINESTR(line) INTERNAL_CATCH_LINESTR2(line)
+
+#define INTERNAL_CATCH_GENERATE(expr) expr.setFileInfo(__FILE__ "(" INTERNAL_CATCH_LINESTR(__LINE__) ")")
+
+// #included from: internal/catch_interfaces_exception.h
+#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
+
+#include <string>
+#include <vector>
+
+// #included from: catch_interfaces_registry_hub.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+class TestCase;
+struct ITestCaseRegistry;
+struct IExceptionTranslatorRegistry;
+struct IExceptionTranslator;
+struct IReporterRegistry;
+struct IReporterFactory;
+
+struct IRegistryHub
+{
+ virtual ~IRegistryHub();
+
+ virtual IReporterRegistry const& getReporterRegistry() const = 0;
+ virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
+ virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
+};
+
+struct IMutableRegistryHub
+{
+ virtual ~IMutableRegistryHub();
+ virtual void registerReporter(std::string const& name, Ptr<IReporterFactory> const& factory) = 0;
+ virtual void registerListener(Ptr<IReporterFactory> const& factory) = 0;
+ virtual void registerTest(TestCase const& testInfo) = 0;
+ virtual void registerTranslator(const IExceptionTranslator* translator) = 0;
+};
+
+IRegistryHub& getRegistryHub();
+IMutableRegistryHub& getMutableRegistryHub();
+void cleanUp();
+std::string translateActiveException();
+}
+
+namespace Catch {
+
+typedef std::string (*exceptionTranslateFunction)();
+
+struct IExceptionTranslator;
+typedef std::vector<const IExceptionTranslator*> ExceptionTranslators;
+
+struct IExceptionTranslator
+{
+ virtual ~IExceptionTranslator();
+ virtual std::string translate(ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd) const = 0;
+};
+
+struct IExceptionTranslatorRegistry
+{
+ virtual ~IExceptionTranslatorRegistry();
+
+ virtual std::string translateActiveException() const = 0;
+};
+
+class ExceptionTranslatorRegistrar
+{
+ template <typename T>
+ class ExceptionTranslator : public IExceptionTranslator
+ {
+ public:
+ ExceptionTranslator(std::string (*translateFunction)(T&))
+ : m_translateFunction(translateFunction)
+ {
+ }
+
+ virtual std::string translate(ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd) const CATCH_OVERRIDE
+ {
+ try
+ {
+ if (it == itEnd)
+ throw;
+ else
+ return (*it)->translate(it + 1, itEnd);
+ }
+ catch (T& ex)
+ {
+ return m_translateFunction(ex);
+ }
+ }
+
+ protected:
+ std::string (*m_translateFunction)(T&);
+ };
+
+ public:
+ template <typename T>
+ ExceptionTranslatorRegistrar(std::string (*translateFunction)(T&))
+ {
+ getMutableRegistryHub().registerTranslator(new ExceptionTranslator<T>(translateFunction));
+ }
+};
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION(signature) \
+ static std::string INTERNAL_CATCH_UNIQUE_NAME(catch_internal_ExceptionTranslator)(signature); \
+ namespace { \
+ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME(catch_internal_ExceptionRegistrar)(&INTERNAL_CATCH_UNIQUE_NAME(catch_internal_ExceptionTranslator)); \
+ } \
+ static std::string INTERNAL_CATCH_UNIQUE_NAME(catch_internal_ExceptionTranslator)(signature)
+
+// #included from: internal/catch_approx.hpp
+#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
+
+#include <cmath>
+#include <limits>
+
+namespace Catch {
+namespace Detail {
+
+class Approx
+{
+ public:
+ explicit Approx(double value)
+ : m_epsilon(std::numeric_limits<float>::epsilon() * 100),
+ m_scale(1.0),
+ m_value(value)
+ {
+ }
+
+ Approx(Approx const& other)
+ : m_epsilon(other.m_epsilon),
+ m_scale(other.m_scale),
+ m_value(other.m_value)
+ {
+ }
+
+ static Approx custom()
+ {
+ return Approx(0);
+ }
+
+ Approx operator()(double value)
+ {
+ Approx approx(value);
+ approx.epsilon(m_epsilon);
+ approx.scale(m_scale);
+ return approx;
+ }
+
+ friend bool operator==(double lhs, Approx const& rhs)
+ {
+ // Thanks to Richard Harris for his help refining this formula
+ return fabs(lhs - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(fabs(lhs), fabs(rhs.m_value)));
+ }
+
+ friend bool operator==(Approx const& lhs, double rhs)
+ {
+ return operator==(rhs, lhs);
+ }
+
+ friend bool operator!=(double lhs, Approx const& rhs)
+ {
+ return !operator==(lhs, rhs);
+ }
+
+ friend bool operator!=(Approx const& lhs, double rhs)
+ {
+ return !operator==(rhs, lhs);
+ }
+
+ Approx& epsilon(double newEpsilon)
+ {
+ m_epsilon = newEpsilon;
+ return *this;
+ }
+
+ Approx& scale(double newScale)
+ {
+ m_scale = newScale;
+ return *this;
+ }
+
+ std::string toString() const
+ {
+ std::ostringstream oss;
+ oss << "Approx( " << Catch::toString(m_value) << " )";
+ return oss.str();
+ }
+
+ private:
+ double m_epsilon;
+ double m_scale;
+ double m_value;
+};
+}
+
+template <>
+inline std::string toString<Detail::Approx>(Detail::Approx const& value)
+{
+ return value.toString();
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_interfaces_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+// #included from: catch_tag_alias.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+struct TagAlias
+{
+ TagAlias(std::string _tag, SourceLineInfo _lineInfo) : tag(_tag), lineInfo(_lineInfo) {}
+
+ std::string tag;
+ SourceLineInfo lineInfo;
+};
+
+struct RegistrarForTagAliases
+{
+ RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo);
+};
+
+} // end namespace Catch
+
+#define CATCH_REGISTER_TAG_ALIAS(alias, spec) \
+ namespace { \
+ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME(AutoRegisterTagAlias)(alias, spec, CATCH_INTERNAL_LINEINFO); \
+ }
+// #included from: catch_option.hpp
+#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
+
+namespace Catch {
+
+// An optional type
+template <typename T>
+class Option
+{
+ public:
+ Option() : nullableValue(CATCH_NULL) {}
+ Option(T const& _value)
+ : nullableValue(new (storage) T(_value))
+ {
+ }
+ Option(Option const& _other)
+ : nullableValue(_other ? new (storage) T(*_other) : CATCH_NULL)
+ {
+ }
+
+ ~Option()
+ {
+ reset();
+ }
+
+ Option& operator=(Option const& _other)
+ {
+ if (&_other != this)
+ {
+ reset();
+ if (_other)
+ nullableValue = new (storage) T(*_other);
+ }
+ return *this;
+ }
+ Option& operator=(T const& _value)
+ {
+ reset();
+ nullableValue = new (storage) T(_value);
+ return *this;
+ }
+
+ void reset()
+ {
+ if (nullableValue)
+ nullableValue->~T();
+ nullableValue = CATCH_NULL;
+ }
+
+ T& operator*() { return *nullableValue; }
+ T const& operator*() const { return *nullableValue; }
+ T* operator->() { return nullableValue; }
+ const T* operator->() const { return nullableValue; }
+
+ T valueOr(T const& defaultValue) const
+ {
+ return nullableValue ? *nullableValue : defaultValue;
+ }
+
+ bool some() const { return nullableValue != CATCH_NULL; }
+ bool none() const { return nullableValue == CATCH_NULL; }
+
+ bool operator!() const { return nullableValue == CATCH_NULL; }
+ operator SafeBool::type() const
+ {
+ return SafeBool::makeSafe(some());
+ }
+
+ private:
+ T* nullableValue;
+ char storage[sizeof(T)];
+};
+
+} // end namespace Catch
+
+namespace Catch {
+
+struct ITagAliasRegistry
+{
+ virtual ~ITagAliasRegistry();
+ virtual Option<TagAlias> find(std::string const& alias) const = 0;
+ virtual std::string expandAliases(std::string const& unexpandedTestSpec) const = 0;
+
+ static ITagAliasRegistry const& get();
+};
+
+} // end namespace Catch
+
+// These files are included here so the single_include script doesn't put them
+// in the conditionally compiled sections
+// #included from: internal/catch_test_case_info.h
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
+
+#include <set>
+#include <string>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+struct ITestCase;
+
+struct TestCaseInfo
+{
+ enum SpecialProperties
+ {
+ None = 0,
+ IsHidden = 1 << 1,
+ ShouldFail = 1 << 2,
+ MayFail = 1 << 3,
+ Throws = 1 << 4
+ };
+
+ TestCaseInfo(std::string const& _name,
+ std::string const& _className,
+ std::string const& _description,
+ std::set<std::string> const& _tags,
+ SourceLineInfo const& _lineInfo);
+
+ TestCaseInfo(TestCaseInfo const& other);
+
+ friend void setTags(TestCaseInfo& testCaseInfo, std::set<std::string> const& tags);
+
+ bool isHidden() const;
+ bool throws() const;
+ bool okToFail() const;
+ bool expectedToFail() const;
+
+ std::string name;
+ std::string className;
+ std::string description;
+ std::set<std::string> tags;
+ std::set<std::string> lcaseTags;
+ std::string tagsAsString;
+ SourceLineInfo lineInfo;
+ SpecialProperties properties;
+};
+
+class TestCase : public TestCaseInfo
+{
+ public:
+ TestCase(ITestCase* testCase, TestCaseInfo const& info);
+ TestCase(TestCase const& other);
+
+ TestCase withName(std::string const& _newName) const;
+
+ void invoke() const;
+
+ TestCaseInfo const& getTestCaseInfo() const;
+
+ void swap(TestCase& other);
+ bool operator==(TestCase const& other) const;
+ bool operator<(TestCase const& other) const;
+ TestCase& operator=(TestCase const& other);
+
+ private:
+ Ptr<ITestCase> test;
+};
+
+TestCase makeTestCase(ITestCase* testCase,
+ std::string const& className,
+ std::string const& name,
+ std::string const& description,
+ SourceLineInfo const& lineInfo);
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#ifdef __OBJC__
+// #included from: internal/catch_objc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
+
+#import <objc/runtime.h>
+
+#include <string>
+
+// NB. Any general catch headers included here must be included
+// in catch.hpp first to make sure they are included by the single
+// header for non obj-usage
+
+///////////////////////////////////////////////////////////////////////////////
+// This protocol is really only here for (self) documenting purposes, since
+// all its methods are optional.
+ at protocol OcFixture
+
+ at optional
+
+- (void)setUp;
+- (void)tearDown;
+
+ at end
+
+namespace Catch {
+
+class OcMethod : public SharedImpl<ITestCase>
+{
+
+ public:
+ OcMethod(Class cls, SEL sel) : m_cls(cls), m_sel(sel) {}
+
+ virtual void invoke() const
+ {
+ id obj = [[m_cls alloc] init];
+
+ performOptionalSelector(obj, @selector(setUp));
+ performOptionalSelector(obj, m_sel);
+ performOptionalSelector(obj, @selector(tearDown));
+
+ arcSafeRelease(obj);
+ }
+
+ private:
+ virtual ~OcMethod() {}
+
+ Class m_cls;
+ SEL m_sel;
+};
+
+namespace Detail {
+
+inline std::string getAnnotation(Class cls,
+ std::string const& annotationName,
+ std::string const& testCaseName)
+{
+ NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
+ SEL sel = NSSelectorFromString(selStr);
+ arcSafeRelease(selStr);
+ id value = performOptionalSelector(cls, sel);
+ if (value)
+ return [(NSString*)value UTF8String];
+ return "";
+}
+}
+
+inline size_t registerTestMethods()
+{
+ size_t noTestMethods = 0;
+ int noClasses = objc_getClassList(CATCH_NULL, 0);
+
+ Class* classes = (CATCH_UNSAFE_UNRETAINED Class*)malloc(sizeof(Class) * noClasses);
+ objc_getClassList(classes, noClasses);
+
+ for (int c = 0; c < noClasses; c++)
+ {
+ Class cls = classes[c];
+ {
+ u_int count;
+ Method* methods = class_copyMethodList(cls, &count);
+ for (u_int m = 0; m < count; m++)
+ {
+ SEL selector = method_getName(methods[m]);
+ std::string methodName = sel_getName(selector);
+ if (startsWith(methodName, "Catch_TestCase_"))
+ {
+ std::string testCaseName = methodName.substr(15);
+ std::string name = Detail::getAnnotation(cls, "Name", testCaseName);
+ std::string desc = Detail::getAnnotation(cls, "Description", testCaseName);
+ const char* className = class_getName(cls);
+
+ getMutableRegistryHub().registerTest(makeTestCase(new OcMethod(cls, selector), className, name.c_str(), desc.c_str(), SourceLineInfo()));
+ noTestMethods++;
+ }
+ }
+ free(methods);
+ }
+ }
+ return noTestMethods;
+}
+
+namespace Matchers {
+namespace Impl {
+namespace NSStringMatchers {
+
+template <typename MatcherT>
+struct StringHolder : MatcherImpl<MatcherT, NSString*>
+{
+ StringHolder(NSString* substr) : m_substr([substr copy]) {}
+ StringHolder(StringHolder const& other) : m_substr([other.m_substr copy]) {}
+ StringHolder()
+ {
+ arcSafeRelease(m_substr);
+ }
+
+ NSString* m_substr;
+};
+
+struct Equals : StringHolder<Equals>
+{
+ Equals(NSString* substr) : StringHolder(substr) {}
+
+ virtual bool match(ExpressionType const& str) const
+ {
+ return (str != nil || m_substr == nil) &&
+ [str isEqualToString:m_substr];
+ }
+
+ virtual std::string toString() const
+ {
+ return "equals string: " + Catch::toString(m_substr);
+ }
+};
+
+struct Contains : StringHolder<Contains>
+{
+ Contains(NSString* substr) : StringHolder(substr) {}
+
+ virtual bool match(ExpressionType const& str) const
+ {
+ return (str != nil || m_substr == nil) &&
+ [str rangeOfString:m_substr].location != NSNotFound;
+ }
+
+ virtual std::string toString() const
+ {
+ return "contains string: " + Catch::toString(m_substr);
+ }
+};
+
+struct StartsWith : StringHolder<StartsWith>
+{
+ StartsWith(NSString* substr) : StringHolder(substr) {}
+
+ virtual bool match(ExpressionType const& str) const
+ {
+ return (str != nil || m_substr == nil) &&
+ [str rangeOfString:m_substr].location == 0;
+ }
+
+ virtual std::string toString() const
+ {
+ return "starts with: " + Catch::toString(m_substr);
+ }
+};
+struct EndsWith : StringHolder<EndsWith>
+{
+ EndsWith(NSString* substr) : StringHolder(substr) {}
+
+ virtual bool match(ExpressionType const& str) const
+ {
+ return (str != nil || m_substr == nil) &&
+ [str rangeOfString:m_substr].location == [str length] - [m_substr length];
+ }
+
+ virtual std::string toString() const
+ {
+ return "ends with: " + Catch::toString(m_substr);
+ }
+};
+
+} // namespace NSStringMatchers
+} // namespace Impl
+
+inline Impl::NSStringMatchers::Equals
+Equals(NSString* substr) { return Impl::NSStringMatchers::Equals(substr); }
+
+inline Impl::NSStringMatchers::Contains
+Contains(NSString* substr) { return Impl::NSStringMatchers::Contains(substr); }
+
+inline Impl::NSStringMatchers::StartsWith
+StartsWith(NSString* substr) { return Impl::NSStringMatchers::StartsWith(substr); }
+
+inline Impl::NSStringMatchers::EndsWith
+EndsWith(NSString* substr) { return Impl::NSStringMatchers::EndsWith(substr); }
+
+} // namespace Matchers
+
+using namespace Matchers;
+
+} // namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define OC_TEST_CASE(name, desc) \
+ +(NSString*)INTERNAL_CATCH_UNIQUE_NAME(Catch_Name_test) \
+ { \
+ return @name; \
+ } \
+ +(NSString*)INTERNAL_CATCH_UNIQUE_NAME(Catch_Description_test) \
+ { \
+ return @desc; \
+ } \
+ -(void)INTERNAL_CATCH_UNIQUE_NAME(Catch_TestCase_test)
+
+#endif
+
+#ifdef CATCH_IMPL
+// #included from: internal/catch_impl.hpp
+#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
+
+// Collect all the implementation files together here
+// These are the equivalent of what would usually be cpp files
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+// #included from: ../catch_session.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
+
+// #included from: internal/catch_commandline.hpp
+#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
+
+// #included from: catch_config.hpp
+#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
+
+// #included from: catch_test_spec_parser.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_test_spec.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_wildcard_pattern.hpp
+#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED
+
+namespace Catch {
+class WildcardPattern
+{
+ enum WildcardPosition
+ {
+ NoWildcard = 0,
+ WildcardAtStart = 1,
+ WildcardAtEnd = 2,
+ WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
+ };
+
+ public:
+ WildcardPattern(std::string const& pattern, CaseSensitive::Choice caseSensitivity)
+ : m_caseSensitivity(caseSensitivity),
+ m_wildcard(NoWildcard),
+ m_pattern(adjustCase(pattern))
+ {
+ if (startsWith(m_pattern, "*"))
+ {
+ m_pattern = m_pattern.substr(1);
+ m_wildcard = WildcardAtStart;
+ }
+ if (endsWith(m_pattern, "*"))
+ {
+ m_pattern = m_pattern.substr(0, m_pattern.size() - 1);
+ m_wildcard = static_cast<WildcardPosition>(m_wildcard | WildcardAtEnd);
+ }
+ }
+ virtual ~WildcardPattern();
+ virtual bool matches(std::string const& str) const
+ {
+ switch (m_wildcard)
+ {
+ case NoWildcard:
+ return m_pattern == adjustCase(str);
+ case WildcardAtStart:
+ return endsWith(adjustCase(str), m_pattern);
+ case WildcardAtEnd:
+ return startsWith(adjustCase(str), m_pattern);
+ case WildcardAtBothEnds:
+ return contains(adjustCase(str), m_pattern);
+ }
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+ throw std::logic_error("Unknown enum");
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+ }
+
+ private:
+ std::string adjustCase(std::string const& str) const
+ {
+ return m_caseSensitivity == CaseSensitive::No ? toLower(str) : str;
+ }
+ CaseSensitive::Choice m_caseSensitivity;
+ WildcardPosition m_wildcard;
+ std::string m_pattern;
+};
+}
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+class TestSpec
+{
+ struct Pattern : SharedImpl<>
+ {
+ virtual ~Pattern();
+ virtual bool matches(TestCaseInfo const& testCase) const = 0;
+ };
+ class NamePattern : public Pattern
+ {
+ public:
+ NamePattern(std::string const& name)
+ : m_wildcardPattern(toLower(name), CaseSensitive::No)
+ {
+ }
+ virtual ~NamePattern();
+ virtual bool matches(TestCaseInfo const& testCase) const
+ {
+ return m_wildcardPattern.matches(toLower(testCase.name));
+ }
+
+ private:
+ WildcardPattern m_wildcardPattern;
+ };
+
+ class TagPattern : public Pattern
+ {
+ public:
+ TagPattern(std::string const& tag) : m_tag(toLower(tag)) {}
+ virtual ~TagPattern();
+ virtual bool matches(TestCaseInfo const& testCase) const
+ {
+ return testCase.lcaseTags.find(m_tag) != testCase.lcaseTags.end();
+ }
+
+ private:
+ std::string m_tag;
+ };
+
+ class ExcludedPattern : public Pattern
+ {
+ public:
+ ExcludedPattern(Ptr<Pattern> const& underlyingPattern) : m_underlyingPattern(underlyingPattern) {}
+ virtual ~ExcludedPattern();
+ virtual bool matches(TestCaseInfo const& testCase) const { return !m_underlyingPattern->matches(testCase); }
+ private:
+ Ptr<Pattern> m_underlyingPattern;
+ };
+
+ struct Filter
+ {
+ std::vector<Ptr<Pattern>> m_patterns;
+
+ bool matches(TestCaseInfo const& testCase) const
+ {
+ // All patterns in a filter must match for the filter to be a match
+ for (std::vector<Ptr<Pattern>>::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it)
+ if (!(*it)->matches(testCase))
+ return false;
+ return true;
+ }
+ };
+
+ public:
+ bool hasFilters() const
+ {
+ return !m_filters.empty();
+ }
+ bool matches(TestCaseInfo const& testCase) const
+ {
+ // A TestSpec matches if any filter matches
+ for (std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it)
+ if (it->matches(testCase))
+ return true;
+ return false;
+ }
+
+ private:
+ std::vector<Filter> m_filters;
+
+ friend class TestSpecParser;
+};
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace Catch {
+
+class TestSpecParser
+{
+ enum Mode
+ {
+ None,
+ Name,
+ QuotedName,
+ Tag
+ };
+ Mode m_mode;
+ bool m_exclusion;
+ std::size_t m_start, m_pos;
+ std::string m_arg;
+ TestSpec::Filter m_currentFilter;
+ TestSpec m_testSpec;
+ ITagAliasRegistry const* m_tagAliases;
+
+ public:
+ TestSpecParser(ITagAliasRegistry const& tagAliases) : m_tagAliases(&tagAliases) {}
+
+ TestSpecParser& parse(std::string const& arg)
+ {
+ m_mode = None;
+ m_exclusion = false;
+ m_start = std::string::npos;
+ m_arg = m_tagAliases->expandAliases(arg);
+ for (m_pos = 0; m_pos < m_arg.size(); ++m_pos)
+ visitChar(m_arg[m_pos]);
+ if (m_mode == Name)
+ addPattern<TestSpec::NamePattern>();
+ return *this;
+ }
+ TestSpec testSpec()
+ {
+ addFilter();
+ return m_testSpec;
+ }
+
+ private:
+ void visitChar(char c)
+ {
+ if (m_mode == None)
+ {
+ switch (c)
+ {
+ case ' ':
+ return;
+ case '~':
+ m_exclusion = true;
+ return;
+ case '[':
+ return startNewMode(Tag, ++m_pos);
+ case '"':
+ return startNewMode(QuotedName, ++m_pos);
+ default:
+ startNewMode(Name, m_pos);
+ break;
+ }
+ }
+ if (m_mode == Name)
+ {
+ if (c == ',')
+ {
+ addPattern<TestSpec::NamePattern>();
+ addFilter();
+ }
+ else if (c == '[')
+ {
+ if (subString() == "exclude:")
+ m_exclusion = true;
+ else
+ addPattern<TestSpec::NamePattern>();
+ startNewMode(Tag, ++m_pos);
+ }
+ }
+ else if (m_mode == QuotedName && c == '"')
+ addPattern<TestSpec::NamePattern>();
+ else if (m_mode == Tag && c == ']')
+ addPattern<TestSpec::TagPattern>();
+ }
+ void startNewMode(Mode mode, std::size_t start)
+ {
+ m_mode = mode;
+ m_start = start;
+ }
+ std::string subString() const { return m_arg.substr(m_start, m_pos - m_start); }
+ template <typename T>
+ void addPattern()
+ {
+ std::string token = subString();
+ if (startsWith(token, "exclude:"))
+ {
+ m_exclusion = true;
+ token = token.substr(8);
+ }
+ if (!token.empty())
+ {
+ Ptr<TestSpec::Pattern> pattern = new T(token);
+ if (m_exclusion)
+ pattern = new TestSpec::ExcludedPattern(pattern);
+ m_currentFilter.m_patterns.push_back(pattern);
+ }
+ m_exclusion = false;
+ m_mode = None;
+ }
+ void addFilter()
+ {
+ if (!m_currentFilter.m_patterns.empty())
+ {
+ m_testSpec.m_filters.push_back(m_currentFilter);
+ m_currentFilter = TestSpec::Filter();
+ }
+ }
+};
+inline TestSpec parseTestSpec(std::string const& arg)
+{
+ return TestSpecParser(ITagAliasRegistry::get()).parse(arg).testSpec();
+}
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// #included from: catch_interfaces_config.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+struct Verbosity
+{
+ enum Level
+ {
+ NoOutput = 0,
+ Quiet,
+ Normal
+ };
+};
+
+struct WarnAbout
+{
+ enum What
+ {
+ Nothing = 0x00,
+ NoAssertions = 0x01
+ };
+};
+
+struct ShowDurations
+{
+ enum OrNot
+ {
+ DefaultForReporter,
+ Always,
+ Never
+ };
+};
+struct RunTests
+{
+ enum InWhatOrder
+ {
+ InDeclarationOrder,
+ InLexicographicalOrder,
+ InRandomOrder
+ };
+};
+
+class TestSpec;
+
+struct IConfig : IShared
+{
+
+ virtual ~IConfig();
+
+ virtual bool allowThrows() const = 0;
+ virtual std::ostream& stream() const = 0;
+ virtual std::string name() const = 0;
+ virtual bool includeSuccessfulResults() const = 0;
+ virtual bool shouldDebugBreak() const = 0;
+ virtual bool warnAboutMissingAssertions() const = 0;
+ virtual int abortAfter() const = 0;
+ virtual bool showInvisibles() const = 0;
+ virtual ShowDurations::OrNot showDurations() const = 0;
+ virtual TestSpec const& testSpec() const = 0;
+ virtual RunTests::InWhatOrder runOrder() const = 0;
+ virtual unsigned int rngSeed() const = 0;
+ virtual bool forceColour() const = 0;
+};
+}
+
+// #included from: catch_stream.h
+#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
+
+// #included from: catch_streambuf.h
+#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
+
+#include <streambuf>
+
+namespace Catch {
+
+class StreamBufBase : public std::streambuf
+{
+ public:
+ virtual ~StreamBufBase() CATCH_NOEXCEPT;
+};
+}
+
+#include <fstream>
+#include <ostream>
+#include <streambuf>
+
+namespace Catch {
+
+std::ostream& cout();
+std::ostream& cerr();
+
+struct IStream
+{
+ virtual ~IStream() CATCH_NOEXCEPT;
+ virtual std::ostream& stream() const = 0;
+};
+
+class FileStream : public IStream
+{
+ mutable std::ofstream m_ofs;
+
+ public:
+ FileStream(std::string const& filename);
+ virtual ~FileStream() CATCH_NOEXCEPT;
+
+ public: // IStream
+ virtual std::ostream& stream() const CATCH_OVERRIDE;
+};
+
+class CoutStream : public IStream
+{
+ mutable std::ostream m_os;
+
+ public:
+ CoutStream();
+ virtual ~CoutStream() CATCH_NOEXCEPT;
+
+ public: // IStream
+ virtual std::ostream& stream() const CATCH_OVERRIDE;
+};
+
+class DebugOutStream : public IStream
+{
+ std::auto_ptr<StreamBufBase> m_streamBuf;
+ mutable std::ostream m_os;
+
+ public:
+ DebugOutStream();
+ virtual ~DebugOutStream() CATCH_NOEXCEPT;
+
+ public: // IStream
+ virtual std::ostream& stream() const CATCH_OVERRIDE;
+};
+}
+
+#include <ctime>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+
+#ifndef CATCH_CONFIG_CONSOLE_WIDTH
+#define CATCH_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+namespace Catch {
+
+struct ConfigData
+{
+
+ ConfigData()
+ : listTests(false),
+ listTags(false),
+ listReporters(false),
+ listTestNamesOnly(false),
+ showSuccessfulTests(false),
+ shouldDebugBreak(false),
+ noThrow(false),
+ showHelp(false),
+ showInvisibles(false),
+ forceColour(false),
+ filenamesAsTags(false),
+ abortAfter(-1),
+ rngSeed(0),
+ verbosity(Verbosity::Normal),
+ warnings(WarnAbout::Nothing),
+ showDurations(ShowDurations::DefaultForReporter),
+ runOrder(RunTests::InDeclarationOrder)
+ {
+ }
+
+ bool listTests;
+ bool listTags;
+ bool listReporters;
+ bool listTestNamesOnly;
+
+ bool showSuccessfulTests;
+ bool shouldDebugBreak;
+ bool noThrow;
+ bool showHelp;
+ bool showInvisibles;
+ bool forceColour;
+ bool filenamesAsTags;
+
+ int abortAfter;
+ unsigned int rngSeed;
+
+ Verbosity::Level verbosity;
+ WarnAbout::What warnings;
+ ShowDurations::OrNot showDurations;
+ RunTests::InWhatOrder runOrder;
+
+ std::string outputFilename;
+ std::string name;
+ std::string processName;
+
+ std::vector<std::string> reporterNames;
+ std::vector<std::string> testsOrTags;
+};
+
+class Config : public SharedImpl<IConfig>
+{
+ private:
+ Config(Config const& other);
+ Config& operator=(Config const& other);
+ virtual void dummy();
+
+ public:
+ Config()
+ {
+ }
+
+ Config(ConfigData const& data)
+ : m_data(data),
+ m_stream(openStream())
+ {
+ if (!data.testsOrTags.empty())
+ {
+ TestSpecParser parser(ITagAliasRegistry::get());
+ for (std::size_t i = 0; i < data.testsOrTags.size(); ++i)
+ parser.parse(data.testsOrTags[i]);
+ m_testSpec = parser.testSpec();
+ }
+ }
+
+ virtual ~Config()
+ {
+ }
+
+ std::string const& getFilename() const
+ {
+ return m_data.outputFilename;
+ }
+
+ bool listTests() const { return m_data.listTests; }
+ bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
+ bool listTags() const { return m_data.listTags; }
+ bool listReporters() const { return m_data.listReporters; }
+
+ std::string getProcessName() const { return m_data.processName; }
+
+ bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
+
+ std::vector<std::string> getReporterNames() const { return m_data.reporterNames; }
+
+ int abortAfter() const { return m_data.abortAfter; }
+
+ TestSpec const& testSpec() const { return m_testSpec; }
+
+ bool showHelp() const { return m_data.showHelp; }
+ bool showInvisibles() const { return m_data.showInvisibles; }
+
+ // IConfig interface
+ virtual bool allowThrows() const { return !m_data.noThrow; }
+ virtual std::ostream& stream() const { return m_stream->stream(); }
+ virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
+ virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
+ virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
+ virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
+ virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; }
+ virtual unsigned int rngSeed() const { return m_data.rngSeed; }
+ virtual bool forceColour() const { return m_data.forceColour; }
+
+ private:
+ IStream const* openStream()
+ {
+ if (m_data.outputFilename.empty())
+ return new CoutStream();
+ else if (m_data.outputFilename[0] == '%')
+ {
+ if (m_data.outputFilename == "%debug")
+ return new DebugOutStream();
+ else
+ throw std::domain_error("Unrecognised stream: " + m_data.outputFilename);
+ }
+ else
+ return new FileStream(m_data.outputFilename);
+ }
+ ConfigData m_data;
+
+ std::auto_ptr<IStream const> m_stream;
+ TestSpec m_testSpec;
+};
+
+} // end namespace Catch
+
+// #included from: catch_clara.h
+#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED
+
+// Use Catch's value for console width (store Clara's off to the side, if present)
+#ifdef CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
+#undef CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+// Declare Clara inside the Catch namespace
+#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
+// #included from: ../external/clara.h
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
+
+#ifndef STITCH_CLARA_OPEN_NAMESPACE
+#define TWOBLUECUBES_CLARA_H_INCLUDED
+#define STITCH_CLARA_OPEN_NAMESPACE
+#define STITCH_CLARA_CLOSE_NAMESPACE
+#else
+#define STITCH_CLARA_CLOSE_NAMESPACE }
+#endif
+
+#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
+
+// ----------- #included from tbc_text_format.h -----------
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE)
+#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+#define TBC_TEXT_FORMAT_H_INCLUDED
+#endif
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+// Use optional outer namespace
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+const unsigned int consoleWidth = 80;
+#endif
+
+struct TextAttributes
+{
+ TextAttributes()
+ : initialIndent(std::string::npos),
+ indent(0),
+ width(consoleWidth - 1),
+ tabChar('\t')
+ {
+ }
+
+ TextAttributes& setInitialIndent(std::size_t _value)
+ {
+ initialIndent = _value;
+ return *this;
+ }
+ TextAttributes& setIndent(std::size_t _value)
+ {
+ indent = _value;
+ return *this;
+ }
+ TextAttributes& setWidth(std::size_t _value)
+ {
+ width = _value;
+ return *this;
+ }
+ TextAttributes& setTabChar(char _value)
+ {
+ tabChar = _value;
+ return *this;
+ }
+
+ std::size_t initialIndent; // indent of first line, or npos
+ std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
+ std::size_t width; // maximum width of text, including indent. Longer text will wrap
+ char tabChar; // If this char is seen the indent is changed to current pos
+};
+
+class Text
+{
+ public:
+ Text(std::string const& _str, TextAttributes const& _attr = TextAttributes())
+ : attr(_attr)
+ {
+ std::string wrappableChars = " [({.,/|\\-";
+ std::size_t indent = _attr.initialIndent != std::string::npos
+ ? _attr.initialIndent
+ : _attr.indent;
+ std::string remainder = _str;
+
+ while (!remainder.empty())
+ {
+ if (lines.size() >= 1000)
+ {
+ lines.push_back("... message truncated due to excessive size");
+ return;
+ }
+ std::size_t tabPos = std::string::npos;
+ std::size_t width = (std::min)(remainder.size(), _attr.width - indent);
+ std::size_t pos = remainder.find_first_of('\n');
+ if (pos <= width)
+ {
+ width = pos;
+ }
+ pos = remainder.find_last_of(_attr.tabChar, width);
+ if (pos != std::string::npos)
+ {
+ tabPos = pos;
+ if (remainder[width] == '\n')
+ width--;
+ remainder = remainder.substr(0, tabPos) + remainder.substr(tabPos + 1);
+ }
+
+ if (width == remainder.size())
+ {
+ spliceLine(indent, remainder, width);
+ }
+ else if (remainder[width] == '\n')
+ {
+ spliceLine(indent, remainder, width);
+ if (width <= 1 || remainder.size() != 1)
+ remainder = remainder.substr(1);
+ indent = _attr.indent;
+ }
+ else
+ {
+ pos = remainder.find_last_of(wrappableChars, width);
+ if (pos != std::string::npos && pos > 0)
+ {
+ spliceLine(indent, remainder, pos);
+ if (remainder[0] == ' ')
+ remainder = remainder.substr(1);
+ }
+ else
+ {
+ spliceLine(indent, remainder, width - 1);
+ lines.back() += "-";
+ }
+ if (lines.size() == 1)
+ indent = _attr.indent;
+ if (tabPos != std::string::npos)
+ indent += tabPos;
+ }
+ }
+ }
+
+ void spliceLine(std::size_t _indent, std::string& _remainder, std::size_t _pos)
+ {
+ lines.push_back(std::string(_indent, ' ') + _remainder.substr(0, _pos));
+ _remainder = _remainder.substr(_pos);
+ }
+
+ typedef std::vector<std::string>::const_iterator const_iterator;
+
+ const_iterator begin() const { return lines.begin(); }
+ const_iterator end() const { return lines.end(); }
+ std::string const& last() const { return lines.back(); }
+ std::size_t size() const { return lines.size(); }
+ std::string const& operator[](std::size_t _index) const { return lines[_index]; }
+ std::string toString() const
+ {
+ std::ostringstream oss;
+ oss << *this;
+ return oss.str();
+ }
+
+ inline friend std::ostream& operator<<(std::ostream& _stream, Text const& _text)
+ {
+ for (Text::const_iterator it = _text.begin(), itEnd = _text.end();
+ it != itEnd; ++it)
+ {
+ if (it != _text.begin())
+ _stream << "\n";
+ _stream << *it;
+ }
+ return _stream;
+ }
+
+ private:
+ std::string str;
+ TextAttributes attr;
+ std::vector<std::string> lines;
+};
+
+} // end namespace Tbc
+
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TBC_TEXT_FORMAT_H_INCLUDED
+
+// ----------- end of #include from tbc_text_format.h -----------
+// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h
+
+#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <stdexcept>
+
+// Use optional outer namespace
+#ifdef STITCH_CLARA_OPEN_NAMESPACE
+STITCH_CLARA_OPEN_NAMESPACE
+#endif
+
+namespace Clara {
+
+struct UnpositionalTag
+{
+};
+
+extern UnpositionalTag _;
+
+#ifdef CLARA_CONFIG_MAIN
+UnpositionalTag _;
+#endif
+
+namespace Detail {
+
+#ifdef CLARA_CONSOLE_WIDTH
+const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
+#else
+const unsigned int consoleWidth = 80;
+#endif
+
+using namespace Tbc;
+
+inline bool startsWith(std::string const& str, std::string const& prefix)
+{
+ return str.size() >= prefix.size() && str.substr(0, prefix.size()) == prefix;
+}
+
+template <typename T>
+struct RemoveConstRef
+{
+ typedef T type;
+};
+template <typename T>
+struct RemoveConstRef<T&>
+{
+ typedef T type;
+};
+template <typename T>
+struct RemoveConstRef<T const&>
+{
+ typedef T type;
+};
+template <typename T>
+struct RemoveConstRef<T const>
+{
+ typedef T type;
+};
+
+template <typename T>
+struct IsBool
+{
+ static const bool value = false;
+};
+template <>
+struct IsBool<bool>
+{
+ static const bool value = true;
+};
+
+template <typename T>
+void convertInto(std::string const& _source, T& _dest)
+{
+ std::stringstream ss;
+ ss << _source;
+ ss >> _dest;
+ if (ss.fail())
+ throw std::runtime_error("Unable to convert " + _source + " to destination type");
+}
+inline void convertInto(std::string const& _source, std::string& _dest)
+{
+ _dest = _source;
+}
+inline void convertInto(std::string const& _source, bool& _dest)
+{
+ std::string sourceLC = _source;
+ std::transform(sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower);
+ if (sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on")
+ _dest = true;
+ else if (sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off")
+ _dest = false;
+ else
+ throw std::runtime_error("Expected a boolean value but did not recognise:\n '" + _source + "'");
+}
+inline void convertInto(bool _source, bool& _dest)
+{
+ _dest = _source;
+}
+template <typename T>
+inline void convertInto(bool, T&)
+{
+ throw std::runtime_error("Invalid conversion");
+}
+
+template <typename ConfigT>
+struct IArgFunction
+{
+ virtual ~IArgFunction() {}
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ IArgFunction() = default;
+ IArgFunction(IArgFunction const&) = default;
+#endif
+ virtual void set(ConfigT& config, std::string const& value) const = 0;
+ virtual void setFlag(ConfigT& config) const = 0;
+ virtual bool takesArg() const = 0;
+ virtual IArgFunction* clone() const = 0;
+};
+
+template <typename ConfigT>
+class BoundArgFunction
+{
+ public:
+ BoundArgFunction() : functionObj(CATCH_NULL) {}
+ BoundArgFunction(IArgFunction<ConfigT>* _functionObj) : functionObj(_functionObj) {}
+ BoundArgFunction(BoundArgFunction const& other) : functionObj(other.functionObj ? other.functionObj->clone() : CATCH_NULL) {}
+ BoundArgFunction& operator=(BoundArgFunction const& other)
+ {
+ IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CATCH_NULL;
+ delete functionObj;
+ functionObj = newFunctionObj;
+ return *this;
+ }
+ ~BoundArgFunction() { delete functionObj; }
+
+ void set(ConfigT& config, std::string const& value) const
+ {
+ functionObj->set(config, value);
+ }
+ void setFlag(ConfigT& config) const
+ {
+ functionObj->setFlag(config);
+ }
+ bool takesArg() const { return functionObj->takesArg(); }
+
+ bool isSet() const
+ {
+ return functionObj != CATCH_NULL;
+ }
+
+ private:
+ IArgFunction<ConfigT>* functionObj;
+};
+
+template <typename C>
+struct NullBinder : IArgFunction<C>
+{
+ virtual void set(C&, std::string const&) const {}
+ virtual void setFlag(C&) const {}
+ virtual bool takesArg() const { return true; }
+ virtual IArgFunction<C>* clone() const { return new NullBinder(*this); }
+};
+
+template <typename C, typename M>
+struct BoundDataMember : IArgFunction<C>
+{
+ BoundDataMember(M C::*_member) : member(_member) {}
+ virtual void set(C& p, std::string const& stringValue) const
+ {
+ convertInto(stringValue, p.*member);
+ }
+ virtual void setFlag(C& p) const
+ {
+ convertInto(true, p.*member);
+ }
+ virtual bool takesArg() const { return !IsBool<M>::value; }
+ virtual IArgFunction<C>* clone() const { return new BoundDataMember(*this); }
+ M C::*member;
+};
+template <typename C, typename M>
+struct BoundUnaryMethod : IArgFunction<C>
+{
+ BoundUnaryMethod(void (C::*_member)(M)) : member(_member) {}
+ virtual void set(C& p, std::string const& stringValue) const
+ {
+ typename RemoveConstRef<M>::type value;
+ convertInto(stringValue, value);
+ (p.*member)(value);
+ }
+ virtual void setFlag(C& p) const
+ {
+ typename RemoveConstRef<M>::type value;
+ convertInto(true, value);
+ (p.*member)(value);
+ }
+ virtual bool takesArg() const { return !IsBool<M>::value; }
+ virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod(*this); }
+ void (C::*member)(M);
+};
+template <typename C>
+struct BoundNullaryMethod : IArgFunction<C>
+{
+ BoundNullaryMethod(void (C::*_member)()) : member(_member) {}
+ virtual void set(C& p, std::string const& stringValue) const
+ {
+ bool value;
+ convertInto(stringValue, value);
+ if (value)
+ (p.*member)();
+ }
+ virtual void setFlag(C& p) const
+ {
+ (p.*member)();
+ }
+ virtual bool takesArg() const { return false; }
+ virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod(*this); }
+ void (C::*member)();
+};
+
+template <typename C>
+struct BoundUnaryFunction : IArgFunction<C>
+{
+ BoundUnaryFunction(void (*_function)(C&)) : function(_function) {}
+ virtual void set(C& obj, std::string const& stringValue) const
+ {
+ bool value;
+ convertInto(stringValue, value);
+ if (value)
+ function(obj);
+ }
+ virtual void setFlag(C& p) const
+ {
+ function(p);
+ }
+ virtual bool takesArg() const { return false; }
+ virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction(*this); }
+ void (*function)(C&);
+};
+
+template <typename C, typename T>
+struct BoundBinaryFunction : IArgFunction<C>
+{
+ BoundBinaryFunction(void (*_function)(C&, T)) : function(_function) {}
+ virtual void set(C& obj, std::string const& stringValue) const
+ {
+ typename RemoveConstRef<T>::type value;
+ convertInto(stringValue, value);
+ function(obj, value);
+ }
+ virtual void setFlag(C& obj) const
+ {
+ typename RemoveConstRef<T>::type value;
+ convertInto(true, value);
+ function(obj, value);
+ }
+ virtual bool takesArg() const { return !IsBool<T>::value; }
+ virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction(*this); }
+ void (*function)(C&, T);
+};
+
+} // namespace Detail
+
+struct Parser
+{
+ Parser() : separators(" \t=:") {}
+
+ struct Token
+ {
+ enum Type
+ {
+ Positional,
+ ShortOpt,
+ LongOpt
+ };
+ Token(Type _type, std::string const& _data) : type(_type), data(_data) {}
+ Type type;
+ std::string data;
+ };
+
+ void parseIntoTokens(int argc, char const* const* argv, std::vector<Parser::Token>& tokens) const
+ {
+ const std::string doubleDash = "--";
+ for (int i = 1; i < argc && argv[i] != doubleDash; ++i)
+ parseIntoTokens(argv[i], tokens);
+ }
+ void parseIntoTokens(std::string arg, std::vector<Parser::Token>& tokens) const
+ {
+ while (!arg.empty())
+ {
+ Parser::Token token(Parser::Token::Positional, arg);
+ arg = "";
+ if (token.data[0] == '-')
+ {
+ if (token.data.size() > 1 && token.data[1] == '-')
+ {
+ token = Parser::Token(Parser::Token::LongOpt, token.data.substr(2));
+ }
+ else
+ {
+ token = Parser::Token(Parser::Token::ShortOpt, token.data.substr(1));
+ if (token.data.size() > 1 && separators.find(token.data[1]) == std::string::npos)
+ {
+ arg = "-" + token.data.substr(1);
+ token.data = token.data.substr(0, 1);
+ }
+ }
+ }
+ if (token.type != Parser::Token::Positional)
+ {
+ std::size_t pos = token.data.find_first_of(separators);
+ if (pos != std::string::npos)
+ {
+ arg = token.data.substr(pos + 1);
+ token.data = token.data.substr(0, pos);
+ }
+ }
+ tokens.push_back(token);
+ }
+ }
+ std::string separators;
+};
+
+template <typename ConfigT>
+struct CommonArgProperties
+{
+ CommonArgProperties() {}
+ CommonArgProperties(Detail::BoundArgFunction<ConfigT> const& _boundField) : boundField(_boundField) {}
+
+ Detail::BoundArgFunction<ConfigT> boundField;
+ std::string description;
+ std::string detail;
+ std::string placeholder; // Only value if boundField takes an arg
+
+ bool takesArg() const
+ {
+ return !placeholder.empty();
+ }
+ void validate() const
+ {
+ if (!boundField.isSet())
+ throw std::logic_error("option not bound");
+ }
+};
+struct OptionArgProperties
+{
+ std::vector<std::string> shortNames;
+ std::string longName;
+
+ bool hasShortName(std::string const& shortName) const
+ {
+ return std::find(shortNames.begin(), shortNames.end(), shortName) != shortNames.end();
+ }
+ bool hasLongName(std::string const& _longName) const
+ {
+ return _longName == longName;
+ }
+};
+struct PositionalArgProperties
+{
+ PositionalArgProperties() : position(-1) {}
+ int position; // -1 means non-positional (floating)
+
+ bool isFixedPositional() const
+ {
+ return position != -1;
+ }
+};
+
+template <typename ConfigT>
+class CommandLine
+{
+
+ struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties
+ {
+ Arg() {}
+ Arg(Detail::BoundArgFunction<ConfigT> const& _boundField) : CommonArgProperties<ConfigT>(_boundField) {}
+
+ using CommonArgProperties<ConfigT>::placeholder; // !TBD
+
+ std::string dbgName() const
+ {
+ if (!longName.empty())
+ return "--" + longName;
+ if (!shortNames.empty())
+ return "-" + shortNames[0];
+ return "positional args";
+ }
+ std::string commands() const
+ {
+ std::ostringstream oss;
+ bool first = true;
+ std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end();
+ for (; it != itEnd; ++it)
+ {
+ if (first)
+ first = false;
+ else
+ oss << ", ";
+ oss << "-" << *it;
+ }
+ if (!longName.empty())
+ {
+ if (!first)
+ oss << ", ";
+ oss << "--" << longName;
+ }
+ if (!placeholder.empty())
+ oss << " <" << placeholder << ">";
+ return oss.str();
+ }
+ };
+
+ typedef CATCH_AUTO_PTR(Arg) ArgAutoPtr;
+
+ friend void addOptName(Arg& arg, std::string const& optName)
+ {
+ if (optName.empty())
+ return;
+ if (Detail::startsWith(optName, "--"))
+ {
+ if (!arg.longName.empty())
+ throw std::logic_error("Only one long opt may be specified. '" + arg.longName + "' already specified, now attempting to add '" + optName + "'");
+ arg.longName = optName.substr(2);
+ }
+ else if (Detail::startsWith(optName, "-"))
+ arg.shortNames.push_back(optName.substr(1));
+ else
+ throw std::logic_error("option must begin with - or --. Option was: '" + optName + "'");
+ }
+ friend void setPositionalArg(Arg& arg, int position)
+ {
+ arg.position = position;
+ }
+
+ class ArgBuilder
+ {
+ public:
+ ArgBuilder(Arg* arg) : m_arg(arg) {}
+
+ // Bind a non-boolean data member (requires placeholder string)
+ template <typename C, typename M>
+ void bind(M C::*field, std::string const& placeholder)
+ {
+ m_arg->boundField = new Detail::BoundDataMember<C, M>(field);
+ m_arg->placeholder = placeholder;
+ }
+ // Bind a boolean data member (no placeholder required)
+ template <typename C>
+ void bind(bool C::*field)
+ {
+ m_arg->boundField = new Detail::BoundDataMember<C, bool>(field);
+ }
+
+ // Bind a method taking a single, non-boolean argument (requires a placeholder string)
+ template <typename C, typename M>
+ void bind(void (C::*unaryMethod)(M), std::string const& placeholder)
+ {
+ m_arg->boundField = new Detail::BoundUnaryMethod<C, M>(unaryMethod);
+ m_arg->placeholder = placeholder;
+ }
+
+ // Bind a method taking a single, boolean argument (no placeholder string required)
+ template <typename C>
+ void bind(void (C::*unaryMethod)(bool))
+ {
+ m_arg->boundField = new Detail::BoundUnaryMethod<C, bool>(unaryMethod);
+ }
+
+ // Bind a method that takes no arguments (will be called if opt is present)
+ template <typename C>
+ void bind(void (C::*nullaryMethod)())
+ {
+ m_arg->boundField = new Detail::BoundNullaryMethod<C>(nullaryMethod);
+ }
+
+ // Bind a free function taking a single argument - the object to operate on (no placeholder string required)
+ template <typename C>
+ void bind(void (*unaryFunction)(C&))
+ {
+ m_arg->boundField = new Detail::BoundUnaryFunction<C>(unaryFunction);
+ }
+
+ // Bind a free function taking a single argument - the object to operate on (requires a placeholder string)
+ template <typename C, typename T>
+ void bind(void (*binaryFunction)(C&, T), std::string const& placeholder)
+ {
+ m_arg->boundField = new Detail::BoundBinaryFunction<C, T>(binaryFunction);
+ m_arg->placeholder = placeholder;
+ }
+
+ ArgBuilder& describe(std::string const& description)
+ {
+ m_arg->description = description;
+ return *this;
+ }
+ ArgBuilder& detail(std::string const& _detail)
+ {
+ m_arg->detail = _detail;
+ return *this;
+ }
+
+ protected:
+ Arg* m_arg;
+ };
+
+ class OptBuilder : public ArgBuilder
+ {
+ public:
+ OptBuilder(Arg* arg) : ArgBuilder(arg) {}
+ OptBuilder(OptBuilder& other) : ArgBuilder(other) {}
+
+ OptBuilder& operator[](std::string const& optName)
+ {
+ addOptName(*ArgBuilder::m_arg, optName);
+ return *this;
+ }
+ };
+
+ public:
+ CommandLine()
+ : m_boundProcessName(new Detail::NullBinder<ConfigT>()),
+ m_highestSpecifiedArgPosition(0),
+ m_throwOnUnrecognisedTokens(false)
+ {
+ }
+ CommandLine(CommandLine const& other)
+ : m_boundProcessName(other.m_boundProcessName),
+ m_options(other.m_options),
+ m_positionalArgs(other.m_positionalArgs),
+ m_highestSpecifiedArgPosition(other.m_highestSpecifiedArgPosition),
+ m_throwOnUnrecognisedTokens(other.m_throwOnUnrecognisedTokens)
+ {
+ if (other.m_floatingArg.get())
+ m_floatingArg.reset(new Arg(*other.m_floatingArg));
+ }
+
+ CommandLine& setThrowOnUnrecognisedTokens(bool shouldThrow = true)
+ {
+ m_throwOnUnrecognisedTokens = shouldThrow;
+ return *this;
+ }
+
+ OptBuilder operator[](std::string const& optName)
+ {
+ m_options.push_back(Arg());
+ addOptName(m_options.back(), optName);
+ OptBuilder builder(&m_options.back());
+ return builder;
+ }
+
+ ArgBuilder operator[](int position)
+ {
+ m_positionalArgs.insert(std::make_pair(position, Arg()));
+ if (position > m_highestSpecifiedArgPosition)
+ m_highestSpecifiedArgPosition = position;
+ setPositionalArg(m_positionalArgs[position], position);
+ ArgBuilder builder(&m_positionalArgs[position]);
+ return builder;
+ }
+
+ // Invoke this with the _ instance
+ ArgBuilder operator[](UnpositionalTag)
+ {
+ if (m_floatingArg.get())
+ throw std::logic_error("Only one unpositional argument can be added");
+ m_floatingArg.reset(new Arg());
+ ArgBuilder builder(m_floatingArg.get());
+ return builder;
+ }
+
+ template <typename C, typename M>
+ void bindProcessName(M C::*field)
+ {
+ m_boundProcessName = new Detail::BoundDataMember<C, M>(field);
+ }
+ template <typename C, typename M>
+ void bindProcessName(void (C::*_unaryMethod)(M))
+ {
+ m_boundProcessName = new Detail::BoundUnaryMethod<C, M>(_unaryMethod);
+ }
+
+ void optUsage(std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth) const
+ {
+ typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it;
+ std::size_t maxWidth = 0;
+ for (it = itBegin; it != itEnd; ++it)
+ maxWidth = (std::max)(maxWidth, it->commands().size());
+
+ for (it = itBegin; it != itEnd; ++it)
+ {
+ Detail::Text usageText(it->commands(), Detail::TextAttributes()
+ .setWidth(maxWidth + indent)
+ .setIndent(indent));
+ Detail::Text desc(it->description, Detail::TextAttributes()
+ .setWidth(width - maxWidth - 3));
+
+ for (std::size_t i = 0; i < (std::max)(usageText.size(), desc.size()); ++i)
+ {
+ std::string usageCol = i < usageText.size() ? usageText[i] : "";
+ os << usageCol;
+
+ if (i < desc.size() && !desc[i].empty())
+ os << std::string(indent + 2 + maxWidth - usageCol.size(), ' ')
+ << desc[i];
+ os << "\n";
+ }
+ }
+ }
+ std::string optUsage() const
+ {
+ std::ostringstream oss;
+ optUsage(oss);
+ return oss.str();
+ }
+
+ void argSynopsis(std::ostream& os) const
+ {
+ for (int i = 1; i <= m_highestSpecifiedArgPosition; ++i)
+ {
+ if (i > 1)
+ os << " ";
+ typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find(i);
+ if (it != m_positionalArgs.end())
+ os << "<" << it->second.placeholder << ">";
+ else if (m_floatingArg.get())
+ os << "<" << m_floatingArg->placeholder << ">";
+ else
+ throw std::logic_error("non consecutive positional arguments with no floating args");
+ }
+ // !TBD No indication of mandatory args
+ if (m_floatingArg.get())
+ {
+ if (m_highestSpecifiedArgPosition > 1)
+ os << " ";
+ os << "[<" << m_floatingArg->placeholder << "> ...]";
+ }
+ }
+ std::string argSynopsis() const
+ {
+ std::ostringstream oss;
+ argSynopsis(oss);
+ return oss.str();
+ }
+
+ void usage(std::ostream& os, std::string const& procName) const
+ {
+ validate();
+ os << "usage:\n " << procName << " ";
+ argSynopsis(os);
+ if (!m_options.empty())
+ {
+ os << " [options]\n\nwhere options are: \n";
+ optUsage(os, 2);
+ }
+ os << "\n";
+ }
+ std::string usage(std::string const& procName) const
+ {
+ std::ostringstream oss;
+ usage(oss, procName);
+ return oss.str();
+ }
+
+ ConfigT parse(int argc, char const* const* argv) const
+ {
+ ConfigT config;
+ parseInto(argc, argv, config);
+ return config;
+ }
+
+ std::vector<Parser::Token> parseInto(int argc, char const* const* argv, ConfigT& config) const
+ {
+ std::string processName = argv[0];
+ std::size_t lastSlash = processName.find_last_of("/\\");
+ if (lastSlash != std::string::npos)
+ processName = processName.substr(lastSlash + 1);
+ m_boundProcessName.set(config, processName);
+ std::vector<Parser::Token> tokens;
+ Parser parser;
+ parser.parseIntoTokens(argc, argv, tokens);
+ return populate(tokens, config);
+ }
+
+ std::vector<Parser::Token> populate(std::vector<Parser::Token> const& tokens, ConfigT& config) const
+ {
+ validate();
+ std::vector<Parser::Token> unusedTokens = populateOptions(tokens, config);
+ unusedTokens = populateFixedArgs(unusedTokens, config);
+ unusedTokens = populateFloatingArgs(unusedTokens, config);
+ return unusedTokens;
+ }
+
+ std::vector<Parser::Token> populateOptions(std::vector<Parser::Token> const& tokens, ConfigT& config) const
+ {
+ std::vector<Parser::Token> unusedTokens;
+ std::vector<std::string> errors;
+ for (std::size_t i = 0; i < tokens.size(); ++i)
+ {
+ Parser::Token const& token = tokens[i];
+ typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
+ for (; it != itEnd; ++it)
+ {
+ Arg const& arg = *it;
+
+ try
+ {
+ if ((token.type == Parser::Token::ShortOpt && arg.hasShortName(token.data)) ||
+ (token.type == Parser::Token::LongOpt && arg.hasLongName(token.data)))
+ {
+ if (arg.takesArg())
+ {
+ if (i == tokens.size() - 1 || tokens[i + 1].type != Parser::Token::Positional)
+ errors.push_back("Expected argument to option: " + token.data);
+ else
+ arg.boundField.set(config, tokens[++i].data);
+ }
+ else
+ {
+ arg.boundField.setFlag(config);
+ }
+ break;
+ }
+ }
+ catch (std::exception& ex)
+ {
+ errors.push_back(std::string(ex.what()) + "\n- while parsing: (" + arg.commands() + ")");
+ }
+ }
+ if (it == itEnd)
+ {
+ if (token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens)
+ unusedTokens.push_back(token);
+ else if (errors.empty() && m_throwOnUnrecognisedTokens)
+ errors.push_back("unrecognised option: " + token.data);
+ }
+ }
+ if (!errors.empty())
+ {
+ std::ostringstream oss;
+ for (std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
+ it != itEnd;
+ ++it)
+ {
+ if (it != errors.begin())
+ oss << "\n";
+ oss << *it;
+ }
+ throw std::runtime_error(oss.str());
+ }
+ return unusedTokens;
+ }
+ std::vector<Parser::Token> populateFixedArgs(std::vector<Parser::Token> const& tokens, ConfigT& config) const
+ {
+ std::vector<Parser::Token> unusedTokens;
+ int position = 1;
+ for (std::size_t i = 0; i < tokens.size(); ++i)
+ {
+ Parser::Token const& token = tokens[i];
+ typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find(position);
+ if (it != m_positionalArgs.end())
+ it->second.boundField.set(config, token.data);
+ else
+ unusedTokens.push_back(token);
+ if (token.type == Parser::Token::Positional)
+ position++;
+ }
+ return unusedTokens;
+ }
+ std::vector<Parser::Token> populateFloatingArgs(std::vector<Parser::Token> const& tokens, ConfigT& config) const
+ {
+ if (!m_floatingArg.get())
+ return tokens;
+ std::vector<Parser::Token> unusedTokens;
+ for (std::size_t i = 0; i < tokens.size(); ++i)
+ {
+ Parser::Token const& token = tokens[i];
+ if (token.type == Parser::Token::Positional)
+ m_floatingArg->boundField.set(config, token.data);
+ else
+ unusedTokens.push_back(token);
+ }
+ return unusedTokens;
+ }
+
+ void validate() const
+ {
+ if (m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get())
+ throw std::logic_error("No options or arguments specified");
+
+ for (typename std::vector<Arg>::const_iterator it = m_options.begin(),
+ itEnd = m_options.end();
+ it != itEnd; ++it)
+ it->validate();
+ }
+
+ private:
+ Detail::BoundArgFunction<ConfigT> m_boundProcessName;
+ std::vector<Arg> m_options;
+ std::map<int, Arg> m_positionalArgs;
+ ArgAutoPtr m_floatingArg;
+ int m_highestSpecifiedArgPosition;
+ bool m_throwOnUnrecognisedTokens;
+};
+
+} // end namespace Clara
+
+STITCH_CLARA_CLOSE_NAMESPACE
+#undef STITCH_CLARA_OPEN_NAMESPACE
+#undef STITCH_CLARA_CLOSE_NAMESPACE
+
+#endif // TWOBLUECUBES_CLARA_H_INCLUDED
+#undef STITCH_CLARA_OPEN_NAMESPACE
+
+// Restore Clara's value for console width, if present
+#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+
+#include <fstream>
+
+namespace Catch {
+
+inline void abortAfterFirst(ConfigData& config) { config.abortAfter = 1; }
+inline void abortAfterX(ConfigData& config, int x)
+{
+ if (x < 1)
+ throw std::runtime_error("Value after -x or --abortAfter must be greater than zero");
+ config.abortAfter = x;
+}
+inline void addTestOrTags(ConfigData& config, std::string const& _testSpec) { config.testsOrTags.push_back(_testSpec); }
+inline void addReporterName(ConfigData& config, std::string const& _reporterName) { config.reporterNames.push_back(_reporterName); }
+
+inline void addWarning(ConfigData& config, std::string const& _warning)
+{
+ if (_warning == "NoAssertions")
+ config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::NoAssertions);
+ else
+ throw std::runtime_error("Unrecognised warning: '" + _warning + "'");
+}
+inline void setOrder(ConfigData& config, std::string const& order)
+{
+ if (startsWith("declared", order))
+ config.runOrder = RunTests::InDeclarationOrder;
+ else if (startsWith("lexical", order))
+ config.runOrder = RunTests::InLexicographicalOrder;
+ else if (startsWith("random", order))
+ config.runOrder = RunTests::InRandomOrder;
+ else
+ throw std::runtime_error("Unrecognised ordering: '" + order + "'");
+}
+inline void setRngSeed(ConfigData& config, std::string const& seed)
+{
+ if (seed == "time")
+ {
+ config.rngSeed = static_cast<unsigned int>(std::time(0));
+ }
+ else
+ {
+ std::stringstream ss;
+ ss << seed;
+ ss >> config.rngSeed;
+ if (ss.fail())
+ throw std::runtime_error("Argment to --rng-seed should be the word 'time' or a number");
+ }
+}
+inline void setVerbosity(ConfigData& config, int level)
+{
+ // !TBD: accept strings?
+ config.verbosity = static_cast<Verbosity::Level>(level);
+}
+inline void setShowDurations(ConfigData& config, bool _showDurations)
+{
+ config.showDurations = _showDurations
+ ? ShowDurations::Always
+ : ShowDurations::Never;
+}
+inline void loadTestNamesFromFile(ConfigData& config, std::string const& _filename)
+{
+ std::ifstream f(_filename.c_str());
+ if (!f.is_open())
+ throw std::domain_error("Unable to load input file: " + _filename);
+
+ std::string line;
+ while (std::getline(f, line))
+ {
+ line = trim(line);
+ if (!line.empty() && !startsWith(line, "#"))
+ addTestOrTags(config, "\"" + line + "\",");
+ }
+}
+
+inline Clara::CommandLine<ConfigData> makeCommandLineParser()
+{
+
+ using namespace Clara;
+ CommandLine<ConfigData> cli;
+
+ cli.bindProcessName(&ConfigData::processName);
+
+ cli["-?"]["-h"]["--help"]
+ .describe("display usage information")
+ .bind(&ConfigData::showHelp);
+
+ cli["-l"]["--list-tests"]
+ .describe("list all/matching test cases")
+ .bind(&ConfigData::listTests);
+
+ cli["-t"]["--list-tags"]
+ .describe("list all/matching tags")
+ .bind(&ConfigData::listTags);
+
+ cli["-s"]["--success"]
+ .describe("include successful tests in output")
+ .bind(&ConfigData::showSuccessfulTests);
+
+ cli["-b"]["--break"]
+ .describe("break into debugger on failure")
+ .bind(&ConfigData::shouldDebugBreak);
+
+ cli["-e"]["--nothrow"]
+ .describe("skip exception tests")
+ .bind(&ConfigData::noThrow);
+
+ cli["-i"]["--invisibles"]
+ .describe("show invisibles (tabs, newlines)")
+ .bind(&ConfigData::showInvisibles);
+
+ cli["-o"]["--out"]
+ .describe("output filename")
+ .bind(&ConfigData::outputFilename, "filename");
+
+ cli["-r"]["--reporter"]
+ // .placeholder( "name[:filename]" )
+ .describe("reporter to use (defaults to console)")
+ .bind(&addReporterName, "name");
+
+ cli["-n"]["--name"]
+ .describe("suite name")
+ .bind(&ConfigData::name, "name");
+
+ cli["-a"]["--abort"]
+ .describe("abort at first failure")
+ .bind(&abortAfterFirst);
+
+ cli["-x"]["--abortx"]
+ .describe("abort after x failures")
+ .bind(&abortAfterX, "no. failures");
+
+ cli["-w"]["--warn"]
+ .describe("enable warnings")
+ .bind(&addWarning, "warning name");
+
+ // - needs updating if reinstated
+ // cli.into( &setVerbosity )
+ // .describe( "level of verbosity (0=no output)" )
+ // .shortOpt( "v")
+ // .longOpt( "verbosity" )
+ // .placeholder( "level" );
+
+ cli[_]
+ .describe("which test or tests to use")
+ .bind(&addTestOrTags, "test name, pattern or tags");
+
+ cli["-d"]["--durations"]
+ .describe("show test durations")
+ .bind(&setShowDurations, "yes/no");
+
+ cli["-f"]["--input-file"]
+ .describe("load test names to run from a file")
+ .bind(&loadTestNamesFromFile, "filename");
+
+ cli["-#"]["--filenames-as-tags"]
+ .describe("adds a tag for the filename")
+ .bind(&ConfigData::filenamesAsTags);
+
+ // Less common commands which don't have a short form
+ cli["--list-test-names-only"]
+ .describe("list all/matching test cases names only")
+ .bind(&ConfigData::listTestNamesOnly);
+
+ cli["--list-reporters"]
+ .describe("list all reporters")
+ .bind(&ConfigData::listReporters);
+
+ cli["--order"]
+ .describe("test case order (defaults to decl)")
+ .bind(&setOrder, "decl|lex|rand");
+
+ cli["--rng-seed"]
+ .describe("set a specific seed for random numbers")
+ .bind(&setRngSeed, "'time'|number");
+
+ cli["--force-colour"]
+ .describe("force colourised output")
+ .bind(&ConfigData::forceColour);
+
+ return cli;
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_list.hpp
+#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
+
+// #included from: catch_text.h
+#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED
+
+#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch
+// #included from: ../external/tbc_text_format.h
+// Only use header guard if we are not using an outer namespace
+#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+#ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#endif
+#else
+#define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+#endif
+#endif
+#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#include <sstream>
+#include <string>
+#include <vector>
+
+// Use optional outer namespace
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+const unsigned int consoleWidth = 80;
+#endif
+
+struct TextAttributes
+{
+ TextAttributes()
+ : initialIndent(std::string::npos),
+ indent(0),
+ width(consoleWidth - 1),
+ tabChar('\t')
+ {
+ }
+
+ TextAttributes& setInitialIndent(std::size_t _value)
+ {
+ initialIndent = _value;
+ return *this;
+ }
+ TextAttributes& setIndent(std::size_t _value)
+ {
+ indent = _value;
+ return *this;
+ }
+ TextAttributes& setWidth(std::size_t _value)
+ {
+ width = _value;
+ return *this;
+ }
+ TextAttributes& setTabChar(char _value)
+ {
+ tabChar = _value;
+ return *this;
+ }
+
+ std::size_t initialIndent; // indent of first line, or npos
+ std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
+ std::size_t width; // maximum width of text, including indent. Longer text will wrap
+ char tabChar; // If this char is seen the indent is changed to current pos
+};
+
+class Text
+{
+ public:
+ Text(std::string const& _str, TextAttributes const& _attr = TextAttributes())
+ : attr(_attr)
+ {
+ std::string wrappableChars = " [({.,/|\\-";
+ std::size_t indent = _attr.initialIndent != std::string::npos
+ ? _attr.initialIndent
+ : _attr.indent;
+ std::string remainder = _str;
+
+ while (!remainder.empty())
+ {
+ if (lines.size() >= 1000)
+ {
+ lines.push_back("... message truncated due to excessive size");
+ return;
+ }
+ std::size_t tabPos = std::string::npos;
+ std::size_t width = (std::min)(remainder.size(), _attr.width - indent);
+ std::size_t pos = remainder.find_first_of('\n');
+ if (pos <= width)
+ {
+ width = pos;
+ }
+ pos = remainder.find_last_of(_attr.tabChar, width);
+ if (pos != std::string::npos)
+ {
+ tabPos = pos;
+ if (remainder[width] == '\n')
+ width--;
+ remainder = remainder.substr(0, tabPos) + remainder.substr(tabPos + 1);
+ }
+
+ if (width == remainder.size())
+ {
+ spliceLine(indent, remainder, width);
+ }
+ else if (remainder[width] == '\n')
+ {
+ spliceLine(indent, remainder, width);
+ if (width <= 1 || remainder.size() != 1)
+ remainder = remainder.substr(1);
+ indent = _attr.indent;
+ }
+ else
+ {
+ pos = remainder.find_last_of(wrappableChars, width);
+ if (pos != std::string::npos && pos > 0)
+ {
+ spliceLine(indent, remainder, pos);
+ if (remainder[0] == ' ')
+ remainder = remainder.substr(1);
+ }
+ else
+ {
+ spliceLine(indent, remainder, width - 1);
+ lines.back() += "-";
+ }
+ if (lines.size() == 1)
+ indent = _attr.indent;
+ if (tabPos != std::string::npos)
+ indent += tabPos;
+ }
+ }
+ }
+
+ void spliceLine(std::size_t _indent, std::string& _remainder, std::size_t _pos)
+ {
+ lines.push_back(std::string(_indent, ' ') + _remainder.substr(0, _pos));
+ _remainder = _remainder.substr(_pos);
+ }
+
+ typedef std::vector<std::string>::const_iterator const_iterator;
+
+ const_iterator begin() const { return lines.begin(); }
+ const_iterator end() const { return lines.end(); }
+ std::string const& last() const { return lines.back(); }
+ std::size_t size() const { return lines.size(); }
+ std::string const& operator[](std::size_t _index) const { return lines[_index]; }
+ std::string toString() const
+ {
+ std::ostringstream oss;
+ oss << *this;
+ return oss.str();
+ }
+
+ inline friend std::ostream& operator<<(std::ostream& _stream, Text const& _text)
+ {
+ for (Text::const_iterator it = _text.begin(), itEnd = _text.end();
+ it != itEnd; ++it)
+ {
+ if (it != _text.begin())
+ _stream << "\n";
+ _stream << *it;
+ }
+ return _stream;
+ }
+
+ private:
+ std::string str;
+ TextAttributes attr;
+ std::vector<std::string> lines;
+};
+
+} // end namespace Tbc
+
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+
+namespace Catch {
+using Tbc::Text;
+using Tbc::TextAttributes;
+}
+
+// #included from: catch_console_colour.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
+
+namespace Catch {
+
+struct Colour
+{
+ enum Code
+ {
+ None = 0,
+
+ White,
+ Red,
+ Green,
+ Blue,
+ Cyan,
+ Yellow,
+ Grey,
+
+ Bright = 0x10,
+
+ BrightRed = Bright | Red,
+ BrightGreen = Bright | Green,
+ LightGrey = Bright | Grey,
+ BrightWhite = Bright | White,
+
+ // By intention
+ FileName = LightGrey,
+ Warning = Yellow,
+ ResultError = BrightRed,
+ ResultSuccess = BrightGreen,
+ ResultExpectedFailure = Warning,
+
+ Error = BrightRed,
+ Success = Green,
+
+ OriginalExpression = Cyan,
+ ReconstructedExpression = Yellow,
+
+ SecondaryText = LightGrey,
+ Headers = White
+ };
+
+ // Use constructed object for RAII guard
+ Colour(Code _colourCode);
+ Colour(Colour const& other);
+ ~Colour();
+
+ // Use static method for one-shot changes
+ static void use(Code _colourCode);
+
+ private:
+ bool m_moved;
+};
+
+inline std::ostream& operator<<(std::ostream& os, Colour const&) { return os; }
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_reporter.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
+
+#include <assert.h>
+#include <map>
+#include <ostream>
+#include <string>
+
+namespace Catch {
+struct ReporterConfig
+{
+ explicit ReporterConfig(Ptr<IConfig const> const& _fullConfig)
+ : m_stream(&_fullConfig->stream()), m_fullConfig(_fullConfig) {}
+
+ ReporterConfig(Ptr<IConfig const> const& _fullConfig, std::ostream& _stream)
+ : m_stream(&_stream), m_fullConfig(_fullConfig) {}
+
+ std::ostream& stream() const { return *m_stream; }
+ Ptr<IConfig const> fullConfig() const { return m_fullConfig; }
+
+ private:
+ std::ostream* m_stream;
+ Ptr<IConfig const> m_fullConfig;
+};
+
+struct ReporterPreferences
+{
+ ReporterPreferences()
+ : shouldRedirectStdOut(false)
+ {
+ }
+
+ bool shouldRedirectStdOut;
+};
+
+template <typename T>
+struct LazyStat : Option<T>
+{
+ LazyStat() : used(false) {}
+ LazyStat& operator=(T const& _value)
+ {
+ Option<T>::operator=(_value);
+ used = false;
+ return *this;
+ }
+ void reset()
+ {
+ Option<T>::reset();
+ used = false;
+ }
+ bool used;
+};
+
+struct TestRunInfo
+{
+ TestRunInfo(std::string const& _name) : name(_name) {}
+ std::string name;
+};
+struct GroupInfo
+{
+ GroupInfo(std::string const& _name,
+ std::size_t _groupIndex,
+ std::size_t _groupsCount)
+ : name(_name),
+ groupIndex(_groupIndex),
+ groupsCounts(_groupsCount)
+ {
+ }
+
+ std::string name;
+ std::size_t groupIndex;
+ std::size_t groupsCounts;
+};
+
+struct AssertionStats
+{
+ AssertionStats(AssertionResult const& _assertionResult,
+ std::vector<MessageInfo> const& _infoMessages,
+ Totals const& _totals)
+ : assertionResult(_assertionResult),
+ infoMessages(_infoMessages),
+ totals(_totals)
+ {
+ if (assertionResult.hasMessage())
+ {
+ // Copy message into messages list.
+ // !TBD This should have been done earlier, somewhere
+ MessageBuilder builder(assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType());
+ builder << assertionResult.getMessage();
+ builder.m_info.message = builder.m_stream.str();
+
+ infoMessages.push_back(builder.m_info);
+ }
+ }
+ virtual ~AssertionStats();
+
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ AssertionStats(AssertionStats const&) = default;
+ AssertionStats(AssertionStats&&) = default;
+ AssertionStats& operator=(AssertionStats const&) = default;
+ AssertionStats& operator=(AssertionStats&&) = default;
+#endif
+
+ AssertionResult assertionResult;
+ std::vector<MessageInfo> infoMessages;
+ Totals totals;
+};
+
+struct SectionStats
+{
+ SectionStats(SectionInfo const& _sectionInfo,
+ Counts const& _assertions,
+ double _durationInSeconds,
+ bool _missingAssertions)
+ : sectionInfo(_sectionInfo),
+ assertions(_assertions),
+ durationInSeconds(_durationInSeconds),
+ missingAssertions(_missingAssertions)
+ {
+ }
+ virtual ~SectionStats();
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ SectionStats(SectionStats const&) = default;
+ SectionStats(SectionStats&&) = default;
+ SectionStats& operator=(SectionStats const&) = default;
+ SectionStats& operator=(SectionStats&&) = default;
+#endif
+
+ SectionInfo sectionInfo;
+ Counts assertions;
+ double durationInSeconds;
+ bool missingAssertions;
+};
+
+struct TestCaseStats
+{
+ TestCaseStats(TestCaseInfo const& _testInfo,
+ Totals const& _totals,
+ std::string const& _stdOut,
+ std::string const& _stdErr,
+ bool _aborting)
+ : testInfo(_testInfo),
+ totals(_totals),
+ stdOut(_stdOut),
+ stdErr(_stdErr),
+ aborting(_aborting)
+ {
+ }
+ virtual ~TestCaseStats();
+
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ TestCaseStats(TestCaseStats const&) = default;
+ TestCaseStats(TestCaseStats&&) = default;
+ TestCaseStats& operator=(TestCaseStats const&) = default;
+ TestCaseStats& operator=(TestCaseStats&&) = default;
+#endif
+
+ TestCaseInfo testInfo;
+ Totals totals;
+ std::string stdOut;
+ std::string stdErr;
+ bool aborting;
+};
+
+struct TestGroupStats
+{
+ TestGroupStats(GroupInfo const& _groupInfo,
+ Totals const& _totals,
+ bool _aborting)
+ : groupInfo(_groupInfo),
+ totals(_totals),
+ aborting(_aborting)
+ {
+ }
+ TestGroupStats(GroupInfo const& _groupInfo)
+ : groupInfo(_groupInfo),
+ aborting(false)
+ {
+ }
+ virtual ~TestGroupStats();
+
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ TestGroupStats(TestGroupStats const&) = default;
+ TestGroupStats(TestGroupStats&&) = default;
+ TestGroupStats& operator=(TestGroupStats const&) = default;
+ TestGroupStats& operator=(TestGroupStats&&) = default;
+#endif
+
+ GroupInfo groupInfo;
+ Totals totals;
+ bool aborting;
+};
+
+struct TestRunStats
+{
+ TestRunStats(TestRunInfo const& _runInfo,
+ Totals const& _totals,
+ bool _aborting)
+ : runInfo(_runInfo),
+ totals(_totals),
+ aborting(_aborting)
+ {
+ }
+ virtual ~TestRunStats();
+
+#ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ TestRunStats(TestRunStats const& _other)
+ : runInfo(_other.runInfo),
+ totals(_other.totals),
+ aborting(_other.aborting)
+ {
+ }
+#else
+ TestRunStats(TestRunStats const&) = default;
+ TestRunStats(TestRunStats&&) = default;
+ TestRunStats& operator=(TestRunStats const&) = default;
+ TestRunStats& operator=(TestRunStats&&) = default;
+#endif
+
+ TestRunInfo runInfo;
+ Totals totals;
+ bool aborting;
+};
+
+struct IStreamingReporter : IShared
+{
+ virtual ~IStreamingReporter();
+
+ // Implementing class must also provide the following static method:
+ // static std::string getDescription();
+
+ virtual ReporterPreferences getPreferences() const = 0;
+
+ virtual void noMatchingTestCases(std::string const& spec) = 0;
+
+ virtual void testRunStarting(TestRunInfo const& testRunInfo) = 0;
+ virtual void testGroupStarting(GroupInfo const& groupInfo) = 0;
+
+ virtual void testCaseStarting(TestCaseInfo const& testInfo) = 0;
+ virtual void sectionStarting(SectionInfo const& sectionInfo) = 0;
+
+ virtual void assertionStarting(AssertionInfo const& assertionInfo) = 0;
+
+ // The return value indicates if the messages buffer should be cleared:
+ virtual bool assertionEnded(AssertionStats const& assertionStats) = 0;
+
+ virtual void sectionEnded(SectionStats const& sectionStats) = 0;
+ virtual void testCaseEnded(TestCaseStats const& testCaseStats) = 0;
+ virtual void testGroupEnded(TestGroupStats const& testGroupStats) = 0;
+ virtual void testRunEnded(TestRunStats const& testRunStats) = 0;
+
+ virtual void skipTest(TestCaseInfo const& testInfo) = 0;
+};
+
+struct IReporterFactory : IShared
+{
+ virtual ~IReporterFactory();
+ virtual IStreamingReporter* create(ReporterConfig const& config) const = 0;
+ virtual std::string getDescription() const = 0;
+};
+
+struct IReporterRegistry
+{
+ typedef std::map<std::string, Ptr<IReporterFactory>> FactoryMap;
+ typedef std::vector<Ptr<IReporterFactory>> Listeners;
+
+ virtual ~IReporterRegistry();
+ virtual IStreamingReporter* create(std::string const& name, Ptr<IConfig const> const& config) const = 0;
+ virtual FactoryMap const& getFactories() const = 0;
+ virtual Listeners const& getListeners() const = 0;
+};
+
+Ptr<IStreamingReporter> addReporter(Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter);
+}
+
+#include <algorithm>
+#include <limits>
+
+namespace Catch {
+
+inline std::size_t listTests(Config const& config)
+{
+
+ TestSpec testSpec = config.testSpec();
+ if (config.testSpec().hasFilters())
+ Catch::cout() << "Matching test cases:\n";
+ else
+ {
+ Catch::cout() << "All available test cases:\n";
+ testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("*").testSpec();
+ }
+
+ std::size_t matchedTests = 0;
+ TextAttributes nameAttr, tagsAttr;
+ nameAttr.setInitialIndent(2).setIndent(4);
+ tagsAttr.setIndent(6);
+
+ std::vector<TestCase> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
+ for (std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+ it != itEnd;
+ ++it)
+ {
+ matchedTests++;
+ TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+ Colour::Code colour = testCaseInfo.isHidden()
+ ? Colour::SecondaryText
+ : Colour::None;
+ Colour colourGuard(colour);
+
+ Catch::cout() << Text(testCaseInfo.name, nameAttr) << std::endl;
+ if (!testCaseInfo.tags.empty())
+ Catch::cout() << Text(testCaseInfo.tagsAsString, tagsAttr) << std::endl;
+ }
+
+ if (!config.testSpec().hasFilters())
+ Catch::cout() << pluralise(matchedTests, "test case") << "\n"
+ << std::endl;
+ else
+ Catch::cout() << pluralise(matchedTests, "matching test case") << "\n"
+ << std::endl;
+ return matchedTests;
+}
+
+inline std::size_t listTestsNamesOnly(Config const& config)
+{
+ TestSpec testSpec = config.testSpec();
+ if (!config.testSpec().hasFilters())
+ testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("*").testSpec();
+ std::size_t matchedTests = 0;
+ std::vector<TestCase> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
+ for (std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+ it != itEnd;
+ ++it)
+ {
+ matchedTests++;
+ TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+ Catch::cout() << testCaseInfo.name << std::endl;
+ }
+ return matchedTests;
+}
+
+struct TagInfo
+{
+ TagInfo() : count(0) {}
+ void add(std::string const& spelling)
+ {
+ ++count;
+ spellings.insert(spelling);
+ }
+ std::string all() const
+ {
+ std::string out;
+ for (std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end();
+ it != itEnd;
+ ++it)
+ out += "[" + *it + "]";
+ return out;
+ }
+ std::set<std::string> spellings;
+ std::size_t count;
+};
+
+inline std::size_t listTags(Config const& config)
+{
+ TestSpec testSpec = config.testSpec();
+ if (config.testSpec().hasFilters())
+ Catch::cout() << "Tags for matching test cases:\n";
+ else
+ {
+ Catch::cout() << "All available tags:\n";
+ testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("*").testSpec();
+ }
+
+ std::map<std::string, TagInfo> tagCounts;
+
+ std::vector<TestCase> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
+ for (std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+ it != itEnd;
+ ++it)
+ {
+ for (std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(),
+ tagItEnd = it->getTestCaseInfo().tags.end();
+ tagIt != tagItEnd;
+ ++tagIt)
+ {
+ std::string tagName = *tagIt;
+ std::string lcaseTagName = toLower(tagName);
+ std::map<std::string, TagInfo>::iterator countIt = tagCounts.find(lcaseTagName);
+ if (countIt == tagCounts.end())
+ countIt = tagCounts.insert(std::make_pair(lcaseTagName, TagInfo())).first;
+ countIt->second.add(tagName);
+ }
+ }
+
+ for (std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(),
+ countItEnd = tagCounts.end();
+ countIt != countItEnd;
+ ++countIt)
+ {
+ std::ostringstream oss;
+ oss << " " << std::setw(2) << countIt->second.count << " ";
+ Text wrapper(countIt->second.all(), TextAttributes()
+ .setInitialIndent(0)
+ .setIndent(oss.str().size())
+ .setWidth(CATCH_CONFIG_CONSOLE_WIDTH - 10));
+ Catch::cout() << oss.str() << wrapper << "\n";
+ }
+ Catch::cout() << pluralise(tagCounts.size(), "tag") << "\n"
+ << std::endl;
+ return tagCounts.size();
+}
+
+inline std::size_t listReporters(Config const& /*config*/)
+{
+ Catch::cout() << "Available reporters:\n";
+ IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
+ IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
+ std::size_t maxNameLen = 0;
+ for (it = itBegin; it != itEnd; ++it)
+ maxNameLen = (std::max)(maxNameLen, it->first.size());
+
+ for (it = itBegin; it != itEnd; ++it)
+ {
+ Text wrapper(it->second->getDescription(), TextAttributes()
+ .setInitialIndent(0)
+ .setIndent(7 + maxNameLen)
+ .setWidth(CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8));
+ Catch::cout() << " "
+ << it->first
+ << ":"
+ << std::string(maxNameLen - it->first.size() + 2, ' ')
+ << wrapper << "\n";
+ }
+ Catch::cout() << std::endl;
+ return factories.size();
+}
+
+inline Option<std::size_t> list(Config const& config)
+{
+ Option<std::size_t> listedCount;
+ if (config.listTests())
+ listedCount = listedCount.valueOr(0) + listTests(config);
+ if (config.listTestNamesOnly())
+ listedCount = listedCount.valueOr(0) + listTestsNamesOnly(config);
+ if (config.listTags())
+ listedCount = listedCount.valueOr(0) + listTags(config);
+ if (config.listReporters())
+ listedCount = listedCount.valueOr(0) + listReporters(config);
+ return listedCount;
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_run_context.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
+
+// #included from: catch_test_case_tracker.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
+
+#include <assert.h>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace Catch {
+namespace TestCaseTracking {
+
+struct ITracker : SharedImpl<>
+{
+ virtual ~ITracker();
+
+ // static queries
+ virtual std::string name() const = 0;
+
+ // dynamic queries
+ virtual bool isComplete() const = 0; // Successfully completed or failed
+ virtual bool isSuccessfullyCompleted() const = 0;
+ virtual bool isOpen() const = 0; // Started but not complete
+ virtual bool hasChildren() const = 0;
+
+ virtual ITracker& parent() = 0;
+
+ // actions
+ virtual void close() = 0; // Successfully complete
+ virtual void fail() = 0;
+ virtual void markAsNeedingAnotherRun() = 0;
+
+ virtual void addChild(Ptr<ITracker> const& child) = 0;
+ virtual ITracker* findChild(std::string const& name) = 0;
+ virtual void openChild() = 0;
+};
+
+class TrackerContext
+{
+
+ enum RunState
+ {
+ NotStarted,
+ Executing,
+ CompletedCycle
+ };
+
+ Ptr<ITracker> m_rootTracker;
+ ITracker* m_currentTracker;
+ RunState m_runState;
+
+ public:
+ static TrackerContext& instance()
+ {
+ static TrackerContext s_instance;
+ return s_instance;
+ }
+
+ TrackerContext()
+ : m_currentTracker(CATCH_NULL),
+ m_runState(NotStarted)
+ {
+ }
+
+ ITracker& startRun();
+
+ void endRun()
+ {
+ m_rootTracker.reset();
+ m_currentTracker = CATCH_NULL;
+ m_runState = NotStarted;
+ }
+
+ void startCycle()
+ {
+ m_currentTracker = m_rootTracker.get();
+ m_runState = Executing;
+ }
+ void completeCycle()
+ {
+ m_runState = CompletedCycle;
+ }
+
+ bool completedCycle() const
+ {
+ return m_runState == CompletedCycle;
+ }
+ ITracker& currentTracker()
+ {
+ return *m_currentTracker;
+ }
+ void setCurrentTracker(ITracker* tracker)
+ {
+ m_currentTracker = tracker;
+ }
+};
+
+class TrackerBase : public ITracker
+{
+ protected:
+ enum CycleState
+ {
+ NotStarted,
+ Executing,
+ ExecutingChildren,
+ NeedsAnotherRun,
+ CompletedSuccessfully,
+ Failed
+ };
+ class TrackerHasName
+ {
+ std::string m_name;
+
+ public:
+ TrackerHasName(std::string const& name) : m_name(name) {}
+ bool operator()(Ptr<ITracker> const& tracker)
+ {
+ return tracker->name() == m_name;
+ }
+ };
+ typedef std::vector<Ptr<ITracker>> Children;
+ std::string m_name;
+ TrackerContext& m_ctx;
+ ITracker* m_parent;
+ Children m_children;
+ CycleState m_runState;
+
+ public:
+ TrackerBase(std::string const& name, TrackerContext& ctx, ITracker* parent)
+ : m_name(name),
+ m_ctx(ctx),
+ m_parent(parent),
+ m_runState(NotStarted)
+ {
+ }
+ virtual ~TrackerBase();
+
+ virtual std::string name() const CATCH_OVERRIDE
+ {
+ return m_name;
+ }
+ virtual bool isComplete() const CATCH_OVERRIDE
+ {
+ return m_runState == CompletedSuccessfully || m_runState == Failed;
+ }
+ virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE
+ {
+ return m_runState == CompletedSuccessfully;
+ }
+ virtual bool isOpen() const CATCH_OVERRIDE
+ {
+ return m_runState != NotStarted && !isComplete();
+ }
+ virtual bool hasChildren() const CATCH_OVERRIDE
+ {
+ return !m_children.empty();
+ }
+
+ virtual void addChild(Ptr<ITracker> const& child) CATCH_OVERRIDE
+ {
+ m_children.push_back(child);
+ }
+
+ virtual ITracker* findChild(std::string const& name) CATCH_OVERRIDE
+ {
+ Children::const_iterator it = std::find_if(m_children.begin(), m_children.end(), TrackerHasName(name));
+ return (it != m_children.end())
+ ? it->get()
+ : CATCH_NULL;
+ }
+ virtual ITracker& parent() CATCH_OVERRIDE
+ {
+ assert(m_parent); // Should always be non-null except for root
+ return *m_parent;
+ }
+
+ virtual void openChild() CATCH_OVERRIDE
+ {
+ if (m_runState != ExecutingChildren)
+ {
+ m_runState = ExecutingChildren;
+ if (m_parent)
+ m_parent->openChild();
+ }
+ }
+ void open()
+ {
+ m_runState = Executing;
+ moveToThis();
+ if (m_parent)
+ m_parent->openChild();
+ }
+
+ virtual void close() CATCH_OVERRIDE
+ {
+
+ // Close any still open children (e.g. generators)
+ while (&m_ctx.currentTracker() != this)
+ m_ctx.currentTracker().close();
+
+ switch (m_runState)
+ {
+ case NotStarted:
+ case CompletedSuccessfully:
+ case Failed:
+ throw std::logic_error("Illogical state");
+
+ case NeedsAnotherRun:
+ break;
+ ;
+
+ case Executing:
+ m_runState = CompletedSuccessfully;
+ break;
+ case ExecutingChildren:
+ if (m_children.empty() || m_children.back()->isComplete())
+ m_runState = CompletedSuccessfully;
+ break;
+
+ default:
+ throw std::logic_error("Unexpected state");
+ }
+ moveToParent();
+ m_ctx.completeCycle();
+ }
+ virtual void fail() CATCH_OVERRIDE
+ {
+ m_runState = Failed;
+ if (m_parent)
+ m_parent->markAsNeedingAnotherRun();
+ moveToParent();
+ m_ctx.completeCycle();
+ }
+ virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE
+ {
+ m_runState = NeedsAnotherRun;
+ }
+
+ private:
+ void moveToParent()
+ {
+ assert(m_parent);
+ m_ctx.setCurrentTracker(m_parent);
+ }
+ void moveToThis()
+ {
+ m_ctx.setCurrentTracker(this);
+ }
+};
+
+class SectionTracker : public TrackerBase
+{
+ public:
+ SectionTracker(std::string const& name, TrackerContext& ctx, ITracker* parent)
+ : TrackerBase(name, ctx, parent)
+ {
+ }
+ virtual ~SectionTracker();
+
+ static SectionTracker& acquire(TrackerContext& ctx, std::string const& name)
+ {
+ SectionTracker* section = CATCH_NULL;
+
+ ITracker& currentTracker = ctx.currentTracker();
+ if (ITracker* childTracker = currentTracker.findChild(name))
+ {
+ section = dynamic_cast<SectionTracker*>(childTracker);
+ assert(section);
+ }
+ else
+ {
+ section = new SectionTracker(name, ctx, ¤tTracker);
+ currentTracker.addChild(section);
+ }
+ if (!ctx.completedCycle() && !section->isComplete())
+ {
+
+ section->open();
+ }
+ return *section;
+ }
+};
+
+class IndexTracker : public TrackerBase
+{
+ int m_size;
+ int m_index;
+
+ public:
+ IndexTracker(std::string const& name, TrackerContext& ctx, ITracker* parent, int size)
+ : TrackerBase(name, ctx, parent),
+ m_size(size),
+ m_index(-1)
+ {
+ }
+ virtual ~IndexTracker();
+
+ static IndexTracker& acquire(TrackerContext& ctx, std::string const& name, int size)
+ {
+ IndexTracker* tracker = CATCH_NULL;
+
+ ITracker& currentTracker = ctx.currentTracker();
+ if (ITracker* childTracker = currentTracker.findChild(name))
+ {
+ tracker = dynamic_cast<IndexTracker*>(childTracker);
+ assert(tracker);
+ }
+ else
+ {
+ tracker = new IndexTracker(name, ctx, ¤tTracker, size);
+ currentTracker.addChild(tracker);
+ }
+
+ if (!ctx.completedCycle() && !tracker->isComplete())
+ {
+ if (tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun)
+ tracker->moveNext();
+ tracker->open();
+ }
+
+ return *tracker;
+ }
+
+ int index() const { return m_index; }
+
+ void moveNext()
+ {
+ m_index++;
+ m_children.clear();
+ }
+
+ virtual void close() CATCH_OVERRIDE
+ {
+ TrackerBase::close();
+ if (m_runState == CompletedSuccessfully && m_index < m_size - 1)
+ m_runState = Executing;
+ }
+};
+
+inline ITracker& TrackerContext::startRun()
+{
+ m_rootTracker = new SectionTracker("{root}", *this, CATCH_NULL);
+ m_currentTracker = CATCH_NULL;
+ m_runState = Executing;
+ return *m_rootTracker;
+}
+
+} // namespace TestCaseTracking
+
+using TestCaseTracking::ITracker;
+using TestCaseTracking::TrackerContext;
+using TestCaseTracking::SectionTracker;
+using TestCaseTracking::IndexTracker;
+
+} // namespace Catch
+
+// #included from: catch_fatal_condition.hpp
+#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
+
+namespace Catch {
+
+// Report the error condition then exit the process
+inline void fatal(std::string const& message, int exitCode)
+{
+ IContext& context = Catch::getCurrentContext();
+ IResultCapture* resultCapture = context.getResultCapture();
+ resultCapture->handleFatalErrorCondition(message);
+
+ if (Catch::alwaysTrue()) // avoids "no return" warnings
+ exit(exitCode);
+}
+
+} // namespace Catch
+
+#if defined(CATCH_PLATFORM_WINDOWS) /////////////////////////////////////////
+
+namespace Catch {
+
+struct FatalConditionHandler
+{
+ void reset() {}
+};
+
+} // namespace Catch
+
+#else // Not Windows - assumed to be POSIX compatible //////////////////////////
+
+#include <signal.h>
+
+namespace Catch {
+
+struct SignalDefs
+{
+ int id;
+ const char* name;
+};
+extern SignalDefs signalDefs[];
+SignalDefs signalDefs[] = {
+ {SIGINT, "SIGINT - Terminal interrupt signal"},
+ {SIGILL, "SIGILL - Illegal instruction signal"},
+ {SIGFPE, "SIGFPE - Floating point error signal"},
+ {SIGSEGV, "SIGSEGV - Segmentation violation signal"},
+ {SIGTERM, "SIGTERM - Termination request signal"},
+ {SIGABRT, "SIGABRT - Abort (abnormal termination) signal"}};
+
+struct FatalConditionHandler
+{
+
+ static void handleSignal(int sig)
+ {
+ for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i)
+ if (sig == signalDefs[i].id)
+ fatal(signalDefs[i].name, -sig);
+ fatal("<unknown signal>", -sig);
+ }
+
+ FatalConditionHandler() : m_isSet(true)
+ {
+ for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i)
+ signal(signalDefs[i].id, handleSignal);
+ }
+ ~FatalConditionHandler()
+ {
+ reset();
+ }
+ void reset()
+ {
+ if (m_isSet)
+ {
+ for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i)
+ signal(signalDefs[i].id, SIG_DFL);
+ m_isSet = false;
+ }
+ }
+
+ bool m_isSet;
+};
+
+} // namespace Catch
+
+#endif // not Windows
+
+#include <set>
+#include <string>
+
+namespace Catch {
+
+class StreamRedirect
+{
+
+ public:
+ StreamRedirect(std::ostream& stream, std::string& targetString)
+ : m_stream(stream),
+ m_prevBuf(stream.rdbuf()),
+ m_targetString(targetString)
+ {
+ stream.rdbuf(m_oss.rdbuf());
+ }
+
+ ~StreamRedirect()
+ {
+ m_targetString += m_oss.str();
+ m_stream.rdbuf(m_prevBuf);
+ }
+
+ private:
+ std::ostream& m_stream;
+ std::streambuf* m_prevBuf;
+ std::ostringstream m_oss;
+ std::string& m_targetString;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+class RunContext : public IResultCapture, public IRunner
+{
+
+ RunContext(RunContext const&);
+ void operator=(RunContext const&);
+
+ public:
+ explicit RunContext(Ptr<IConfig const> const& _config, Ptr<IStreamingReporter> const& reporter)
+ : m_runInfo(_config->name()),
+ m_context(getCurrentMutableContext()),
+ m_activeTestCase(CATCH_NULL),
+ m_config(_config),
+ m_reporter(reporter)
+ {
+ m_context.setRunner(this);
+ m_context.setConfig(m_config);
+ m_context.setResultCapture(this);
+ m_reporter->testRunStarting(m_runInfo);
+ }
+
+ virtual ~RunContext()
+ {
+ m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
+ }
+
+ void testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount)
+ {
+ m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount));
+ }
+ void testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount)
+ {
+ m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting()));
+ }
+
+ Totals runTest(TestCase const& testCase)
+ {
+ Totals prevTotals = m_totals;
+
+ std::string redirectedCout;
+ std::string redirectedCerr;
+
+ TestCaseInfo testInfo = testCase.getTestCaseInfo();
+
+ m_reporter->testCaseStarting(testInfo);
+
+ m_activeTestCase = &testCase;
+
+ do
+ {
+ m_trackerContext.startRun();
+ do
+ {
+ m_trackerContext.startCycle();
+ m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, testInfo.name);
+ runCurrentTest(redirectedCout, redirectedCerr);
+ } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
+ }
+ // !TBD: deprecated - this will be replaced by indexed trackers
+ while (getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting());
+
+ Totals deltaTotals = m_totals.delta(prevTotals);
+ m_totals.testCases += deltaTotals.testCases;
+ m_reporter->testCaseEnded(TestCaseStats(testInfo,
+ deltaTotals,
+ redirectedCout,
+ redirectedCerr,
+ aborting()));
+
+ m_activeTestCase = CATCH_NULL;
+ m_testCaseTracker = CATCH_NULL;
+
+ return deltaTotals;
+ }
+
+ Ptr<IConfig const> config() const
+ {
+ return m_config;
+ }
+
+ private: // IResultCapture
+ virtual void assertionEnded(AssertionResult const& result)
+ {
+ if (result.getResultType() == ResultWas::Ok)
+ {
+ m_totals.assertions.passed++;
+ }
+ else if (!result.isOk())
+ {
+ m_totals.assertions.failed++;
+ }
+
+ if (m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)))
+ m_messages.clear();
+
+ // Reset working state
+ m_lastAssertionInfo = AssertionInfo("", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}", m_lastAssertionInfo.resultDisposition);
+ m_lastResult = result;
+ }
+
+ virtual bool sectionStarted(
+ SectionInfo const& sectionInfo,
+ Counts& assertions)
+ {
+ std::ostringstream oss;
+ oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
+
+ ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, oss.str());
+ if (!sectionTracker.isOpen())
+ return false;
+ m_activeSections.push_back(§ionTracker);
+
+ m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
+
+ m_reporter->sectionStarting(sectionInfo);
+
+ assertions = m_totals.assertions;
+
+ return true;
+ }
+ bool testForMissingAssertions(Counts& assertions)
+ {
+ if (assertions.total() != 0)
+ return false;
+ if (!m_config->warnAboutMissingAssertions())
+ return false;
+ if (m_trackerContext.currentTracker().hasChildren())
+ return false;
+ m_totals.assertions.failed++;
+ assertions.failed++;
+ return true;
+ }
+
+ virtual void sectionEnded(SectionEndInfo const& endInfo)
+ {
+ Counts assertions = m_totals.assertions - endInfo.prevAssertions;
+ bool missingAssertions = testForMissingAssertions(assertions);
+
+ if (!m_activeSections.empty())
+ {
+ m_activeSections.back()->close();
+ m_activeSections.pop_back();
+ }
+
+ m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
+ m_messages.clear();
+ }
+
+ virtual void sectionEndedEarly(SectionEndInfo const& endInfo)
+ {
+ if (m_unfinishedSections.empty())
+ m_activeSections.back()->fail();
+ else
+ m_activeSections.back()->close();
+ m_activeSections.pop_back();
+
+ m_unfinishedSections.push_back(endInfo);
+ }
+
+ virtual void pushScopedMessage(MessageInfo const& message)
+ {
+ m_messages.push_back(message);
+ }
+
+ virtual void popScopedMessage(MessageInfo const& message)
+ {
+ m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
+ }
+
+ virtual std::string getCurrentTestName() const
+ {
+ return m_activeTestCase
+ ? m_activeTestCase->getTestCaseInfo().name
+ : "";
+ }
+
+ virtual const AssertionResult* getLastResult() const
+ {
+ return &m_lastResult;
+ }
+
+ virtual void handleFatalErrorCondition(std::string const& message)
+ {
+ ResultBuilder resultBuilder = makeUnexpectedResultBuilder();
+ resultBuilder.setResultType(ResultWas::FatalErrorCondition);
+ resultBuilder << message;
+ resultBuilder.captureExpression();
+
+ handleUnfinishedSections();
+
+ // Recreate section for test case (as we will lose the one that was in scope)
+ TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+ SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
+
+ Counts assertions;
+ assertions.failed = 1;
+ SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false);
+ m_reporter->sectionEnded(testCaseSectionStats);
+
+ TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo();
+
+ Totals deltaTotals;
+ deltaTotals.testCases.failed = 1;
+ m_reporter->testCaseEnded(TestCaseStats(testInfo,
+ deltaTotals,
+ "",
+ "",
+ false));
+ m_totals.testCases.failed++;
+ testGroupEnded("", m_totals, 1, 1);
+ m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
+ }
+
+ public:
+ // !TBD We need to do this another way!
+ bool aborting() const
+ {
+ return m_totals.assertions.failed == static_cast<std::size_t>(m_config->abortAfter());
+ }
+
+ private:
+ void runCurrentTest(std::string& redirectedCout, std::string& redirectedCerr)
+ {
+ TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+ SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
+ m_reporter->sectionStarting(testCaseSection);
+ Counts prevAssertions = m_totals.assertions;
+ double duration = 0;
+ try
+ {
+ m_lastAssertionInfo = AssertionInfo("TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal);
+
+ seedRng(*m_config);
+
+ Timer timer;
+ timer.start();
+ if (m_reporter->getPreferences().shouldRedirectStdOut)
+ {
+ StreamRedirect coutRedir(Catch::cout(), redirectedCout);
+ StreamRedirect cerrRedir(Catch::cerr(), redirectedCerr);
+ invokeActiveTestCase();
+ }
+ else
+ {
+ invokeActiveTestCase();
+ }
+ duration = timer.getElapsedSeconds();
+ }
+ catch (TestFailureException&)
+ {
+ // This just means the test was aborted due to failure
+ }
+ catch (...)
+ {
+ makeUnexpectedResultBuilder().useActiveException();
+ }
+ m_testCaseTracker->close();
+ handleUnfinishedSections();
+ m_messages.clear();
+
+ Counts assertions = m_totals.assertions - prevAssertions;
+ bool missingAssertions = testForMissingAssertions(assertions);
+
+ if (testCaseInfo.okToFail())
+ {
+ std::swap(assertions.failedButOk, assertions.failed);
+ m_totals.assertions.failed -= assertions.failedButOk;
+ m_totals.assertions.failedButOk += assertions.failedButOk;
+ }
+
+ SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
+ m_reporter->sectionEnded(testCaseSectionStats);
+ }
+
+ void invokeActiveTestCase()
+ {
+ FatalConditionHandler fatalConditionHandler; // Handle signals
+ m_activeTestCase->invoke();
+ fatalConditionHandler.reset();
+ }
+
+ private:
+ ResultBuilder makeUnexpectedResultBuilder() const
+ {
+ return ResultBuilder(m_lastAssertionInfo.macroName.c_str(),
+ m_lastAssertionInfo.lineInfo,
+ m_lastAssertionInfo.capturedExpression.c_str(),
+ m_lastAssertionInfo.resultDisposition);
+ }
+
+ void handleUnfinishedSections()
+ {
+ // If sections ended prematurely due to an exception we stored their
+ // infos here so we can tear them down outside the unwind process.
+ for (std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
+ itEnd = m_unfinishedSections.rend();
+ it != itEnd;
+ ++it)
+ sectionEnded(*it);
+ m_unfinishedSections.clear();
+ }
+
+ TestRunInfo m_runInfo;
+ IMutableContext& m_context;
+ TestCase const* m_activeTestCase;
+ ITracker* m_testCaseTracker;
+ ITracker* m_currentSectionTracker;
+ AssertionResult m_lastResult;
+
+ Ptr<IConfig const> m_config;
+ Totals m_totals;
+ Ptr<IStreamingReporter> m_reporter;
+ std::vector<MessageInfo> m_messages;
+ AssertionInfo m_lastAssertionInfo;
+ std::vector<SectionEndInfo> m_unfinishedSections;
+ std::vector<ITracker*> m_activeSections;
+ TrackerContext m_trackerContext;
+};
+
+IResultCapture& getResultCapture()
+{
+ if (IResultCapture* capture = getCurrentContext().getResultCapture())
+ return *capture;
+ else
+ throw std::logic_error("No result capture instance");
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_version.h
+#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED
+
+namespace Catch {
+
+// Versioning information
+struct Version
+{
+ Version(unsigned int _majorVersion,
+ unsigned int _minorVersion,
+ unsigned int _patchNumber,
+ std::string const& _branchName,
+ unsigned int _buildNumber);
+
+ unsigned int const majorVersion;
+ unsigned int const minorVersion;
+ unsigned int const patchNumber;
+
+ // buildNumber is only used if branchName is not null
+ std::string const branchName;
+ unsigned int const buildNumber;
+
+ friend std::ostream& operator<<(std::ostream& os, Version const& version);
+
+ private:
+ void operator=(Version const&);
+};
+
+extern Version libraryVersion;
+}
+
+#include <fstream>
+#include <limits>
+#include <stdlib.h>
+
+namespace Catch {
+
+Ptr<IStreamingReporter> createReporter(std::string const& reporterName, Ptr<Config> const& config)
+{
+ Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create(reporterName, config.get());
+ if (!reporter)
+ {
+ std::ostringstream oss;
+ oss << "No reporter registered with name: '" << reporterName << "'";
+ throw std::domain_error(oss.str());
+ }
+ return reporter;
+}
+
+Ptr<IStreamingReporter> makeReporter(Ptr<Config> const& config)
+{
+ std::vector<std::string> reporters = config->getReporterNames();
+ if (reporters.empty())
+ reporters.push_back("console");
+
+ Ptr<IStreamingReporter> reporter;
+ for (std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
+ it != itEnd;
+ ++it)
+ reporter = addReporter(reporter, createReporter(*it, config));
+ return reporter;
+}
+Ptr<IStreamingReporter> addListeners(Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters)
+{
+ IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners();
+ for (IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end();
+ it != itEnd;
+ ++it)
+ reporters = addReporter(reporters, (*it)->create(ReporterConfig(config)));
+ return reporters;
+}
+
+Totals runTests(Ptr<Config> const& config)
+{
+
+ Ptr<IConfig const> iconfig = config.get();
+
+ Ptr<IStreamingReporter> reporter = makeReporter(config);
+ reporter = addListeners(iconfig, reporter);
+
+ RunContext context(iconfig, reporter);
+
+ Totals totals;
+
+ context.testGroupStarting(config->name(), 1, 1);
+
+ TestSpec testSpec = config->testSpec();
+ if (!testSpec.hasFilters())
+ testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("~[.]").testSpec(); // All not hidden tests
+
+ std::vector<TestCase> const& allTestCases = getAllTestCasesSorted(*iconfig);
+ for (std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end();
+ it != itEnd;
+ ++it)
+ {
+ if (!context.aborting() && matchTest(*it, testSpec, *iconfig))
+ totals += context.runTest(*it);
+ else
+ reporter->skipTest(*it);
+ }
+
+ context.testGroupEnded(iconfig->name(), totals, 1, 1);
+ return totals;
+}
+
+void applyFilenamesAsTags(IConfig const& config)
+{
+ std::vector<TestCase> const& tests = getAllTestCasesSorted(config);
+ for (std::size_t i = 0; i < tests.size(); ++i)
+ {
+ TestCase& test = const_cast<TestCase&>(tests[i]);
+ std::set<std::string> tags = test.tags;
+
+ std::string filename = test.lineInfo.file;
+ std::string::size_type lastSlash = filename.find_last_of("\\/");
+ if (lastSlash != std::string::npos)
+ filename = filename.substr(lastSlash + 1);
+
+ std::string::size_type lastDot = filename.find_last_of(".");
+ if (lastDot != std::string::npos)
+ filename = filename.substr(0, lastDot);
+
+ tags.insert("#" + filename);
+ setTags(test, tags);
+ }
+}
+
+class Session : NonCopyable
+{
+ static bool alreadyInstantiated;
+
+ public:
+ struct OnUnusedOptions
+ {
+ enum DoWhat
+ {
+ Ignore,
+ Fail
+ };
+ };
+
+ Session()
+ : m_cli(makeCommandLineParser())
+ {
+ if (alreadyInstantiated)
+ {
+ std::string msg = "Only one instance of Catch::Session can ever be used";
+ Catch::cerr() << msg << std::endl;
+ throw std::logic_error(msg);
+ }
+ alreadyInstantiated = true;
+ }
+ ~Session()
+ {
+ Catch::cleanUp();
+ }
+
+ void showHelp(std::string const& processName)
+ {
+ Catch::cout() << "\nCatch v" << libraryVersion << "\n";
+
+ m_cli.usage(Catch::cout(), processName);
+ Catch::cout() << "For more detail usage please see the project docs\n"
+ << std::endl;
+ }
+
+ int applyCommandLine(int argc, char const* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail)
+ {
+ try
+ {
+ m_cli.setThrowOnUnrecognisedTokens(unusedOptionBehaviour == OnUnusedOptions::Fail);
+ m_unusedTokens = m_cli.parseInto(argc, argv, m_configData);
+ if (m_configData.showHelp)
+ showHelp(m_configData.processName);
+ m_config.reset();
+ }
+ catch (std::exception& ex)
+ {
+ {
+ Colour colourGuard(Colour::Red);
+ Catch::cerr()
+ << "\nError(s) in input:\n"
+ << Text(ex.what(), TextAttributes().setIndent(2))
+ << "\n\n";
+ }
+ m_cli.usage(Catch::cout(), m_configData.processName);
+ return (std::numeric_limits<int>::max)();
+ }
+ return 0;
+ }
+
+ void useConfigData(ConfigData const& _configData)
+ {
+ m_configData = _configData;
+ m_config.reset();
+ }
+
+ int run(int argc, char const* const argv[])
+ {
+
+ int returnCode = applyCommandLine(argc, argv);
+ if (returnCode == 0)
+ returnCode = run();
+ return returnCode;
+ }
+
+ int run()
+ {
+ if (m_configData.showHelp)
+ return 0;
+
+ try
+ {
+ config(); // Force config to be constructed
+
+ seedRng(*m_config);
+
+ if (m_configData.filenamesAsTags)
+ applyFilenamesAsTags(*m_config);
+
+ // Handle list request
+ if (Option<std::size_t> listed = list(config()))
+ return static_cast<int>(*listed);
+
+ return static_cast<int>(runTests(m_config).assertions.failed);
+ }
+ catch (std::exception& ex)
+ {
+ Catch::cerr() << ex.what() << std::endl;
+ return (std::numeric_limits<int>::max)();
+ }
+ }
+
+ Clara::CommandLine<ConfigData> const& cli() const
+ {
+ return m_cli;
+ }
+ std::vector<Clara::Parser::Token> const& unusedTokens() const
+ {
+ return m_unusedTokens;
+ }
+ ConfigData& configData()
+ {
+ return m_configData;
+ }
+ Config& config()
+ {
+ if (!m_config)
+ m_config = new Config(m_configData);
+ return *m_config;
+ }
+
+ private:
+ Clara::CommandLine<ConfigData> m_cli;
+ std::vector<Clara::Parser::Token> m_unusedTokens;
+ ConfigData m_configData;
+ Ptr<Config> m_config;
+};
+
+bool Session::alreadyInstantiated = false;
+
+} // end namespace Catch
+
+// #included from: catch_registry_hub.hpp
+#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
+
+// #included from: catch_test_case_registry_impl.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
+
+#include <algorithm>
+#include <iostream>
+#include <set>
+#include <sstream>
+#include <vector>
+
+namespace Catch {
+
+struct LexSort
+{
+ bool operator()(TestCase i, TestCase j) const { return (i < j); }
+};
+struct RandomNumberGenerator
+{
+ int operator()(int n) const { return std::rand() % n; }
+};
+
+inline std::vector<TestCase> sortTests(IConfig const& config, std::vector<TestCase> const& unsortedTestCases)
+{
+
+ std::vector<TestCase> sorted = unsortedTestCases;
+
+ switch (config.runOrder())
+ {
+ case RunTests::InLexicographicalOrder:
+ std::sort(sorted.begin(), sorted.end(), LexSort());
+ break;
+ case RunTests::InRandomOrder:
+ {
+ seedRng(config);
+
+ RandomNumberGenerator rng;
+ std::random_shuffle(sorted.begin(), sorted.end(), rng);
+ }
+ break;
+ case RunTests::InDeclarationOrder:
+ // already in declaration order
+ break;
+ }
+ return sorted;
+}
+bool matchTest(TestCase const& testCase, TestSpec const& testSpec, IConfig const& config)
+{
+ return testSpec.matches(testCase) && (config.allowThrows() || !testCase.throws());
+}
+
+void enforceNoDuplicateTestCases(std::vector<TestCase> const& functions)
+{
+ std::set<TestCase> seenFunctions;
+ for (std::vector<TestCase>::const_iterator it = functions.begin(), itEnd = functions.end();
+ it != itEnd;
+ ++it)
+ {
+ std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert(*it);
+ if (!prev.second)
+ {
+ Catch::cerr()
+ << Colour(Colour::Red)
+ << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
+ << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
+ << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
+ exit(1);
+ }
+ }
+}
+
+std::vector<TestCase> filterTests(std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config)
+{
+ std::vector<TestCase> filtered;
+ filtered.reserve(testCases.size());
+ for (std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
+ it != itEnd;
+ ++it)
+ if (matchTest(*it, testSpec, config))
+ filtered.push_back(*it);
+ return filtered;
+}
+std::vector<TestCase> const& getAllTestCasesSorted(IConfig const& config)
+{
+ return getRegistryHub().getTestCaseRegistry().getAllTestsSorted(config);
+}
+
+class TestRegistry : public ITestCaseRegistry
+{
+ public:
+ TestRegistry()
+ : m_currentSortOrder(RunTests::InDeclarationOrder),
+ m_unnamedCount(0)
+ {
+ }
+ virtual ~TestRegistry();
+
+ virtual void registerTest(TestCase const& testCase)
+ {
+ std::string name = testCase.getTestCaseInfo().name;
+ if (name == "")
+ {
+ std::ostringstream oss;
+ oss << "Anonymous test case " << ++m_unnamedCount;
+ return registerTest(testCase.withName(oss.str()));
+ }
+ m_functions.push_back(testCase);
+ }
+
+ virtual std::vector<TestCase> const& getAllTests() const
+ {
+ return m_functions;
+ }
+ virtual std::vector<TestCase> const& getAllTestsSorted(IConfig const& config) const
+ {
+ if (m_sortedFunctions.empty())
+ enforceNoDuplicateTestCases(m_functions);
+
+ if (m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty())
+ {
+ m_sortedFunctions = sortTests(config, m_functions);
+ m_currentSortOrder = config.runOrder();
+ }
+ return m_sortedFunctions;
+ }
+
+ private:
+ std::vector<TestCase> m_functions;
+ mutable RunTests::InWhatOrder m_currentSortOrder;
+ mutable std::vector<TestCase> m_sortedFunctions;
+ size_t m_unnamedCount;
+ std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+class FreeFunctionTestCase : public SharedImpl<ITestCase>
+{
+ public:
+ FreeFunctionTestCase(TestFunction fun) : m_fun(fun) {}
+
+ virtual void invoke() const
+ {
+ m_fun();
+ }
+
+ private:
+ virtual ~FreeFunctionTestCase();
+
+ TestFunction m_fun;
+};
+
+inline std::string extractClassName(std::string const& classOrQualifiedMethodName)
+{
+ std::string className = classOrQualifiedMethodName;
+ if (startsWith(className, "&"))
+ {
+ std::size_t lastColons = className.rfind("::");
+ std::size_t penultimateColons = className.rfind("::", lastColons - 1);
+ if (penultimateColons == std::string::npos)
+ penultimateColons = 1;
+ className = className.substr(penultimateColons, lastColons - penultimateColons);
+ }
+ return className;
+}
+
+void registerTestCase(ITestCase* testCase,
+ char const* classOrQualifiedMethodName,
+ NameAndDesc const& nameAndDesc,
+ SourceLineInfo const& lineInfo)
+{
+
+ getMutableRegistryHub().registerTest(makeTestCase(testCase,
+ extractClassName(classOrQualifiedMethodName),
+ nameAndDesc.name,
+ nameAndDesc.description,
+ lineInfo));
+}
+void registerTestCaseFunction(TestFunction function,
+ SourceLineInfo const& lineInfo,
+ NameAndDesc const& nameAndDesc)
+{
+ registerTestCase(new FreeFunctionTestCase(function), "", nameAndDesc, lineInfo);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+AutoReg::AutoReg(TestFunction function,
+ SourceLineInfo const& lineInfo,
+ NameAndDesc const& nameAndDesc)
+{
+ registerTestCaseFunction(function, lineInfo, nameAndDesc);
+}
+
+AutoReg::~AutoReg() {}
+
+} // end namespace Catch
+
+// #included from: catch_reporter_registry.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+class ReporterRegistry : public IReporterRegistry
+{
+
+ public:
+ virtual ~ReporterRegistry() CATCH_OVERRIDE {}
+
+ virtual IStreamingReporter* create(std::string const& name, Ptr<IConfig const> const& config) const CATCH_OVERRIDE
+ {
+ FactoryMap::const_iterator it = m_factories.find(name);
+ if (it == m_factories.end())
+ return CATCH_NULL;
+ return it->second->create(ReporterConfig(config));
+ }
+
+ void registerReporter(std::string const& name, Ptr<IReporterFactory> const& factory)
+ {
+ m_factories.insert(std::make_pair(name, factory));
+ }
+ void registerListener(Ptr<IReporterFactory> const& factory)
+ {
+ m_listeners.push_back(factory);
+ }
+
+ virtual FactoryMap const& getFactories() const CATCH_OVERRIDE
+ {
+ return m_factories;
+ }
+ virtual Listeners const& getListeners() const CATCH_OVERRIDE
+ {
+ return m_listeners;
+ }
+
+ private:
+ FactoryMap m_factories;
+ Listeners m_listeners;
+};
+}
+
+// #included from: catch_exception_translator_registry.hpp
+#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
+
+#ifdef __OBJC__
+#import "Foundation/Foundation.h"
+#endif
+
+namespace Catch {
+
+class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry
+{
+ public:
+ ~ExceptionTranslatorRegistry()
+ {
+ deleteAll(m_translators);
+ }
+
+ virtual void registerTranslator(const IExceptionTranslator* translator)
+ {
+ m_translators.push_back(translator);
+ }
+
+ virtual std::string translateActiveException() const
+ {
+ try
+ {
+#ifdef __OBJC__
+ // In Objective-C try objective-c exceptions first
+ @try
+ {
+ return tryTranslators();
+ }
+ @catch (NSException* exception)
+ {
+ return Catch::toString([exception description]);
+ }
+#else
+ return tryTranslators();
+#endif
+ }
+ catch (TestFailureException&)
+ {
+ throw;
+ }
+ catch (std::exception& ex)
+ {
+ return ex.what();
+ }
+ catch (std::string& msg)
+ {
+ return msg;
+ }
+ catch (const char* msg)
+ {
+ return msg;
+ }
+ catch (...)
+ {
+ return "Unknown exception";
+ }
+ }
+
+ std::string tryTranslators() const
+ {
+ if (m_translators.empty())
+ throw;
+ else
+ return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end());
+ }
+
+ private:
+ std::vector<const IExceptionTranslator*> m_translators;
+};
+}
+
+namespace Catch {
+
+namespace {
+
+class RegistryHub : public IRegistryHub, public IMutableRegistryHub
+{
+
+ RegistryHub(RegistryHub const&);
+ void operator=(RegistryHub const&);
+
+ public: // IRegistryHub
+ RegistryHub()
+ {
+ }
+ virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE
+ {
+ return m_reporterRegistry;
+ }
+ virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE
+ {
+ return m_testCaseRegistry;
+ }
+ virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE
+ {
+ return m_exceptionTranslatorRegistry;
+ }
+
+ public: // IMutableRegistryHub
+ virtual void registerReporter(std::string const& name, Ptr<IReporterFactory> const& factory) CATCH_OVERRIDE
+ {
+ m_reporterRegistry.registerReporter(name, factory);
+ }
+ virtual void registerListener(Ptr<IReporterFactory> const& factory) CATCH_OVERRIDE
+ {
+ m_reporterRegistry.registerListener(factory);
+ }
+ virtual void registerTest(TestCase const& testInfo) CATCH_OVERRIDE
+ {
+ m_testCaseRegistry.registerTest(testInfo);
+ }
+ virtual void registerTranslator(const IExceptionTranslator* translator) CATCH_OVERRIDE
+ {
+ m_exceptionTranslatorRegistry.registerTranslator(translator);
+ }
+
+ private:
+ TestRegistry m_testCaseRegistry;
+ ReporterRegistry m_reporterRegistry;
+ ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
+};
+
+// Single, global, instance
+inline RegistryHub*& getTheRegistryHub()
+{
+ static RegistryHub* theRegistryHub = CATCH_NULL;
+ if (!theRegistryHub)
+ theRegistryHub = new RegistryHub();
+ return theRegistryHub;
+}
+}
+
+IRegistryHub& getRegistryHub()
+{
+ return *getTheRegistryHub();
+}
+IMutableRegistryHub& getMutableRegistryHub()
+{
+ return *getTheRegistryHub();
+}
+void cleanUp()
+{
+ delete getTheRegistryHub();
+ getTheRegistryHub() = CATCH_NULL;
+ cleanUpContext();
+}
+std::string translateActiveException()
+{
+ return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
+}
+
+} // end namespace Catch
+
+// #included from: catch_notimplemented_exception.hpp
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
+
+#include <ostream>
+
+namespace Catch {
+
+NotImplementedException::NotImplementedException(SourceLineInfo const& lineInfo)
+ : m_lineInfo(lineInfo)
+{
+ std::ostringstream oss;
+ oss << lineInfo << ": function ";
+ oss << "not implemented";
+ m_what = oss.str();
+}
+
+const char* NotImplementedException::what() const CATCH_NOEXCEPT
+{
+ return m_what.c_str();
+}
+
+} // end namespace Catch
+
+// #included from: catch_context_impl.hpp
+#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
+
+// #included from: catch_stream.hpp
+#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
+
+#include <cstdio>
+#include <iostream>
+#include <stdexcept>
+
+namespace Catch {
+
+template <typename WriterF, size_t bufferSize = 256>
+class StreamBufImpl : public StreamBufBase
+{
+ char data[bufferSize];
+ WriterF m_writer;
+
+ public:
+ StreamBufImpl()
+ {
+ setp(data, data + sizeof(data));
+ }
+
+ ~StreamBufImpl() CATCH_NOEXCEPT
+ {
+ sync();
+ }
+
+ private:
+ int overflow(int c)
+ {
+ sync();
+
+ if (c != EOF)
+ {
+ if (pbase() == epptr())
+ m_writer(std::string(1, static_cast<char>(c)));
+ else
+ sputc(static_cast<char>(c));
+ }
+ return 0;
+ }
+
+ int sync()
+ {
+ if (pbase() != pptr())
+ {
+ m_writer(std::string(pbase(), static_cast<std::string::size_type>(pptr() - pbase())));
+ setp(pbase(), epptr());
+ }
+ return 0;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+FileStream::FileStream(std::string const& filename)
+{
+ m_ofs.open(filename.c_str());
+ if (m_ofs.fail())
+ {
+ std::ostringstream oss;
+ oss << "Unable to open file: '" << filename << "'";
+ throw std::domain_error(oss.str());
+ }
+}
+
+std::ostream& FileStream::stream() const
+{
+ return m_ofs;
+}
+
+struct OutputDebugWriter
+{
+
+ void operator()(std::string const& str)
+ {
+ writeToDebugConsole(str);
+ }
+};
+
+DebugOutStream::DebugOutStream()
+ : m_streamBuf(new StreamBufImpl<OutputDebugWriter>()),
+ m_os(m_streamBuf.get())
+{
+}
+
+std::ostream& DebugOutStream::stream() const
+{
+ return m_os;
+}
+
+// Store the streambuf from cout up-front because
+// cout may get redirected when running tests
+CoutStream::CoutStream()
+ : m_os(Catch::cout().rdbuf())
+{
+}
+
+std::ostream& CoutStream::stream() const
+{
+ return m_os;
+}
+
+#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions
+std::ostream& cout()
+{
+ return std::cout;
+}
+std::ostream& cerr()
+{
+ return std::cerr;
+}
+#endif
+}
+
+namespace Catch {
+
+class Context : public IMutableContext
+{
+
+ Context() : m_config(CATCH_NULL), m_runner(CATCH_NULL), m_resultCapture(CATCH_NULL) {}
+ Context(Context const&);
+ void operator=(Context const&);
+
+ public: // IContext
+ virtual IResultCapture* getResultCapture()
+ {
+ return m_resultCapture;
+ }
+ virtual IRunner* getRunner()
+ {
+ return m_runner;
+ }
+ virtual size_t getGeneratorIndex(std::string const& fileInfo, size_t totalSize)
+ {
+ return getGeneratorsForCurrentTest()
+ .getGeneratorInfo(fileInfo, totalSize)
+ .getCurrentIndex();
+ }
+ virtual bool advanceGeneratorsForCurrentTest()
+ {
+ IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+ return generators && generators->moveNext();
+ }
+
+ virtual Ptr<IConfig const> getConfig() const
+ {
+ return m_config;
+ }
+
+ public: // IMutableContext
+ virtual void setResultCapture(IResultCapture* resultCapture)
+ {
+ m_resultCapture = resultCapture;
+ }
+ virtual void setRunner(IRunner* runner)
+ {
+ m_runner = runner;
+ }
+ virtual void setConfig(Ptr<IConfig const> const& config)
+ {
+ m_config = config;
+ }
+
+ friend IMutableContext& getCurrentMutableContext();
+
+ private:
+ IGeneratorsForTest* findGeneratorsForCurrentTest()
+ {
+ std::string testName = getResultCapture()->getCurrentTestName();
+
+ std::map<std::string, IGeneratorsForTest*>::const_iterator it =
+ m_generatorsByTestName.find(testName);
+ return it != m_generatorsByTestName.end()
+ ? it->second
+ : CATCH_NULL;
+ }
+
+ IGeneratorsForTest& getGeneratorsForCurrentTest()
+ {
+ IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+ if (!generators)
+ {
+ std::string testName = getResultCapture()->getCurrentTestName();
+ generators = createGeneratorsForTest();
+ m_generatorsByTestName.insert(std::make_pair(testName, generators));
+ }
+ return *generators;
+ }
+
+ private:
+ Ptr<IConfig const> m_config;
+ IRunner* m_runner;
+ IResultCapture* m_resultCapture;
+ std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
+};
+
+namespace {
+Context* currentContext = CATCH_NULL;
+}
+IMutableContext& getCurrentMutableContext()
+{
+ if (!currentContext)
+ currentContext = new Context();
+ return *currentContext;
+}
+IContext& getCurrentContext()
+{
+ return getCurrentMutableContext();
+}
+
+void cleanUpContext()
+{
+ delete currentContext;
+ currentContext = CATCH_NULL;
+}
+}
+
+// #included from: catch_console_colour_impl.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
+
+namespace Catch {
+namespace {
+
+struct IColourImpl
+{
+ virtual ~IColourImpl() {}
+ virtual void use(Colour::Code _colourCode) = 0;
+};
+
+struct NoColourImpl : IColourImpl
+{
+ void use(Colour::Code) {}
+
+ static IColourImpl* instance()
+ {
+ static NoColourImpl s_instance;
+ return &s_instance;
+ }
+};
+
+} // anon namespace
+} // namespace Catch
+
+#if !defined(CATCH_CONFIG_COLOUR_NONE) && !defined(CATCH_CONFIG_COLOUR_WINDOWS) && !defined(CATCH_CONFIG_COLOUR_ANSI)
+#ifdef CATCH_PLATFORM_WINDOWS
+#define CATCH_CONFIG_COLOUR_WINDOWS
+#else
+#define CATCH_CONFIG_COLOUR_ANSI
+#endif
+#endif
+
+#if defined(CATCH_CONFIG_COLOUR_WINDOWS) /////////////////////////////////////////
+
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#ifdef __AFXDLL
+#include <AfxWin.h>
+#else
+#include <windows.h>
+#endif
+
+namespace Catch {
+namespace {
+
+class Win32ColourImpl : public IColourImpl
+{
+ public:
+ Win32ColourImpl() : stdoutHandle(GetStdHandle(STD_OUTPUT_HANDLE))
+ {
+ CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+ GetConsoleScreenBufferInfo(stdoutHandle, &csbiInfo);
+ originalForegroundAttributes = csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
+ originalBackgroundAttributes = csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
+ }
+
+ virtual void use(Colour::Code _colourCode)
+ {
+ switch (_colourCode)
+ {
+ case Colour::None:
+ return setTextAttribute(originalForegroundAttributes);
+ case Colour::White:
+ return setTextAttribute(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE);
+ case Colour::Red:
+ return setTextAttribute(FOREGROUND_RED);
+ case Colour::Green:
+ return setTextAttribute(FOREGROUND_GREEN);
+ case Colour::Blue:
+ return setTextAttribute(FOREGROUND_BLUE);
+ case Colour::Cyan:
+ return setTextAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN);
+ case Colour::Yellow:
+ return setTextAttribute(FOREGROUND_RED | FOREGROUND_GREEN);
+ case Colour::Grey:
+ return setTextAttribute(0);
+
+ case Colour::LightGrey:
+ return setTextAttribute(FOREGROUND_INTENSITY);
+ case Colour::BrightRed:
+ return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_RED);
+ case Colour::BrightGreen:
+ return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_GREEN);
+ case Colour::BrightWhite:
+ return setTextAttribute(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE);
+
+ case Colour::Bright:
+ throw std::logic_error("not a colour");
+ }
+ }
+
+ private:
+ void setTextAttribute(WORD _textAttribute)
+ {
+ SetConsoleTextAttribute(stdoutHandle, _textAttribute | originalBackgroundAttributes);
+ }
+ HANDLE stdoutHandle;
+ WORD originalForegroundAttributes;
+ WORD originalBackgroundAttributes;
+};
+
+IColourImpl* platformColourInstance()
+{
+ static Win32ColourImpl s_instance;
+ return &s_instance;
+}
+
+} // end anon namespace
+} // end namespace Catch
+
+#elif defined(CATCH_CONFIG_COLOUR_ANSI) //////////////////////////////////////
+
+#include <unistd.h>
+
+namespace Catch {
+namespace {
+
+// use POSIX/ ANSI console terminal codes
+// Thanks to Adam Strzelecki for original contribution
+// (http://github.com/nanoant)
+// https://github.com/philsquared/Catch/pull/131
+class PosixColourImpl : public IColourImpl
+{
+ public:
+ virtual void use(Colour::Code _colourCode)
+ {
+ switch (_colourCode)
+ {
+ case Colour::None:
+ case Colour::White:
+ return setColour("[0m");
+ case Colour::Red:
+ return setColour("[0;31m");
+ case Colour::Green:
+ return setColour("[0;32m");
+ case Colour::Blue:
+ return setColour("[0:34m");
+ case Colour::Cyan:
+ return setColour("[0;36m");
+ case Colour::Yellow:
+ return setColour("[0;33m");
+ case Colour::Grey:
+ return setColour("[1;30m");
+
+ case Colour::LightGrey:
+ return setColour("[0;37m");
+ case Colour::BrightRed:
+ return setColour("[1;31m");
+ case Colour::BrightGreen:
+ return setColour("[1;32m");
+ case Colour::BrightWhite:
+ return setColour("[1;37m");
+
+ case Colour::Bright:
+ throw std::logic_error("not a colour");
+ }
+ }
+ static IColourImpl* instance()
+ {
+ static PosixColourImpl s_instance;
+ return &s_instance;
+ }
+
+ private:
+ void setColour(const char* _escapeCode)
+ {
+ Catch::cout() << '\033' << _escapeCode;
+ }
+};
+
+IColourImpl* platformColourInstance()
+{
+ Ptr<IConfig const> config = getCurrentContext().getConfig();
+ return (config && config->forceColour()) || isatty(STDOUT_FILENO)
+ ? PosixColourImpl::instance()
+ : NoColourImpl::instance();
+}
+
+} // end anon namespace
+} // end namespace Catch
+
+#else // not Windows or ANSI ///////////////////////////////////////////////
+
+namespace Catch {
+
+static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }
+
+} // end namespace Catch
+
+#endif // Windows/ ANSI/ None
+
+namespace Catch {
+
+Colour::Colour(Code _colourCode) : m_moved(false) { use(_colourCode); }
+Colour::Colour(Colour const& _other) : m_moved(false) { const_cast<Colour&>(_other).m_moved = true; }
+Colour::~Colour()
+{
+ if (!m_moved) use(None);
+}
+
+void Colour::use(Code _colourCode)
+{
+ static IColourImpl* impl = isDebuggerActive()
+ ? NoColourImpl::instance()
+ : platformColourInstance();
+ impl->use(_colourCode);
+}
+
+} // end namespace Catch
+
+// #included from: catch_generators_impl.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+struct GeneratorInfo : IGeneratorInfo
+{
+
+ GeneratorInfo(std::size_t size)
+ : m_size(size),
+ m_currentIndex(0)
+ {
+ }
+
+ bool moveNext()
+ {
+ if (++m_currentIndex == m_size)
+ {
+ m_currentIndex = 0;
+ return false;
+ }
+ return true;
+ }
+
+ std::size_t getCurrentIndex() const
+ {
+ return m_currentIndex;
+ }
+
+ std::size_t m_size;
+ std::size_t m_currentIndex;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+class GeneratorsForTest : public IGeneratorsForTest
+{
+
+ public:
+ ~GeneratorsForTest()
+ {
+ deleteAll(m_generatorsInOrder);
+ }
+
+ IGeneratorInfo& getGeneratorInfo(std::string const& fileInfo, std::size_t size)
+ {
+ std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find(fileInfo);
+ if (it == m_generatorsByName.end())
+ {
+ IGeneratorInfo* info = new GeneratorInfo(size);
+ m_generatorsByName.insert(std::make_pair(fileInfo, info));
+ m_generatorsInOrder.push_back(info);
+ return *info;
+ }
+ return *it->second;
+ }
+
+ bool moveNext()
+ {
+ std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
+ std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
+ for (; it != itEnd; ++it)
+ {
+ if ((*it)->moveNext())
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ std::map<std::string, IGeneratorInfo*> m_generatorsByName;
+ std::vector<IGeneratorInfo*> m_generatorsInOrder;
+};
+
+IGeneratorsForTest* createGeneratorsForTest()
+{
+ return new GeneratorsForTest();
+}
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.hpp
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
+
+namespace Catch {
+
+AssertionInfo::AssertionInfo(std::string const& _macroName,
+ SourceLineInfo const& _lineInfo,
+ std::string const& _capturedExpression,
+ ResultDisposition::Flags _resultDisposition)
+ : macroName(_macroName),
+ lineInfo(_lineInfo),
+ capturedExpression(_capturedExpression),
+ resultDisposition(_resultDisposition)
+{
+}
+
+AssertionResult::AssertionResult() {}
+
+AssertionResult::AssertionResult(AssertionInfo const& info, AssertionResultData const& data)
+ : m_info(info),
+ m_resultData(data)
+{
+}
+
+AssertionResult::~AssertionResult() {}
+
+// Result was a success
+bool AssertionResult::succeeded() const
+{
+ return Catch::isOk(m_resultData.resultType);
+}
+
+// Result was a success, or failure is suppressed
+bool AssertionResult::isOk() const
+{
+ return Catch::isOk(m_resultData.resultType) || shouldSuppressFailure(m_info.resultDisposition);
+}
+
+ResultWas::OfType AssertionResult::getResultType() const
+{
+ return m_resultData.resultType;
+}
+
+bool AssertionResult::hasExpression() const
+{
+ return !m_info.capturedExpression.empty();
+}
+
+bool AssertionResult::hasMessage() const
+{
+ return !m_resultData.message.empty();
+}
+
+std::string AssertionResult::getExpression() const
+{
+ if (isFalseTest(m_info.resultDisposition))
+ return "!" + m_info.capturedExpression;
+ else
+ return m_info.capturedExpression;
+}
+std::string AssertionResult::getExpressionInMacro() const
+{
+ if (m_info.macroName.empty())
+ return m_info.capturedExpression;
+ else
+ return m_info.macroName + "( " + m_info.capturedExpression + " )";
+}
+
+bool AssertionResult::hasExpandedExpression() const
+{
+ return hasExpression() && getExpandedExpression() != getExpression();
+}
+
+std::string AssertionResult::getExpandedExpression() const
+{
+ return m_resultData.reconstructedExpression;
+}
+
+std::string AssertionResult::getMessage() const
+{
+ return m_resultData.message;
+}
+SourceLineInfo AssertionResult::getSourceInfo() const
+{
+ return m_info.lineInfo;
+}
+
+std::string AssertionResult::getTestMacroName() const
+{
+ return m_info.macroName;
+}
+
+} // end namespace Catch
+
+// #included from: catch_test_case_info.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
+
+namespace Catch {
+
+inline TestCaseInfo::SpecialProperties parseSpecialTag(std::string const& tag)
+{
+ if (startsWith(tag, ".") ||
+ tag == "hide" ||
+ tag == "!hide")
+ return TestCaseInfo::IsHidden;
+ else if (tag == "!throws")
+ return TestCaseInfo::Throws;
+ else if (tag == "!shouldfail")
+ return TestCaseInfo::ShouldFail;
+ else if (tag == "!mayfail")
+ return TestCaseInfo::MayFail;
+ else
+ return TestCaseInfo::None;
+}
+inline bool isReservedTag(std::string const& tag)
+{
+ return parseSpecialTag(tag) == TestCaseInfo::None && tag.size() > 0 && !isalnum(tag[0]);
+}
+inline void enforceNotReservedTag(std::string const& tag, SourceLineInfo const& _lineInfo)
+{
+ if (isReservedTag(tag))
+ {
+ {
+ Colour colourGuard(Colour::Red);
+ Catch::cerr()
+ << "Tag name [" << tag << "] not allowed.\n"
+ << "Tag names starting with non alpha-numeric characters are reserved\n";
+ }
+ {
+ Colour colourGuard(Colour::FileName);
+ Catch::cerr() << _lineInfo << std::endl;
+ }
+ exit(1);
+ }
+}
+
+TestCase makeTestCase(ITestCase* _testCase,
+ std::string const& _className,
+ std::string const& _name,
+ std::string const& _descOrTags,
+ SourceLineInfo const& _lineInfo)
+{
+ bool isHidden(startsWith(_name, "./")); // Legacy support
+
+ // Parse out tags
+ std::set<std::string> tags;
+ std::string desc, tag;
+ bool inTag = false;
+ for (std::size_t i = 0; i < _descOrTags.size(); ++i)
+ {
+ char c = _descOrTags[i];
+ if (!inTag)
+ {
+ if (c == '[')
+ inTag = true;
+ else
+ desc += c;
+ }
+ else
+ {
+ if (c == ']')
+ {
+ TestCaseInfo::SpecialProperties prop = parseSpecialTag(tag);
+ if (prop == TestCaseInfo::IsHidden)
+ isHidden = true;
+ else if (prop == TestCaseInfo::None)
+ enforceNotReservedTag(tag, _lineInfo);
+
+ tags.insert(tag);
+ tag.clear();
+ inTag = false;
+ }
+ else
+ tag += c;
+ }
+ }
+ if (isHidden)
+ {
+ tags.insert("hide");
+ tags.insert(".");
+ }
+
+ TestCaseInfo info(_name, _className, desc, tags, _lineInfo);
+ return TestCase(_testCase, info);
+}
+
+void setTags(TestCaseInfo& testCaseInfo, std::set<std::string> const& tags)
+{
+ testCaseInfo.tags = tags;
+ testCaseInfo.lcaseTags.clear();
+
+ std::ostringstream oss;
+ for (std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it)
+ {
+ oss << "[" << *it << "]";
+ std::string lcaseTag = toLower(*it);
+ testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>(testCaseInfo.properties | parseSpecialTag(lcaseTag));
+ testCaseInfo.lcaseTags.insert(lcaseTag);
+ }
+ testCaseInfo.tagsAsString = oss.str();
+}
+
+TestCaseInfo::TestCaseInfo(std::string const& _name,
+ std::string const& _className,
+ std::string const& _description,
+ std::set<std::string> const& _tags,
+ SourceLineInfo const& _lineInfo)
+ : name(_name),
+ className(_className),
+ description(_description),
+ lineInfo(_lineInfo),
+ properties(None)
+{
+ setTags(*this, _tags);
+}
+
+TestCaseInfo::TestCaseInfo(TestCaseInfo const& other)
+ : name(other.name),
+ className(other.className),
+ description(other.description),
+ tags(other.tags),
+ lcaseTags(other.lcaseTags),
+ tagsAsString(other.tagsAsString),
+ lineInfo(other.lineInfo),
+ properties(other.properties)
+{
+}
+
+bool TestCaseInfo::isHidden() const
+{
+ return (properties & IsHidden) != 0;
+}
+bool TestCaseInfo::throws() const
+{
+ return (properties & Throws) != 0;
+}
+bool TestCaseInfo::okToFail() const
+{
+ return (properties & (ShouldFail | MayFail)) != 0;
+}
+bool TestCaseInfo::expectedToFail() const
+{
+ return (properties & (ShouldFail)) != 0;
+}
+
+TestCase::TestCase(ITestCase* testCase, TestCaseInfo const& info) : TestCaseInfo(info), test(testCase) {}
+
+TestCase::TestCase(TestCase const& other)
+ : TestCaseInfo(other),
+ test(other.test)
+{
+}
+
+TestCase TestCase::withName(std::string const& _newName) const
+{
+ TestCase other(*this);
+ other.name = _newName;
+ return other;
+}
+
+void TestCase::swap(TestCase& other)
+{
+ test.swap(other.test);
+ name.swap(other.name);
+ className.swap(other.className);
+ description.swap(other.description);
+ tags.swap(other.tags);
+ lcaseTags.swap(other.lcaseTags);
+ tagsAsString.swap(other.tagsAsString);
+ std::swap(TestCaseInfo::properties, static_cast<TestCaseInfo&>(other).properties);
+ std::swap(lineInfo, other.lineInfo);
+}
+
+void TestCase::invoke() const
+{
+ test->invoke();
+}
+
+bool TestCase::operator==(TestCase const& other) const
+{
+ return test.get() == other.test.get() &&
+ name == other.name &&
+ className == other.className;
+}
+
+bool TestCase::operator<(TestCase const& other) const
+{
+ return name < other.name;
+}
+TestCase& TestCase::operator=(TestCase const& other)
+{
+ TestCase temp(other);
+ swap(temp);
+ return *this;
+}
+
+TestCaseInfo const& TestCase::getTestCaseInfo() const
+{
+ return *this;
+}
+
+} // end namespace Catch
+
+// #included from: catch_version.hpp
+#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED
+
+namespace Catch {
+
+Version::Version(unsigned int _majorVersion,
+ unsigned int _minorVersion,
+ unsigned int _patchNumber,
+ std::string const& _branchName,
+ unsigned int _buildNumber)
+ : majorVersion(_majorVersion),
+ minorVersion(_minorVersion),
+ patchNumber(_patchNumber),
+ branchName(_branchName),
+ buildNumber(_buildNumber)
+{
+}
+
+std::ostream& operator<<(std::ostream& os, Version const& version)
+{
+ os << version.majorVersion << "."
+ << version.minorVersion << "."
+ << version.patchNumber;
+
+ if (!version.branchName.empty())
+ {
+ os << "-" << version.branchName
+ << "." << version.buildNumber;
+ }
+ return os;
+}
+
+Version libraryVersion(1, 3, 2, "", 0);
+}
+
+// #included from: catch_message.hpp
+#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
+
+namespace Catch {
+
+MessageInfo::MessageInfo(std::string const& _macroName,
+ SourceLineInfo const& _lineInfo,
+ ResultWas::OfType _type)
+ : macroName(_macroName),
+ lineInfo(_lineInfo),
+ type(_type),
+ sequence(++globalCount)
+{
+}
+
+// This may need protecting if threading support is added
+unsigned int MessageInfo::globalCount = 0;
+
+////////////////////////////////////////////////////////////////////////////
+
+ScopedMessage::ScopedMessage(MessageBuilder const& builder)
+ : m_info(builder.m_info)
+{
+ m_info.message = builder.m_stream.str();
+ getResultCapture().pushScopedMessage(m_info);
+}
+ScopedMessage::ScopedMessage(ScopedMessage const& other)
+ : m_info(other.m_info)
+{
+}
+
+ScopedMessage::~ScopedMessage()
+{
+ getResultCapture().popScopedMessage(m_info);
+}
+
+} // end namespace Catch
+
+// #included from: catch_legacy_reporter_adapter.hpp
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
+
+// #included from: catch_legacy_reporter_adapter.h
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
+
+namespace Catch {
+// Deprecated
+struct IReporter : IShared
+{
+ virtual ~IReporter();
+
+ virtual bool shouldRedirectStdout() const = 0;
+
+ virtual void StartTesting() = 0;
+ virtual void EndTesting(Totals const& totals) = 0;
+ virtual void StartGroup(std::string const& groupName) = 0;
+ virtual void EndGroup(std::string const& groupName, Totals const& totals) = 0;
+ virtual void StartTestCase(TestCaseInfo const& testInfo) = 0;
+ virtual void EndTestCase(TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr) = 0;
+ virtual void StartSection(std::string const& sectionName, std::string const& description) = 0;
+ virtual void EndSection(std::string const& sectionName, Counts const& assertions) = 0;
+ virtual void NoAssertionsInSection(std::string const& sectionName) = 0;
+ virtual void NoAssertionsInTestCase(std::string const& testName) = 0;
+ virtual void Aborted() = 0;
+ virtual void Result(AssertionResult const& result) = 0;
+};
+
+class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
+{
+ public:
+ LegacyReporterAdapter(Ptr<IReporter> const& legacyReporter);
+ virtual ~LegacyReporterAdapter();
+
+ virtual ReporterPreferences getPreferences() const;
+ virtual void noMatchingTestCases(std::string const&);
+ virtual void testRunStarting(TestRunInfo const&);
+ virtual void testGroupStarting(GroupInfo const& groupInfo);
+ virtual void testCaseStarting(TestCaseInfo const& testInfo);
+ virtual void sectionStarting(SectionInfo const& sectionInfo);
+ virtual void assertionStarting(AssertionInfo const&);
+ virtual bool assertionEnded(AssertionStats const& assertionStats);
+ virtual void sectionEnded(SectionStats const& sectionStats);
+ virtual void testCaseEnded(TestCaseStats const& testCaseStats);
+ virtual void testGroupEnded(TestGroupStats const& testGroupStats);
+ virtual void testRunEnded(TestRunStats const& testRunStats);
+ virtual void skipTest(TestCaseInfo const&);
+
+ private:
+ Ptr<IReporter> m_legacyReporter;
+};
+}
+
+namespace Catch {
+LegacyReporterAdapter::LegacyReporterAdapter(Ptr<IReporter> const& legacyReporter)
+ : m_legacyReporter(legacyReporter)
+{
+}
+LegacyReporterAdapter::~LegacyReporterAdapter() {}
+
+ReporterPreferences LegacyReporterAdapter::getPreferences() const
+{
+ ReporterPreferences prefs;
+ prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
+ return prefs;
+}
+
+void LegacyReporterAdapter::noMatchingTestCases(std::string const&) {}
+void LegacyReporterAdapter::testRunStarting(TestRunInfo const&)
+{
+ m_legacyReporter->StartTesting();
+}
+void LegacyReporterAdapter::testGroupStarting(GroupInfo const& groupInfo)
+{
+ m_legacyReporter->StartGroup(groupInfo.name);
+}
+void LegacyReporterAdapter::testCaseStarting(TestCaseInfo const& testInfo)
+{
+ m_legacyReporter->StartTestCase(testInfo);
+}
+void LegacyReporterAdapter::sectionStarting(SectionInfo const& sectionInfo)
+{
+ m_legacyReporter->StartSection(sectionInfo.name, sectionInfo.description);
+}
+void LegacyReporterAdapter::assertionStarting(AssertionInfo const&)
+{
+ // Not on legacy interface
+}
+
+bool LegacyReporterAdapter::assertionEnded(AssertionStats const& assertionStats)
+{
+ if (assertionStats.assertionResult.getResultType() != ResultWas::Ok)
+ {
+ for (std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+ it != itEnd;
+ ++it)
+ {
+ if (it->type == ResultWas::Info)
+ {
+ ResultBuilder rb(it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal);
+ rb << it->message;
+ rb.setResultType(ResultWas::Info);
+ AssertionResult result = rb.build();
+ m_legacyReporter->Result(result);
+ }
+ }
+ }
+ m_legacyReporter->Result(assertionStats.assertionResult);
+ return true;
+}
+void LegacyReporterAdapter::sectionEnded(SectionStats const& sectionStats)
+{
+ if (sectionStats.missingAssertions)
+ m_legacyReporter->NoAssertionsInSection(sectionStats.sectionInfo.name);
+ m_legacyReporter->EndSection(sectionStats.sectionInfo.name, sectionStats.assertions);
+}
+void LegacyReporterAdapter::testCaseEnded(TestCaseStats const& testCaseStats)
+{
+ m_legacyReporter->EndTestCase(testCaseStats.testInfo,
+ testCaseStats.totals,
+ testCaseStats.stdOut,
+ testCaseStats.stdErr);
+}
+void LegacyReporterAdapter::testGroupEnded(TestGroupStats const& testGroupStats)
+{
+ if (testGroupStats.aborting)
+ m_legacyReporter->Aborted();
+ m_legacyReporter->EndGroup(testGroupStats.groupInfo.name, testGroupStats.totals);
+}
+void LegacyReporterAdapter::testRunEnded(TestRunStats const& testRunStats)
+{
+ m_legacyReporter->EndTesting(testRunStats.totals);
+}
+void LegacyReporterAdapter::skipTest(TestCaseInfo const&)
+{
+}
+}
+
+// #included from: catch_timer.hpp
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++11-long-long"
+#endif
+
+#ifdef CATCH_PLATFORM_WINDOWS
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+
+namespace Catch {
+
+namespace {
+#ifdef CATCH_PLATFORM_WINDOWS
+uint64_t getCurrentTicks()
+{
+ static uint64_t hz = 0, hzo = 0;
+ if (!hz)
+ {
+ QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&hz));
+ QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&hzo));
+ }
+ uint64_t t;
+ QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&t));
+ return ((t - hzo) * 1000000) / hz;
+}
+#else
+uint64_t getCurrentTicks()
+{
+ timeval t;
+ gettimeofday(&t, CATCH_NULL);
+ return static_cast<uint64_t>(t.tv_sec) * 1000000ull + static_cast<uint64_t>(t.tv_usec);
+}
+#endif
+}
+
+void Timer::start()
+{
+ m_ticks = getCurrentTicks();
+}
+unsigned int Timer::getElapsedMicroseconds() const
+{
+ return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
+}
+unsigned int Timer::getElapsedMilliseconds() const
+{
+ return static_cast<unsigned int>(getElapsedMicroseconds() / 1000);
+}
+double Timer::getElapsedSeconds() const
+{
+ return getElapsedMicroseconds() / 1000000.0;
+}
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+// #included from: catch_common.hpp
+#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
+
+namespace Catch {
+
+bool startsWith(std::string const& s, std::string const& prefix)
+{
+ return s.size() >= prefix.size() && s.substr(0, prefix.size()) == prefix;
+}
+bool endsWith(std::string const& s, std::string const& suffix)
+{
+ return s.size() >= suffix.size() && s.substr(s.size() - suffix.size(), suffix.size()) == suffix;
+}
+bool contains(std::string const& s, std::string const& infix)
+{
+ return s.find(infix) != std::string::npos;
+}
+void toLowerInPlace(std::string& s)
+{
+ std::transform(s.begin(), s.end(), s.begin(), ::tolower);
+}
+std::string toLower(std::string const& s)
+{
+ std::string lc = s;
+ toLowerInPlace(lc);
+ return lc;
+}
+std::string trim(std::string const& str)
+{
+ static char const* whitespaceChars = "\n\r\t ";
+ std::string::size_type start = str.find_first_not_of(whitespaceChars);
+ std::string::size_type end = str.find_last_not_of(whitespaceChars);
+
+ return start != std::string::npos ? str.substr(start, 1 + end - start) : "";
+}
+
+bool replaceInPlace(std::string& str, std::string const& replaceThis, std::string const& withThis)
+{
+ bool replaced = false;
+ std::size_t i = str.find(replaceThis);
+ while (i != std::string::npos)
+ {
+ replaced = true;
+ str = str.substr(0, i) + withThis + str.substr(i + replaceThis.size());
+ if (i < str.size() - withThis.size())
+ i = str.find(replaceThis, i + withThis.size());
+ else
+ i = std::string::npos;
+ }
+ return replaced;
+}
+
+pluralise::pluralise(std::size_t count, std::string const& label)
+ : m_count(count),
+ m_label(label)
+{
+}
+
+std::ostream& operator<<(std::ostream& os, pluralise const& pluraliser)
+{
+ os << pluraliser.m_count << " " << pluraliser.m_label;
+ if (pluraliser.m_count != 1)
+ os << "s";
+ return os;
+}
+
+SourceLineInfo::SourceLineInfo() : line(0) {}
+SourceLineInfo::SourceLineInfo(char const* _file, std::size_t _line)
+ : file(_file),
+ line(_line)
+{
+}
+SourceLineInfo::SourceLineInfo(SourceLineInfo const& other)
+ : file(other.file),
+ line(other.line)
+{
+}
+bool SourceLineInfo::empty() const
+{
+ return file.empty();
+}
+bool SourceLineInfo::operator==(SourceLineInfo const& other) const
+{
+ return line == other.line && file == other.file;
+}
+bool SourceLineInfo::operator<(SourceLineInfo const& other) const
+{
+ return line < other.line || (line == other.line && file < other.file);
+}
+
+void seedRng(IConfig const& config)
+{
+ if (config.rngSeed() != 0)
+ std::srand(config.rngSeed());
+}
+unsigned int rngSeed()
+{
+ return getCurrentContext().getConfig()->rngSeed();
+}
+
+std::ostream& operator<<(std::ostream& os, SourceLineInfo const& info)
+{
+#ifndef __GNUG__
+ os << info.file << "(" << info.line << ")";
+#else
+ os << info.file << ":" << info.line;
+#endif
+ return os;
+}
+
+void throwLogicError(std::string const& message, SourceLineInfo const& locationInfo)
+{
+ std::ostringstream oss;
+ oss << locationInfo << ": Internal Catch error: '" << message << "'";
+ if (alwaysTrue())
+ throw std::logic_error(oss.str());
+}
+}
+
+// #included from: catch_section.hpp
+#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
+
+namespace Catch {
+
+SectionInfo::SectionInfo(SourceLineInfo const& _lineInfo,
+ std::string const& _name,
+ std::string const& _description)
+ : name(_name),
+ description(_description),
+ lineInfo(_lineInfo)
+{
+}
+
+Section::Section(SectionInfo const& info)
+ : m_info(info),
+ m_sectionIncluded(getResultCapture().sectionStarted(m_info, m_assertions))
+{
+ m_timer.start();
+}
+
+Section::~Section()
+{
+ if (m_sectionIncluded)
+ {
+ SectionEndInfo endInfo(m_info, m_assertions, m_timer.getElapsedSeconds());
+ if (std::uncaught_exception())
+ getResultCapture().sectionEndedEarly(endInfo);
+ else
+ getResultCapture().sectionEnded(endInfo);
+ }
+}
+
+// This indicates whether the section should be executed or not
+Section::operator bool() const
+{
+ return m_sectionIncluded;
+}
+
+} // end namespace Catch
+
+// #included from: catch_debugger.hpp
+#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
+
+#include <iostream>
+
+#ifdef CATCH_PLATFORM_MAC
+
+#include <assert.h>
+#include <stdbool.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace Catch {
+
+// The following function is taken directly from the following technical note:
+// http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
+
+// Returns true if the current process is being debugged (either
+// running under the debugger or has a debugger attached post facto).
+bool isDebuggerActive()
+{
+
+ int mib[4];
+ struct kinfo_proc info;
+ size_t size;
+
+ // Initialize the flags so that, if sysctl fails for some bizarre
+ // reason, we get a predictable result.
+
+ info.kp_proc.p_flag = 0;
+
+ // Initialize mib, which tells sysctl the info we want, in this case
+ // we're looking for information about a specific process ID.
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = getpid();
+
+ // Call sysctl.
+
+ size = sizeof(info);
+ if (sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0)
+ {
+ Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n"
+ << std::endl;
+ return false;
+ }
+
+ // We're being debugged if the P_TRACED flag is set.
+
+ return ((info.kp_proc.p_flag & P_TRACED) != 0);
+}
+} // namespace Catch
+
+#elif defined(_MSC_VER)
+extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+namespace Catch {
+bool isDebuggerActive()
+{
+ return IsDebuggerPresent() != 0;
+}
+}
+#elif defined(__MINGW32__)
+extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+namespace Catch {
+bool isDebuggerActive()
+{
+ return IsDebuggerPresent() != 0;
+}
+}
+#else
+namespace Catch {
+inline bool isDebuggerActive() { return false; }
+}
+#endif // Platform
+
+#ifdef CATCH_PLATFORM_WINDOWS
+extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char*);
+namespace Catch {
+void writeToDebugConsole(std::string const& text)
+{
+ ::OutputDebugStringA(text.c_str());
+}
+}
+#else
+namespace Catch {
+void writeToDebugConsole(std::string const& text)
+{
+ // !TBD: Need a version for Mac/ XCode and other IDEs
+ Catch::cout() << text;
+}
+}
+#endif // Platform
+
+// #included from: catch_tostring.hpp
+#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
+
+namespace Catch {
+
+namespace Detail {
+
+const std::string unprintableString = "{?}";
+
+namespace {
+const int hexThreshold = 255;
+
+struct Endianness
+{
+ enum Arch
+ {
+ Big,
+ Little
+ };
+
+ static Arch which()
+ {
+ union _
+ {
+ int asInt;
+ char asChar[sizeof(int)];
+ } u;
+
+ u.asInt = 1;
+ return (u.asChar[sizeof(int) - 1] == 1) ? Big : Little;
+ }
+};
+}
+
+std::string rawMemoryToString(const void* object, std::size_t size)
+{
+ // Reverse order for little endian architectures
+ int i = 0, end = static_cast<int>(size), inc = 1;
+ if (Endianness::which() == Endianness::Little)
+ {
+ i = end - 1;
+ end = inc = -1;
+ }
+
+ unsigned char const* bytes = static_cast<unsigned char const*>(object);
+ std::ostringstream os;
+ os << "0x" << std::setfill('0') << std::hex;
+ for (; i != end; i += inc)
+ os << std::setw(2) << static_cast<unsigned>(bytes[i]);
+ return os.str();
+}
+}
+
+std::string toString(std::string const& value)
+{
+ std::string s = value;
+ if (getCurrentContext().getConfig()->showInvisibles())
+ {
+ for (size_t i = 0; i < s.size(); ++i)
+ {
+ std::string subs;
+ switch (s[i])
+ {
+ case '\n':
+ subs = "\\n";
+ break;
+ case '\t':
+ subs = "\\t";
+ break;
+ default:
+ break;
+ }
+ if (!subs.empty())
+ {
+ s = s.substr(0, i) + subs + s.substr(i + 1);
+ ++i;
+ }
+ }
+ }
+ return "\"" + s + "\"";
+}
+std::string toString(std::wstring const& value)
+{
+
+ std::string s;
+ s.reserve(value.size());
+ for (size_t i = 0; i < value.size(); ++i)
+ s += value[i] <= 0xff ? static_cast<char>(value[i]) : '?';
+ return Catch::toString(s);
+}
+
+std::string toString(const char* const value)
+{
+ return value ? Catch::toString(std::string(value)) : std::string("{null string}");
+}
+
+std::string toString(char* const value)
+{
+ return Catch::toString(static_cast<const char*>(value));
+}
+
+std::string toString(const wchar_t* const value)
+{
+ return value ? Catch::toString(std::wstring(value)) : std::string("{null string}");
+}
+
+std::string toString(wchar_t* const value)
+{
+ return Catch::toString(static_cast<const wchar_t*>(value));
+}
+
+std::string toString(int value)
+{
+ std::ostringstream oss;
+ oss << value;
+ if (value > Detail::hexThreshold)
+ oss << " (0x" << std::hex << value << ")";
+ return oss.str();
+}
+
+std::string toString(unsigned long value)
+{
+ std::ostringstream oss;
+ oss << value;
+ if (value > Detail::hexThreshold)
+ oss << " (0x" << std::hex << value << ")";
+ return oss.str();
+}
+
+std::string toString(unsigned int value)
+{
+ return Catch::toString(static_cast<unsigned long>(value));
+}
+
+template <typename T>
+std::string fpToString(T value, int precision)
+{
+ std::ostringstream oss;
+ oss << std::setprecision(precision)
+ << std::fixed
+ << value;
+ std::string d = oss.str();
+ std::size_t i = d.find_last_not_of('0');
+ if (i != std::string::npos && i != d.size() - 1)
+ {
+ if (d[i] == '.')
+ i++;
+ d = d.substr(0, i + 1);
+ }
+ return d;
+}
+
+std::string toString(const double value)
+{
+ return fpToString(value, 10);
+}
+std::string toString(const float value)
+{
+ return fpToString(value, 5) + "f";
+}
+
+std::string toString(bool value)
+{
+ return value ? "true" : "false";
+}
+
+std::string toString(char value)
+{
+ return value < ' '
+ ? toString(static_cast<unsigned int>(value))
+ : Detail::makeString(value);
+}
+
+std::string toString(signed char value)
+{
+ return toString(static_cast<char>(value));
+}
+
+std::string toString(unsigned char value)
+{
+ return toString(static_cast<char>(value));
+}
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+std::string toString(long long value)
+{
+ std::ostringstream oss;
+ oss << value;
+ if (value > Detail::hexThreshold)
+ oss << " (0x" << std::hex << value << ")";
+ return oss.str();
+}
+std::string toString(unsigned long long value)
+{
+ std::ostringstream oss;
+ oss << value;
+ if (value > Detail::hexThreshold)
+ oss << " (0x" << std::hex << value << ")";
+ return oss.str();
+}
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString(std::nullptr_t)
+{
+ return "nullptr";
+}
+#endif
+
+#ifdef __OBJC__
+std::string toString(NSString const* const& nsstring)
+{
+ if (!nsstring)
+ return "nil";
+ return "@" + toString([nsstring UTF8String]);
+}
+std::string toString(NSString* CATCH_ARC_STRONG const& nsstring)
+{
+ if (!nsstring)
+ return "nil";
+ return "@" + toString([nsstring UTF8String]);
+}
+std::string toString(NSObject* const& nsObject)
+{
+ return toString([nsObject description]);
+}
+#endif
+
+} // end namespace Catch
+
+// #included from: catch_result_builder.hpp
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED
+
+namespace Catch {
+
+std::string capturedExpressionWithSecondArgument(std::string const& capturedExpression, std::string const& secondArg)
+{
+ return secondArg.empty() || secondArg == "\"\""
+ ? capturedExpression
+ : capturedExpression + ", " + secondArg;
+}
+ResultBuilder::ResultBuilder(char const* macroName,
+ SourceLineInfo const& lineInfo,
+ char const* capturedExpression,
+ ResultDisposition::Flags resultDisposition,
+ char const* secondArg)
+ : m_assertionInfo(macroName, lineInfo, capturedExpressionWithSecondArgument(capturedExpression, secondArg), resultDisposition),
+ m_shouldDebugBreak(false),
+ m_shouldThrow(false)
+{
+}
+
+ResultBuilder& ResultBuilder::setResultType(ResultWas::OfType result)
+{
+ m_data.resultType = result;
+ return *this;
+}
+ResultBuilder& ResultBuilder::setResultType(bool result)
+{
+ m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
+ return *this;
+}
+ResultBuilder& ResultBuilder::setLhs(std::string const& lhs)
+{
+ m_exprComponents.lhs = lhs;
+ return *this;
+}
+ResultBuilder& ResultBuilder::setRhs(std::string const& rhs)
+{
+ m_exprComponents.rhs = rhs;
+ return *this;
+}
+ResultBuilder& ResultBuilder::setOp(std::string const& op)
+{
+ m_exprComponents.op = op;
+ return *this;
+}
+
+void ResultBuilder::endExpression()
+{
+ m_exprComponents.testFalse = isFalseTest(m_assertionInfo.resultDisposition);
+ captureExpression();
+}
+
+void ResultBuilder::useActiveException(ResultDisposition::Flags resultDisposition)
+{
+ m_assertionInfo.resultDisposition = resultDisposition;
+ m_stream.oss << Catch::translateActiveException();
+ captureResult(ResultWas::ThrewException);
+}
+
+void ResultBuilder::captureResult(ResultWas::OfType resultType)
+{
+ setResultType(resultType);
+ captureExpression();
+}
+void ResultBuilder::captureExpectedException(std::string const& expectedMessage)
+{
+ if (expectedMessage.empty())
+ captureExpectedException(Matchers::Impl::Generic::AllOf<std::string>());
+ else
+ captureExpectedException(Matchers::Equals(expectedMessage));
+}
+
+void ResultBuilder::captureExpectedException(Matchers::Impl::Matcher<std::string> const& matcher)
+{
+
+ assert(m_exprComponents.testFalse == false);
+ AssertionResultData data = m_data;
+ data.resultType = ResultWas::Ok;
+ data.reconstructedExpression = m_assertionInfo.capturedExpression;
+
+ std::string actualMessage = Catch::translateActiveException();
+ if (!matcher.match(actualMessage))
+ {
+ data.resultType = ResultWas::ExpressionFailed;
+ data.reconstructedExpression = actualMessage;
+ }
+ AssertionResult result(m_assertionInfo, data);
+ handleResult(result);
+}
+
+void ResultBuilder::captureExpression()
+{
+ AssertionResult result = build();
+ handleResult(result);
+}
+void ResultBuilder::handleResult(AssertionResult const& result)
+{
+ getResultCapture().assertionEnded(result);
+
+ if (!result.isOk())
+ {
+ if (getCurrentContext().getConfig()->shouldDebugBreak())
+ m_shouldDebugBreak = true;
+ if (getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal))
+ m_shouldThrow = true;
+ }
+}
+void ResultBuilder::react()
+{
+ if (m_shouldThrow)
+ throw Catch::TestFailureException();
+}
+
+bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; }
+bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); }
+
+AssertionResult ResultBuilder::build() const
+{
+ assert(m_data.resultType != ResultWas::Unknown);
+
+ AssertionResultData data = m_data;
+
+ // Flip bool results if testFalse is set
+ if (m_exprComponents.testFalse)
+ {
+ if (data.resultType == ResultWas::Ok)
+ data.resultType = ResultWas::ExpressionFailed;
+ else if (data.resultType == ResultWas::ExpressionFailed)
+ data.resultType = ResultWas::Ok;
+ }
+
+ data.message = m_stream.oss.str();
+ data.reconstructedExpression = reconstructExpression();
+ if (m_exprComponents.testFalse)
+ {
+ if (m_exprComponents.op == "")
+ data.reconstructedExpression = "!" + data.reconstructedExpression;
+ else
+ data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
+ }
+ return AssertionResult(m_assertionInfo, data);
+}
+std::string ResultBuilder::reconstructExpression() const
+{
+ if (m_exprComponents.op == "")
+ return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs;
+ else if (m_exprComponents.op == "matches")
+ return m_exprComponents.lhs + " " + m_exprComponents.rhs;
+ else if (m_exprComponents.op != "!")
+ {
+ if (m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
+ m_exprComponents.lhs.find("\n") == std::string::npos &&
+ m_exprComponents.rhs.find("\n") == std::string::npos)
+ return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
+ else
+ return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
+ }
+ else
+ return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}";
+}
+
+} // end namespace Catch
+
+// #included from: catch_tag_alias_registry.hpp
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+
+// #included from: catch_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+class TagAliasRegistry : public ITagAliasRegistry
+{
+ public:
+ virtual ~TagAliasRegistry();
+ virtual Option<TagAlias> find(std::string const& alias) const;
+ virtual std::string expandAliases(std::string const& unexpandedTestSpec) const;
+ void add(char const* alias, char const* tag, SourceLineInfo const& lineInfo);
+ static TagAliasRegistry& get();
+
+ private:
+ std::map<std::string, TagAlias> m_registry;
+};
+
+} // end namespace Catch
+
+#include <iostream>
+#include <map>
+
+namespace Catch {
+
+TagAliasRegistry::~TagAliasRegistry() {}
+
+Option<TagAlias> TagAliasRegistry::find(std::string const& alias) const
+{
+ std::map<std::string, TagAlias>::const_iterator it = m_registry.find(alias);
+ if (it != m_registry.end())
+ return it->second;
+ else
+ return Option<TagAlias>();
+}
+
+std::string TagAliasRegistry::expandAliases(std::string const& unexpandedTestSpec) const
+{
+ std::string expandedTestSpec = unexpandedTestSpec;
+ for (std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end();
+ it != itEnd;
+ ++it)
+ {
+ std::size_t pos = expandedTestSpec.find(it->first);
+ if (pos != std::string::npos)
+ {
+ expandedTestSpec = expandedTestSpec.substr(0, pos) +
+ it->second.tag +
+ expandedTestSpec.substr(pos + it->first.size());
+ }
+ }
+ return expandedTestSpec;
+}
+
+void TagAliasRegistry::add(char const* alias, char const* tag, SourceLineInfo const& lineInfo)
+{
+
+ if (!startsWith(alias, "[@") || !endsWith(alias, "]"))
+ {
+ std::ostringstream oss;
+ oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n"
+ << lineInfo;
+ throw std::domain_error(oss.str().c_str());
+ }
+ if (!m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second)
+ {
+ std::ostringstream oss;
+ oss << "error: tag alias, \"" << alias << "\" already registered.\n"
+ << "\tFirst seen at " << find(alias)->lineInfo << "\n"
+ << "\tRedefined at " << lineInfo;
+ throw std::domain_error(oss.str().c_str());
+ }
+}
+
+TagAliasRegistry& TagAliasRegistry::get()
+{
+ static TagAliasRegistry instance;
+ return instance;
+}
+
+ITagAliasRegistry::~ITagAliasRegistry() {}
+ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); }
+
+RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo)
+{
+ try
+ {
+ TagAliasRegistry::get().add(alias, tag, lineInfo);
+ }
+ catch (std::exception& ex)
+ {
+ Colour colourGuard(Colour::Red);
+ Catch::cerr() << ex.what() << std::endl;
+ exit(1);
+ }
+}
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_multi.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED
+
+namespace Catch {
+
+class MultipleReporters : public SharedImpl<IStreamingReporter>
+{
+ typedef std::vector<Ptr<IStreamingReporter>> Reporters;
+ Reporters m_reporters;
+
+ public:
+ void add(Ptr<IStreamingReporter> const& reporter)
+ {
+ m_reporters.push_back(reporter);
+ }
+
+ public: // IStreamingReporter
+ virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE
+ {
+ return m_reporters[0]->getPreferences();
+ }
+
+ virtual void noMatchingTestCases(std::string const& spec) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->noMatchingTestCases(spec);
+ }
+
+ virtual void testRunStarting(TestRunInfo const& testRunInfo) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->testRunStarting(testRunInfo);
+ }
+
+ virtual void testGroupStarting(GroupInfo const& groupInfo) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->testGroupStarting(groupInfo);
+ }
+
+ virtual void testCaseStarting(TestCaseInfo const& testInfo) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->testCaseStarting(testInfo);
+ }
+
+ virtual void sectionStarting(SectionInfo const& sectionInfo) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->sectionStarting(sectionInfo);
+ }
+
+ virtual void assertionStarting(AssertionInfo const& assertionInfo) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->assertionStarting(assertionInfo);
+ }
+
+ // The return value indicates if the messages buffer should be cleared:
+ virtual bool assertionEnded(AssertionStats const& assertionStats) CATCH_OVERRIDE
+ {
+ bool clearBuffer = false;
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ clearBuffer |= (*it)->assertionEnded(assertionStats);
+ return clearBuffer;
+ }
+
+ virtual void sectionEnded(SectionStats const& sectionStats) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->sectionEnded(sectionStats);
+ }
+
+ virtual void testCaseEnded(TestCaseStats const& testCaseStats) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->testCaseEnded(testCaseStats);
+ }
+
+ virtual void testGroupEnded(TestGroupStats const& testGroupStats) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->testGroupEnded(testGroupStats);
+ }
+
+ virtual void testRunEnded(TestRunStats const& testRunStats) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->testRunEnded(testRunStats);
+ }
+
+ virtual void skipTest(TestCaseInfo const& testInfo) CATCH_OVERRIDE
+ {
+ for (Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it)
+ (*it)->skipTest(testInfo);
+ }
+};
+
+Ptr<IStreamingReporter> addReporter(Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter)
+{
+ Ptr<IStreamingReporter> resultingReporter;
+
+ if (existingReporter)
+ {
+ MultipleReporters* multi = dynamic_cast<MultipleReporters*>(existingReporter.get());
+ if (!multi)
+ {
+ multi = new MultipleReporters;
+ resultingReporter = Ptr<IStreamingReporter>(multi);
+ if (existingReporter)
+ multi->add(existingReporter);
+ }
+ else
+ resultingReporter = existingReporter;
+ multi->add(additionalReporter);
+ }
+ else
+ resultingReporter = additionalReporter;
+
+ return resultingReporter;
+}
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_xml.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
+
+// #included from: catch_reporter_bases.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
+
+#include <cstring>
+
+namespace Catch {
+
+struct StreamingReporterBase : SharedImpl<IStreamingReporter>
+{
+
+ StreamingReporterBase(ReporterConfig const& _config)
+ : m_config(_config.fullConfig()),
+ stream(_config.stream())
+ {
+ m_reporterPrefs.shouldRedirectStdOut = false;
+ }
+
+ virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE
+ {
+ return m_reporterPrefs;
+ }
+
+ virtual ~StreamingReporterBase() CATCH_OVERRIDE;
+
+ virtual void noMatchingTestCases(std::string const&) CATCH_OVERRIDE {}
+
+ virtual void testRunStarting(TestRunInfo const& _testRunInfo) CATCH_OVERRIDE
+ {
+ currentTestRunInfo = _testRunInfo;
+ }
+ virtual void testGroupStarting(GroupInfo const& _groupInfo) CATCH_OVERRIDE
+ {
+ currentGroupInfo = _groupInfo;
+ }
+
+ virtual void testCaseStarting(TestCaseInfo const& _testInfo) CATCH_OVERRIDE
+ {
+ currentTestCaseInfo = _testInfo;
+ }
+ virtual void sectionStarting(SectionInfo const& _sectionInfo) CATCH_OVERRIDE
+ {
+ m_sectionStack.push_back(_sectionInfo);
+ }
+
+ virtual void sectionEnded(SectionStats const& /* _sectionStats */) CATCH_OVERRIDE
+ {
+ m_sectionStack.pop_back();
+ }
+ virtual void testCaseEnded(TestCaseStats const& /* _testCaseStats */) CATCH_OVERRIDE
+ {
+ currentTestCaseInfo.reset();
+ }
+ virtual void testGroupEnded(TestGroupStats const& /* _testGroupStats */) CATCH_OVERRIDE
+ {
+ currentGroupInfo.reset();
+ }
+ virtual void testRunEnded(TestRunStats const& /* _testRunStats */) CATCH_OVERRIDE
+ {
+ currentTestCaseInfo.reset();
+ currentGroupInfo.reset();
+ currentTestRunInfo.reset();
+ }
+
+ virtual void skipTest(TestCaseInfo const&) CATCH_OVERRIDE
+ {
+ // Don't do anything with this by default.
+ // It can optionally be overridden in the derived class.
+ }
+
+ Ptr<IConfig const> m_config;
+ std::ostream& stream;
+
+ LazyStat<TestRunInfo> currentTestRunInfo;
+ LazyStat<GroupInfo> currentGroupInfo;
+ LazyStat<TestCaseInfo> currentTestCaseInfo;
+
+ std::vector<SectionInfo> m_sectionStack;
+ ReporterPreferences m_reporterPrefs;
+};
+
+struct CumulativeReporterBase : SharedImpl<IStreamingReporter>
+{
+ template <typename T, typename ChildNodeT>
+ struct Node : SharedImpl<>
+ {
+ explicit Node(T const& _value) : value(_value) {}
+ virtual ~Node() {}
+
+ typedef std::vector<Ptr<ChildNodeT>> ChildNodes;
+ T value;
+ ChildNodes children;
+ };
+ struct SectionNode : SharedImpl<>
+ {
+ explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}
+ virtual ~SectionNode();
+
+ bool operator==(SectionNode const& other) const
+ {
+ return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
+ }
+ bool operator==(Ptr<SectionNode> const& other) const
+ {
+ return operator==(*other);
+ }
+
+ SectionStats stats;
+ typedef std::vector<Ptr<SectionNode>> ChildSections;
+ typedef std::vector<AssertionStats> Assertions;
+ ChildSections childSections;
+ Assertions assertions;
+ std::string stdOut;
+ std::string stdErr;
+ };
+
+ struct BySectionInfo
+ {
+ BySectionInfo(SectionInfo const& other) : m_other(other) {}
+ BySectionInfo(BySectionInfo const& other) : m_other(other.m_other) {}
+ bool operator()(Ptr<SectionNode> const& node) const
+ {
+ return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
+ }
+
+ private:
+ void operator=(BySectionInfo const&);
+ SectionInfo const& m_other;
+ };
+
+ typedef Node<TestCaseStats, SectionNode> TestCaseNode;
+ typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
+ typedef Node<TestRunStats, TestGroupNode> TestRunNode;
+
+ CumulativeReporterBase(ReporterConfig const& _config)
+ : m_config(_config.fullConfig()),
+ stream(_config.stream())
+ {
+ m_reporterPrefs.shouldRedirectStdOut = false;
+ }
+ ~CumulativeReporterBase();
+
+ virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE
+ {
+ return m_reporterPrefs;
+ }
+
+ virtual void testRunStarting(TestRunInfo const&) CATCH_OVERRIDE {}
+ virtual void testGroupStarting(GroupInfo const&) CATCH_OVERRIDE {}
+
+ virtual void testCaseStarting(TestCaseInfo const&) CATCH_OVERRIDE {}
+
+ virtual void sectionStarting(SectionInfo const& sectionInfo) CATCH_OVERRIDE
+ {
+ SectionStats incompleteStats(sectionInfo, Counts(), 0, false);
+ Ptr<SectionNode> node;
+ if (m_sectionStack.empty())
+ {
+ if (!m_rootSection)
+ m_rootSection = new SectionNode(incompleteStats);
+ node = m_rootSection;
+ }
+ else
+ {
+ SectionNode& parentNode = *m_sectionStack.back();
+ SectionNode::ChildSections::const_iterator it =
+ std::find_if(parentNode.childSections.begin(),
+ parentNode.childSections.end(),
+ BySectionInfo(sectionInfo));
+ if (it == parentNode.childSections.end())
+ {
+ node = new SectionNode(incompleteStats);
+ parentNode.childSections.push_back(node);
+ }
+ else
+ node = *it;
+ }
+ m_sectionStack.push_back(node);
+ m_deepestSection = node;
+ }
+
+ virtual void assertionStarting(AssertionInfo const&) CATCH_OVERRIDE {}
+
+ virtual bool assertionEnded(AssertionStats const& assertionStats)
+ {
+ assert(!m_sectionStack.empty());
+ SectionNode& sectionNode = *m_sectionStack.back();
+ sectionNode.assertions.push_back(assertionStats);
+ return true;
+ }
+ virtual void sectionEnded(SectionStats const& sectionStats) CATCH_OVERRIDE
+ {
+ assert(!m_sectionStack.empty());
+ SectionNode& node = *m_sectionStack.back();
+ node.stats = sectionStats;
+ m_sectionStack.pop_back();
+ }
+ virtual void testCaseEnded(TestCaseStats const& testCaseStats) CATCH_OVERRIDE
+ {
+ Ptr<TestCaseNode> node = new TestCaseNode(testCaseStats);
+ assert(m_sectionStack.size() == 0);
+ node->children.push_back(m_rootSection);
+ m_testCases.push_back(node);
+ m_rootSection.reset();
+
+ assert(m_deepestSection);
+ m_deepestSection->stdOut = testCaseStats.stdOut;
+ m_deepestSection->stdErr = testCaseStats.stdErr;
+ }
+ virtual void testGroupEnded(TestGroupStats const& testGroupStats) CATCH_OVERRIDE
+ {
+ Ptr<TestGroupNode> node = new TestGroupNode(testGroupStats);
+ node->children.swap(m_testCases);
+ m_testGroups.push_back(node);
+ }
+ virtual void testRunEnded(TestRunStats const& testRunStats) CATCH_OVERRIDE
+ {
+ Ptr<TestRunNode> node = new TestRunNode(testRunStats);
+ node->children.swap(m_testGroups);
+ m_testRuns.push_back(node);
+ testRunEndedCumulative();
+ }
+ virtual void testRunEndedCumulative() = 0;
+
+ virtual void skipTest(TestCaseInfo const&) CATCH_OVERRIDE {}
+
+ Ptr<IConfig const> m_config;
+ std::ostream& stream;
+ std::vector<AssertionStats> m_assertions;
+ std::vector<std::vector<Ptr<SectionNode>>> m_sections;
+ std::vector<Ptr<TestCaseNode>> m_testCases;
+ std::vector<Ptr<TestGroupNode>> m_testGroups;
+
+ std::vector<Ptr<TestRunNode>> m_testRuns;
+
+ Ptr<SectionNode> m_rootSection;
+ Ptr<SectionNode> m_deepestSection;
+ std::vector<Ptr<SectionNode>> m_sectionStack;
+ ReporterPreferences m_reporterPrefs;
+};
+
+template <char C>
+char const* getLineOfChars()
+{
+ static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
+ if (!*line)
+ {
+ memset(line, C, CATCH_CONFIG_CONSOLE_WIDTH - 1);
+ line[CATCH_CONFIG_CONSOLE_WIDTH - 1] = 0;
+ }
+ return line;
+}
+
+struct TestEventListenerBase : StreamingReporterBase
+{
+ TestEventListenerBase(ReporterConfig const& _config)
+ : StreamingReporterBase(_config)
+ {
+ }
+
+ virtual void assertionStarting(AssertionInfo const&) CATCH_OVERRIDE {}
+ virtual bool assertionEnded(AssertionStats const&) CATCH_OVERRIDE
+ {
+ return false;
+ }
+};
+
+} // end namespace Catch
+
+// #included from: ../internal/catch_reporter_registrars.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
+
+namespace Catch {
+
+template <typename T>
+class LegacyReporterRegistrar
+{
+
+ class ReporterFactory : public IReporterFactory
+ {
+ virtual IStreamingReporter* create(ReporterConfig const& config) const
+ {
+ return new LegacyReporterAdapter(new T(config));
+ }
+
+ virtual std::string getDescription() const
+ {
+ return T::getDescription();
+ }
+ };
+
+ public:
+ LegacyReporterRegistrar(std::string const& name)
+ {
+ getMutableRegistryHub().registerReporter(name, new ReporterFactory());
+ }
+};
+
+template <typename T>
+class ReporterRegistrar
+{
+
+ class ReporterFactory : public SharedImpl<IReporterFactory>
+ {
+
+ // *** Please Note ***:
+ // - If you end up here looking at a compiler error because it's trying to register
+ // your custom reporter class be aware that the native reporter interface has changed
+ // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
+ // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
+ // However please consider updating to the new interface as the old one is now
+ // deprecated and will probably be removed quite soon!
+ // Please contact me via github if you have any questions at all about this.
+ // In fact, ideally, please contact me anyway to let me know you've hit this - as I have
+ // no idea who is actually using custom reporters at all (possibly no-one!).
+ // The new interface is designed to minimise exposure to interface changes in the future.
+ virtual IStreamingReporter* create(ReporterConfig const& config) const
+ {
+ return new T(config);
+ }
+
+ virtual std::string getDescription() const
+ {
+ return T::getDescription();
+ }
+ };
+
+ public:
+ ReporterRegistrar(std::string const& name)
+ {
+ getMutableRegistryHub().registerReporter(name, new ReporterFactory());
+ }
+};
+
+template <typename T>
+class ListenerRegistrar
+{
+
+ class ListenerFactory : public SharedImpl<IReporterFactory>
+ {
+
+ virtual IStreamingReporter* create(ReporterConfig const& config) const
+ {
+ return new T(config);
+ }
+ virtual std::string getDescription() const
+ {
+ return "";
+ }
+ };
+
+ public:
+ ListenerRegistrar()
+ {
+ getMutableRegistryHub().registerListener(new ListenerFactory());
+ }
+};
+}
+
+#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER(name, reporterType) \
+ namespace { \
+ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType(name); \
+ }
+
+#define INTERNAL_CATCH_REGISTER_REPORTER(name, reporterType) \
+ namespace { \
+ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType(name); \
+ }
+
+#define INTERNAL_CATCH_REGISTER_LISTENER(listenerType) \
+ namespace { \
+ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; \
+ }
+
+// #included from: ../internal/catch_xmlwriter.hpp
+#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
+
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+class XmlEncode
+{
+ public:
+ enum ForWhat
+ {
+ ForTextNodes,
+ ForAttributes
+ };
+
+ XmlEncode(std::string const& str, ForWhat forWhat = ForTextNodes)
+ : m_str(str),
+ m_forWhat(forWhat)
+ {
+ }
+
+ void encodeTo(std::ostream& os) const
+ {
+
+ // Apostrophe escaping not necessary if we always use " to write attributes
+ // (see: http://www.w3.org/TR/xml/#syntax)
+
+ for (std::size_t i = 0; i < m_str.size(); ++i)
+ {
+ char c = m_str[i];
+ switch (c)
+ {
+ case '<':
+ os << "<";
+ break;
+ case '&':
+ os << "&";
+ break;
+
+ case '>':
+ // See: http://www.w3.org/TR/xml/#syntax
+ if (i > 2 && m_str[i - 1] == ']' && m_str[i - 2] == ']')
+ os << ">";
+ else
+ os << c;
+ break;
+
+ case '\"':
+ if (m_forWhat == ForAttributes)
+ os << """;
+ else
+ os << c;
+ break;
+
+ default:
+ // Escape control chars - based on contribution by @espenalb in PR #465
+ if ((c < '\x09') || (c > '\x0D' && c < '\x20') || c == '\x7F')
+ os << "&#x" << std::uppercase << std::hex << static_cast<int>(c);
+ else
+ os << c;
+ }
+ }
+ }
+
+ friend std::ostream& operator<<(std::ostream& os, XmlEncode const& xmlEncode)
+ {
+ xmlEncode.encodeTo(os);
+ return os;
+ }
+
+ private:
+ std::string m_str;
+ ForWhat m_forWhat;
+};
+
+class XmlWriter
+{
+ public:
+ class ScopedElement
+ {
+ public:
+ ScopedElement(XmlWriter* writer)
+ : m_writer(writer)
+ {
+ }
+
+ ScopedElement(ScopedElement const& other)
+ : m_writer(other.m_writer)
+ {
+ other.m_writer = CATCH_NULL;
+ }
+
+ ~ScopedElement()
+ {
+ if (m_writer)
+ m_writer->endElement();
+ }
+
+ ScopedElement& writeText(std::string const& text, bool indent = true)
+ {
+ m_writer->writeText(text, indent);
+ return *this;
+ }
+
+ template <typename T>
+ ScopedElement& writeAttribute(std::string const& name, T const& attribute)
+ {
+ m_writer->writeAttribute(name, attribute);
+ return *this;
+ }
+
+ private:
+ mutable XmlWriter* m_writer;
+ };
+
+ XmlWriter()
+ : m_tagIsOpen(false),
+ m_needsNewline(false),
+ m_os(&Catch::cout())
+ {
+ }
+
+ XmlWriter(std::ostream& os)
+ : m_tagIsOpen(false),
+ m_needsNewline(false),
+ m_os(&os)
+ {
+ }
+
+ ~XmlWriter()
+ {
+ while (!m_tags.empty())
+ endElement();
+ }
+
+ XmlWriter& startElement(std::string const& name)
+ {
+ ensureTagClosed();
+ newlineIfNecessary();
+ stream() << m_indent << "<" << name;
+ m_tags.push_back(name);
+ m_indent += " ";
+ m_tagIsOpen = true;
+ return *this;
+ }
+
+ ScopedElement scopedElement(std::string const& name)
+ {
+ ScopedElement scoped(this);
+ startElement(name);
+ return scoped;
+ }
+
+ XmlWriter& endElement()
+ {
+ newlineIfNecessary();
+ m_indent = m_indent.substr(0, m_indent.size() - 2);
+ if (m_tagIsOpen)
+ {
+ stream() << "/>\n";
+ m_tagIsOpen = false;
+ }
+ else
+ {
+ stream() << m_indent << "</" << m_tags.back() << ">\n";
+ }
+ m_tags.pop_back();
+ return *this;
+ }
+
+ XmlWriter& writeAttribute(std::string const& name, std::string const& attribute)
+ {
+ if (!name.empty() && !attribute.empty())
+ stream() << " " << name << "=\"" << XmlEncode(attribute, XmlEncode::ForAttributes) << "\"";
+ return *this;
+ }
+
+ XmlWriter& writeAttribute(std::string const& name, bool attribute)
+ {
+ stream() << " " << name << "=\"" << (attribute ? "true" : "false") << "\"";
+ return *this;
+ }
+
+ template <typename T>
+ XmlWriter& writeAttribute(std::string const& name, T const& attribute)
+ {
+ std::ostringstream oss;
+ oss << attribute;
+ return writeAttribute(name, oss.str());
+ }
+
+ XmlWriter& writeText(std::string const& text, bool indent = true)
+ {
+ if (!text.empty())
+ {
+ bool tagWasOpen = m_tagIsOpen;
+ ensureTagClosed();
+ if (tagWasOpen && indent)
+ stream() << m_indent;
+ stream() << XmlEncode(text);
+ m_needsNewline = true;
+ }
+ return *this;
+ }
+
+ XmlWriter& writeComment(std::string const& text)
+ {
+ ensureTagClosed();
+ stream() << m_indent << "<!--" << text << "-->";
+ m_needsNewline = true;
+ return *this;
+ }
+
+ XmlWriter& writeBlankLine()
+ {
+ ensureTagClosed();
+ stream() << "\n";
+ return *this;
+ }
+
+ void setStream(std::ostream& os)
+ {
+ m_os = &os;
+ }
+
+ private:
+ XmlWriter(XmlWriter const&);
+ void operator=(XmlWriter const&);
+
+ std::ostream& stream()
+ {
+ return *m_os;
+ }
+
+ void ensureTagClosed()
+ {
+ if (m_tagIsOpen)
+ {
+ stream() << ">\n";
+ m_tagIsOpen = false;
+ }
+ }
+
+ void newlineIfNecessary()
+ {
+ if (m_needsNewline)
+ {
+ stream() << "\n";
+ m_needsNewline = false;
+ }
+ }
+
+ bool m_tagIsOpen;
+ bool m_needsNewline;
+ std::vector<std::string> m_tags;
+ std::string m_indent;
+ std::ostream* m_os;
+};
+}
+// #included from: catch_reenable_warnings.h
+
+#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+#ifdef __ICC // icpc defines the __clang__ macro
+#pragma warning(pop)
+#else
+#pragma clang diagnostic pop
+#endif
+#elif defined __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+namespace Catch {
+class XmlReporter : public StreamingReporterBase
+{
+ public:
+ XmlReporter(ReporterConfig const& _config)
+ : StreamingReporterBase(_config),
+ m_sectionDepth(0)
+ {
+ m_reporterPrefs.shouldRedirectStdOut = true;
+ }
+
+ virtual ~XmlReporter() CATCH_OVERRIDE;
+
+ static std::string getDescription()
+ {
+ return "Reports test results as an XML document";
+ }
+
+ public: // StreamingReporterBase
+ virtual void noMatchingTestCases(std::string const& s) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::noMatchingTestCases(s);
+ }
+
+ virtual void testRunStarting(TestRunInfo const& testInfo) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::testRunStarting(testInfo);
+ m_xml.setStream(stream);
+ m_xml.startElement("Catch");
+ if (!m_config->name().empty())
+ m_xml.writeAttribute("name", m_config->name());
+ }
+
+ virtual void testGroupStarting(GroupInfo const& groupInfo) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::testGroupStarting(groupInfo);
+ m_xml.startElement("Group")
+ .writeAttribute("name", groupInfo.name);
+ }
+
+ virtual void testCaseStarting(TestCaseInfo const& testInfo) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::testCaseStarting(testInfo);
+ m_xml.startElement("TestCase").writeAttribute("name", trim(testInfo.name));
+
+ if (m_config->showDurations() == ShowDurations::Always)
+ m_testCaseTimer.start();
+ }
+
+ virtual void sectionStarting(SectionInfo const& sectionInfo) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::sectionStarting(sectionInfo);
+ if (m_sectionDepth++ > 0)
+ {
+ m_xml.startElement("Section")
+ .writeAttribute("name", trim(sectionInfo.name))
+ .writeAttribute("description", sectionInfo.description);
+ }
+ }
+
+ virtual void assertionStarting(AssertionInfo const&) CATCH_OVERRIDE {}
+
+ virtual bool assertionEnded(AssertionStats const& assertionStats) CATCH_OVERRIDE
+ {
+ const AssertionResult& assertionResult = assertionStats.assertionResult;
+
+ // Print any info messages in <Info> tags.
+ if (assertionStats.assertionResult.getResultType() != ResultWas::Ok)
+ {
+ for (std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+ it != itEnd;
+ ++it)
+ {
+ if (it->type == ResultWas::Info)
+ {
+ m_xml.scopedElement("Info")
+ .writeText(it->message);
+ }
+ else if (it->type == ResultWas::Warning)
+ {
+ m_xml.scopedElement("Warning")
+ .writeText(it->message);
+ }
+ }
+ }
+
+ // Drop out if result was successful but we're not printing them.
+ if (!m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()))
+ return true;
+
+ // Print the expression if there is one.
+ if (assertionResult.hasExpression())
+ {
+ m_xml.startElement("Expression")
+ .writeAttribute("success", assertionResult.succeeded())
+ .writeAttribute("type", assertionResult.getTestMacroName())
+ .writeAttribute("filename", assertionResult.getSourceInfo().file)
+ .writeAttribute("line", assertionResult.getSourceInfo().line);
+
+ m_xml.scopedElement("Original")
+ .writeText(assertionResult.getExpression());
+ m_xml.scopedElement("Expanded")
+ .writeText(assertionResult.getExpandedExpression());
+ }
+
+ // And... Print a result applicable to each result type.
+ switch (assertionResult.getResultType())
+ {
+ case ResultWas::ThrewException:
+ m_xml.scopedElement("Exception")
+ .writeAttribute("filename", assertionResult.getSourceInfo().file)
+ .writeAttribute("line", assertionResult.getSourceInfo().line)
+ .writeText(assertionResult.getMessage());
+ break;
+ case ResultWas::FatalErrorCondition:
+ m_xml.scopedElement("Fatal Error Condition")
+ .writeAttribute("filename", assertionResult.getSourceInfo().file)
+ .writeAttribute("line", assertionResult.getSourceInfo().line)
+ .writeText(assertionResult.getMessage());
+ break;
+ case ResultWas::Info:
+ m_xml.scopedElement("Info")
+ .writeText(assertionResult.getMessage());
+ break;
+ case ResultWas::Warning:
+ // Warning will already have been written
+ break;
+ case ResultWas::ExplicitFailure:
+ m_xml.scopedElement("Failure")
+ .writeText(assertionResult.getMessage());
+ break;
+ default:
+ break;
+ }
+
+ if (assertionResult.hasExpression())
+ m_xml.endElement();
+
+ return true;
+ }
+
+ virtual void sectionEnded(SectionStats const& sectionStats) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::sectionEnded(sectionStats);
+ if (--m_sectionDepth > 0)
+ {
+ XmlWriter::ScopedElement e = m_xml.scopedElement("OverallResults");
+ e.writeAttribute("successes", sectionStats.assertions.passed);
+ e.writeAttribute("failures", sectionStats.assertions.failed);
+ e.writeAttribute("expectedFailures", sectionStats.assertions.failedButOk);
+
+ if (m_config->showDurations() == ShowDurations::Always)
+ e.writeAttribute("durationInSeconds", sectionStats.durationInSeconds);
+
+ m_xml.endElement();
+ }
+ }
+
+ virtual void testCaseEnded(TestCaseStats const& testCaseStats) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::testCaseEnded(testCaseStats);
+ XmlWriter::ScopedElement e = m_xml.scopedElement("OverallResult");
+ e.writeAttribute("success", testCaseStats.totals.assertions.allOk());
+
+ if (m_config->showDurations() == ShowDurations::Always)
+ e.writeAttribute("durationInSeconds", m_testCaseTimer.getElapsedSeconds());
+
+ m_xml.endElement();
+ }
+
+ virtual void testGroupEnded(TestGroupStats const& testGroupStats) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::testGroupEnded(testGroupStats);
+ // TODO: Check testGroupStats.aborting and act accordingly.
+ m_xml.scopedElement("OverallResults")
+ .writeAttribute("successes", testGroupStats.totals.assertions.passed)
+ .writeAttribute("failures", testGroupStats.totals.assertions.failed)
+ .writeAttribute("expectedFailures", testGroupStats.totals.assertions.failedButOk);
+ m_xml.endElement();
+ }
+
+ virtual void testRunEnded(TestRunStats const& testRunStats) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::testRunEnded(testRunStats);
+ m_xml.scopedElement("OverallResults")
+ .writeAttribute("successes", testRunStats.totals.assertions.passed)
+ .writeAttribute("failures", testRunStats.totals.assertions.failed)
+ .writeAttribute("expectedFailures", testRunStats.totals.assertions.failedButOk);
+ m_xml.endElement();
+ }
+
+ private:
+ Timer m_testCaseTimer;
+ XmlWriter m_xml;
+ int m_sectionDepth;
+};
+
+INTERNAL_CATCH_REGISTER_REPORTER("xml", XmlReporter)
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_junit.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
+
+#include <assert.h>
+
+namespace Catch {
+
+class JunitReporter : public CumulativeReporterBase
+{
+ public:
+ JunitReporter(ReporterConfig const& _config)
+ : CumulativeReporterBase(_config),
+ xml(_config.stream())
+ {
+ m_reporterPrefs.shouldRedirectStdOut = true;
+ }
+
+ virtual ~JunitReporter() CATCH_OVERRIDE;
+
+ static std::string getDescription()
+ {
+ return "Reports test results in an XML format that looks like Ant's junitreport target";
+ }
+
+ virtual void noMatchingTestCases(std::string const& /*spec*/) CATCH_OVERRIDE {}
+
+ virtual void testRunStarting(TestRunInfo const& runInfo) CATCH_OVERRIDE
+ {
+ CumulativeReporterBase::testRunStarting(runInfo);
+ xml.startElement("testsuites");
+ }
+
+ virtual void testGroupStarting(GroupInfo const& groupInfo) CATCH_OVERRIDE
+ {
+ suiteTimer.start();
+ stdOutForSuite.str("");
+ stdErrForSuite.str("");
+ unexpectedExceptions = 0;
+ CumulativeReporterBase::testGroupStarting(groupInfo);
+ }
+
+ virtual bool assertionEnded(AssertionStats const& assertionStats) CATCH_OVERRIDE
+ {
+ if (assertionStats.assertionResult.getResultType() == ResultWas::ThrewException)
+ unexpectedExceptions++;
+ return CumulativeReporterBase::assertionEnded(assertionStats);
+ }
+
+ virtual void testCaseEnded(TestCaseStats const& testCaseStats) CATCH_OVERRIDE
+ {
+ stdOutForSuite << testCaseStats.stdOut;
+ stdErrForSuite << testCaseStats.stdErr;
+ CumulativeReporterBase::testCaseEnded(testCaseStats);
+ }
+
+ virtual void testGroupEnded(TestGroupStats const& testGroupStats) CATCH_OVERRIDE
+ {
+ double suiteTime = suiteTimer.getElapsedSeconds();
+ CumulativeReporterBase::testGroupEnded(testGroupStats);
+ writeGroup(*m_testGroups.back(), suiteTime);
+ }
+
+ virtual void testRunEndedCumulative() CATCH_OVERRIDE
+ {
+ xml.endElement();
+ }
+
+ void writeGroup(TestGroupNode const& groupNode, double suiteTime)
+ {
+ XmlWriter::ScopedElement e = xml.scopedElement("testsuite");
+ TestGroupStats const& stats = groupNode.value;
+ xml.writeAttribute("name", stats.groupInfo.name);
+ xml.writeAttribute("errors", unexpectedExceptions);
+ xml.writeAttribute("failures", stats.totals.assertions.failed - unexpectedExceptions);
+ xml.writeAttribute("tests", stats.totals.assertions.total());
+ xml.writeAttribute("hostname", "tbd"); // !TBD
+ if (m_config->showDurations() == ShowDurations::Never)
+ xml.writeAttribute("time", "");
+ else
+ xml.writeAttribute("time", suiteTime);
+ xml.writeAttribute("timestamp", "tbd"); // !TBD
+
+ // Write test cases
+ for (TestGroupNode::ChildNodes::const_iterator
+ it = groupNode.children.begin(),
+ itEnd = groupNode.children.end();
+ it != itEnd;
+ ++it)
+ writeTestCase(**it);
+
+ xml.scopedElement("system-out").writeText(trim(stdOutForSuite.str()), false);
+ xml.scopedElement("system-err").writeText(trim(stdErrForSuite.str()), false);
+ }
+
+ void writeTestCase(TestCaseNode const& testCaseNode)
+ {
+ TestCaseStats const& stats = testCaseNode.value;
+
+ // All test cases have exactly one section - which represents the
+ // test case itself. That section may have 0-n nested sections
+ assert(testCaseNode.children.size() == 1);
+ SectionNode const& rootSection = *testCaseNode.children.front();
+
+ std::string className = stats.testInfo.className;
+
+ if (className.empty())
+ {
+ if (rootSection.childSections.empty())
+ className = "global";
+ }
+ writeSection(className, "", rootSection);
+ }
+
+ void writeSection(std::string const& className,
+ std::string const& rootName,
+ SectionNode const& sectionNode)
+ {
+ std::string name = trim(sectionNode.stats.sectionInfo.name);
+ if (!rootName.empty())
+ name = rootName + "/" + name;
+
+ if (!sectionNode.assertions.empty() ||
+ !sectionNode.stdOut.empty() ||
+ !sectionNode.stdErr.empty())
+ {
+ XmlWriter::ScopedElement e = xml.scopedElement("testcase");
+ if (className.empty())
+ {
+ xml.writeAttribute("classname", name);
+ xml.writeAttribute("name", "root");
+ }
+ else
+ {
+ xml.writeAttribute("classname", className);
+ xml.writeAttribute("name", name);
+ }
+ xml.writeAttribute("time", Catch::toString(sectionNode.stats.durationInSeconds));
+
+ writeAssertions(sectionNode);
+
+ if (!sectionNode.stdOut.empty())
+ xml.scopedElement("system-out").writeText(trim(sectionNode.stdOut), false);
+ if (!sectionNode.stdErr.empty())
+ xml.scopedElement("system-err").writeText(trim(sectionNode.stdErr), false);
+ }
+ for (SectionNode::ChildSections::const_iterator
+ it = sectionNode.childSections.begin(),
+ itEnd = sectionNode.childSections.end();
+ it != itEnd;
+ ++it)
+ if (className.empty())
+ writeSection(name, "", **it);
+ else
+ writeSection(className, name, **it);
+ }
+
+ void writeAssertions(SectionNode const& sectionNode)
+ {
+ for (SectionNode::Assertions::const_iterator
+ it = sectionNode.assertions.begin(),
+ itEnd = sectionNode.assertions.end();
+ it != itEnd;
+ ++it)
+ writeAssertion(*it);
+ }
+ void writeAssertion(AssertionStats const& stats)
+ {
+ AssertionResult const& result = stats.assertionResult;
+ if (!result.isOk())
+ {
+ std::string elementName;
+ switch (result.getResultType())
+ {
+ case ResultWas::ThrewException:
+ case ResultWas::FatalErrorCondition:
+ elementName = "error";
+ break;
+ case ResultWas::ExplicitFailure:
+ elementName = "failure";
+ break;
+ case ResultWas::ExpressionFailed:
+ elementName = "failure";
+ break;
+ case ResultWas::DidntThrowException:
+ elementName = "failure";
+ break;
+
+ // We should never see these here:
+ case ResultWas::Info:
+ case ResultWas::Warning:
+ case ResultWas::Ok:
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ elementName = "internalError";
+ break;
+ }
+
+ XmlWriter::ScopedElement e = xml.scopedElement(elementName);
+
+ xml.writeAttribute("message", result.getExpandedExpression());
+ xml.writeAttribute("type", result.getTestMacroName());
+
+ std::ostringstream oss;
+ if (!result.getMessage().empty())
+ oss << result.getMessage() << "\n";
+ for (std::vector<MessageInfo>::const_iterator
+ it = stats.infoMessages.begin(),
+ itEnd = stats.infoMessages.end();
+ it != itEnd;
+ ++it)
+ if (it->type == ResultWas::Info)
+ oss << it->message << "\n";
+
+ oss << "at " << result.getSourceInfo();
+ xml.writeText(oss.str(), false);
+ }
+ }
+
+ XmlWriter xml;
+ Timer suiteTimer;
+ std::ostringstream stdOutForSuite;
+ std::ostringstream stdErrForSuite;
+ unsigned int unexpectedExceptions;
+};
+
+INTERNAL_CATCH_REGISTER_REPORTER("junit", JunitReporter)
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_console.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
+
+namespace Catch {
+
+struct ConsoleReporter : StreamingReporterBase
+{
+ ConsoleReporter(ReporterConfig const& _config)
+ : StreamingReporterBase(_config),
+ m_headerPrinted(false)
+ {
+ }
+
+ virtual ~ConsoleReporter() CATCH_OVERRIDE;
+ static std::string getDescription()
+ {
+ return "Reports test results as plain lines of text";
+ }
+
+ virtual void noMatchingTestCases(std::string const& spec) CATCH_OVERRIDE
+ {
+ stream << "No test cases matched '" << spec << "'" << std::endl;
+ }
+
+ virtual void assertionStarting(AssertionInfo const&) CATCH_OVERRIDE
+ {
+ }
+
+ virtual bool assertionEnded(AssertionStats const& _assertionStats) CATCH_OVERRIDE
+ {
+ AssertionResult const& result = _assertionStats.assertionResult;
+
+ bool printInfoMessages = true;
+
+ // Drop out if result was successful and we're not printing those
+ if (!m_config->includeSuccessfulResults() && result.isOk())
+ {
+ if (result.getResultType() != ResultWas::Warning)
+ return false;
+ printInfoMessages = false;
+ }
+
+ lazyPrint();
+
+ AssertionPrinter printer(stream, _assertionStats, printInfoMessages);
+ printer.print();
+ stream << std::endl;
+ return true;
+ }
+
+ virtual void sectionStarting(SectionInfo const& _sectionInfo) CATCH_OVERRIDE
+ {
+ m_headerPrinted = false;
+ StreamingReporterBase::sectionStarting(_sectionInfo);
+ }
+ virtual void sectionEnded(SectionStats const& _sectionStats) CATCH_OVERRIDE
+ {
+ if (_sectionStats.missingAssertions)
+ {
+ lazyPrint();
+ Colour colour(Colour::ResultError);
+ if (m_sectionStack.size() > 1)
+ stream << "\nNo assertions in section";
+ else
+ stream << "\nNo assertions in test case";
+ stream << " '" << _sectionStats.sectionInfo.name << "'\n"
+ << std::endl;
+ }
+ if (m_headerPrinted)
+ {
+ if (m_config->showDurations() == ShowDurations::Always)
+ stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
+ m_headerPrinted = false;
+ }
+ else
+ {
+ if (m_config->showDurations() == ShowDurations::Always)
+ stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
+ }
+ StreamingReporterBase::sectionEnded(_sectionStats);
+ }
+
+ virtual void testCaseEnded(TestCaseStats const& _testCaseStats) CATCH_OVERRIDE
+ {
+ StreamingReporterBase::testCaseEnded(_testCaseStats);
+ m_headerPrinted = false;
+ }
+ virtual void testGroupEnded(TestGroupStats const& _testGroupStats) CATCH_OVERRIDE
+ {
+ if (currentGroupInfo.used)
+ {
+ printSummaryDivider();
+ stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
+ printTotals(_testGroupStats.totals);
+ stream << "\n"
+ << std::endl;
+ }
+ StreamingReporterBase::testGroupEnded(_testGroupStats);
+ }
+ virtual void testRunEnded(TestRunStats const& _testRunStats) CATCH_OVERRIDE
+ {
+ printTotalsDivider(_testRunStats.totals);
+ printTotals(_testRunStats.totals);
+ stream << std::endl;
+ StreamingReporterBase::testRunEnded(_testRunStats);
+ }
+
+ private:
+ class AssertionPrinter
+ {
+ void operator=(AssertionPrinter const&);
+
+ public:
+ AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
+ : stream(_stream),
+ stats(_stats),
+ result(_stats.assertionResult),
+ colour(Colour::None),
+ message(result.getMessage()),
+ messages(_stats.infoMessages),
+ printInfoMessages(_printInfoMessages)
+ {
+ switch (result.getResultType())
+ {
+ case ResultWas::Ok:
+ colour = Colour::Success;
+ passOrFail = "PASSED";
+ //if( result.hasMessage() )
+ if (_stats.infoMessages.size() == 1)
+ messageLabel = "with message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel = "with messages";
+ break;
+ case ResultWas::ExpressionFailed:
+ if (result.isOk())
+ {
+ colour = Colour::Success;
+ passOrFail = "FAILED - but was ok";
+ }
+ else
+ {
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ }
+ if (_stats.infoMessages.size() == 1)
+ messageLabel = "with message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel = "with messages";
+ break;
+ case ResultWas::ThrewException:
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ messageLabel = "due to unexpected exception with message";
+ break;
+ case ResultWas::FatalErrorCondition:
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ messageLabel = "due to a fatal error condition";
+ break;
+ case ResultWas::DidntThrowException:
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ messageLabel = "because no exception was thrown where one was expected";
+ break;
+ case ResultWas::Info:
+ messageLabel = "info";
+ break;
+ case ResultWas::Warning:
+ messageLabel = "warning";
+ break;
+ case ResultWas::ExplicitFailure:
+ passOrFail = "FAILED";
+ colour = Colour::Error;
+ if (_stats.infoMessages.size() == 1)
+ messageLabel = "explicitly with message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel = "explicitly with messages";
+ break;
+ // These cases are here to prevent compiler warnings
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ passOrFail = "** internal error **";
+ colour = Colour::Error;
+ break;
+ }
+ }
+
+ void print() const
+ {
+ printSourceInfo();
+ if (stats.totals.assertions.total() > 0)
+ {
+ if (result.isOk())
+ stream << "\n";
+ printResultType();
+ printOriginalExpression();
+ printReconstructedExpression();
+ }
+ else
+ {
+ stream << "\n";
+ }
+ printMessage();
+ }
+
+ private:
+ void printResultType() const
+ {
+ if (!passOrFail.empty())
+ {
+ Colour colourGuard(colour);
+ stream << passOrFail << ":\n";
+ }
+ }
+ void printOriginalExpression() const
+ {
+ if (result.hasExpression())
+ {
+ Colour colourGuard(Colour::OriginalExpression);
+ stream << " ";
+ stream << result.getExpressionInMacro();
+ stream << "\n";
+ }
+ }
+ void printReconstructedExpression() const
+ {
+ if (result.hasExpandedExpression())
+ {
+ stream << "with expansion:\n";
+ Colour colourGuard(Colour::ReconstructedExpression);
+ stream << Text(result.getExpandedExpression(), TextAttributes().setIndent(2)) << "\n";
+ }
+ }
+ void printMessage() const
+ {
+ if (!messageLabel.empty())
+ stream << messageLabel << ":"
+ << "\n";
+ for (std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
+ it != itEnd;
+ ++it)
+ {
+ // If this assertion is a warning ignore any INFO messages
+ if (printInfoMessages || it->type != ResultWas::Info)
+ stream << Text(it->message, TextAttributes().setIndent(2)) << "\n";
+ }
+ }
+ void printSourceInfo() const
+ {
+ Colour colourGuard(Colour::FileName);
+ stream << result.getSourceInfo() << ": ";
+ }
+
+ std::ostream& stream;
+ AssertionStats const& stats;
+ AssertionResult const& result;
+ Colour::Code colour;
+ std::string passOrFail;
+ std::string messageLabel;
+ std::string message;
+ std::vector<MessageInfo> messages;
+ bool printInfoMessages;
+ };
+
+ void lazyPrint()
+ {
+
+ if (!currentTestRunInfo.used)
+ lazyPrintRunInfo();
+ if (!currentGroupInfo.used)
+ lazyPrintGroupInfo();
+
+ if (!m_headerPrinted)
+ {
+ printTestCaseAndSectionHeader();
+ m_headerPrinted = true;
+ }
+ }
+ void lazyPrintRunInfo()
+ {
+ stream << "\n"
+ << getLineOfChars<'~'>() << "\n";
+ Colour colour(Colour::SecondaryText);
+ stream << currentTestRunInfo->name
+ << " is a Catch v" << libraryVersion << " host application.\n"
+ << "Run with -? for options\n\n";
+
+ if (m_config->rngSeed() != 0)
+ stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
+
+ currentTestRunInfo.used = true;
+ }
+ void lazyPrintGroupInfo()
+ {
+ if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1)
+ {
+ printClosedHeader("Group: " + currentGroupInfo->name);
+ currentGroupInfo.used = true;
+ }
+ }
+ void printTestCaseAndSectionHeader()
+ {
+ assert(!m_sectionStack.empty());
+ printOpenHeader(currentTestCaseInfo->name);
+
+ if (m_sectionStack.size() > 1)
+ {
+ Colour colourGuard(Colour::Headers);
+
+ std::vector<SectionInfo>::const_iterator
+ it = m_sectionStack.begin() + 1, // Skip first section (test case)
+ itEnd = m_sectionStack.end();
+ for (; it != itEnd; ++it)
+ printHeaderString(it->name, 2);
+ }
+
+ SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
+
+ if (!lineInfo.empty())
+ {
+ stream << getLineOfChars<'-'>() << "\n";
+ Colour colourGuard(Colour::FileName);
+ stream << lineInfo << "\n";
+ }
+ stream << getLineOfChars<'.'>() << "\n"
+ << std::endl;
+ }
+
+ void printClosedHeader(std::string const& _name)
+ {
+ printOpenHeader(_name);
+ stream << getLineOfChars<'.'>() << "\n";
+ }
+ void printOpenHeader(std::string const& _name)
+ {
+ stream << getLineOfChars<'-'>() << "\n";
+ {
+ Colour colourGuard(Colour::Headers);
+ printHeaderString(_name);
+ }
+ }
+
+ // if string has a : in first line will set indent to follow it on
+ // subsequent lines
+ void printHeaderString(std::string const& _string, std::size_t indent = 0)
+ {
+ std::size_t i = _string.find(": ");
+ if (i != std::string::npos)
+ i += 2;
+ else
+ i = 0;
+ stream << Text(_string, TextAttributes()
+ .setIndent(indent + i)
+ .setInitialIndent(indent))
+ << "\n";
+ }
+
+ struct SummaryColumn
+ {
+
+ SummaryColumn(std::string const& _label, Colour::Code _colour)
+ : label(_label),
+ colour(_colour)
+ {
+ }
+ SummaryColumn addRow(std::size_t count)
+ {
+ std::ostringstream oss;
+ oss << count;
+ std::string row = oss.str();
+ for (std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it)
+ {
+ while (it->size() < row.size())
+ *it = " " + *it;
+ while (it->size() > row.size())
+ row = " " + row;
+ }
+ rows.push_back(row);
+ return *this;
+ }
+
+ std::string label;
+ Colour::Code colour;
+ std::vector<std::string> rows;
+ };
+
+ void printTotals(Totals const& totals)
+ {
+ if (totals.testCases.total() == 0)
+ {
+ stream << Colour(Colour::Warning) << "No tests ran\n";
+ }
+ else if (totals.assertions.total() > 0 && totals.assertions.allPassed())
+ {
+ stream << Colour(Colour::ResultSuccess) << "All tests passed";
+ stream << " ("
+ << pluralise(totals.assertions.passed, "assertion") << " in "
+ << pluralise(totals.testCases.passed, "test case") << ")"
+ << "\n";
+ }
+ else
+ {
+
+ std::vector<SummaryColumn> columns;
+ columns.push_back(SummaryColumn("", Colour::None)
+ .addRow(totals.testCases.total())
+ .addRow(totals.assertions.total()));
+ columns.push_back(SummaryColumn("passed", Colour::Success)
+ .addRow(totals.testCases.passed)
+ .addRow(totals.assertions.passed));
+ columns.push_back(SummaryColumn("failed", Colour::ResultError)
+ .addRow(totals.testCases.failed)
+ .addRow(totals.assertions.failed));
+ columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure)
+ .addRow(totals.testCases.failedButOk)
+ .addRow(totals.assertions.failedButOk));
+
+ printSummaryRow("test cases", columns, 0);
+ printSummaryRow("assertions", columns, 1);
+ }
+ }
+ void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row)
+ {
+ for (std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it)
+ {
+ std::string value = it->rows[row];
+ if (it->label.empty())
+ {
+ stream << label << ": ";
+ if (value != "0")
+ stream << value;
+ else
+ stream << Colour(Colour::Warning) << "- none -";
+ }
+ else if (value != "0")
+ {
+ stream << Colour(Colour::LightGrey) << " | ";
+ stream << Colour(it->colour)
+ << value << " " << it->label;
+ }
+ }
+ stream << "\n";
+ }
+
+ static std::size_t makeRatio(std::size_t number, std::size_t total)
+ {
+ std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;
+ return (ratio == 0 && number > 0) ? 1 : ratio;
+ }
+ static std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k)
+ {
+ if (i > j && i > k)
+ return i;
+ else if (j > k)
+ return j;
+ else
+ return k;
+ }
+
+ void printTotalsDivider(Totals const& totals)
+ {
+ if (totals.testCases.total() > 0)
+ {
+ std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
+ std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
+ std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());
+ while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)
+ findMax(failedRatio, failedButOkRatio, passedRatio)++;
+ while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)
+ findMax(failedRatio, failedButOkRatio, passedRatio)--;
+
+ stream << Colour(Colour::Error) << std::string(failedRatio, '=');
+ stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '=');
+ if (totals.testCases.allPassed())
+ stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '=');
+ else
+ stream << Colour(Colour::Success) << std::string(passedRatio, '=');
+ }
+ else
+ {
+ stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '=');
+ }
+ stream << "\n";
+ }
+ void printSummaryDivider()
+ {
+ stream << getLineOfChars<'-'>() << "\n";
+ }
+
+ private:
+ bool m_headerPrinted;
+};
+
+INTERNAL_CATCH_REGISTER_REPORTER("console", ConsoleReporter)
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_compact.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED
+
+namespace Catch {
+
+struct CompactReporter : StreamingReporterBase
+{
+
+ CompactReporter(ReporterConfig const& _config)
+ : StreamingReporterBase(_config)
+ {
+ }
+
+ virtual ~CompactReporter();
+
+ static std::string getDescription()
+ {
+ return "Reports test results on a single line, suitable for IDEs";
+ }
+
+ virtual ReporterPreferences getPreferences() const
+ {
+ ReporterPreferences prefs;
+ prefs.shouldRedirectStdOut = false;
+ return prefs;
+ }
+
+ virtual void noMatchingTestCases(std::string const& spec)
+ {
+ stream << "No test cases matched '" << spec << "'" << std::endl;
+ }
+
+ virtual void assertionStarting(AssertionInfo const&)
+ {
+ }
+
+ virtual bool assertionEnded(AssertionStats const& _assertionStats)
+ {
+ AssertionResult const& result = _assertionStats.assertionResult;
+
+ bool printInfoMessages = true;
+
+ // Drop out if result was successful and we're not printing those
+ if (!m_config->includeSuccessfulResults() && result.isOk())
+ {
+ if (result.getResultType() != ResultWas::Warning)
+ return false;
+ printInfoMessages = false;
+ }
+
+ AssertionPrinter printer(stream, _assertionStats, printInfoMessages);
+ printer.print();
+
+ stream << std::endl;
+ return true;
+ }
+
+ virtual void testRunEnded(TestRunStats const& _testRunStats)
+ {
+ printTotals(_testRunStats.totals);
+ stream << "\n"
+ << std::endl;
+ StreamingReporterBase::testRunEnded(_testRunStats);
+ }
+
+ private:
+ class AssertionPrinter
+ {
+ void operator=(AssertionPrinter const&);
+
+ public:
+ AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
+ : stream(_stream), stats(_stats), result(_stats.assertionResult), messages(_stats.infoMessages), itMessage(_stats.infoMessages.begin()), printInfoMessages(_printInfoMessages)
+ {
+ }
+
+ void print()
+ {
+ printSourceInfo();
+
+ itMessage = messages.begin();
+
+ switch (result.getResultType())
+ {
+ case ResultWas::Ok:
+ printResultType(Colour::ResultSuccess, passedString());
+ printOriginalExpression();
+ printReconstructedExpression();
+ if (!result.hasExpression())
+ printRemainingMessages(Colour::None);
+ else
+ printRemainingMessages();
+ break;
+ case ResultWas::ExpressionFailed:
+ if (result.isOk())
+ printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok"));
+ else
+ printResultType(Colour::Error, failedString());
+ printOriginalExpression();
+ printReconstructedExpression();
+ printRemainingMessages();
+ break;
+ case ResultWas::ThrewException:
+ printResultType(Colour::Error, failedString());
+ printIssue("unexpected exception with message:");
+ printMessage();
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::FatalErrorCondition:
+ printResultType(Colour::Error, failedString());
+ printIssue("fatal error condition with message:");
+ printMessage();
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::DidntThrowException:
+ printResultType(Colour::Error, failedString());
+ printIssue("expected exception, got none");
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::Info:
+ printResultType(Colour::None, "info");
+ printMessage();
+ printRemainingMessages();
+ break;
+ case ResultWas::Warning:
+ printResultType(Colour::None, "warning");
+ printMessage();
+ printRemainingMessages();
+ break;
+ case ResultWas::ExplicitFailure:
+ printResultType(Colour::Error, failedString());
+ printIssue("explicitly");
+ printRemainingMessages(Colour::None);
+ break;
+ // These cases are here to prevent compiler warnings
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ printResultType(Colour::Error, "** internal error **");
+ break;
+ }
+ }
+
+ private:
+ // Colour::LightGrey
+
+ static Colour::Code dimColour() { return Colour::FileName; }
+
+#ifdef CATCH_PLATFORM_MAC
+ static const char* failedString()
+ {
+ return "FAILED";
+ }
+ static const char* passedString() { return "PASSED"; }
+#else
+ static const char* failedString()
+ {
+ return "failed";
+ }
+ static const char* passedString() { return "passed"; }
+#endif
+
+ void printSourceInfo() const
+ {
+ Colour colourGuard(Colour::FileName);
+ stream << result.getSourceInfo() << ":";
+ }
+
+ void printResultType(Colour::Code colour, std::string passOrFail) const
+ {
+ if (!passOrFail.empty())
+ {
+ {
+ Colour colourGuard(colour);
+ stream << " " << passOrFail;
+ }
+ stream << ":";
+ }
+ }
+
+ void printIssue(std::string issue) const
+ {
+ stream << " " << issue;
+ }
+
+ void printExpressionWas()
+ {
+ if (result.hasExpression())
+ {
+ stream << ";";
+ {
+ Colour colour(dimColour());
+ stream << " expression was:";
+ }
+ printOriginalExpression();
+ }
+ }
+
+ void printOriginalExpression() const
+ {
+ if (result.hasExpression())
+ {
+ stream << " " << result.getExpression();
+ }
+ }
+
+ void printReconstructedExpression() const
+ {
+ if (result.hasExpandedExpression())
+ {
+ {
+ Colour colour(dimColour());
+ stream << " for: ";
+ }
+ stream << result.getExpandedExpression();
+ }
+ }
+
+ void printMessage()
+ {
+ if (itMessage != messages.end())
+ {
+ stream << " '" << itMessage->message << "'";
+ ++itMessage;
+ }
+ }
+
+ void printRemainingMessages(Colour::Code colour = dimColour())
+ {
+ if (itMessage == messages.end())
+ return;
+
+ // using messages.end() directly yields compilation error:
+ std::vector<MessageInfo>::const_iterator itEnd = messages.end();
+ const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
+
+ {
+ Colour colourGuard(colour);
+ stream << " with " << pluralise(N, "message") << ":";
+ }
+
+ for (; itMessage != itEnd;)
+ {
+ // If this assertion is a warning ignore any INFO messages
+ if (printInfoMessages || itMessage->type != ResultWas::Info)
+ {
+ stream << " '" << itMessage->message << "'";
+ if (++itMessage != itEnd)
+ {
+ Colour colourGuard(dimColour());
+ stream << " and";
+ }
+ }
+ }
+ }
+
+ private:
+ std::ostream& stream;
+ AssertionStats const& stats;
+ AssertionResult const& result;
+ std::vector<MessageInfo> messages;
+ std::vector<MessageInfo>::const_iterator itMessage;
+ bool printInfoMessages;
+ };
+
+ // Colour, message variants:
+ // - white: No tests ran.
+ // - red: Failed [both/all] N test cases, failed [both/all] M assertions.
+ // - white: Passed [both/all] N test cases (no assertions).
+ // - red: Failed N tests cases, failed M assertions.
+ // - green: Passed [both/all] N tests cases with M assertions.
+
+ std::string bothOrAll(std::size_t count) const
+ {
+ return count == 1 ? "" : count == 2 ? "both " : "all ";
+ }
+
+ void printTotals(const Totals& totals) const
+ {
+ if (totals.testCases.total() == 0)
+ {
+ stream << "No tests ran.";
+ }
+ else if (totals.testCases.failed == totals.testCases.total())
+ {
+ Colour colour(Colour::ResultError);
+ const std::string qualify_assertions_failed =
+ totals.assertions.failed == totals.assertions.total() ? bothOrAll(totals.assertions.failed) : "";
+ stream << "Failed " << bothOrAll(totals.testCases.failed)
+ << pluralise(totals.testCases.failed, "test case") << ", "
+ "failed "
+ << qualify_assertions_failed << pluralise(totals.assertions.failed, "assertion") << ".";
+ }
+ else if (totals.assertions.total() == 0)
+ {
+ stream << "Passed " << bothOrAll(totals.testCases.total())
+ << pluralise(totals.testCases.total(), "test case")
+ << " (no assertions).";
+ }
+ else if (totals.assertions.failed)
+ {
+ Colour colour(Colour::ResultError);
+ stream << "Failed " << pluralise(totals.testCases.failed, "test case") << ", "
+ "failed "
+ << pluralise(totals.assertions.failed, "assertion") << ".";
+ }
+ else
+ {
+ Colour colour(Colour::ResultSuccess);
+ stream << "Passed " << bothOrAll(totals.testCases.passed)
+ << pluralise(totals.testCases.passed, "test case") << " with " << pluralise(totals.assertions.passed, "assertion") << ".";
+ }
+ }
+};
+
+INTERNAL_CATCH_REGISTER_REPORTER("compact", CompactReporter)
+
+} // end namespace Catch
+
+namespace Catch {
+// These are all here to avoid warnings about not having any out of line
+// virtual methods
+NonCopyable::~NonCopyable() {}
+IShared::~IShared() {}
+IStream::~IStream() CATCH_NOEXCEPT {}
+FileStream::~FileStream() CATCH_NOEXCEPT {}
+CoutStream::~CoutStream() CATCH_NOEXCEPT {}
+DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {}
+StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
+IContext::~IContext() {}
+IResultCapture::~IResultCapture() {}
+ITestCase::~ITestCase() {}
+ITestCaseRegistry::~ITestCaseRegistry() {}
+IRegistryHub::~IRegistryHub() {}
+IMutableRegistryHub::~IMutableRegistryHub() {}
+IExceptionTranslator::~IExceptionTranslator() {}
+IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
+IReporter::~IReporter() {}
+IReporterFactory::~IReporterFactory() {}
+IReporterRegistry::~IReporterRegistry() {}
+IStreamingReporter::~IStreamingReporter() {}
+AssertionStats::~AssertionStats() {}
+SectionStats::~SectionStats() {}
+TestCaseStats::~TestCaseStats() {}
+TestGroupStats::~TestGroupStats() {}
+TestRunStats::~TestRunStats() {}
+CumulativeReporterBase::SectionNode::~SectionNode() {}
+CumulativeReporterBase::~CumulativeReporterBase() {}
+
+StreamingReporterBase::~StreamingReporterBase() {}
+ConsoleReporter::~ConsoleReporter() {}
+CompactReporter::~CompactReporter() {}
+IRunner::~IRunner() {}
+IMutableContext::~IMutableContext() {}
+IConfig::~IConfig() {}
+XmlReporter::~XmlReporter() {}
+JunitReporter::~JunitReporter() {}
+TestRegistry::~TestRegistry() {}
+FreeFunctionTestCase::~FreeFunctionTestCase() {}
+IGeneratorInfo::~IGeneratorInfo() {}
+IGeneratorsForTest::~IGeneratorsForTest() {}
+WildcardPattern::~WildcardPattern() {}
+TestSpec::Pattern::~Pattern() {}
+TestSpec::NamePattern::~NamePattern() {}
+TestSpec::TagPattern::~TagPattern() {}
+TestSpec::ExcludedPattern::~ExcludedPattern() {}
+
+Matchers::Impl::StdString::Equals::~Equals() {}
+Matchers::Impl::StdString::Contains::~Contains() {}
+Matchers::Impl::StdString::StartsWith::~StartsWith() {}
+Matchers::Impl::StdString::EndsWith::~EndsWith() {}
+
+void Config::dummy() {}
+
+namespace TestCaseTracking {
+ITracker::~ITracker() {}
+TrackerBase::~TrackerBase() {}
+SectionTracker::~SectionTracker() {}
+IndexTracker::~IndexTracker() {}
+}
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_MAIN
+// #included from: internal/catch_default_main.hpp
+#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
+
+#ifndef __OBJC__
+
+// Standard C/C++ main entry point
+int main(int argc, char* argv[])
+{
+ return Catch::Session().run(argc, argv);
+}
+
+#else // __OBJC__
+
+// Objective-C entry point
+int main(int argc, char* const argv[])
+{
+#if !CATCH_ARC_ENABLED
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+#endif
+
+ Catch::registerTestMethods();
+ int result = Catch::Session().run(argc, (char* const*)argv);
+
+#if !CATCH_ARC_ENABLED
+ [pool drain];
+#endif
+
+ return result;
+}
+
+#endif // __OBJC__
+
+#endif
+
+#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
+#undef CLARA_CONFIG_MAIN
+#endif
+
+//////
+
+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
+#ifdef CATCH_CONFIG_PREFIX_ALL
+
+#define CATCH_REQUIRE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE")
+#define CATCH_REQUIRE_FALSE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE")
+
+#define CATCH_REQUIRE_THROWS(expr) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS")
+#define CATCH_REQUIRE_THROWS_AS(expr, exceptionType) INTERNAL_CATCH_THROWS_AS(expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS")
+#define CATCH_REQUIRE_THROWS_WITH(expr, matcher) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH")
+#define CATCH_REQUIRE_NOTHROW(expr) INTERNAL_CATCH_NO_THROW(expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW")
+
+#define CATCH_CHECK(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK")
+#define CATCH_CHECK_FALSE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE")
+#define CATCH_CHECKED_IF(expr) INTERNAL_CATCH_IF(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF")
+#define CATCH_CHECKED_ELSE(expr) INTERNAL_CATCH_ELSE(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE")
+#define CATCH_CHECK_NOFAIL(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL")
+
+#define CATCH_CHECK_THROWS(expr) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS")
+#define CATCH_CHECK_THROWS_AS(expr, exceptionType) INTERNAL_CATCH_THROWS_AS(expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS")
+#define CATCH_CHECK_THROWS_WITH(expr, matcher) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH")
+#define CATCH_CHECK_NOTHROW(expr) INTERNAL_CATCH_NO_THROW(expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW")
+
+#define CHECK_THAT(arg, matcher) INTERNAL_CHECK_THAT(arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT")
+#define CATCH_REQUIRE_THAT(arg, matcher) INTERNAL_CHECK_THAT(arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT")
+
+#define CATCH_INFO(msg) INTERNAL_CATCH_INFO(msg, "CATCH_INFO")
+#define CATCH_WARN(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg)
+#define CATCH_SCOPED_INFO(msg) INTERNAL_CATCH_INFO(msg, "CATCH_INFO")
+#define CATCH_CAPTURE(msg) INTERNAL_CATCH_INFO(#msg " := " << msg, "CATCH_CAPTURE")
+#define CATCH_SCOPED_CAPTURE(msg) INTERNAL_CATCH_INFO(#msg " := " << msg, "CATCH_CAPTURE")
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define CATCH_TEST_CASE(...) INTERNAL_CATCH_TESTCASE(__VA_ARGS__)
+#define CATCH_TEST_CASE_METHOD(className, ...) INTERNAL_CATCH_TEST_CASE_METHOD(className, __VA_ARGS__)
+#define CATCH_METHOD_AS_TEST_CASE(method, ...) INTERNAL_CATCH_METHOD_AS_TEST_CASE(method, __VA_ARGS__)
+#define CATCH_REGISTER_TEST_CASE(...) INTERNAL_CATCH_REGISTER_TESTCASE(__VA_ARGS__)
+#define CATCH_SECTION(...) INTERNAL_CATCH_SECTION(__VA_ARGS__)
+#define CATCH_FAIL(...) INTERNAL_CATCH_MSG(Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__)
+#define CATCH_SUCCEED(...) INTERNAL_CATCH_MSG(Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__)
+#else
+#define CATCH_TEST_CASE(name, description) INTERNAL_CATCH_TESTCASE(name, description)
+#define CATCH_TEST_CASE_METHOD(className, name, description) INTERNAL_CATCH_TEST_CASE_METHOD(className, name, description)
+#define CATCH_METHOD_AS_TEST_CASE(method, name, description) INTERNAL_CATCH_METHOD_AS_TEST_CASE(method, name, description)
+#define CATCH_REGISTER_TEST_CASE(function, name, description) INTERNAL_CATCH_REGISTER_TESTCASE(function, name, description)
+#define CATCH_SECTION(name, description) INTERNAL_CATCH_SECTION(name, description)
+#define CATCH_FAIL(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg)
+#define CATCH_SUCCEED(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg)
+#endif
+#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE("", "")
+
+#define CATCH_REGISTER_REPORTER(name, reporterType) INTERNAL_CATCH_REGISTER_REPORTER(name, reporterType)
+#define CATCH_REGISTER_LEGACY_REPORTER(name, reporterType) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER(name, reporterType)
+
+#define CATCH_GENERATE(expr) INTERNAL_CATCH_GENERATE(expr)
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define CATCH_SCENARIO(...) CATCH_TEST_CASE("Scenario: " __VA_ARGS__)
+#define CATCH_SCENARIO_METHOD(className, ...) INTERNAL_CATCH_TEST_CASE_METHOD(className, "Scenario: " __VA_ARGS__)
+#else
+#define CATCH_SCENARIO(name, tags) CATCH_TEST_CASE("Scenario: " name, tags)
+#define CATCH_SCENARIO_METHOD(className, name, tags) INTERNAL_CATCH_TEST_CASE_METHOD(className, "Scenario: " name, tags)
+#endif
+#define CATCH_GIVEN(desc) CATCH_SECTION(std::string("Given: ") + desc, "")
+#define CATCH_WHEN(desc) CATCH_SECTION(std::string(" When: ") + desc, "")
+#define CATCH_AND_WHEN(desc) CATCH_SECTION(std::string(" And: ") + desc, "")
+#define CATCH_THEN(desc) CATCH_SECTION(std::string(" Then: ") + desc, "")
+#define CATCH_AND_THEN(desc) CATCH_SECTION(std::string(" And: ") + desc, "")
+
+// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
+#else
+
+#define REQUIRE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::Normal, "REQUIRE")
+#define REQUIRE_FALSE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE")
+
+#define REQUIRE_THROWS(expr) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS")
+#define REQUIRE_THROWS_AS(expr, exceptionType) INTERNAL_CATCH_THROWS_AS(expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS")
+#define REQUIRE_THROWS_WITH(expr, matcher) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH")
+#define REQUIRE_NOTHROW(expr) INTERNAL_CATCH_NO_THROW(expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW")
+
+#define CHECK(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK")
+#define CHECK_FALSE(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE")
+#define CHECKED_IF(expr) INTERNAL_CATCH_IF(expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF")
+#define CHECKED_ELSE(expr) INTERNAL_CATCH_ELSE(expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE")
+#define CHECK_NOFAIL(expr) INTERNAL_CATCH_TEST(expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL")
+
+#define CHECK_THROWS(expr) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS")
+#define CHECK_THROWS_AS(expr, exceptionType) INTERNAL_CATCH_THROWS_AS(expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS")
+#define CHECK_THROWS_WITH(expr, matcher) INTERNAL_CATCH_THROWS(expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH")
+#define CHECK_NOTHROW(expr) INTERNAL_CATCH_NO_THROW(expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW")
+
+#define CHECK_THAT(arg, matcher) INTERNAL_CHECK_THAT(arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT")
+#define REQUIRE_THAT(arg, matcher) INTERNAL_CHECK_THAT(arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT")
+
+#define INFO(msg) INTERNAL_CATCH_INFO(msg, "INFO")
+#define WARN(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg)
+#define SCOPED_INFO(msg) INTERNAL_CATCH_INFO(msg, "INFO")
+#define CAPTURE(msg) INTERNAL_CATCH_INFO(#msg " := " << msg, "CAPTURE")
+#define SCOPED_CAPTURE(msg) INTERNAL_CATCH_INFO(#msg " := " << msg, "CAPTURE")
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define TEST_CASE(...) INTERNAL_CATCH_TESTCASE(__VA_ARGS__)
+#define TEST_CASE_METHOD(className, ...) INTERNAL_CATCH_TEST_CASE_METHOD(className, __VA_ARGS__)
+#define METHOD_AS_TEST_CASE(method, ...) INTERNAL_CATCH_METHOD_AS_TEST_CASE(method, __VA_ARGS__)
+#define REGISTER_TEST_CASE(...) INTERNAL_CATCH_REGISTER_TESTCASE(__VA_ARGS__)
+#define SECTION(...) INTERNAL_CATCH_SECTION(__VA_ARGS__)
+#define FAIL(...) INTERNAL_CATCH_MSG(Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__)
+#define SUCCEED(...) INTERNAL_CATCH_MSG(Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__)
+#else
+#define TEST_CASE(name, description) INTERNAL_CATCH_TESTCASE(name, description)
+#define TEST_CASE_METHOD(className, name, description) INTERNAL_CATCH_TEST_CASE_METHOD(className, name, description)
+#define METHOD_AS_TEST_CASE(method, name, description) INTERNAL_CATCH_METHOD_AS_TEST_CASE(method, name, description)
+#define REGISTER_TEST_CASE(method, name, description) INTERNAL_CATCH_REGISTER_TESTCASE(method, name, description)
+#define SECTION(name, description) INTERNAL_CATCH_SECTION(name, description)
+#define FAIL(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg)
+#define SUCCEED(msg) INTERNAL_CATCH_MSG(Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg)
+#endif
+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE("", "")
+
+#define REGISTER_REPORTER(name, reporterType) INTERNAL_CATCH_REGISTER_REPORTER(name, reporterType)
+#define REGISTER_LEGACY_REPORTER(name, reporterType) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER(name, reporterType)
+
+#define GENERATE(expr) INTERNAL_CATCH_GENERATE(expr)
+
+#endif
+
+#define CATCH_TRANSLATE_EXCEPTION(signature) INTERNAL_CATCH_TRANSLATE_EXCEPTION(signature)
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define SCENARIO(...) TEST_CASE("Scenario: " __VA_ARGS__)
+#define SCENARIO_METHOD(className, ...) INTERNAL_CATCH_TEST_CASE_METHOD(className, "Scenario: " __VA_ARGS__)
+#else
+#define SCENARIO(name, tags) TEST_CASE("Scenario: " name, tags)
+#define SCENARIO_METHOD(className, name, tags) INTERNAL_CATCH_TEST_CASE_METHOD(className, "Scenario: " name, tags)
+#endif
+#define GIVEN(desc) SECTION(std::string(" Given: ") + desc, "")
+#define WHEN(desc) SECTION(std::string(" When: ") + desc, "")
+#define AND_WHEN(desc) SECTION(std::string("And when: ") + desc, "")
+#define THEN(desc) SECTION(std::string(" Then: ") + desc, "")
+#define AND_THEN(desc) SECTION(std::string(" And: ") + desc, "")
+
+using Catch::Detail::Approx;
+
+#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
diff --git a/third_party/variant/test/optional_unit.cpp b/third_party/variant/test/optional_unit.cpp
deleted file mode 100644
index a6573ca..0000000
--- a/third_party/variant/test/optional_unit.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#define CATCH_CONFIG_RUNNER
-#include "catch.hpp"
-
-#include "optional.hpp"
-
-using namespace mapbox;
-
-struct dummy {
- dummy(int _m_1, int _m_2) : m_1(_m_1), m_2(_m_2) {}
- int m_1;
- int m_2;
-
-};
-
-int main (int argc, char* const argv[])
-{
- int result = Catch::Session().run(argc, argv);
- if (!result) printf("\x1b[1;32m ✓ \x1b[0m\n");
- return result;
-}
-
-TEST_CASE( "optional can be instantiated with a POD type", "[optiona]" ) {
- mapbox::util::optional<double> dbl_opt;
-
- REQUIRE(!dbl_opt);
- dbl_opt = 3.1415;
- REQUIRE(dbl_opt);
-
- REQUIRE(dbl_opt.get() == 3.1415);
- REQUIRE(*dbl_opt == 3.1415);
-}
-
-TEST_CASE( "copy c'tor", "[optiona]" ) {
- mapbox::util::optional<double> dbl_opt;
-
- REQUIRE(!dbl_opt);
- dbl_opt = 3.1415;
- REQUIRE(dbl_opt);
-
- mapbox::util::optional<double> other = dbl_opt;
-
- REQUIRE(other.get() == 3.1415);
- REQUIRE(*other == 3.1415);
-}
-
-TEST_CASE( "const operator*, const get()", "[optiona]" ) {
- mapbox::util::optional<double> dbl_opt = 3.1415;
-
- REQUIRE(dbl_opt);
-
- const double pi1 = dbl_opt.get();
- const double pi2 = *dbl_opt;
-
- REQUIRE(pi1 == 3.1415);
- REQUIRE(pi2 == 3.1415);
-}
-
-TEST_CASE( "emplace initialization, reset", "[optional]" ) {
- mapbox::util::optional<dummy> dummy_opt;
- REQUIRE(!dummy_opt);
-
- // rvalues, baby!
- dummy_opt.emplace(1, 2);
- REQUIRE(dummy_opt);
- REQUIRE(dummy_opt.get().m_1 == 1);
- REQUIRE((*dummy_opt).m_2 == 2);
-
- dummy_opt.reset();
- REQUIRE(!dummy_opt);
-}
-
-TEST_CASE( "assignment", "[optional]") {
- mapbox::util::optional<int> a;
- mapbox::util::optional<int> b;
-
- a = 1; b = 3;
- REQUIRE(a.get() == 1);
- REQUIRE(b.get() == 3);
- b = a;
- REQUIRE(a.get() == b.get());
- REQUIRE(b.get() == 1);
-}
diff --git a/third_party/variant/test/our_variant_hello_world.cpp b/third_party/variant/test/our_variant_hello_world.cpp
new file mode 100644
index 0000000..be5996b
--- /dev/null
+++ b/third_party/variant/test/our_variant_hello_world.cpp
@@ -0,0 +1,20 @@
+#include "variant.hpp"
+
+#include <stdexcept>
+
+struct check
+{
+ template <typename T>
+ void operator()(T const& val) const
+ {
+ if (val != 0) throw std::runtime_error("invalid");
+ }
+};
+
+int main()
+{
+ typedef mapbox::util::variant<bool, int, double> variant_type;
+ variant_type v(0);
+ mapbox::util::apply_visitor(check(), v);
+ return 0;
+}
diff --git a/third_party/variant/test/recursive_wrapper_test.cpp b/third_party/variant/test/recursive_wrapper_test.cpp
index 3cd79b5..0492af4 100644
--- a/third_party/variant/test/recursive_wrapper_test.cpp
+++ b/third_party/variant/test/recursive_wrapper_test.cpp
@@ -1,11 +1,12 @@
+
+#include <cstdlib>
#include <iostream>
-#include <vector>
-#include <thread>
#include <string>
-#include <sstream>
+#include <typeinfo>
#include <utility>
-#include <type_traits>
+
#include <boost/timer/timer.hpp>
+
#include "variant.hpp"
using namespace mapbox;
@@ -14,48 +15,48 @@ namespace test {
struct add;
struct sub;
-template <typename OpTag> struct binary_op;
-typedef util::variant<int ,
+template <typename OpTag>
+struct binary_op;
+
+typedef util::variant<int,
util::recursive_wrapper<binary_op<add>>,
- util::recursive_wrapper<binary_op<sub>>
- > expression;
+ util::recursive_wrapper<binary_op<sub>>>
+ expression;
template <typename Op>
struct binary_op
{
- expression left; // variant instantiated here...
+ expression left; // variant instantiated here...
expression right;
- binary_op(expression && lhs, expression && rhs)
+ binary_op(expression&& lhs, expression&& rhs)
: left(std::move(lhs)), right(std::move(rhs))
{
}
};
-struct print : util::static_visitor<void>
+struct print
{
template <typename T>
- void operator() (T const& val) const
+ void operator()(T const& val) const
{
std::cerr << val << ":" << typeid(T).name() << std::endl;
}
};
-
-struct test : util::static_visitor<std::string>
+struct test
{
template <typename T>
- std::string operator() (T const& obj) const
+ std::string operator()(T const& obj) const
{
return std::string("TYPE_ID=") + typeid(obj).name();
}
};
-struct calculator : public util::static_visitor<int>
+struct calculator
{
-public:
-
+ public:
int operator()(int value) const
{
return value;
@@ -63,21 +64,18 @@ public:
int operator()(binary_op<add> const& binary) const
{
- return util::apply_visitor(calculator(), binary.left)
- + util::apply_visitor(calculator(), binary.right);
+ return util::apply_visitor(calculator(), binary.left) + util::apply_visitor(calculator(), binary.right);
}
int operator()(binary_op<sub> const& binary) const
{
- return util::apply_visitor(calculator(), binary.left)
- - util::apply_visitor(calculator(), binary.right);
+ return util::apply_visitor(calculator(), binary.left) - util::apply_visitor(calculator(), binary.right);
}
};
-struct to_string : public util::static_visitor<std::string>
+struct to_string
{
-public:
-
+ public:
std::string operator()(int value) const
{
return std::to_string(value);
@@ -85,23 +83,19 @@ public:
std::string operator()(binary_op<add> const& binary) const
{
- return util::apply_visitor(to_string(), binary.left) + std::string("+")
- + util::apply_visitor(to_string(), binary.right);
+ return util::apply_visitor(to_string(), binary.left) + std::string("+") + util::apply_visitor(to_string(), binary.right);
}
std::string operator()(binary_op<sub> const& binary) const
{
- return util::apply_visitor(to_string(), binary.left) + std::string("-")
- + util::apply_visitor(to_string(), binary.right);
+ return util::apply_visitor(to_string(), binary.left) + std::string("-") + util::apply_visitor(to_string(), binary.right);
}
-
};
} // namespace test
-int main (int argc, char** argv)
+int main(int argc, char** argv)
{
-
if (argc != 2)
{
std::cerr << "Usage" << argv[0] << " <num-iter>" << std::endl;
@@ -110,21 +104,20 @@ int main (int argc, char** argv)
const std::size_t NUM_ITER = static_cast<std::size_t>(std::stol(argv[1]));
- test::expression result(
- test::binary_op<test::sub>(
- test::binary_op<test::add>(2, 3), 4));
+ test::expression sum(test::binary_op<test::add>(2, 3));
+ test::expression result(test::binary_op<test::sub>(std::move(sum), 4));
std::cerr << "TYPE OF RESULT-> " << util::apply_visitor(test::test(), result) << std::endl;
+ int total = 0;
{
boost::timer::auto_cpu_timer t;
- int total = 0;
for (std::size_t i = 0; i < NUM_ITER; ++i)
{
total += util::apply_visitor(test::calculator(), result);
}
- std::cerr << "total=" << total << std::endl;
}
+ std::cerr << "total=" << total << std::endl;
std::cerr << util::apply_visitor(test::to_string(), result) << "=" << util::apply_visitor(test::calculator(), result) << std::endl;
diff --git a/third_party/variant/test/reference_wrapper_test.cpp b/third_party/variant/test/reference_wrapper_test.cpp
index 2abf027..dc1209f 100644
--- a/third_party/variant/test/reference_wrapper_test.cpp
+++ b/third_party/variant/test/reference_wrapper_test.cpp
@@ -1,11 +1,11 @@
+#include <cstdlib>
+#include <functional>
#include <iostream>
-#include <vector>
-#include <thread>
-#include <string>
-#include <sstream>
-#include <utility>
#include <type_traits>
-#include <boost/timer/timer.hpp>
+#include <typeinfo>
+#include <utility>
+#include <vector>
+
#include "variant.hpp"
using namespace mapbox;
@@ -14,15 +14,19 @@ namespace test {
struct point
{
-public:
- point (double x_, double y_)
+ public:
+ point(double x_, double y_)
: x(x_), y(y_) {}
double x;
double y;
};
-struct line_string : std::vector<point> {};
-struct polygon : std::vector<line_string> {};
+struct line_string : std::vector<point>
+{
+};
+struct polygon : std::vector<line_string>
+{
+};
using variant = util::variant<std::reference_wrapper<const point>,
std::reference_wrapper<const line_string>,
std::reference_wrapper<const polygon>>;
@@ -30,11 +34,11 @@ using variant = util::variant<std::reference_wrapper<const point>,
struct print
{
using result_type = void;
- void operator() (point const& pt) const
+ void operator()(point const& pt) const
{
std::cerr << "Point(" << pt.x << "," << pt.y << ")" << std::endl;
}
- void operator() (line_string const& line) const
+ void operator()(line_string const& line) const
{
std::cerr << "Line(";
for (auto const& pt : line)
@@ -44,27 +48,25 @@ struct print
std::cerr << ")" << std::endl;
}
template <typename T>
- void operator() (T const& val) const
+ void operator()(T const& val) const
{
std::cerr << typeid(T).name() << std::endl;
}
};
-
-
}
-int main (int argc, char** argv)
+int main()
{
std::cerr << sizeof(test::polygon) << std::endl;
std::cerr << sizeof(test::variant) << std::endl;
- test::point pt(123,456);
- test::variant var = std::move(std::cref(pt));
+ test::point pt(123, 456);
+ test::variant var = std::cref(pt);
util::apply_visitor(test::print(), var);
test::line_string line;
line.push_back(pt);
line.push_back(pt);
- line.push_back(test::point(999,333));
- var = std::move(std::cref(line));
+ line.push_back(test::point(999, 333));
+ var = std::cref(line);
util::apply_visitor(test::print(), var);
std::cerr << "Is line (cref) ? " << var.is<std::reference_wrapper<test::line_string const>>() << std::endl;
auto const& line2 = var.get<test::line_string>(); // accessing underlying type of std::reference_wrapper<T>
diff --git a/third_party/variant/test/t/binary_visitor_1.cpp b/third_party/variant/test/t/binary_visitor_1.cpp
new file mode 100644
index 0000000..298a40b
--- /dev/null
+++ b/third_party/variant/test/t/binary_visitor_1.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " i-d"
+using variant_type = mapbox::util::variant<int, double>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/third_party/variant/test/t/binary_visitor_2.cpp b/third_party/variant/test/t/binary_visitor_2.cpp
new file mode 100644
index 0000000..33768b6
--- /dev/null
+++ b/third_party/variant/test/t/binary_visitor_2.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " b-i-d"
+using variant_type = mapbox::util::variant<bool, int, double>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/third_party/variant/test/t/binary_visitor_3.cpp b/third_party/variant/test/t/binary_visitor_3.cpp
new file mode 100644
index 0000000..d35af4e
--- /dev/null
+++ b/third_party/variant/test/t/binary_visitor_3.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " i-d-b"
+using variant_type = mapbox::util::variant<int, double, bool>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/third_party/variant/test/t/binary_visitor_4.cpp b/third_party/variant/test/t/binary_visitor_4.cpp
new file mode 100644
index 0000000..daacc1b
--- /dev/null
+++ b/third_party/variant/test/t/binary_visitor_4.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " b-i-d-c"
+using variant_type = mapbox::util::variant<bool, int, double, char>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/third_party/variant/test/t/binary_visitor_5.cpp b/third_party/variant/test/t/binary_visitor_5.cpp
new file mode 100644
index 0000000..28669be
--- /dev/null
+++ b/third_party/variant/test/t/binary_visitor_5.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " b-i-c-d-i"
+using variant_type = mapbox::util::variant<bool, int, char, double, int>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/third_party/variant/test/t/binary_visitor_6.cpp b/third_party/variant/test/t/binary_visitor_6.cpp
new file mode 100644
index 0000000..c881b0f
--- /dev/null
+++ b/third_party/variant/test/t/binary_visitor_6.cpp
@@ -0,0 +1,7 @@
+
+#include "variant.hpp"
+
+#define NAME_EXT " b-i-i-d-c-u"
+using variant_type = mapbox::util::variant<bool, int, int, double, char, short int>;
+
+#include "binary_visitor_impl.hpp"
diff --git a/third_party/variant/test/t/binary_visitor_impl.hpp b/third_party/variant/test/t/binary_visitor_impl.hpp
new file mode 100644
index 0000000..4d9a43f
--- /dev/null
+++ b/third_party/variant/test/t/binary_visitor_impl.hpp
@@ -0,0 +1,204 @@
+
+#include <type_traits>
+
+#include "catch.hpp"
+
+#include "variant_io.hpp"
+
+struct add_visitor
+{
+ add_visitor() {}
+
+ template <typename A, typename B>
+ double operator()(A a, B b) const
+ {
+ return a + b;
+ }
+};
+
+TEST_CASE("const binary visitor works on const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+ const variant_type a{7};
+ const variant_type b = 3;
+ const variant_type c{7.1};
+ const variant_type d = 2.9;
+
+ const add_visitor v;
+
+ REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
+
+ REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
+}
+
+TEST_CASE("non-const binary visitor works on const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+ const variant_type a = 7;
+ const variant_type b = 3;
+ const variant_type c = 7.1;
+ const variant_type d = 2.9;
+
+ add_visitor v;
+
+ REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
+
+ REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
+}
+
+TEST_CASE("const binary visitor works on non-const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+ variant_type a = 7;
+ variant_type b = 3;
+ variant_type c = 7.1;
+ variant_type d = 2.9;
+
+ const add_visitor v;
+
+ REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
+
+ REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
+}
+
+TEST_CASE("non-const binary visitor works on non-const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+ variant_type a = 7;
+ variant_type b = 3;
+ variant_type c = 7.1;
+ variant_type d = 2.9;
+
+ add_visitor v;
+
+ REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
+
+ REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
+}
+
+TEST_CASE("rvalue binary visitor works on const variants" NAME_EXT, "[visitor][binary visitor]")
+{
+ const variant_type a = 7;
+ const variant_type b = 3;
+ const variant_type c = 7.1;
+ const variant_type d = 2.9;
+
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, a, b) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, c, d) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, a, c) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, a, d) == Approx(9.9));
+
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, b, a) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, d, c) == Approx(10));
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, c, a) == Approx(14.1));
+ REQUIRE(mapbox::util::apply_visitor(add_visitor{}, d, a) == Approx(9.9));
+}
+
+struct sum_mul_visitor
+{
+ double sum;
+
+ sum_mul_visitor() : sum(0.0) {}
+
+ template <typename A, typename B>
+ double operator()(A a, B b)
+ {
+ double m = a * b;
+ sum += m;
+ return m;
+ }
+};
+
+TEST_CASE("mutable binary visitor works" NAME_EXT, "[visitor][binary visitor]")
+{
+ const variant_type a = 2;
+ const variant_type b = 3;
+ const variant_type c = 0.1;
+ const variant_type d = 0.2;
+
+ sum_mul_visitor v;
+
+ REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(6));
+ REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(0.02));
+ REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(0.2));
+ REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(0.4));
+
+ REQUIRE(v.sum == Approx(6.62));
+
+ REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(6));
+ REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(0.02));
+ REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(0.2));
+ REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(0.4));
+}
+
+struct swap_visitor
+{
+ swap_visitor(){};
+
+ template <typename A, typename B>
+ void operator()(A& a, B& b) const
+ {
+ using T = typename std::common_type<A, B>::type;
+ T tmp = a;
+ a = b;
+ b = tmp;
+ }
+};
+
+TEST_CASE("static mutating visitor on mutable variants works" NAME_EXT, "[visitor][binary visitor]")
+{
+ variant_type a = 2;
+ variant_type b = 3;
+ variant_type c = 0.1;
+ variant_type d = 0.2;
+
+ const swap_visitor v;
+
+ SECTION("swap a and b")
+ {
+ mapbox::util::apply_visitor(v, a, b);
+ REQUIRE(a.get<int>() == 3);
+ REQUIRE(b.get<int>() == 2);
+ }
+
+ SECTION("swap c and d")
+ {
+ mapbox::util::apply_visitor(v, c, d);
+ REQUIRE(c.get<double>() == Approx(0.2));
+ REQUIRE(d.get<double>() == Approx(0.1));
+ }
+
+ SECTION("swap a and c")
+ {
+ mapbox::util::apply_visitor(v, a, c);
+ REQUIRE(a.get<int>() == 0);
+ REQUIRE(c.get<double>() == Approx(2.0));
+ }
+
+ SECTION("swap c and a")
+ {
+ mapbox::util::apply_visitor(v, c, a);
+ REQUIRE(a.get<int>() == 0);
+ REQUIRE(c.get<double>() == Approx(2.0));
+ }
+}
diff --git a/third_party/variant/test/t/issue21.cpp b/third_party/variant/test/t/issue21.cpp
new file mode 100644
index 0000000..b952313
--- /dev/null
+++ b/third_party/variant/test/t/issue21.cpp
@@ -0,0 +1,48 @@
+
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+// https://github.com/mapbox/variant/issues/21
+
+static int count;
+
+struct t1
+{
+ int value;
+ t1(int v) : value(v)
+ {
+ ++count;
+ }
+ ~t1()
+ {
+ --count;
+ }
+};
+
+struct t2
+{
+ int value;
+ t2(int v) : value(v)
+ { // constructor fails
+ throw std::runtime_error("fail");
+ }
+};
+
+TEST_CASE("set() works cleanly even if the constructor throws ", "[variant]")
+{
+
+ using variant_type = mapbox::util::variant<t1, t2>;
+
+ count = 0;
+ {
+ variant_type v{42};
+ REQUIRE(v.is<t1>());
+ REQUIRE(v.get<t1>().value == 42);
+ REQUIRE_THROWS({
+ v.set<t2>(13);
+ });
+ }
+ REQUIRE(count == 0);
+}
diff --git a/third_party/variant/test/t/mutating_visitor.cpp b/third_party/variant/test/t/mutating_visitor.cpp
new file mode 100644
index 0000000..f07afb8
--- /dev/null
+++ b/third_party/variant/test/t/mutating_visitor.cpp
@@ -0,0 +1,36 @@
+
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+#include <string>
+
+template <typename T>
+struct mutating_visitor
+{
+ mutating_visitor(T& val)
+ : val_(val) {}
+
+ void operator()(T& val) const
+ {
+ val = val_;
+ }
+
+ template <typename T1>
+ void operator()(T1&) const
+ {
+ } // no-op
+
+ T& val_;
+};
+
+TEST_CASE("variant visitation", "[visitor][unary visitor]")
+{
+ mapbox::util::variant<int, double, std::string> var(123);
+ REQUIRE(var.get<int>() == 123);
+ int val = 456;
+ const mutating_visitor<int> visitor(val);
+ mapbox::util::apply_visitor(visitor, var);
+ REQUIRE(var.get<int>() == 456);
+}
diff --git a/third_party/variant/test/t/optional.cpp b/third_party/variant/test/t/optional.cpp
new file mode 100644
index 0000000..b77beda
--- /dev/null
+++ b/third_party/variant/test/t/optional.cpp
@@ -0,0 +1,102 @@
+
+#include "catch.hpp"
+
+#include "optional.hpp"
+
+struct dummy
+{
+ dummy(int _m_1, int _m_2) : m_1(_m_1), m_2(_m_2) {}
+ int m_1;
+ int m_2;
+};
+
+TEST_CASE("optional can be instantiated with a POD type", "[optional]")
+{
+ mapbox::util::optional<int> dbl_opt;
+
+ REQUIRE(!dbl_opt);
+ dbl_opt = 3;
+ REQUIRE(dbl_opt);
+
+ REQUIRE(dbl_opt.get() == 3);
+ REQUIRE(*dbl_opt == 3);
+}
+
+TEST_CASE("copy c'tor", "[optional]")
+{
+ mapbox::util::optional<int> dbl_opt;
+
+ REQUIRE(!dbl_opt);
+ dbl_opt = 3;
+ REQUIRE(dbl_opt);
+
+ mapbox::util::optional<int> other = dbl_opt;
+
+ REQUIRE(other.get() == 3);
+ REQUIRE(*other == 3);
+}
+
+TEST_CASE("const operator*, const get()", "[optional]")
+{
+ const mapbox::util::optional<int> dbl_opt = 3;
+
+ REQUIRE(dbl_opt);
+
+ auto pi1 = dbl_opt.get();
+ auto pi2 = *dbl_opt;
+
+ REQUIRE(pi1 == 3);
+ REQUIRE(pi2 == 3);
+}
+
+TEST_CASE("non-const operator*, non-const get()", "[optional]")
+{
+ mapbox::util::optional<int> dbl_opt = 3;
+
+ REQUIRE(dbl_opt);
+
+ auto pi1 = dbl_opt.get();
+ auto pi2 = *dbl_opt;
+
+ REQUIRE(pi1 == 3);
+ REQUIRE(pi2 == 3);
+}
+
+TEST_CASE("emplace initialization, reset", "[optional]")
+{
+ mapbox::util::optional<dummy> dummy_opt;
+ REQUIRE(!dummy_opt);
+
+ // rvalues, baby!
+ dummy_opt.emplace(1, 2);
+ REQUIRE(dummy_opt);
+ REQUIRE(dummy_opt.get().m_1 == 1);
+ REQUIRE((*dummy_opt).m_2 == 2);
+
+ dummy_opt.reset();
+ REQUIRE(!dummy_opt);
+}
+
+TEST_CASE("assignment", "[optional]")
+{
+ mapbox::util::optional<int> a;
+ mapbox::util::optional<int> b;
+
+ a = 1;
+ b = 3;
+ REQUIRE(a.get() == 1);
+ REQUIRE(b.get() == 3);
+ b = a;
+ REQUIRE(a.get() == b.get());
+ REQUIRE(b.get() == 1);
+}
+
+TEST_CASE("self assignment", "[optional]")
+{
+ mapbox::util::optional<int> a;
+
+ a = 1;
+ REQUIRE(a.get() == 1);
+ a = a;
+ REQUIRE(a.get() == 1);
+}
diff --git a/third_party/variant/test/t/recursive_wrapper.cpp b/third_party/variant/test/t/recursive_wrapper.cpp
new file mode 100644
index 0000000..b2dec45
--- /dev/null
+++ b/third_party/variant/test/t/recursive_wrapper.cpp
@@ -0,0 +1,158 @@
+
+#include "catch.hpp"
+
+#include "recursive_wrapper.hpp"
+
+#include <type_traits>
+#include <utility>
+
+using rwi = mapbox::util::recursive_wrapper<int>;
+using rwp = mapbox::util::recursive_wrapper<std::pair<int, int>>;
+
+static_assert(std::is_same<rwi::type, int>::value, "type check failed");
+
+TEST_CASE("recursive wrapper of int")
+{
+
+ SECTION("construct with value")
+ {
+ rwi a{7};
+
+ REQUIRE(a.get() == 7);
+ REQUIRE(*a.get_pointer() == 7);
+
+ a = 8;
+ REQUIRE(a.get() == 8);
+
+ rwi b{a};
+ REQUIRE(b.get() == 8);
+
+ rwi c;
+ c = b;
+ REQUIRE(b.get() == 8);
+ REQUIRE(c.get() == 8);
+
+ c = 9;
+ REQUIRE(c.get() == 9);
+
+ int x = 10;
+ c = x;
+ REQUIRE(c.get() == 10);
+
+ b = std::move(c);
+ REQUIRE(b.get() == 10);
+ }
+
+ SECTION("construct with const reference")
+ {
+ int i = 7;
+ rwi a{i};
+
+ REQUIRE(a.get() == 7);
+ }
+
+ SECTION("implicit conversion to reference of underlying type")
+ {
+
+ SECTION("const")
+ {
+ rwi const a{7};
+ REQUIRE(a.get() == 7);
+ REQUIRE(*a.get_pointer() == 7);
+
+ rwi::type const& underlying = a;
+ REQUIRE(underlying == 7);
+ }
+
+ SECTION("non const")
+ {
+ rwi a{7};
+ REQUIRE(a.get() == 7);
+ REQUIRE(*a.get_pointer() == 7);
+
+ rwi::type& underlying = a;
+ REQUIRE(underlying == 7);
+ a = 8;
+ REQUIRE(underlying == 8);
+ }
+ }
+}
+
+TEST_CASE("move of recursive wrapper")
+{
+ rwi a{1};
+
+ SECTION("move constructor")
+ {
+ rwi b{std::move(a)};
+ REQUIRE(b.get() == 1);
+ }
+
+ SECTION("operator= on rvalue")
+ {
+ rwi b{2};
+ b = std::move(a);
+ REQUIRE(b.get() == 1);
+ }
+}
+
+TEST_CASE("swap")
+{
+ rwi a{1};
+ rwi b{2};
+
+ REQUIRE(a.get() == 1);
+ REQUIRE(b.get() == 2);
+
+ using std::swap;
+ swap(a, b);
+
+ REQUIRE(a.get() == 2);
+ REQUIRE(b.get() == 1);
+}
+
+TEST_CASE("recursive wrapper of pair<int, int>")
+{
+
+ SECTION("default constructed")
+ {
+ rwp a;
+ REQUIRE(a.get().first == 0);
+ REQUIRE(a.get().second == 0);
+ }
+
+ SECTION("construct with value")
+ {
+ rwp a{std::make_pair(1, 2)};
+
+ REQUIRE(a.get().first == 1);
+ REQUIRE(a.get().second == 2);
+
+ REQUIRE(a.get_pointer()->first == 1);
+ REQUIRE(a.get_pointer()->second == 2);
+
+ a = {3, 4};
+ REQUIRE(a.get().first == 3);
+ REQUIRE(a.get().second == 4);
+
+ rwp b{a};
+ REQUIRE(b.get().first == 3);
+ REQUIRE(b.get().second == 4);
+
+ rwp c;
+ c = b;
+ REQUIRE(b.get().first == 3);
+ REQUIRE(b.get().second == 4);
+ REQUIRE(c.get().first == 3);
+ REQUIRE(c.get().second == 4);
+
+ c = {5, 6};
+ REQUIRE(c.get().first == 5);
+ REQUIRE(c.get().second == 6);
+
+ b = std::move(c);
+ REQUIRE(b.get().first == 5);
+ REQUIRE(b.get().second == 6);
+ // REQUIRE(c.get_pointer() == nullptr);
+ }
+}
diff --git a/third_party/variant/test/t/sizeof.cpp b/third_party/variant/test/t/sizeof.cpp
new file mode 100644
index 0000000..0e74ce5
--- /dev/null
+++ b/third_party/variant/test/t/sizeof.cpp
@@ -0,0 +1,52 @@
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+struct some_struct
+{
+ int a;
+ bool b;
+ std::string c;
+};
+
+using variant_internal_index_type = size_t;
+
+TEST_CASE("size of variants")
+{
+ constexpr const auto min_overhead = sizeof(variant_internal_index_type);
+
+ using namespace std; // workaround for bug in GCC <= 4.8 where max_align_t is not in std
+ constexpr const auto max_overhead = alignof(max_align_t) + min_overhead;
+
+ using v1 = mapbox::util::variant<int>;
+ using v2 = mapbox::util::variant<int, bool, int64_t>;
+ using v3 = mapbox::util::variant<int, std::string>;
+ using v4 = mapbox::util::variant<std::string, std::string>;
+ using v5 = mapbox::util::variant<some_struct>;
+
+ constexpr const auto si = sizeof(int);
+ constexpr const auto sb = sizeof(bool);
+ constexpr const auto si64 = sizeof(int64_t);
+ constexpr const auto sd = sizeof(double);
+ constexpr const auto sstr = sizeof(std::string);
+ constexpr const auto spi = sizeof(std::pair<int, int>);
+ constexpr const auto ss = sizeof(some_struct);
+
+ REQUIRE(sizeof(v1) <= max_overhead + si);
+ REQUIRE(sizeof(v2) <= max_overhead + std::max({si, sb, si64}));
+ REQUIRE(sizeof(v3) <= max_overhead + std::max({si, sstr}));
+ REQUIRE(sizeof(v4) <= max_overhead + sstr);
+ REQUIRE(sizeof(v5) <= max_overhead + ss);
+
+ REQUIRE(sizeof(v1) >= min_overhead + si);
+ REQUIRE(sizeof(v2) >= min_overhead + std::max({si, sb, si64}));
+ REQUIRE(sizeof(v3) >= min_overhead + std::max({si, sstr}));
+ REQUIRE(sizeof(v4) >= min_overhead + sstr);
+ REQUIRE(sizeof(v5) >= min_overhead + ss);
+}
diff --git a/third_party/variant/test/t/unary_visitor.cpp b/third_party/variant/test/t/unary_visitor.cpp
new file mode 100644
index 0000000..8df6110
--- /dev/null
+++ b/third_party/variant/test/t/unary_visitor.cpp
@@ -0,0 +1,127 @@
+
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+#include <string>
+
+struct some_visitor
+{
+ int var_;
+
+ some_visitor(int init)
+ : var_(init) {}
+
+ int operator()(int val) const
+ {
+ return var_ + val;
+ }
+
+ int operator()(double val) const
+ {
+ return var_ + int(val);
+ }
+
+ int operator()(const std::string&) const
+ {
+ return 0;
+ }
+};
+
+TEST_CASE("non-const visitor works on const variants", "[visitor][unary visitor]")
+{
+ using variant_type = const mapbox::util::variant<int, double, std::string>;
+ variant_type var1(123);
+ variant_type var2(3.2);
+ variant_type var3("foo");
+ REQUIRE(var1.get<int>() == 123);
+ REQUIRE(var2.get<double>() == Approx(3.2));
+ REQUIRE(var3.get<std::string>() == "foo");
+
+ some_visitor visitor{1};
+
+ REQUIRE(mapbox::util::apply_visitor(visitor, var1) == 124);
+ REQUIRE(mapbox::util::apply_visitor(visitor, var2) == 4);
+ REQUIRE(mapbox::util::apply_visitor(visitor, var3) == 0);
+}
+
+TEST_CASE("const visitor works on const variants", "[visitor][unary visitor]")
+{
+ using variant_type = const mapbox::util::variant<int, double, std::string>;
+ variant_type var1(123);
+ variant_type var2(3.2);
+ variant_type var3("foo");
+ REQUIRE(var1.get<int>() == 123);
+ REQUIRE(var2.get<double>() == Approx(3.2));
+ REQUIRE(var3.get<std::string>() == "foo");
+
+ const some_visitor visitor{1};
+
+ REQUIRE(mapbox::util::apply_visitor(visitor, var1) == 124);
+ REQUIRE(mapbox::util::apply_visitor(visitor, var2) == 4);
+ REQUIRE(mapbox::util::apply_visitor(visitor, var3) == 0);
+}
+
+TEST_CASE("rvalue visitor works on const variants", "[visitor][unary visitor]")
+{
+ using variant_type = const mapbox::util::variant<int, double, std::string>;
+ variant_type var1(123);
+ variant_type var2(3.2);
+ variant_type var3("foo");
+ REQUIRE(var1.get<int>() == 123);
+ REQUIRE(var2.get<double>() == Approx(3.2));
+ REQUIRE(var3.get<std::string>() == "foo");
+
+ REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, var1) == 124);
+ REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, var2) == 4);
+ REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, var3) == 0);
+}
+
+TEST_CASE("visitor works on rvalue variants", "[visitor][unary visitor]")
+{
+ using variant_type = const mapbox::util::variant<int, double, std::string>;
+
+ REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, variant_type{123}) == 124);
+ REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, variant_type{3.2}) == 4);
+ REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, variant_type{"foo"}) == 0);
+}
+
+struct total_sizeof
+{
+ total_sizeof() : total_(0) {}
+
+ template <class Value>
+ int operator()(const Value&) const
+ {
+ total_ += int(sizeof(Value));
+ return total_;
+ }
+
+ int result() const
+ {
+ return total_;
+ }
+
+ mutable int total_;
+
+}; // total_sizeof
+
+TEST_CASE("changes in visitor should be visible", "[visitor][unary visitor]")
+{
+ using variant_type = mapbox::util::variant<int, std::string, double>;
+ variant_type v;
+ total_sizeof ts;
+ v = 5.9;
+ REQUIRE(mapbox::util::apply_visitor(ts, v) == sizeof(double));
+ REQUIRE(ts.result() == sizeof(double));
+}
+
+TEST_CASE("changes in const visitor (with mutable internals) should be visible", "[visitor][unary visitor]")
+{
+ using variant_type = const mapbox::util::variant<int, std::string, double>;
+ variant_type v{"foo"};
+ const total_sizeof ts;
+ REQUIRE(mapbox::util::apply_visitor(ts, v) == sizeof(std::string));
+ REQUIRE(ts.result() == sizeof(std::string));
+}
diff --git a/third_party/variant/test/t/variant.cpp b/third_party/variant/test/t/variant.cpp
new file mode 100644
index 0000000..36655a5
--- /dev/null
+++ b/third_party/variant/test/t/variant.cpp
@@ -0,0 +1,570 @@
+#include "catch.hpp"
+
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+#include <algorithm>
+#include <cstdint>
+#include <functional>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <ostream>
+#include <sstream>
+#include <string>
+
+// Hack to make nullptr work with Catch
+namespace std {
+
+template <class C, class T>
+std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& os, std::nullptr_t)
+{
+ return os << (void*)nullptr;
+}
+}
+
+TEST_CASE("variant can be moved into vector", "[variant]")
+{
+ using variant_type = mapbox::util::variant<bool, std::string>;
+ variant_type v(std::string("test"));
+ std::vector<variant_type> vec;
+ vec.emplace_back(std::move(v));
+ REQUIRE(v.get<std::string>() != std::string("test"));
+ REQUIRE(vec.at(0).get<std::string>() == std::string("test"));
+}
+
+TEST_CASE("variant should support built-in types", "[variant]")
+{
+ SECTION("bool")
+ {
+ mapbox::util::variant<bool> v(true);
+ REQUIRE(v.valid());
+ REQUIRE(v.is<bool>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<bool>() == true);
+ v.set<bool>(false);
+ REQUIRE(v.get<bool>() == false);
+ v = true;
+ REQUIRE(v == mapbox::util::variant<bool>(true));
+ }
+ SECTION("nullptr")
+ {
+ using value_type = std::nullptr_t;
+ mapbox::util::variant<value_type> v(nullptr);
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<value_type>() == nullptr);
+ REQUIRE(v == mapbox::util::variant<value_type>(nullptr));
+ }
+ SECTION("unique_ptr")
+ {
+ using value_type = std::unique_ptr<std::string>;
+ mapbox::util::variant<value_type> v(value_type(new std::string("hello")));
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(*v.get<value_type>().get() == *value_type(new std::string("hello")).get());
+ REQUIRE(*v.get<value_type>() == "hello");
+ }
+ SECTION("string")
+ {
+ using value_type = std::string;
+ mapbox::util::variant<value_type> v(value_type("hello"));
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<value_type>() == value_type("hello"));
+ v.set<value_type>(value_type("there"));
+ REQUIRE(v.get<value_type>() == value_type("there"));
+ v = value_type("variant");
+ REQUIRE(v == mapbox::util::variant<value_type>(value_type("variant")));
+ }
+ SECTION("size_t")
+ {
+ using value_type = std::size_t;
+ mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+ v.set<value_type>(value_type(0));
+ REQUIRE(v.get<value_type>() == value_type(0));
+ v = value_type(1);
+ REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+ }
+ SECTION("int8_t")
+ {
+ using value_type = std::int8_t;
+ mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+ v.set<value_type>(0);
+ REQUIRE(v.get<value_type>() == value_type(0));
+ v = value_type(1);
+ REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+ }
+ SECTION("int16_t")
+ {
+ using value_type = std::int16_t;
+ mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+ v.set<value_type>(0);
+ REQUIRE(v.get<value_type>() == value_type(0));
+ v = value_type(1);
+ REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+ }
+ SECTION("int32_t")
+ {
+ using value_type = std::int32_t;
+ mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+ v.set<value_type>(0);
+ REQUIRE(v.get<value_type>() == value_type(0));
+ v = value_type(1);
+ REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+ }
+ SECTION("int64_t")
+ {
+ using value_type = std::int64_t;
+ mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
+ REQUIRE(v.valid());
+ REQUIRE(v.is<value_type>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
+ v.set<value_type>(0);
+ REQUIRE(v.get<value_type>() == value_type(0));
+ v = value_type(1);
+ REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
+ }
+}
+
+struct MissionInteger
+{
+ using value_type = uint64_t;
+ value_type val_;
+
+ public:
+ MissionInteger(uint64_t val) : val_(val) {}
+
+ bool operator==(MissionInteger const& rhs) const
+ {
+ return (val_ == rhs.get());
+ }
+
+ uint64_t get() const
+ {
+ return val_;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, MissionInteger const& rhs)
+{
+ os << rhs.get();
+ return os;
+}
+
+TEST_CASE("variant should support custom types", "[variant]")
+{
+ // http://www.missionintegers.com/integer/34838300
+ mapbox::util::variant<MissionInteger> v(MissionInteger(34838300));
+ REQUIRE(v.valid());
+ REQUIRE(v.is<MissionInteger>());
+ REQUIRE(v.which() == 0);
+ REQUIRE(v.get<MissionInteger>() == MissionInteger(34838300));
+ REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(34838300));
+ // TODO: should both of the set usages below compile?
+ v.set<MissionInteger>(MissionInteger::value_type(0));
+ v.set<MissionInteger>(MissionInteger(0));
+ REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(0));
+ v = MissionInteger(1);
+ REQUIRE(v == mapbox::util::variant<MissionInteger>(MissionInteger(1)));
+}
+
+TEST_CASE("variant::which() returns zero based index of stored type", "[variant]")
+{
+ using variant_type = mapbox::util::variant<bool, std::string, std::uint64_t, std::int64_t, double, float>;
+ // which() returns index in forward order
+ REQUIRE(0 == variant_type(true).which());
+ REQUIRE(1 == variant_type(std::string("test")).which());
+ REQUIRE(2 == variant_type(std::uint64_t(0)).which());
+ REQUIRE(3 == variant_type(std::int64_t(0)).which());
+ REQUIRE(4 == variant_type(double(0.0)).which());
+ REQUIRE(5 == variant_type(float(0.0)).which());
+}
+
+TEST_CASE("get with wrong type (here: double) should throw", "[variant]")
+{
+ using variant_type = mapbox::util::variant<int, double>;
+ variant_type var = 5;
+ REQUIRE(var.is<int>());
+ REQUIRE_FALSE(var.is<double>());
+ REQUIRE(var.get<int>() == 5);
+ REQUIRE_THROWS_AS({
+ var.get<double>();
+ },
+ mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("get with wrong type (here: int) should throw", "[variant]")
+{
+ using variant_type = mapbox::util::variant<int, double>;
+ variant_type var = 5.0;
+ REQUIRE(var.is<double>());
+ REQUIRE_FALSE(var.is<int>());
+ REQUIRE(var.get<double>() == 5.0);
+ REQUIRE(mapbox::util::get<double>(var) == 5.0);
+ REQUIRE_THROWS_AS({
+ var.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+ REQUIRE_THROWS_AS({
+ mapbox::util::get<int>(var);
+ },
+ mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("get on const varint with wrong type (here: int) should throw", "[variant]")
+{
+ using variant_type = mapbox::util::variant<int, double>;
+ const variant_type var = 5.0;
+ REQUIRE(var.is<double>());
+ REQUIRE_FALSE(var.is<int>());
+ REQUIRE(var.get<double>() == 5.0);
+ REQUIRE(mapbox::util::get<double>(var) == 5.0);
+ REQUIRE_THROWS_AS({
+ var.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+ REQUIRE_THROWS_AS({
+ mapbox::util::get<int>(var);
+ },
+ mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("get with any type should throw if not initialized", "[variant]")
+{
+ mapbox::util::variant<int, double> var{mapbox::util::no_init()};
+ REQUIRE_THROWS_AS({
+ var.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+ REQUIRE_THROWS_AS({
+ var.get<double>();
+ },
+ mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("no_init variant can be copied and moved from", "[variant]")
+{
+ using variant_type = mapbox::util::variant<int, double>;
+
+ variant_type v1{mapbox::util::no_init()};
+ variant_type v2{42};
+ variant_type v3{23};
+
+ REQUIRE(v2.get<int>() == 42);
+ v2 = v1;
+ REQUIRE_THROWS_AS({
+ v2.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+
+ REQUIRE(v3.get<int>() == 23);
+ v3 = std::move(v1);
+ REQUIRE_THROWS_AS({
+ v3.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("no_init variant can be copied and moved to", "[variant]")
+{
+ using variant_type = mapbox::util::variant<int, double>;
+
+ variant_type v1{42};
+ variant_type v2{mapbox::util::no_init()};
+ variant_type v3{mapbox::util::no_init()};
+
+ REQUIRE_THROWS_AS({
+ v2.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+
+ REQUIRE(v1.get<int>() == 42);
+ v2 = v1;
+ REQUIRE(v2.get<int>() == 42);
+ REQUIRE(v1.get<int>() == 42);
+
+ REQUIRE_THROWS_AS({
+ v3.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+
+ v3 = std::move(v1);
+ REQUIRE(v3.get<int>() == 42);
+}
+
+TEST_CASE("implicit conversion", "[variant][implicit conversion]")
+{
+ using variant_type = mapbox::util::variant<int>;
+ variant_type var(5.0); // converted to int
+ REQUIRE(var.get<int>() == 5);
+ var = 6.0; // works for operator=, too
+ REQUIRE(var.get<int>() == 6);
+}
+
+TEST_CASE("implicit conversion to first type in variant type list", "[variant][implicit conversion]")
+{
+ using variant_type = mapbox::util::variant<long, char>;
+ variant_type var = 5.0; // converted to long
+ REQUIRE(var.get<long>() == 5);
+ REQUIRE_THROWS_AS({
+ var.get<char>();
+ },
+ mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("implicit conversion to unsigned char", "[variant][implicit conversion]")
+{
+ using variant_type = mapbox::util::variant<unsigned char>;
+ variant_type var = 100.0;
+ CHECK(var.get<unsigned char>() == static_cast<unsigned char>(100.0));
+ CHECK(var.get<unsigned char>() == static_cast<unsigned char>(static_cast<unsigned int>(100.0)));
+}
+
+struct dummy
+{
+};
+
+TEST_CASE("implicit conversion to a suitable type", "[variant][implicit conversion]")
+{
+ using mapbox::util::variant;
+ CHECK_NOTHROW((variant<dummy, float, std::string>(123)).get<float>());
+ CHECK_NOTHROW((variant<dummy, float, std::string>("foo")).get<std::string>());
+}
+
+TEST_CASE("value_traits for non-convertible type", "[variant::detail]")
+{
+ namespace detail = mapbox::util::detail;
+ using target_type = detail::value_traits<dummy, int>::target_type;
+ CHECK((std::is_same<target_type, void>::value) == true);
+}
+
+TEST_CASE("Type indexing should work with variants with duplicated types", "[variant::detail]")
+{
+ // Index is in reverse order
+ REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, double, std::string>::index == 3));
+ REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, double, int>::index == 3));
+ REQUIRE((mapbox::util::detail::value_traits<int, bool, int, double, std::string>::index == 2));
+ REQUIRE((mapbox::util::detail::value_traits<int, bool, int, double, int>::index == 2));
+ REQUIRE((mapbox::util::detail::value_traits<double, bool, int, double, std::string>::index == 1));
+ REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, bool, std::string>::index == 3));
+ REQUIRE((mapbox::util::detail::value_traits<std::string, bool, int, double, std::string>::index == 0));
+ REQUIRE((mapbox::util::detail::value_traits<dummy, bool, int, double, std::string>::index == mapbox::util::detail::invalid_value));
+ REQUIRE((mapbox::util::detail::value_traits<std::vector<int>, bool, int, double, std::string>::index == mapbox::util::detail::invalid_value));
+}
+
+TEST_CASE("variant default constructor", "[variant][default constructor]")
+{
+ // By default variant is initialised with (default constructed) first type in template parameters pack
+ // As a result first type in Types... must be default constructable
+ // NOTE: index in reverse order -> index = N - 1
+ using variant_type = mapbox::util::variant<int, double, std::string>;
+ REQUIRE(variant_type{}.which() == 0);
+ REQUIRE(variant_type{}.valid());
+ REQUIRE_FALSE(variant_type{mapbox::util::no_init()}.valid());
+}
+
+TEST_CASE("variant printer", "[visitor][unary visitor][printer]")
+{
+ using variant_type = mapbox::util::variant<int, double, std::string>;
+ std::vector<variant_type> var = {2.1, 123, "foo", 456};
+ std::stringstream out;
+ std::copy(var.begin(), var.end(), std::ostream_iterator<variant_type>(out, ","));
+ out << var[2];
+ REQUIRE(out.str() == "2.1,123,foo,456,foo");
+}
+
+TEST_CASE("swapping variants should do the right thing", "[variant]")
+{
+ using variant_type = mapbox::util::variant<int, double, std::string>;
+ variant_type a = 7;
+ variant_type b = 3;
+ variant_type c = 3.141;
+ variant_type d = "foo";
+ variant_type e = "a long string that is longer than small string optimization";
+
+ using std::swap;
+ swap(a, b);
+ REQUIRE(a.get<int>() == 3);
+ REQUIRE(a.which() == 0);
+ REQUIRE(b.get<int>() == 7);
+ REQUIRE(b.which() == 0);
+
+ swap(b, c);
+ REQUIRE(b.get<double>() == Approx(3.141));
+ REQUIRE(b.which() == 1);
+ REQUIRE(c.get<int>() == 7);
+ REQUIRE(c.which() == 0);
+
+ swap(b, d);
+ REQUIRE(b.get<std::string>() == "foo");
+ REQUIRE(b.which() == 2);
+ REQUIRE(d.get<double>() == Approx(3.141));
+ REQUIRE(d.which() == 1);
+
+ swap(b, e);
+ REQUIRE(b.get<std::string>() == "a long string that is longer than small string optimization");
+ REQUIRE(b.which() == 2);
+ REQUIRE(e.get<std::string>() == "foo");
+ REQUIRE(e.which() == 2);
+}
+
+TEST_CASE("variant should work with equality operators")
+{
+ using variant_type = mapbox::util::variant<int, std::string>;
+
+ variant_type a{1};
+ variant_type b{1};
+ variant_type c{2};
+ variant_type s{"foo"};
+
+ REQUIRE(a == a);
+ REQUIRE(a == b);
+ REQUIRE_FALSE(a == c);
+ REQUIRE_FALSE(a == s);
+ REQUIRE_FALSE(c == s);
+
+ REQUIRE_FALSE(a != a);
+ REQUIRE_FALSE(a != b);
+ REQUIRE(a != c);
+ REQUIRE(a != s);
+ REQUIRE(c != s);
+}
+
+TEST_CASE("variant should work with comparison operators")
+{
+ using variant_type = mapbox::util::variant<int, std::string>;
+
+ variant_type a{1};
+ variant_type b{1};
+ variant_type c{2};
+ variant_type s{"foo"};
+ variant_type t{"bar"};
+
+ REQUIRE_FALSE(a < a);
+ REQUIRE_FALSE(a < b);
+ REQUIRE(a < c);
+ REQUIRE(a < s);
+ REQUIRE(c < s);
+ REQUIRE(t < s);
+
+ REQUIRE_FALSE(a > a);
+ REQUIRE_FALSE(a > b);
+ REQUIRE_FALSE(a > c);
+ REQUIRE_FALSE(a > s);
+ REQUIRE_FALSE(c > s);
+ REQUIRE_FALSE(t > s);
+
+ REQUIRE(a <= a);
+ REQUIRE(a <= b);
+ REQUIRE(a <= c);
+ REQUIRE(a <= s);
+ REQUIRE(c <= s);
+ REQUIRE(t <= s);
+
+ REQUIRE(a >= a);
+ REQUIRE(a >= b);
+ REQUIRE_FALSE(a >= c);
+ REQUIRE_FALSE(a >= s);
+ REQUIRE_FALSE(c >= s);
+ REQUIRE_FALSE(t >= s);
+}
+
+TEST_CASE("storing reference wrappers works")
+{
+ using variant_type = mapbox::util::variant<std::reference_wrapper<int>, std::reference_wrapper<double>>;
+
+ int a = 1;
+ variant_type v{std::ref(a)};
+ REQUIRE(v.get<int>() == 1);
+ REQUIRE(mapbox::util::get<int>(v) == 1);
+ REQUIRE_THROWS_AS({
+ v.get<double>();
+ },
+ mapbox::util::bad_variant_access&);
+ REQUIRE_THROWS_AS({
+ mapbox::util::get<double>(v);
+ },
+ mapbox::util::bad_variant_access&);
+ a = 2;
+ REQUIRE(v.get<int>() == 2);
+ v.get<int>() = 3;
+ REQUIRE(a == 3);
+
+ double b = 3.141;
+ v = std::ref(b);
+ REQUIRE(v.get<double>() == Approx(3.141));
+ REQUIRE(mapbox::util::get<double>(v) == Approx(3.141));
+ REQUIRE_THROWS_AS({
+ v.get<int>();
+ },
+ mapbox::util::bad_variant_access&);
+ REQUIRE_THROWS_AS({
+ mapbox::util::get<int>(v);
+ },
+ mapbox::util::bad_variant_access&);
+ b = 2.718;
+ REQUIRE(v.get<double>() == Approx(2.718));
+ a = 3;
+ REQUIRE(v.get<double>() == Approx(2.718));
+ v.get<double>() = 4.1;
+ REQUIRE(b == Approx(4.1));
+
+ REQUIRE_THROWS_AS({
+ v.get<int>() = 4;
+ },
+ mapbox::util::bad_variant_access&);
+}
+
+TEST_CASE("storing reference wrappers to consts works")
+{
+ using variant_type = mapbox::util::variant<std::reference_wrapper<int const>, std::reference_wrapper<double const>>;
+
+ int a = 1;
+ variant_type v{std::cref(a)};
+ REQUIRE(v.get<int const>() == 1);
+ REQUIRE(v.get<int>() == 1); // this works (see #82)
+ REQUIRE(mapbox::util::get<int const>(v) == 1);
+ // REQUIRE(mapbox::util::get<int>(v) == 1); // this doesn't work (see #82)
+ REQUIRE_THROWS_AS({
+ v.get<double const>();
+ },
+ mapbox::util::bad_variant_access&);
+ REQUIRE_THROWS_AS({
+ mapbox::util::get<double const>(v);
+ },
+ mapbox::util::bad_variant_access&);
+
+ double b = 3.141;
+ v = std::cref(b);
+ REQUIRE(v.get<double const>() == Approx(3.141));
+ REQUIRE(mapbox::util::get<double const>(v) == Approx(3.141));
+ REQUIRE_THROWS_AS({
+ v.get<int const>();
+ },
+ mapbox::util::bad_variant_access&);
+ REQUIRE_THROWS_AS({
+ mapbox::util::get<int const>(v);
+ },
+ mapbox::util::bad_variant_access&);
+}
diff --git a/third_party/variant/test/unique_ptr_test.cpp b/third_party/variant/test/unique_ptr_test.cpp
index 2a51efe..6578991 100644
--- a/third_party/variant/test/unique_ptr_test.cpp
+++ b/third_party/variant/test/unique_ptr_test.cpp
@@ -1,12 +1,13 @@
+
+#include <cstdlib>
#include <iostream>
-#include <vector>
-#include <thread>
+#include <memory>
#include <string>
-#include <sstream>
+#include <typeinfo>
#include <utility>
-#include <type_traits>
-#include <boost/variant.hpp>
+
#include <boost/timer/timer.hpp>
+
#include "variant.hpp"
using namespace mapbox;
@@ -15,46 +16,48 @@ namespace test {
struct add;
struct sub;
-template <typename OpTag> struct binary_op;
-typedef util::variant<int ,
+template <typename OpTag>
+struct binary_op;
+
+typedef util::variant<int,
std::unique_ptr<binary_op<add>>,
- std::unique_ptr<binary_op<sub>>
- > expression;
+ std::unique_ptr<binary_op<sub>>>
+ expression;
template <typename Op>
struct binary_op
{
- expression left; // variant instantiated here...
+ expression left; // variant instantiated here...
expression right;
- binary_op(expression && lhs, expression && rhs)
- : left(std::move(lhs)), right(std::move(rhs)) {}
+ binary_op(expression&& lhs, expression&& rhs)
+ : left(std::move(lhs)), right(std::move(rhs))
+ {
+ }
};
-struct print : util::static_visitor<void>
+struct print
{
template <typename T>
- void operator() (T const& val) const
+ void operator()(T const& val) const
{
std::cerr << val << ":" << typeid(T).name() << std::endl;
}
};
-
-struct test : util::static_visitor<std::string>
+struct test
{
template <typename T>
- std::string operator() (T const& obj) const
+ std::string operator()(T const& obj) const
{
return std::string("TYPE_ID=") + typeid(obj).name();
}
};
-struct calculator : public util::static_visitor<int>
+struct calculator
{
-public:
-
+ public:
int operator()(int value) const
{
return value;
@@ -62,21 +65,18 @@ public:
int operator()(std::unique_ptr<binary_op<add>> const& binary) const
{
- return util::apply_visitor(calculator(), binary->left)
- + util::apply_visitor(calculator(), binary->right);
+ return util::apply_visitor(calculator(), binary->left) + util::apply_visitor(calculator(), binary->right);
}
int operator()(std::unique_ptr<binary_op<sub>> const& binary) const
{
- return util::apply_visitor(calculator(), binary->left)
- - util::apply_visitor(calculator(), binary->right);
+ return util::apply_visitor(calculator(), binary->left) - util::apply_visitor(calculator(), binary->right);
}
};
-struct to_string : public util::static_visitor<std::string>
+struct to_string
{
-public:
-
+ public:
std::string operator()(int value) const
{
return std::to_string(value);
@@ -84,21 +84,18 @@ public:
std::string operator()(std::unique_ptr<binary_op<add>> const& binary) const
{
- return util::apply_visitor(to_string(), binary->left) + std::string("+")
- + util::apply_visitor(to_string(), binary->right);
+ return util::apply_visitor(to_string(), binary->left) + std::string("+") + util::apply_visitor(to_string(), binary->right);
}
std::string operator()(std::unique_ptr<binary_op<sub>> const& binary) const
{
- return util::apply_visitor(to_string(), binary->left) + std::string("-")
- + util::apply_visitor(to_string(), binary->right);
+ return util::apply_visitor(to_string(), binary->left) + std::string("-") + util::apply_visitor(to_string(), binary->right);
}
-
};
} // namespace test
-int main (int argc, char** argv)
+int main(int argc, char** argv)
{
if (argc != 2)
{
@@ -110,17 +107,18 @@ int main (int argc, char** argv)
test::expression sum(std::unique_ptr<test::binary_op<test::add>>(new test::binary_op<test::add>(2, 3)));
test::expression result(std::unique_ptr<test::binary_op<test::sub>>(new test::binary_op<test::sub>(std::move(sum), 4)));
+
std::cerr << "TYPE OF RESULT-> " << util::apply_visitor(test::test(), result) << std::endl;
+ int total = 0;
{
boost::timer::auto_cpu_timer t;
- int total = 0;
for (std::size_t i = 0; i < NUM_ITER; ++i)
{
total += util::apply_visitor(test::calculator(), result);
}
- std::cerr << "total=" << total << std::endl;
}
+ std::cerr << "total=" << total << std::endl;
std::cerr << util::apply_visitor(test::to_string(), result) << "=" << util::apply_visitor(test::calculator(), result) << std::endl;
diff --git a/third_party/variant/test/unit.cpp b/third_party/variant/test/unit.cpp
index 9b874c7..0c7c351 100644
--- a/third_party/variant/test/unit.cpp
+++ b/third_party/variant/test/unit.cpp
@@ -1,314 +1,2 @@
-#define CATCH_CONFIG_RUNNER
+#define CATCH_CONFIG_MAIN
#include "catch.hpp"
-
-#include "variant.hpp"
-#include "variant_io.hpp"
-#include <algorithm>
-#include <cstdint>
-#include <iterator>
-#include <limits>
-#include <memory>
-#include <ostream>
-#include <sstream>
-#include <string>
-
-using namespace mapbox;
-
-template <typename T>
-struct mutating_visitor
-{
- mutating_visitor(T & val)
- : val_(val) {}
-
- void operator() (T & val) const
- {
- val = val_;
- }
-
- template <typename T1>
- void operator() (T1& ) const {} // no-op
-
- T & val_;
-};
-
-
-
-TEST_CASE( "variant version", "[variant]" ) {
- unsigned int version = VARIANT_VERSION;
- REQUIRE(version == 100);
- #if VARIANT_VERSION == 100
- REQUIRE(true);
- #else
- REQUIRE(false);
- #endif
-}
-
-TEST_CASE( "variant can be moved into vector", "[variant]" ) {
- typedef util::variant<bool,std::string> variant_type;
- variant_type v(std::string("test"));
- std::vector<variant_type> vec;
- vec.emplace_back(std::move(v));
- REQUIRE(v.get<std::string>() != std::string("test"));
- REQUIRE(vec.at(0).get<std::string>() == std::string("test"));
-}
-
-TEST_CASE( "variant should support built-in types", "[variant]" ) {
- SECTION( "bool" ) {
- util::variant<bool> v(true);
- REQUIRE(v.valid());
- REQUIRE(v.is<bool>());
- REQUIRE(v.get_type_index() == 0);
- REQUIRE(v.get<bool>() == true);
- v.set<bool>(false);
- REQUIRE(v.get<bool>() == false);
- v = true;
- REQUIRE(v == util::variant<bool>(true));
- }
- SECTION( "nullptr" ) {
- typedef std::nullptr_t value_type;
- util::variant<value_type> v(nullptr);
- REQUIRE(v.valid());
- REQUIRE(v.is<value_type>());
- REQUIRE(v.get_type_index() == 0);
- // TODO: commented since it breaks on windows: 'operator << is ambiguous'
- //REQUIRE(v.get<value_type>() == nullptr);
- // FIXME: does not compile: ./variant.hpp:340:14: error: use of overloaded operator '<<' is ambiguous (with operand types 'std::__1::basic_ostream<char>' and 'const nullptr_t')
- // https://github.com/mapbox/variant/issues/14
- //REQUIRE(v == util::variant<value_type>(nullptr));
- }
- SECTION( "unique_ptr" ) {
- typedef std::unique_ptr<std::string> value_type;
- util::variant<value_type> v(value_type(new std::string("hello")));
- REQUIRE(v.valid());
- REQUIRE(v.is<value_type>());
- REQUIRE(v.get_type_index() == 0);
- REQUIRE(*v.get<value_type>().get() == *value_type(new std::string("hello")).get());
- }
- SECTION( "string" ) {
- typedef std::string value_type;
- util::variant<value_type> v(value_type("hello"));
- REQUIRE(v.valid());
- REQUIRE(v.is<value_type>());
- REQUIRE(v.get_type_index() == 0);
- REQUIRE(v.get<value_type>() == value_type("hello"));
- v.set<value_type>(value_type("there"));
- REQUIRE(v.get<value_type>() == value_type("there"));
- v = value_type("variant");
- REQUIRE(v == util::variant<value_type>(value_type("variant")));
- }
- SECTION( "size_t" ) {
- typedef std::size_t value_type;
- util::variant<value_type> v(std::numeric_limits<value_type>::max());
- REQUIRE(v.valid());
- REQUIRE(v.is<value_type>());
- REQUIRE(v.get_type_index() == 0);
- REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
- v.set<value_type>(value_type(0));
- REQUIRE(v.get<value_type>() == value_type(0));
- v = value_type(1);
- REQUIRE(v == util::variant<value_type>(value_type(1)));
- }
- SECTION( "int8_t" ) {
- typedef std::int8_t value_type;
- util::variant<value_type> v(std::numeric_limits<value_type>::max());
- REQUIRE(v.valid());
- REQUIRE(v.is<value_type>());
- REQUIRE(v.get_type_index() == 0);
- REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
- v.set<value_type>(0);
- REQUIRE(v.get<value_type>() == value_type(0));
- v = value_type(1);
- REQUIRE(v == util::variant<value_type>(value_type(1)));
- }
- SECTION( "int16_t" ) {
- typedef std::int16_t value_type;
- util::variant<value_type> v(std::numeric_limits<value_type>::max());
- REQUIRE(v.valid());
- REQUIRE(v.is<value_type>());
- REQUIRE(v.get_type_index() == 0);
- REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
- v.set<value_type>(0);
- REQUIRE(v.get<value_type>() == value_type(0));
- v = value_type(1);
- REQUIRE(v == util::variant<value_type>(value_type(1)));
- }
- SECTION( "int32_t" ) {
- typedef std::int32_t value_type;
- util::variant<value_type> v(std::numeric_limits<value_type>::max());
- REQUIRE(v.valid());
- REQUIRE(v.is<value_type>());
- REQUIRE(v.get_type_index() == 0);
- REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
- v.set<value_type>(0);
- REQUIRE(v.get<value_type>() == value_type(0));
- v = value_type(1);
- REQUIRE(v == util::variant<value_type>(value_type(1)));
- }
- SECTION( "int64_t" ) {
- typedef std::int64_t value_type;
- util::variant<value_type> v(std::numeric_limits<value_type>::max());
- REQUIRE(v.valid());
- REQUIRE(v.is<value_type>());
- REQUIRE(v.get_type_index() == 0);
- REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
- v.set<value_type>(0);
- REQUIRE(v.get<value_type>() == value_type(0));
- v = value_type(1);
- REQUIRE(v == util::variant<value_type>(value_type(1)));
- }
-}
-
-struct MissionInteger
-{
- typedef uint64_t value_type;
- value_type val_;
- public:
- MissionInteger(uint64_t val) :
- val_(val) {}
-
- bool operator==(MissionInteger const& rhs) const
- {
- return (val_ == rhs.get());
- }
-
- uint64_t get() const
- {
- return val_;
- }
-};
-
-// TODO - remove after https://github.com/mapbox/variant/issues/14
-std::ostream& operator<<(std::ostream& os, MissionInteger const& rhs)
-{
- os << rhs.get();
- return os;
-}
-
-TEST_CASE( "variant should support custom types", "[variant]" ) {
- // http://www.missionintegers.com/integer/34838300
- util::variant<MissionInteger> v(MissionInteger(34838300));
- REQUIRE(v.valid());
- REQUIRE(v.is<MissionInteger>());
- REQUIRE(v.get_type_index() == 0);
- REQUIRE(v.get<MissionInteger>() == MissionInteger(34838300));
- REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(34838300));
- // TODO: should both of the set usages below compile?
- v.set<MissionInteger>(MissionInteger::value_type(0));
- v.set<MissionInteger>(MissionInteger(0));
- REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(0));
- v = MissionInteger(1);
- REQUIRE(v == util::variant<MissionInteger>(MissionInteger(1)));
-}
-
-// Test internal api
-TEST_CASE( "variant should correctly index types", "[variant]" ) {
- typedef util::variant<bool,std::string,std::uint64_t,std::int64_t,double,float> variant_type;
- // Index is in reverse order
- REQUIRE(variant_type(true).get_type_index() == 5);
- REQUIRE(variant_type(std::string("test")).get_type_index() == 4);
- REQUIRE(variant_type(std::uint64_t(0)).get_type_index() == 3);
- REQUIRE(variant_type(std::int64_t(0)).get_type_index() == 2);
- REQUIRE(variant_type(double(0.0)).get_type_index() == 1);
- REQUIRE(variant_type(float(0.0)).get_type_index() == 0);
-}
-
-// Test internal api
-TEST_CASE( "variant::which() returns zero based index of stored type", "[variant]" ) {
- typedef util::variant<bool,std::string,std::uint64_t,std::int64_t,double,float> variant_type;
- // Index is in reverse order
- REQUIRE(variant_type(true).which() == 0);
- REQUIRE(variant_type(std::string("test")).which() == 1);
- REQUIRE(variant_type(std::uint64_t(0)).which() == 2);
- REQUIRE(variant_type(std::int64_t(0)).which() == 3);
- REQUIRE(variant_type(double(0.0)).which() == 4);
- REQUIRE(variant_type(float(0.0)).which() == 5);
-}
-
-TEST_CASE( "get with type not in variant type list should throw", "[variant]" ) {
- typedef util::variant<int> variant_type;
- variant_type var = 5;
- REQUIRE(var.get<int>() == 5);
-}
-
-TEST_CASE( "get with wrong type (here: double) should throw", "[variant]" ) {
- typedef util::variant<int, double> variant_type;
- variant_type var = 5;
- REQUIRE(var.get<int>() == 5);
- REQUIRE_THROWS(var.get<double>());
-}
-
-TEST_CASE( "get with wrong type (here: int) should throw", "[variant]" ) {
- typedef util::variant<int, double> variant_type;
- variant_type var = 5.0;
- REQUIRE(var.get<double>() == 5.0);
- REQUIRE_THROWS(var.get<int>());
-}
-
-TEST_CASE( "implicit conversion", "[variant][implicit conversion]" ) {
- typedef util::variant<int> variant_type;
- variant_type var(5.0); // converted to int
- REQUIRE(var.get<int>() == 5);
- var = 6.0; // works for operator=, too
- REQUIRE(var.get<int>() == 6);
-}
-
-TEST_CASE( "implicit conversion to first type in variant type list", "[variant][implicit conversion]" ) {
- typedef util::variant<long, char> variant_type;
- variant_type var = 5.0; // converted to long
- REQUIRE(var.get<long>() == 5);
- REQUIRE_THROWS(var.get<char>());
-}
-
-TEST_CASE( "implicit conversion to unsigned char", "[variant][implicit conversion]" ) {
- typedef util::variant<unsigned char> variant_type;
- variant_type var = 100.0;
- CHECK(var.get<unsigned char>() == static_cast<unsigned char>(100.0));
- CHECK(var.get<unsigned char>() == static_cast<unsigned char>(static_cast<unsigned int>(100.0)));
-}
-
-struct dummy {};
-
-TEST_CASE( "variant value traits", "[variant::detail]" ) {
- // Users should not create variants with duplicated types
- // however our type indexing should still work
- // Index is in reverse order
- REQUIRE((util::detail::value_traits<bool, bool, int, double, std::string>::index == 3));
- REQUIRE((util::detail::value_traits<int, bool, int, double, std::string>::index == 2));
- REQUIRE((util::detail::value_traits<double, bool, int, double, std::string>::index == 1));
- REQUIRE((util::detail::value_traits<std::string, bool, int, double, std::string>::index == 0));
- REQUIRE((util::detail::value_traits<dummy, bool, int, double, std::string>::index == util::detail::invalid_value));
- REQUIRE((util::detail::value_traits<std::vector<int>, bool, int, double, std::string>::index == util::detail::invalid_value));
-}
-
-TEST_CASE( "variant default constructor", "[variant][default constructor]" ) {
- // By default variant is initialised with (default constructed) first type in template parameters pack
- // As a result first type in Types... must be default constructable
- // NOTE: index in reverse order -> index = N - 1
- REQUIRE((util::variant<int, double, std::string>().get_type_index() == 2));
- REQUIRE((util::variant<int, double, std::string>(util::no_init()).get_type_index() == util::detail::invalid_value));
-}
-
-TEST_CASE( "variant visitation", "[visitor][unary visitor]" ) {
- util::variant<int, double, std::string> var(123);
- REQUIRE(var.get<int>() == 123);
- int val = 456;
- mutating_visitor<int> visitor(val);
- util::apply_visitor(visitor, var);
- REQUIRE(var.get<int>() == 456);
-}
-
-TEST_CASE( "variant printer", "[visitor][unary visitor][printer]" ) {
- typedef util::variant<int, double, std::string> variant_type;
- std::vector<variant_type> var = {2.1, 123, "foo", 456};
- std::stringstream out;
- std::copy(var.begin(), var.end(), std::ostream_iterator<variant_type>(out, ","));
- out << var[2];
- REQUIRE(out.str() == "2.1,123,foo,456,foo");
-}
-
-int main (int argc, char* const argv[])
-{
- int result = Catch::Session().run(argc, argv);
- if (!result) printf("\x1b[1;32m ✓ \x1b[0m\n");
- return result;
-}
diff --git a/third_party/variant/test/variant_hello_world.cpp b/third_party/variant/test/variant_hello_world.cpp
deleted file mode 100644
index b445fdb..0000000
--- a/third_party/variant/test/variant_hello_world.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#include "variant.hpp"
-#include <cstdint>
-#include <stdexcept>
-
-using namespace mapbox;
-
-struct check : util::static_visitor<>
-{
- template <typename T>
- void operator() (T const& val) const
- {
- if (val != 0) throw std::runtime_error("invalid");
- }
-};
-
-
-int main() {
- typedef util::variant<bool, int, double> variant_type;
- variant_type v(0);
- util::apply_visitor(check(), v);
- return 0;
-}
diff --git a/third_party/variant/variant.gyp b/third_party/variant/variant.gyp
index 712cafe..b1f3801 100644
--- a/third_party/variant/variant.gyp
+++ b/third_party/variant/variant.gyp
@@ -7,15 +7,29 @@
"target_name": "tests",
"type": "executable",
"sources": [
- "test/unit.cpp"
+ "test/unit.cpp",
+ "test/t/binary_visitor_1.cpp",
+ "test/t/binary_visitor_2.cpp",
+ "test/t/binary_visitor_3.cpp",
+ "test/t/binary_visitor_4.cpp",
+ "test/t/binary_visitor_5.cpp",
+ "test/t/binary_visitor_6.cpp",
+ "test/t/issue21.cpp",
+ "test/t/mutating_visitor.cpp",
+ "test/t/optional.cpp",
+ "test/t/recursive_wrapper.cpp",
+ "test/t/sizeof.cpp",
+ "test/t/unary_visitor.cpp",
+ "test/t/variant.cpp"
],
"xcode_settings": {
"SDKROOT": "macosx",
"SUPPORTED_PLATFORMS":["macosx"]
},
"include_dirs": [
- "./"
+ "./",
+ "test/include"
]
}
]
-}
\ No newline at end of file
+}
diff --git a/third_party/variant/variant.hpp b/third_party/variant/variant.hpp
index 90aacae..db5d3c8 100644
--- a/third_party/variant/variant.hpp
+++ b/third_party/variant/variant.hpp
@@ -1,19 +1,35 @@
#ifndef MAPBOX_UTIL_VARIANT_HPP
#define MAPBOX_UTIL_VARIANT_HPP
-#include <utility>
-#include <typeinfo>
-#include <type_traits>
+#include <cassert>
+#include <cstddef> // size_t
+#include <new> // operator new
#include <stdexcept> // runtime_error
-#include <new> // operator new
-#include <cstddef> // size_t
-#include <iosfwd>
#include <string>
+#include <tuple>
+#include <type_traits>
+#include <typeinfo>
+#include <utility>
#include "recursive_wrapper.hpp"
+// clang-format off
+// [[deprecated]] is only available in C++14, use this for the time being
+#if __cplusplus <= 201103L
+# ifdef __GNUC__
+# define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated))
+# elif defined(_MSC_VER)
+# define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated)
+# else
+# define MAPBOX_VARIANT_DEPRECATED
+# endif
+#else
+# define MAPBOX_VARIANT_DEPRECATED [[deprecated]]
+#endif
+
+
#ifdef _MSC_VER
- // http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx
+ // https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
#ifdef NDEBUG
#define VARIANT_INLINE __forceinline
#else
@@ -26,22 +42,37 @@
#define VARIANT_INLINE __attribute__((noinline))
#endif
#endif
+// clang-format on
-#define VARIANT_MAJOR_VERSION 0
+#define VARIANT_MAJOR_VERSION 1
#define VARIANT_MINOR_VERSION 1
#define VARIANT_PATCH_VERSION 0
-// translates to 100
-#define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION)
+#define VARIANT_VERSION (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + (VARIANT_PATCH_VERSION)
+
+namespace mapbox {
+namespace util {
+
+// XXX This should derive from std::logic_error instead of std::runtime_error.
+// See https://github.com/mapbox/variant/issues/48 for details.
+class bad_variant_access : public std::runtime_error
+{
+
+ public:
+ explicit bad_variant_access(const std::string& what_arg)
+ : runtime_error(what_arg) {}
-namespace mapbox { namespace util {
+ explicit bad_variant_access(const char* what_arg)
+ : runtime_error(what_arg) {}
+
+}; // class bad_variant_access
-// static visitor
template <typename R = void>
-struct static_visitor
+struct MAPBOX_VARIANT_DEPRECATED static_visitor
{
using result_type = R;
-protected:
+
+ protected:
static_visitor() {}
~static_visitor() {}
};
@@ -50,14 +81,15 @@ namespace detail {
static constexpr std::size_t invalid_value = std::size_t(-1);
-template <typename T, typename...Types>
+template <typename T, typename... Types>
struct direct_type;
-template <typename T, typename First, typename...Types>
+template <typename T, typename First, typename... Types>
struct direct_type<T, First, Types...>
{
static constexpr std::size_t index = std::is_same<T, First>::value
- ? sizeof...(Types) : direct_type<T, Types...>::index;
+ ? sizeof...(Types)
+ : direct_type<T, Types...>::index;
};
template <typename T>
@@ -66,14 +98,15 @@ struct direct_type<T>
static constexpr std::size_t index = invalid_value;
};
-template <typename T, typename...Types>
+template <typename T, typename... Types>
struct convertible_type;
-template <typename T, typename First, typename...Types>
+template <typename T, typename First, typename... Types>
struct convertible_type<T, First, Types...>
{
static constexpr std::size_t index = std::is_convertible<T, First>::value
- ? sizeof...(Types) : convertible_type<T, Types...>::index;
+ ? sizeof...(Types)
+ : convertible_type<T, Types...>::index;
};
template <typename T>
@@ -82,64 +115,53 @@ struct convertible_type<T>
static constexpr std::size_t index = invalid_value;
};
-template <typename T, typename...Types>
+template <typename T, typename... Types>
struct value_traits
{
- static constexpr std::size_t direct_index = direct_type<T, Types...>::index;
- static constexpr std::size_t index =
- (direct_index == invalid_value) ? convertible_type<T, Types...>::index : direct_index;
+ using value_type = typename std::remove_reference<T>::type;
+ static constexpr std::size_t direct_index = direct_type<value_type, Types...>::index;
+ static constexpr bool is_direct = direct_index != invalid_value;
+ static constexpr std::size_t index = is_direct ? direct_index : convertible_type<value_type, Types...>::index;
+ static constexpr bool is_valid = index != invalid_value;
+ static constexpr std::size_t tindex = is_valid ? sizeof...(Types)-index : 0;
+ using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
};
// check if T is in Types...
-template <typename T, typename...Types>
+template <typename T, typename... Types>
struct has_type;
template <typename T, typename First, typename... Types>
struct has_type<T, First, Types...>
{
- static constexpr bool value = std::is_same<T, First>::value
- || has_type<T, Types...>::value;
+ static constexpr bool value = std::is_same<T, First>::value || has_type<T, Types...>::value;
};
template <typename T>
-struct has_type<T> : std::false_type {};
-//
+struct has_type<T> : std::false_type
+{
+};
-template <typename T, typename...Types>
+template <typename T, typename... Types>
struct is_valid_type;
template <typename T, typename First, typename... Types>
struct is_valid_type<T, First, Types...>
{
- static constexpr bool value = std::is_convertible<T, First>::value
- || is_valid_type<T, Types...>::value;
+ static constexpr bool value = std::is_convertible<T, First>::value || is_valid_type<T, Types...>::value;
};
template <typename T>
-struct is_valid_type<T> : std::false_type {};
-
-template <std::size_t N, typename ... Types>
-struct select_type
+struct is_valid_type<T> : std::false_type
{
- static_assert(N < sizeof...(Types), "index out of bounds");
};
-template <std::size_t N, typename T, typename ... Types>
-struct select_type<N, T, Types...>
-{
- using type = typename select_type<N - 1, Types...>::type;
-};
-
-template <typename T, typename ... Types>
-struct select_type<0, T, Types...>
+template <typename T, typename R = void>
+struct enable_if_type
{
- using type = T;
+ using type = R;
};
-
-template <typename T, typename R = void>
-struct enable_if_type { using type = R; };
-
template <typename F, typename V, typename Enable = void>
struct result_of_unary_visit
{
@@ -147,29 +169,24 @@ struct result_of_unary_visit
};
template <typename F, typename V>
-struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type >
+struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
{
using type = typename F::result_type;
};
-template <typename F, typename V, class Enable = void>
+template <typename F, typename V, typename Enable = void>
struct result_of_binary_visit
{
- using type = typename std::result_of<F(V&,V&)>::type;
+ using type = typename std::result_of<F(V&, V&)>::type;
};
-
template <typename F, typename V>
-struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type >
+struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
{
using type = typename F::result_type;
};
-
-} // namespace detail
-
-
-template <std::size_t arg1, std::size_t ... others>
+template <std::size_t arg1, std::size_t... others>
struct static_max;
template <std::size_t arg>
@@ -178,326 +195,305 @@ struct static_max<arg>
static const std::size_t value = arg;
};
-template <std::size_t arg1, std::size_t arg2, std::size_t ... others>
+template <std::size_t arg1, std::size_t arg2, std::size_t... others>
struct static_max<arg1, arg2, others...>
{
- static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value :
- static_max<arg2, others...>::value;
+ static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value : static_max<arg2, others...>::value;
};
-template<typename... Types>
+template <typename... Types>
struct variant_helper;
-template<typename T, typename... Types>
+template <typename T, typename... Types>
struct variant_helper<T, Types...>
{
- VARIANT_INLINE static void destroy(const std::size_t id, void * data)
+ VARIANT_INLINE static void destroy(const std::size_t type_index, void* data)
{
- if (id == sizeof...(Types))
+ if (type_index == sizeof...(Types))
{
reinterpret_cast<T*>(data)->~T();
}
else
{
- variant_helper<Types...>::destroy(id, data);
+ variant_helper<Types...>::destroy(type_index, data);
}
}
- VARIANT_INLINE static void move(const std::size_t old_id, void * old_value, void * new_value)
+ VARIANT_INLINE static void move(const std::size_t old_type_index, void* old_value, void* new_value)
{
- if (old_id == sizeof...(Types))
+ if (old_type_index == sizeof...(Types))
{
new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
- //std::memcpy(new_value, old_value, sizeof(T));
- // ^^ DANGER: this should only be considered for relocatable types e.g built-in types
- // Also, I don't see any measurable performance benefit just yet
}
else
{
- variant_helper<Types...>::move(old_id, old_value, new_value);
+ variant_helper<Types...>::move(old_type_index, old_value, new_value);
}
}
- VARIANT_INLINE static void copy(const std::size_t old_id, const void * old_value, void * new_value)
+ VARIANT_INLINE static void copy(const std::size_t old_type_index, const void* old_value, void* new_value)
{
- if (old_id == sizeof...(Types))
+ if (old_type_index == sizeof...(Types))
{
new (new_value) T(*reinterpret_cast<const T*>(old_value));
}
else
{
- variant_helper<Types...>::copy(old_id, old_value, new_value);
- }
- }
-
- VARIANT_INLINE static void direct_swap(const std::size_t id, void * lhs, void * rhs)
- {
- using std::swap; //enable ADL
- if (id == sizeof...(Types))
- {
- // both lhs and rhs hold T
- swap(*reinterpret_cast<T*>(lhs), *reinterpret_cast<T*>(rhs));
- }
- else
- {
- variant_helper<Types...>::direct_swap(id, lhs, rhs);
+ variant_helper<Types...>::copy(old_type_index, old_value, new_value);
}
}
};
-template<> struct variant_helper<>
+template <>
+struct variant_helper<>
{
- VARIANT_INLINE static void destroy(const std::size_t, void *) {}
- VARIANT_INLINE static void move(const std::size_t, void *, void *) {}
- VARIANT_INLINE static void copy(const std::size_t, const void *, void *) {}
- VARIANT_INLINE static void direct_swap(const std::size_t, void *, void *) {}
+ VARIANT_INLINE static void destroy(const std::size_t, void*) {}
+ VARIANT_INLINE static void move(const std::size_t, void*, void*) {}
+ VARIANT_INLINE static void copy(const std::size_t, const void*, void*) {}
};
-namespace detail {
-
template <typename T>
struct unwrapper
{
- T const& operator() (T const& obj) const
- {
- return obj;
- }
-
- T& operator() (T & obj) const
- {
- return obj;
- }
+ static T const& apply_const(T const& obj) { return obj; }
+ static T& apply(T& obj) { return obj; }
};
-
template <typename T>
struct unwrapper<recursive_wrapper<T>>
{
- auto operator() (recursive_wrapper<T> const& obj) const
+ static auto apply_const(recursive_wrapper<T> const& obj)
-> typename recursive_wrapper<T>::type const&
{
return obj.get();
}
+ static auto apply(recursive_wrapper<T>& obj)
+ -> typename recursive_wrapper<T>::type&
+ {
+ return obj.get();
+ }
};
template <typename T>
struct unwrapper<std::reference_wrapper<T>>
{
- auto operator() (std::reference_wrapper<T> const& obj) const
+ static auto apply_const(std::reference_wrapper<T> const& obj)
-> typename std::reference_wrapper<T>::type const&
{
return obj.get();
}
-
+ static auto apply(std::reference_wrapper<T>& obj)
+ -> typename std::reference_wrapper<T>::type&
+ {
+ return obj.get();
+ }
};
-
-template <typename F, typename V, typename R, typename...Types>
+template <typename F, typename V, typename R, typename... Types>
struct dispatcher;
-template <typename F, typename V, typename R, typename T, typename...Types>
+template <typename F, typename V, typename R, typename T, typename... Types>
struct dispatcher<F, V, R, T, Types...>
{
- using result_type = R;
- VARIANT_INLINE static result_type apply_const(V const& v, F f)
+ VARIANT_INLINE static R apply_const(V const& v, F&& f)
{
- if (v.get_type_index() == sizeof...(Types))
+ if (v.template is<T>())
{
- return f(unwrapper<T>()(v. template get<T>()));
+ return f(unwrapper<T>::apply_const(v.template get<T>()));
}
else
{
- return dispatcher<F, V, R, Types...>::apply_const(v, f);
+ return dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
}
}
- VARIANT_INLINE static result_type apply(V & v, F f)
+ VARIANT_INLINE static R apply(V& v, F&& f)
{
- if (v.get_type_index() == sizeof...(Types))
+ if (v.template is<T>())
{
- return f(unwrapper<T>()(v. template get<T>()));
+ return f(unwrapper<T>::apply(v.template get<T>()));
}
else
{
- return dispatcher<F, V, R, Types...>::apply(v, f);
+ return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
}
}
};
-template<typename F, typename V, typename R>
-struct dispatcher<F, V, R>
+template <typename F, typename V, typename R, typename T>
+struct dispatcher<F, V, R, T>
{
- using result_type = R;
- VARIANT_INLINE static result_type apply_const(V const&, F)
+ VARIANT_INLINE static R apply_const(V const& v, F&& f)
{
- throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
+ return f(unwrapper<T>::apply_const(v.template get<T>()));
}
- VARIANT_INLINE static result_type apply(V &, F)
+ VARIANT_INLINE static R apply(V& v, F&& f)
{
- throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
+ return f(unwrapper<T>::apply(v.template get<T>()));
}
};
-
-template <typename F, typename V, typename R, typename T, typename...Types>
+template <typename F, typename V, typename R, typename T, typename... Types>
struct binary_dispatcher_rhs;
-template <typename F, typename V, typename R, typename T0, typename T1, typename...Types>
+template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
{
- using result_type = R;
- VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
+ VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
{
- if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
+ if (rhs.template is<T1>()) // call binary functor
{
- return f(unwrapper<T0>()(lhs. template get<T0>()),
- unwrapper<T1>()(rhs. template get<T1>()));
+ return f(unwrapper<T0>::apply_const(lhs.template get<T0>()),
+ unwrapper<T1>::apply_const(rhs.template get<T1>()));
}
else
{
- return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, f);
+ return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
}
}
- VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
+ VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{
- if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
+ if (rhs.template is<T1>()) // call binary functor
{
- return f(unwrapper<T0>()(lhs. template get<T0>()),
- unwrapper<T1>()(rhs. template get<T1>()));
+ return f(unwrapper<T0>::apply(lhs.template get<T0>()),
+ unwrapper<T1>::apply(rhs.template get<T1>()));
}
else
{
- return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, f);
+ return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
}
}
-
};
-template<typename F, typename V, typename R, typename T>
-struct binary_dispatcher_rhs<F, V, R, T>
+template <typename F, typename V, typename R, typename T0, typename T1>
+struct binary_dispatcher_rhs<F, V, R, T0, T1>
{
- using result_type = R;
- VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+ VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
{
- throw std::runtime_error("binary dispatch: FAIL");
+ return f(unwrapper<T0>::apply_const(lhs.template get<T0>()),
+ unwrapper<T1>::apply_const(rhs.template get<T1>()));
}
- VARIANT_INLINE static result_type apply(V &, V &, F)
+
+ VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{
- throw std::runtime_error("binary dispatch: FAIL");
+ return f(unwrapper<T0>::apply(lhs.template get<T0>()),
+ unwrapper<T1>::apply(rhs.template get<T1>()));
}
};
-
-template <typename F, typename V, typename R, typename T, typename...Types>
+template <typename F, typename V, typename R, typename T, typename... Types>
struct binary_dispatcher_lhs;
-template <typename F, typename V, typename R, typename T0, typename T1, typename...Types>
+template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
{
- using result_type = R;
- VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
+ VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
{
- if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
+ if (lhs.template is<T1>()) // call binary functor
{
- return f(lhs. template get<T1>(), rhs. template get<T0>());
+ return f(unwrapper<T1>::apply_const(lhs.template get<T1>()),
+ unwrapper<T0>::apply_const(rhs.template get<T0>()));
}
else
{
- return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, f);
+ return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
}
}
- VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
+ VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{
- if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
+ if (lhs.template is<T1>()) // call binary functor
{
- return f(lhs. template get<T1>(), rhs. template get<T0>());
+ return f(unwrapper<T1>::apply(lhs.template get<T1>()),
+ unwrapper<T0>::apply(rhs.template get<T0>()));
}
else
{
- return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, f);
+ return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
}
}
-
};
-template<typename F, typename V, typename R, typename T>
-struct binary_dispatcher_lhs<F, V, R, T>
+template <typename F, typename V, typename R, typename T0, typename T1>
+struct binary_dispatcher_lhs<F, V, R, T0, T1>
{
- using result_type = R;
- VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+ VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
{
- throw std::runtime_error("binary dispatch: FAIL");
+ return f(unwrapper<T1>::apply_const(lhs.template get<T1>()),
+ unwrapper<T0>::apply_const(rhs.template get<T0>()));
}
- VARIANT_INLINE static result_type apply(V &, V &, F)
+ VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{
- throw std::runtime_error("binary dispatch: FAIL");
+ return f(unwrapper<T1>::apply(lhs.template get<T1>()),
+ unwrapper<T0>::apply(rhs.template get<T0>()));
}
};
-template <typename F, typename V, typename R, typename...Types>
+template <typename F, typename V, typename R, typename... Types>
struct binary_dispatcher;
-template <typename F, typename V, typename R, typename T, typename...Types>
+template <typename F, typename V, typename R, typename T, typename... Types>
struct binary_dispatcher<F, V, R, T, Types...>
{
- using result_type = R;
- VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f)
+ VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
{
- if (v0.get_type_index() == sizeof...(Types))
+ if (v0.template is<T>())
{
- if (v0.get_type_index() == v1.get_type_index())
+ if (v1.template is<T>())
{
- return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
+ return f(unwrapper<T>::apply_const(v0.template get<T>()),
+ unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor
}
else
{
- return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, f);
+ return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
}
}
- else if (v1.get_type_index() == sizeof...(Types))
+ else if (v1.template is<T>())
{
- return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, f);
+ return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
}
- return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, f);
+ return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
}
- VARIANT_INLINE static result_type apply(V & v0, V & v1, F f)
+ VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
{
- if (v0.get_type_index() == sizeof...(Types))
+ if (v0.template is<T>())
{
- if (v0.get_type_index() == v1.get_type_index())
+ if (v1.template is<T>())
{
- return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
+ return f(unwrapper<T>::apply(v0.template get<T>()),
+ unwrapper<T>::apply(v1.template get<T>())); // call binary functor
}
else
{
- return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, f);
+ return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
}
}
- else if (v1.get_type_index() == sizeof...(Types))
+ else if (v1.template is<T>())
{
- return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, f);
+ return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
}
- return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, f);
+ return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
}
};
-template<typename F, typename V, typename R>
-struct binary_dispatcher<F, V, R>
+template <typename F, typename V, typename R, typename T>
+struct binary_dispatcher<F, V, R, T>
{
- using result_type = R;
- VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+ VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
{
- throw std::runtime_error("binary dispatch: FAIL");
+ return f(unwrapper<T>::apply_const(v0.template get<T>()),
+ unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor
}
- VARIANT_INLINE static result_type apply(V &, V &, F)
+ VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
{
- throw std::runtime_error("binary dispatch: FAIL");
+ return f(unwrapper<T>::apply(v0.template get<T>()),
+ unwrapper<T>::apply(v1.template get<T>())); // call binary functor
}
};
@@ -523,60 +519,77 @@ struct less_comp
template <typename Variant, typename Comp>
class comparer
{
-public:
+ public:
explicit comparer(Variant const& lhs) noexcept
: lhs_(lhs) {}
comparer& operator=(comparer const&) = delete;
// visitor
- template<typename T>
+ template <typename T>
bool operator()(T const& rhs_content) const
{
T const& lhs_content = lhs_.template get<T>();
return Comp()(lhs_content, rhs_content);
}
-private:
+
+ private:
Variant const& lhs_;
};
+// True if Predicate matches for all of the types Ts
+template <template <typename> class Predicate, typename... Ts>
+struct static_all_of : std::is_same<std::tuple<std::true_type, typename Predicate<Ts>::type...>,
+ std::tuple<typename Predicate<Ts>::type..., std::true_type>>
+{
+};
+
+// True if Predicate matches for none of the types Ts
+template <template <typename> class Predicate, typename... Ts>
+struct static_none_of : std::is_same<std::tuple<std::false_type, typename Predicate<Ts>::type...>,
+ std::tuple<typename Predicate<Ts>::type..., std::false_type>>
+{
+};
} // namespace detail
-struct no_init {};
+struct no_init
+{
+};
-template<typename... Types>
+template <typename... Types>
class variant
{
-private:
+ static_assert(sizeof...(Types) > 0, "Template parameter type list of variant can not be empty");
+ static_assert(detail::static_none_of<std::is_reference, Types...>::value, "Variant can not hold reference types. Maybe use std::reference?");
- static const std::size_t data_size = static_max<sizeof(Types)...>::value;
- static const std::size_t data_align = static_max<alignof(Types)...>::value;
+ private:
+ static const std::size_t data_size = detail::static_max<sizeof(Types)...>::value;
+ static const std::size_t data_align = detail::static_max<alignof(Types)...>::value;
+ using first_type = typename std::tuple_element<0, std::tuple<Types...>>::type;
using data_type = typename std::aligned_storage<data_size, data_align>::type;
- using helper_type = variant_helper<Types...>;
+ using helper_type = detail::variant_helper<Types...>;
std::size_t type_index;
data_type data;
-public:
-
- VARIANT_INLINE variant()
- : type_index(sizeof...(Types) - 1)
+ public:
+ VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value)
+ : type_index(sizeof...(Types)-1)
{
- new (&data) typename detail::select_type<0, Types...>::type();
+ static_assert(std::is_default_constructible<first_type>::value, "First type in variant must be default constructible to allow default construction of variant");
+ new (&data) first_type();
}
- VARIANT_INLINE variant(no_init)
+ VARIANT_INLINE variant(no_init) noexcept
: type_index(detail::invalid_value) {}
// http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
- template <typename T, class = typename std::enable_if<
- detail::is_valid_type<typename std::remove_reference<T>::type, Types...>::value>::type>
- VARIANT_INLINE variant(T && val) noexcept
- : type_index(detail::value_traits<typename std::remove_reference<T>::type, Types...>::index)
+ template <typename T, typename Traits = detail::value_traits<T, Types...>,
+ typename Enable = typename std::enable_if<Traits::is_valid>::type>
+ VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value)
+ : type_index(Traits::index)
{
- constexpr std::size_t index = sizeof...(Types) - detail::value_traits<typename std::remove_reference<T>::type, Types...>::index - 1;
- using target_type = typename detail::select_type<index, Types...>::type;
- new (&data) target_type(std::forward<T>(val)); // nothrow
+ new (&data) typename Traits::target_type(std::forward<T>(val));
}
VARIANT_INLINE variant(variant<Types...> const& old)
@@ -585,13 +598,13 @@ public:
helper_type::copy(old.type_index, &old.data, &data);
}
- VARIANT_INLINE variant(variant<Types...>&& old) noexcept
+ VARIANT_INLINE variant(variant<Types...>&& old) noexcept(std::is_nothrow_move_constructible<std::tuple<Types...>>::value)
: type_index(old.type_index)
{
helper_type::move(old.type_index, &old.data, &data);
}
-private:
+ private:
VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
{
helper_type::destroy(type_index, &data);
@@ -600,7 +613,7 @@ private:
type_index = rhs.type_index;
}
- VARIANT_INLINE void move_assign(variant<Types...> && rhs)
+ VARIANT_INLINE void move_assign(variant<Types...>&& rhs)
{
helper_type::destroy(type_index, &data);
type_index = detail::invalid_value;
@@ -608,8 +621,8 @@ private:
type_index = rhs.type_index;
}
-public:
- VARIANT_INLINE variant<Types...>& operator=(variant<Types...> && other)
+ public:
+ VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
{
move_assign(std::move(other));
return *this;
@@ -624,7 +637,7 @@ public:
// conversions
// move-assign
template <typename T>
- VARIANT_INLINE variant<Types...>& operator=(T && rhs) noexcept
+ VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept
{
variant<Types...> temp(std::forward<T>(rhs));
move_assign(std::move(temp));
@@ -640,30 +653,30 @@ public:
return *this;
}
- template<typename T>
+ template <typename T>
VARIANT_INLINE bool is() const
{
static_assert(detail::has_type<T, Types...>::value, "invalid type in T in `is<T>()` for this variant");
- return (type_index == detail::direct_type<T, Types...>::index);
+ return type_index == detail::direct_type<T, Types...>::index;
}
VARIANT_INLINE bool valid() const
{
- return (type_index != detail::invalid_value);
+ return type_index != detail::invalid_value;
}
- template<typename T, typename... Args>
+ template <typename T, typename... Args>
VARIANT_INLINE void set(Args&&... args)
{
helper_type::destroy(type_index, &data);
+ type_index = detail::invalid_value;
new (&data) T(std::forward<Args>(args)...);
type_index = detail::direct_type<T, Types...>::index;
}
// get<T>()
- template<typename T, typename std::enable_if<
- (detail::direct_type<T, Types...>::index != detail::invalid_value)
- >::type* = nullptr>
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T& get()
{
if (type_index == detail::direct_type<T, Types...>::index)
@@ -672,13 +685,12 @@ public:
}
else
{
- throw std::runtime_error("in get<T>()");
+ throw bad_variant_access("in get<T>()");
}
}
template <typename T, typename std::enable_if<
- (detail::direct_type<T, Types...>::index != detail::invalid_value)
- >::type* = nullptr>
+ (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T const& get() const
{
if (type_index == detail::direct_type<T, Types...>::index)
@@ -687,14 +699,13 @@ public:
}
else
{
- throw std::runtime_error("in get<T>()");
+ throw bad_variant_access("in get<T>()");
}
}
// get<T>() - T stored as recursive_wrapper<T>
template <typename T, typename std::enable_if<
- (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)
- >::type* = nullptr>
+ (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T& get()
{
if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
@@ -703,13 +714,12 @@ public:
}
else
{
- throw std::runtime_error("in get<T>()");
+ throw bad_variant_access("in get<T>()");
}
}
- template <typename T,typename std::enable_if<
- (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)
- >::type* = nullptr>
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T const& get() const
{
if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
@@ -718,14 +728,13 @@ public:
}
else
{
- throw std::runtime_error("in get<T>()");
+ throw bad_variant_access("in get<T>()");
}
}
// get<T>() - T stored as std::reference_wrapper<T>
template <typename T, typename std::enable_if<
- (detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)
- >::type* = nullptr>
+ (detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T& get()
{
if (type_index == detail::direct_type<std::reference_wrapper<T>, Types...>::index)
@@ -734,13 +743,12 @@ public:
}
else
{
- throw std::runtime_error("in get<T>()");
+ throw bad_variant_access("in get<T>()");
}
}
- template <typename T,typename std::enable_if<
- (detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)
- >::type* = nullptr>
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T const& get() const
{
if (type_index == detail::direct_type<std::reference_wrapper<T const>, Types...>::index)
@@ -749,69 +757,55 @@ public:
}
else
{
- throw std::runtime_error("in get<T>()");
+ throw bad_variant_access("in get<T>()");
}
}
- VARIANT_INLINE std::size_t get_type_index() const
+ // This function is deprecated because it returns an internal index field.
+ // Use which() instead.
+ MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const
{
return type_index;
}
VARIANT_INLINE int which() const noexcept
{
- return static_cast<int>(sizeof...(Types) - type_index - 1);
+ return static_cast<int>(sizeof...(Types)-type_index - 1);
}
// visitor
// unary
- template <typename F, typename V>
- auto VARIANT_INLINE
- static visit(V const& v, F f)
- -> decltype(detail::dispatcher<F, V,
- typename detail::result_of_unary_visit<F,
- typename detail::select_type<0, Types...>::type>::type, Types...>::apply_const(v, f))
+ template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
+ auto VARIANT_INLINE static visit(V const& v, F&& f)
+ -> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f)))
{
- using R = typename detail::result_of_unary_visit<F, typename detail::select_type<0, Types...>::type>::type;
- return detail::dispatcher<F, V, R, Types...>::apply_const(v, f);
+ return detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
}
// non-const
- template <typename F, typename V>
- auto VARIANT_INLINE
- static visit(V & v, F f)
- -> decltype(detail::dispatcher<F, V,
- typename detail::result_of_unary_visit<F,
- typename detail::select_type<0, Types...>::type>::type, Types...>::apply(v, f))
+ template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
+ auto VARIANT_INLINE static visit(V& v, F&& f)
+ -> decltype(detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)))
{
- using R = typename detail::result_of_unary_visit<F, typename detail::select_type<0, Types...>::type>::type;
- return detail::dispatcher<F, V, R, Types...>::apply(v, f);
+ return detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
}
// binary
// const
- template <typename F, typename V>
- auto VARIANT_INLINE
- static binary_visit(V const& v0, V const& v1, F f)
- -> decltype(detail::binary_dispatcher<F, V,
- typename detail::result_of_binary_visit<F,
- typename detail::select_type<0, Types...>::type>::type, Types...>::apply_const(v0, v1, f))
+ template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
+ auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f)
+ -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)))
{
- using R = typename detail::result_of_binary_visit<F,typename detail::select_type<0, Types...>::type>::type;
- return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, f);
+ return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
}
// non-const
- template <typename F, typename V>
- auto VARIANT_INLINE
- static binary_visit(V& v0, V& v1, F f)
- -> decltype(detail::binary_dispatcher<F, V,
- typename detail::result_of_binary_visit<F,
- typename detail::select_type<0, Types...>::type>::type, Types...>::apply(v0, v1, f))
+ template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
+ auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f)
+ -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f)))
{
- using R = typename detail::result_of_binary_visit<F,typename detail::select_type<0, Types...>::type>::type;
- return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, f);
+ return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
}
- ~variant() noexcept
+ ~variant() noexcept // no-throw destructor
{
helper_type::destroy(type_index, &data);
}
@@ -820,67 +814,88 @@ public:
// equality
VARIANT_INLINE bool operator==(variant const& rhs) const
{
- if (this->get_type_index() != rhs.get_type_index())
+ assert(valid() && rhs.valid());
+ if (this->which() != rhs.which())
+ {
return false;
+ }
detail::comparer<variant, detail::equal_comp> visitor(*this);
return visit(rhs, visitor);
}
+
+ VARIANT_INLINE bool operator!=(variant const& rhs) const
+ {
+ return !(*this == rhs);
+ }
+
// less than
VARIANT_INLINE bool operator<(variant const& rhs) const
{
- if (this->get_type_index() != rhs.get_type_index())
+ assert(valid() && rhs.valid());
+ if (this->which() != rhs.which())
{
- return this->get_type_index() < rhs.get_type_index();
- // ^^ borrowed from boost::variant
+ return this->which() < rhs.which();
}
detail::comparer<variant, detail::less_comp> visitor(*this);
return visit(rhs, visitor);
}
+ VARIANT_INLINE bool operator>(variant const& rhs) const
+ {
+ return rhs < *this;
+ }
+ VARIANT_INLINE bool operator<=(variant const& rhs) const
+ {
+ return !(*this > rhs);
+ }
+ VARIANT_INLINE bool operator>=(variant const& rhs) const
+ {
+ return !(*this < rhs);
+ }
};
// unary visitor interface
-
// const
-template <typename V, typename F>
-auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f))
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V const& v) -> decltype(V::visit(v, std::forward<F>(f)))
{
- return V::visit(v, f);
+ return V::visit(v, std::forward<F>(f));
}
+
// non-const
-template <typename V, typename F>
-auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f))
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V& v) -> decltype(V::visit(v, std::forward<F>(f)))
{
- return V::visit(v, f);
+ return V::visit(v, std::forward<F>(f));
}
// binary visitor interface
// const
-template <typename V, typename F>
-auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f))
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
{
- return V::binary_visit(v0, v1, f);
+ return V::binary_visit(v0, v1, std::forward<F>(f));
}
+
// non-const
-template <typename V, typename F>
-auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f))
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
{
- return V::binary_visit(v0, v1, f);
+ return V::binary_visit(v0, v1, std::forward<F>(f));
}
// getter interface
-template<typename ResultType, typename T>
-ResultType & get(T & var)
+template <typename ResultType, typename T>
+ResultType& get(T& var)
{
return var.template get<ResultType>();
}
-template<typename ResultType, typename T>
+template <typename ResultType, typename T>
ResultType const& get(T const& var)
{
return var.template get<ResultType>();
}
+} // namespace util
+} // namespace mapbox
-
-}}
-
-#endif // MAPBOX_UTIL_VARIANT_HPP
+#endif // MAPBOX_UTIL_VARIANT_HPP
diff --git a/third_party/variant/variant_io.hpp b/third_party/variant/variant_io.hpp
index 8b0c137..e64cbad 100644
--- a/third_party/variant/variant_io.hpp
+++ b/third_party/variant/variant_io.hpp
@@ -1,39 +1,45 @@
#ifndef MAPBOX_UTIL_VARIANT_IO_HPP
#define MAPBOX_UTIL_VARIANT_IO_HPP
-namespace mapbox { namespace util {
+#include <iosfwd>
+
+#include "variant.hpp"
+
+namespace mapbox {
+namespace util {
namespace detail {
// operator<< helper
template <typename Out>
class printer
{
-public:
- explicit printer(Out & out)
+ public:
+ explicit printer(Out& out)
: out_(out) {}
printer& operator=(printer const&) = delete;
-// visitor
+ // visitor
template <typename T>
void operator()(T const& operand) const
{
out_ << operand;
}
-private:
- Out & out_;
+
+ private:
+ Out& out_;
};
}
// operator<<
-template <typename charT, typename traits, typename... Types>
-VARIANT_INLINE std::basic_ostream<charT, traits>&
-operator<< (std::basic_ostream<charT, traits>& out, variant<Types...> const& rhs)
+template <typename CharT, typename Traits, typename... Types>
+VARIANT_INLINE std::basic_ostream<CharT, Traits>&
+operator<<(std::basic_ostream<CharT, Traits>& out, variant<Types...> const& rhs)
{
- detail::printer<std::basic_ostream<charT, traits>> visitor(out);
+ detail::printer<std::basic_ostream<CharT, Traits>> visitor(out);
apply_visitor(visitor, rhs);
return out;
}
+} // namespace util
+} // namespace mapbox
-}}
-
-#endif //MAPBOX_UTIL_VARIANT_IO_HPP
+#endif // MAPBOX_UTIL_VARIANT_IO_HPP
diff --git a/third_party/variant/vcbuild.bat b/third_party/variant/vcbuild.bat
deleted file mode 100644
index 21489a1..0000000
--- a/third_party/variant/vcbuild.bat
+++ /dev/null
@@ -1,8 +0,0 @@
-SET configuration=Debug
-IF NOT EXIST deps\gyp\ git clone --depth 1 https://chromium.googlesource.com/external/gyp.git deps/gyp
-IF EXIST %configuration% rd /s /q %configuration%
-del variant.sln
-del tests.vcxproj
-C:\Python27\python.exe deps/gyp/gyp_main.py variant.gyp --depth=. -f msvs -G msvs_version=2013
-msbuild variant.sln /nologo /p:Configuration=%configuration%;Platform=Win32
-.\"%configuration%"\tests.exe
\ No newline at end of file
diff --git a/tools/check-hsgr.cpp b/tools/check-hsgr.cpp
deleted file mode 100644
index 2418a47..0000000
--- a/tools/check-hsgr.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-#include "../data_structures/percent.hpp"
-#include "../data_structures/query_edge.hpp"
-#include "../data_structures/static_graph.hpp"
-#include "../util/integer_range.hpp"
-#include "../util/graph_loader.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/osrm_exception.hpp"
-
-#include <boost/assert.hpp>
-#include <boost/filesystem.hpp>
-
-#include <memory>
-#include <vector>
-
-using EdgeData = QueryEdge::EdgeData;
-using QueryGraph = StaticGraph<EdgeData>;
-
-int main(int argc, char *argv[])
-{
- LogPolicy::GetInstance().Unmute();
- try
- {
- if (argc != 2)
- {
- SimpleLogger().Write(logWARNING) << "usage: " << argv[0] << " <file.hsgr>";
- return 1;
- }
-
- boost::filesystem::path hsgr_path(argv[1]);
-
- std::vector<QueryGraph::NodeArrayEntry> node_list;
- std::vector<QueryGraph::EdgeArrayEntry> edge_list;
- SimpleLogger().Write() << "loading graph from " << hsgr_path.string();
-
- unsigned m_check_sum = 0;
- unsigned m_number_of_nodes =
- readHSGRFromStream(hsgr_path, node_list, edge_list, &m_check_sum);
- SimpleLogger().Write() << "expecting " << m_number_of_nodes
- << " nodes, checksum: " << m_check_sum;
- BOOST_ASSERT_MSG(0 != node_list.size(), "node list empty");
- SimpleLogger().Write() << "loaded " << node_list.size() << " nodes and " << edge_list.size()
- << " edges";
- auto m_query_graph = std::make_shared<QueryGraph>(node_list, edge_list);
-
- BOOST_ASSERT_MSG(0 == node_list.size(), "node list not flushed");
- BOOST_ASSERT_MSG(0 == edge_list.size(), "edge list not flushed");
-
- Percent progress(m_query_graph->GetNumberOfNodes());
- for (const auto node_u : osrm::irange(0u, m_query_graph->GetNumberOfNodes()))
- {
- for (const auto eid : m_query_graph->GetAdjacentEdgeRange(node_u))
- {
- const EdgeData &data = m_query_graph->GetEdgeData(eid);
- if (!data.shortcut)
- {
- continue;
- }
- const unsigned node_v = m_query_graph->GetTarget(eid);
- const EdgeID edge_id_1 = m_query_graph->FindEdgeInEitherDirection(node_u, data.id);
- if (SPECIAL_EDGEID == edge_id_1)
- {
- throw osrm::exception("cannot find first segment of edge (" +
- std::to_string(node_u) + "," + std::to_string(data.id) +
- "," + std::to_string(node_v) + "), eid: " +
- std::to_string(eid));
- }
- const EdgeID edge_id_2 = m_query_graph->FindEdgeInEitherDirection(data.id, node_v);
- if (SPECIAL_EDGEID == edge_id_2)
- {
- throw osrm::exception("cannot find second segment of edge (" +
- std::to_string(node_u) + "," + std::to_string(data.id) +
- "," + std::to_string(node_v) + "), eid: " +
- std::to_string(eid));
- }
- }
- progress.printStatus(node_u);
- }
- m_query_graph.reset();
- SimpleLogger().Write() << "Data file " << argv[0] << " appears to be OK";
- }
- catch (const std::exception &e)
- {
- SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
- }
- return 0;
-}
diff --git a/tools/components.cpp b/tools/components.cpp
deleted file mode 100644
index db0e526..0000000
--- a/tools/components.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "../typedefs.h"
-#include "../algorithms/tarjan_scc.hpp"
-#include "../algorithms/coordinate_calculation.hpp"
-#include "../data_structures/dynamic_graph.hpp"
-#include "../data_structures/static_graph.hpp"
-#include "../util/fingerprint.hpp"
-#include "../util/graph_loader.hpp"
-#include "../util/make_unique.hpp"
-#include "../util/osrm_exception.hpp"
-#include "../util/simple_logger.hpp"
-
-#include <boost/filesystem.hpp>
-
-#if defined(__APPLE__) || defined(_WIN32)
-#include <gdal.h>
-#include <ogrsf_frmts.h>
-#else
-#include <gdal/gdal.h>
-#include <gdal/ogrsf_frmts.h>
-#endif
-
-#include <osrm/coordinate.hpp>
-
-#include <fstream>
-#include <memory>
-#include <string>
-#include <vector>
-
-namespace
-{
-
-struct TarjanEdgeData
-{
- TarjanEdgeData() : distance(INVALID_EDGE_WEIGHT), name_id(INVALID_NAMEID) {}
- TarjanEdgeData(unsigned distance, unsigned name_id) : distance(distance), name_id(name_id) {}
- unsigned distance;
- unsigned name_id;
-};
-
-using TarjanGraph = StaticGraph<TarjanEdgeData>;
-using TarjanEdge = TarjanGraph::InputEdge;
-
-void DeleteFileIfExists(const std::string &file_name)
-{
- if (boost::filesystem::exists(file_name))
- {
- boost::filesystem::remove(file_name);
- }
-}
-}
-
-std::size_t LoadGraph(const char *path,
- std::vector<QueryNode> &coordinate_list,
- std::vector<TarjanEdge> &graph_edge_list)
-{
- std::ifstream input_stream(path, std::ifstream::in | std::ifstream::binary);
- if (!input_stream.is_open())
- {
- throw osrm::exception("Cannot open osrm file");
- }
-
- // load graph data
- std::vector<NodeBasedEdge> edge_list;
- std::vector<NodeID> traffic_light_node_list;
- std::vector<NodeID> barrier_node_list;
-
- auto number_of_nodes = loadNodesFromFile(input_stream, barrier_node_list,
- traffic_light_node_list, coordinate_list);
-
- loadEdgesFromFile(input_stream, edge_list);
-
- traffic_light_node_list.clear();
- traffic_light_node_list.shrink_to_fit();
-
- // Building an node-based graph
- for (const auto &input_edge : edge_list)
- {
- if (input_edge.source == input_edge.target)
- {
- continue;
- }
-
- if (input_edge.forward)
- {
- graph_edge_list.emplace_back(input_edge.source, input_edge.target,
- (std::max)(input_edge.weight, 1), input_edge.name_id);
- }
- if (input_edge.backward)
- {
- graph_edge_list.emplace_back(input_edge.target, input_edge.source,
- (std::max)(input_edge.weight, 1), input_edge.name_id);
- }
- }
-
- return number_of_nodes;
-}
-
-int main(int argc, char *argv[])
-{
- std::vector<QueryNode> coordinate_list;
-
- LogPolicy::GetInstance().Unmute();
- try
- {
- // enable logging
- if (argc < 2)
- {
- SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0] << " <osrm>";
- return -1;
- }
-
- std::vector<TarjanEdge> graph_edge_list;
- auto number_of_nodes = LoadGraph(argv[1], coordinate_list, graph_edge_list);
-
- tbb::parallel_sort(graph_edge_list.begin(), graph_edge_list.end());
- const auto graph = std::make_shared<TarjanGraph>(number_of_nodes, graph_edge_list);
- graph_edge_list.clear();
- graph_edge_list.shrink_to_fit();
-
- SimpleLogger().Write() << "Starting SCC graph traversal";
-
- auto tarjan = osrm::make_unique<TarjanSCC<TarjanGraph>>(graph);
- tarjan->run();
- SimpleLogger().Write() << "identified: " << tarjan->get_number_of_components()
- << " many components";
- SimpleLogger().Write() << "identified " << tarjan->get_size_one_count() << " size 1 SCCs";
-
- // output
- TIMER_START(SCC_RUN_SETUP);
-
- // remove files from previous run if exist
- DeleteFileIfExists("component.dbf");
- DeleteFileIfExists("component.shx");
- DeleteFileIfExists("component.shp");
-
- Percent percentage(graph->GetNumberOfNodes());
-
- OGRRegisterAll();
-
- const char *pszDriverName = "ESRI Shapefile";
- OGRSFDriver *poDriver =
- OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(pszDriverName);
- if (nullptr == poDriver)
- {
- throw osrm::exception("ESRI Shapefile driver not available");
- }
- OGRDataSource *poDS = poDriver->CreateDataSource("component.shp", nullptr);
-
- if (nullptr == poDS)
- {
- throw osrm::exception("Creation of output file failed");
- }
-
- OGRSpatialReference *poSRS = new OGRSpatialReference();
- poSRS->importFromEPSG(4326);
-
- OGRLayer *poLayer = poDS->CreateLayer("component", poSRS, wkbLineString, nullptr);
-
- if (nullptr == poLayer)
- {
- throw osrm::exception("Layer creation failed.");
- }
- TIMER_STOP(SCC_RUN_SETUP);
- SimpleLogger().Write() << "shapefile setup took " << TIMER_MSEC(SCC_RUN_SETUP) / 1000.
- << "s";
-
- uint64_t total_network_length = 0;
- percentage.reinit(graph->GetNumberOfNodes());
- TIMER_START(SCC_OUTPUT);
- for (const NodeID source : osrm::irange(0u, graph->GetNumberOfNodes()))
- {
- percentage.printIncrement();
- for (const auto current_edge : graph->GetAdjacentEdgeRange(source))
- {
- const TarjanGraph::NodeIterator target = graph->GetTarget(current_edge);
-
- if (source < target || SPECIAL_EDGEID == graph->FindEdge(target, source))
- {
- total_network_length +=
- 100 * coordinate_calculation::great_circle_distance(
- coordinate_list[source].lat, coordinate_list[source].lon,
- coordinate_list[target].lat, coordinate_list[target].lon);
-
- BOOST_ASSERT(current_edge != SPECIAL_EDGEID);
- BOOST_ASSERT(source != SPECIAL_NODEID);
- BOOST_ASSERT(target != SPECIAL_NODEID);
-
- const unsigned size_of_containing_component =
- std::min(tarjan->get_component_size(tarjan->get_component_id(source)),
- tarjan->get_component_size(tarjan->get_component_id(target)));
-
- // edges that end on bollard nodes may actually be in two distinct components
- if (size_of_containing_component < 1000)
- {
- OGRLineString lineString;
- lineString.addPoint(coordinate_list[source].lon / COORDINATE_PRECISION,
- coordinate_list[source].lat / COORDINATE_PRECISION);
- lineString.addPoint(coordinate_list[target].lon / COORDINATE_PRECISION,
- coordinate_list[target].lat / COORDINATE_PRECISION);
-
- OGRFeature *poFeature = OGRFeature::CreateFeature(poLayer->GetLayerDefn());
-
- poFeature->SetGeometry(&lineString);
- if (OGRERR_NONE != poLayer->CreateFeature(poFeature))
- {
- throw osrm::exception("Failed to create feature in shapefile.");
- }
- OGRFeature::DestroyFeature(poFeature);
- }
- }
- }
- }
- OGRSpatialReference::DestroySpatialReference(poSRS);
- OGRDataSource::DestroyDataSource(poDS);
- TIMER_STOP(SCC_OUTPUT);
- SimpleLogger().Write() << "generating output took: " << TIMER_MSEC(SCC_OUTPUT) / 1000.
- << "s";
-
- SimpleLogger().Write() << "total network distance: "
- << static_cast<uint64_t>(total_network_length / 100 / 1000.)
- << " km";
-
- SimpleLogger().Write() << "finished component analysis";
- }
- catch (const std::exception &e)
- {
- SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
- }
- return 0;
-}
diff --git a/tools/io-benchmark.cpp b/tools/io-benchmark.cpp
deleted file mode 100644
index 41e41b2..0000000
--- a/tools/io-benchmark.cpp
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "util/version.hpp"
-#include "../util/osrm_exception.hpp"
-#include "../util/simple_logger.hpp"
-#include "../util/timing_util.hpp"
-
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-
-#include <cmath>
-#include <cstdio>
-#include <fcntl.h>
-#ifdef __linux__
-#include <malloc.h>
-#endif
-
-#include <algorithm>
-#include <chrono>
-#include <iomanip>
-#include <numeric>
-#include <random>
-#include <vector>
-
-const unsigned number_of_elements = 268435456;
-
-struct Statistics
-{
- double min, max, med, mean, dev;
-};
-
-void RunStatistics(std::vector<double> &timings_vector, Statistics &stats)
-{
- std::sort(timings_vector.begin(), timings_vector.end());
- stats.min = timings_vector.front();
- stats.max = timings_vector.back();
- stats.med = timings_vector[timings_vector.size() / 2];
- double primary_sum = std::accumulate(timings_vector.begin(), timings_vector.end(), 0.0);
- stats.mean = primary_sum / timings_vector.size();
-
- double primary_sq_sum = std::inner_product(timings_vector.begin(), timings_vector.end(),
- timings_vector.begin(), 0.0);
- stats.dev = std::sqrt(primary_sq_sum / timings_vector.size() - (stats.mean * stats.mean));
-}
-
-int main(int argc, char *argv[])
-{
-
-#ifdef __FreeBSD__
- SimpleLogger().Write() << "Not supported on FreeBSD";
- return 0;
-#endif
-#ifdef _WIN32
- SimpleLogger().Write() << "Not supported on Windows";
- return 0;
-#else
-
- LogPolicy::GetInstance().Unmute();
- boost::filesystem::path test_path;
- try
- {
- SimpleLogger().Write() << "starting up engines, " << OSRM_VERSION;
-
- if (1 == argc)
- {
- SimpleLogger().Write(logWARNING) << "usage: " << argv[0] << " /path/on/device";
- return -1;
- }
-
- test_path = boost::filesystem::path(argv[1]);
- test_path /= "osrm.tst";
- SimpleLogger().Write(logDEBUG) << "temporary file: " << test_path.string();
-
- // create files for testing
- if (2 == argc)
- {
- // create file to test
- if (boost::filesystem::exists(test_path))
- {
- throw osrm::exception("Data file already exists");
- }
-
- int *random_array = new int[number_of_elements];
- std::generate(random_array, random_array + number_of_elements, std::rand);
-#ifdef __APPLE__
- FILE *fd = fopen(test_path.string().c_str(), "w");
- fcntl(fileno(fd), F_NOCACHE, 1);
- fcntl(fileno(fd), F_RDAHEAD, 0);
- TIMER_START(write_1gb);
- write(fileno(fd), (char *)random_array, number_of_elements * sizeof(unsigned));
- TIMER_STOP(write_1gb);
- fclose(fd);
-#endif
-#ifdef __linux__
- int file_desc =
- open(test_path.string().c_str(), O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, S_IRWXU);
- if (-1 == file_desc)
- {
- throw osrm::exception("Could not open random data file");
- }
- TIMER_START(write_1gb);
- int ret = write(file_desc, random_array, number_of_elements * sizeof(unsigned));
- if (0 > ret)
- {
- throw osrm::exception("could not write random data file");
- }
- TIMER_STOP(write_1gb);
- close(file_desc);
-#endif
- delete[] random_array;
- SimpleLogger().Write(logDEBUG) << "writing raw 1GB took " << TIMER_SEC(write_1gb)
- << "s";
- SimpleLogger().Write() << "raw write performance: " << std::setprecision(5)
- << std::fixed << 1024 * 1024 / TIMER_SEC(write_1gb) << "MB/sec";
-
- SimpleLogger().Write(logDEBUG)
- << "finished creation of random data. Flush disk cache now!";
- }
- else
- {
- // Run Non-Cached I/O benchmarks
- if (!boost::filesystem::exists(test_path))
- {
- throw osrm::exception("data file does not exist");
- }
-
- // volatiles do not get optimized
- Statistics stats;
-
-#ifdef __APPLE__
- volatile unsigned single_block[1024];
- char *raw_array = new char[number_of_elements * sizeof(unsigned)];
- FILE *fd = fopen(test_path.string().c_str(), "r");
- fcntl(fileno(fd), F_NOCACHE, 1);
- fcntl(fileno(fd), F_RDAHEAD, 0);
-#endif
-#ifdef __linux__
- char *single_block = (char *)memalign(512, 1024 * sizeof(unsigned));
-
- int file_desc = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
- if (-1 == file_desc)
- {
- SimpleLogger().Write(logDEBUG) << "opened, error: " << strerror(errno);
- return -1;
- }
- char *raw_array = (char *)memalign(512, number_of_elements * sizeof(unsigned));
-#endif
- TIMER_START(read_1gb);
-#ifdef __APPLE__
- read(fileno(fd), raw_array, number_of_elements * sizeof(unsigned));
- close(fileno(fd));
- fd = fopen(test_path.string().c_str(), "r");
-#endif
-#ifdef __linux__
- int ret = read(file_desc, raw_array, number_of_elements * sizeof(unsigned));
- SimpleLogger().Write(logDEBUG) << "read " << ret
- << " bytes, error: " << strerror(errno);
- close(file_desc);
- file_desc = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
- SimpleLogger().Write(logDEBUG) << "opened, error: " << strerror(errno);
-#endif
- TIMER_STOP(read_1gb);
-
- SimpleLogger().Write(logDEBUG) << "reading raw 1GB took " << TIMER_SEC(read_1gb) << "s";
- SimpleLogger().Write() << "raw read performance: " << std::setprecision(5) << std::fixed
- << 1024 * 1024 / TIMER_SEC(read_1gb) << "MB/sec";
-
- std::vector<double> timing_results_raw_random;
- SimpleLogger().Write(logDEBUG) << "running 1000 random I/Os of 4KB";
-
-#ifdef __APPLE__
- fseek(fd, 0, SEEK_SET);
-#endif
-#ifdef __linux__
- lseek(file_desc, 0, SEEK_SET);
-#endif
- // make 1000 random access, time each I/O seperately
- unsigned number_of_blocks = (number_of_elements * sizeof(unsigned) - 1) / 4096;
- std::random_device rd;
- std::default_random_engine e1(rd());
- std::uniform_int_distribution<unsigned> uniform_dist(0, number_of_blocks - 1);
- for (unsigned i = 0; i < 1000; ++i)
- {
- unsigned block_to_read = uniform_dist(e1);
- off_t current_offset = block_to_read * 4096;
- TIMER_START(random_access);
-#ifdef __APPLE__
- int ret1 = fseek(fd, current_offset, SEEK_SET);
- int ret2 = read(fileno(fd), (char *)&single_block[0], 4096);
-#endif
-
-#ifdef __FreeBSD__
- int ret1 = 0;
- int ret2 = 0;
-#endif
-
-#ifdef __linux__
- int ret1 = lseek(file_desc, current_offset, SEEK_SET);
- int ret2 = read(file_desc, (char *)single_block, 4096);
-#endif
- TIMER_STOP(random_access);
- if (((off_t)-1) == ret1)
- {
- SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
- SimpleLogger().Write(logWARNING) << "seek error " << strerror(errno);
- throw osrm::exception("seek error");
- }
- if (-1 == ret2)
- {
- SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
- SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
- throw osrm::exception("read error");
- }
- timing_results_raw_random.push_back(TIMER_SEC(random_access));
- }
-
- // Do statistics
- SimpleLogger().Write(logDEBUG) << "running raw random I/O statistics";
- std::ofstream random_csv("random.csv", std::ios::trunc);
- for (unsigned i = 0; i < timing_results_raw_random.size(); ++i)
- {
- random_csv << i << ", " << timing_results_raw_random[i] << std::endl;
- }
- random_csv.close();
- RunStatistics(timing_results_raw_random, stats);
-
- SimpleLogger().Write() << "raw random I/O: " << std::setprecision(5) << std::fixed
- << "min: " << stats.min << "ms, "
- << "mean: " << stats.mean << "ms, "
- << "med: " << stats.med << "ms, "
- << "max: " << stats.max << "ms, "
- << "dev: " << stats.dev << "ms";
-
- std::vector<double> timing_results_raw_seq;
-#ifdef __APPLE__
- fseek(fd, 0, SEEK_SET);
-#endif
-#ifdef __linux__
- lseek(file_desc, 0, SEEK_SET);
-#endif
-
- // read every 100th block
- for (unsigned i = 0; i < 1000; ++i)
- {
- off_t current_offset = i * 4096;
- TIMER_START(read_every_100);
-#ifdef __APPLE__
- int ret1 = fseek(fd, current_offset, SEEK_SET);
- int ret2 = read(fileno(fd), (char *)&single_block, 4096);
-#endif
-
-#ifdef __FreeBSD__
- int ret1 = 0;
- int ret2 = 0;
-#endif
-
-#ifdef __linux__
- int ret1 = lseek(file_desc, current_offset, SEEK_SET);
-
- int ret2 = read(file_desc, (char *)single_block, 4096);
-#endif
- TIMER_STOP(read_every_100);
- if (((off_t)-1) == ret1)
- {
- SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
- SimpleLogger().Write(logWARNING) << "seek error " << strerror(errno);
- throw osrm::exception("seek error");
- }
- if (-1 == ret2)
- {
- SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
- SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
- throw osrm::exception("read error");
- }
- timing_results_raw_seq.push_back(TIMER_SEC(read_every_100));
- }
-#ifdef __APPLE__
- fclose(fd);
- // free(single_element);
- free(raw_array);
-// free(single_block);
-#endif
-#ifdef __linux__
- close(file_desc);
-#endif
- // Do statistics
- SimpleLogger().Write(logDEBUG) << "running sequential I/O statistics";
- // print simple statistics: min, max, median, variance
- std::ofstream seq_csv("sequential.csv", std::ios::trunc);
- for (unsigned i = 0; i < timing_results_raw_seq.size(); ++i)
- {
- seq_csv << i << ", " << timing_results_raw_seq[i] << std::endl;
- }
- seq_csv.close();
- RunStatistics(timing_results_raw_seq, stats);
- SimpleLogger().Write() << "raw sequential I/O: " << std::setprecision(5) << std::fixed
- << "min: " << stats.min << "ms, "
- << "mean: " << stats.mean << "ms, "
- << "med: " << stats.med << "ms, "
- << "max: " << stats.max << "ms, "
- << "dev: " << stats.dev << "ms";
-
- if (boost::filesystem::exists(test_path))
- {
- boost::filesystem::remove(test_path);
- SimpleLogger().Write(logDEBUG) << "removing temporary files";
- }
- }
- }
- catch (const std::exception &e)
- {
- SimpleLogger().Write(logWARNING) << "caught exception: " << e.what();
- SimpleLogger().Write(logWARNING) << "cleaning up, and exiting";
- if (boost::filesystem::exists(test_path))
- {
- boost::filesystem::remove(test_path);
- SimpleLogger().Write(logWARNING) << "removing temporary files";
- }
- return -1;
- }
- return 0;
-#endif
-}
diff --git a/tools/simpleclient.cpp b/tools/simpleclient.cpp
deleted file mode 100644
index 17058a6..0000000
--- a/tools/simpleclient.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "util/version.hpp"
-#include "../util/json_renderer.hpp"
-#include "../util/routed_options.hpp"
-#include "../util/simple_logger.hpp"
-
-#include <osrm/json_container.hpp>
-#include <osrm/libosrm_config.hpp>
-#include <osrm/route_parameters.hpp>
-#include <osrm/osrm.hpp>
-
-#include <string>
-
-int main(int argc, const char *argv[])
-{
- LogPolicy::GetInstance().Unmute();
- try
- {
- std::string ip_address;
- int ip_port, requested_thread_num;
- bool trial_run = false;
- LibOSRMConfig lib_config;
- const unsigned init_result = GenerateServerProgramOptions(
- argc, argv, lib_config.server_paths, ip_address, ip_port, requested_thread_num,
- lib_config.use_shared_memory, trial_run, lib_config.max_locations_trip,
- lib_config.max_locations_viaroute, lib_config.max_locations_distance_table,
- lib_config.max_locations_map_matching);
-
- if (init_result == INIT_OK_DO_NOT_START_ENGINE)
- {
- return 0;
- }
- if (init_result == INIT_FAILED)
- {
- return 1;
- }
- SimpleLogger().Write() << "starting up engines, " << OSRM_VERSION;
-
- OSRM routing_machine(lib_config);
-
- RouteParameters route_parameters;
- route_parameters.zoom_level = 18; // no generalization
- route_parameters.print_instructions = true; // turn by turn instructions
- route_parameters.alternate_route = true; // get an alternate route, too
- route_parameters.geometry = true; // retrieve geometry of route
- route_parameters.compression = true; // polyline encoding
- route_parameters.check_sum = -1; // see wiki
- route_parameters.service = "viaroute"; // that's routing
- route_parameters.output_format = "json";
- route_parameters.jsonp_parameter = ""; // set for jsonp wrapping
- route_parameters.language = ""; // unused atm
- // route_parameters.hints.push_back(); // see wiki, saves I/O if done properly
-
- // start_coordinate
- route_parameters.coordinates.emplace_back(52.519930 * COORDINATE_PRECISION,
- 13.438640 * COORDINATE_PRECISION);
- // target_coordinate
- route_parameters.coordinates.emplace_back(52.513191 * COORDINATE_PRECISION,
- 13.415852 * COORDINATE_PRECISION);
- osrm::json::Object json_result;
- const int result_code = routing_machine.RunQuery(route_parameters, json_result);
- SimpleLogger().Write() << "http code: " << result_code;
- osrm::json::render(SimpleLogger().Write(), json_result);
- }
- catch (std::exception ¤t_exception)
- {
- SimpleLogger().Write(logWARNING) << "caught exception: " << current_exception.what();
- return -1;
- }
- return 0;
-}
diff --git a/tools/springclean.cpp b/tools/springclean.cpp
deleted file mode 100644
index 18e5711..0000000
--- a/tools/springclean.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include <cstdio>
-
-#include "../data_structures/shared_memory_factory.hpp"
-#include "../server/data_structures/shared_datatype.hpp"
-#include "util/version.hpp"
-#include "../util/simple_logger.hpp"
-
-void delete_region(const SharedDataType region)
-{
- if (SharedMemory::RegionExists(region) && !SharedMemory::Remove(region))
- {
- const std::string name = [&]
- {
- switch (region)
- {
- case CURRENT_REGIONS:
- return "CURRENT_REGIONS";
- case LAYOUT_1:
- return "LAYOUT_1";
- case DATA_1:
- return "DATA_1";
- case LAYOUT_2:
- return "LAYOUT_2";
- case DATA_2:
- return "DATA_2";
- case LAYOUT_NONE:
- return "LAYOUT_NONE";
- default: // DATA_NONE:
- return "DATA_NONE";
- }
- }();
-
- SimpleLogger().Write(logWARNING) << "could not delete shared memory region " << name;
- }
-}
-
-// find all existing shmem regions and remove them.
-void springclean()
-{
- SimpleLogger().Write() << "spring-cleaning all shared memory regions";
- delete_region(DATA_1);
- delete_region(LAYOUT_1);
- delete_region(DATA_2);
- delete_region(LAYOUT_2);
- delete_region(CURRENT_REGIONS);
-}
-
-int main()
-{
- LogPolicy::GetInstance().Unmute();
- try
- {
- SimpleLogger().Write() << "starting up engines, " << OSRM_VERSION << "\n\n";
- SimpleLogger().Write() << "Releasing all locks";
- SimpleLogger().Write() << "ATTENTION! BE CAREFUL!";
- SimpleLogger().Write() << "----------------------";
- SimpleLogger().Write() << "This tool may put osrm-routed into an undefined state!";
- SimpleLogger().Write() << "Type 'Y' to acknowledge that you know what your are doing.";
- SimpleLogger().Write() << "\n\nDo you want to purge all shared memory allocated "
- << "by osrm-datastore? [type 'Y' to confirm]";
-
- const auto letter = getchar();
- if (letter != 'Y')
- {
- SimpleLogger().Write() << "aborted.";
- return 0;
- }
- springclean();
- }
- catch (const std::exception &e)
- {
- SimpleLogger().Write(logWARNING) << "[excpetion] " << e.what();
- }
- return 0;
-}
diff --git a/tools/unlock_all_mutexes.cpp b/tools/unlock_all_mutexes.cpp
deleted file mode 100644
index 953254b..0000000
--- a/tools/unlock_all_mutexes.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "util/version.hpp"
-#include "../util/simple_logger.hpp"
-#include "../server/data_structures/shared_barriers.hpp"
-
-#include <iostream>
-
-int main()
-{
- LogPolicy::GetInstance().Unmute();
- try
- {
- SimpleLogger().Write() << "starting up engines, " << OSRM_VERSION;
- SimpleLogger().Write() << "Releasing all locks";
- SharedBarriers barrier;
- barrier.pending_update_mutex.unlock();
- barrier.query_mutex.unlock();
- barrier.update_mutex.unlock();
- }
- catch (const std::exception &e)
- {
- SimpleLogger().Write(logWARNING) << "[excpetion] " << e.what();
- }
- return 0;
-}
diff --git a/unit_tests/algorithms/douglas_peucker.cpp b/unit_tests/algorithms/douglas_peucker.cpp
deleted file mode 100644
index 8a39209..0000000
--- a/unit_tests/algorithms/douglas_peucker.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "../../algorithms/douglas_peucker.hpp"
-#include "../../data_structures/segment_information.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <boost/test/test_case_template.hpp>
-
-#include <osrm/coordinate.hpp>
-
-#include <vector>
-
-BOOST_AUTO_TEST_SUITE(douglas_peucker)
-
-SegmentInformation getTestInfo(int lat, int lon, bool necessary)
-{
- return SegmentInformation(FixedPointCoordinate(lat, lon), 0, 0, 0, TurnInstruction::HeadOn,
- necessary, false, 0);
-}
-
-BOOST_AUTO_TEST_CASE(all_necessary_test)
-{
- /*
- * x
- * / \
- * x \
- * / \
- * x x
- */
- std::vector<SegmentInformation> info = {getTestInfo(5, 5, true),
- getTestInfo(6, 6, true),
- getTestInfo(10, 10, true),
- getTestInfo(5, 15, true)};
- DouglasPeucker dp;
- for (unsigned z = 0; z < DOUGLAS_PEUCKER_THRESHOLDS.size(); z++)
- {
- dp.Run(info, z);
- for (const auto &i : info)
- {
- BOOST_CHECK_EQUAL(i.necessary, true);
- }
- }
-}
-
-BOOST_AUTO_TEST_CASE(remove_second_node_test)
-{
- DouglasPeucker dp;
- for (unsigned z = 0; z < DOUGLAS_PEUCKER_THRESHOLDS.size(); z++)
- {
- /*
- * x--x
- * | \
- * x-x x
- * |
- * x
- */
- std::vector<SegmentInformation> info = {
- getTestInfo(5 * COORDINATE_PRECISION, 5 * COORDINATE_PRECISION, true),
- getTestInfo(5 * COORDINATE_PRECISION,
- 5 * COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z], false),
- getTestInfo(10 * COORDINATE_PRECISION, 10 * COORDINATE_PRECISION, false),
- getTestInfo(10 * COORDINATE_PRECISION,
- 10 + COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z] * 2, false),
- getTestInfo(5 * COORDINATE_PRECISION, 15 * COORDINATE_PRECISION, false),
- getTestInfo(5 * COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z],
- 15 * COORDINATE_PRECISION, true),
- };
- BOOST_TEST_MESSAGE("Threshold (" << z << "): " << DOUGLAS_PEUCKER_THRESHOLDS[z]);
- dp.Run(info, z);
- BOOST_CHECK_EQUAL(info[0].necessary, true);
- BOOST_CHECK_EQUAL(info[1].necessary, false);
- BOOST_CHECK_EQUAL(info[2].necessary, true);
- BOOST_CHECK_EQUAL(info[3].necessary, true);
- BOOST_CHECK_EQUAL(info[4].necessary, false);
- BOOST_CHECK_EQUAL(info[5].necessary, true);
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/algorithms/duration_parsing.cpp b/unit_tests/algorithms/duration_parsing.cpp
deleted file mode 100644
index e3035dc..0000000
--- a/unit_tests/algorithms/duration_parsing.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "../../extractor/extraction_helper_functions.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <boost/test/test_case_template.hpp>
-
-BOOST_AUTO_TEST_SUITE(durations_are_valid)
-
-BOOST_AUTO_TEST_CASE(all_necessary_test)
-{
- BOOST_CHECK_EQUAL(durationIsValid("00:01"), true);
- BOOST_CHECK_EQUAL(durationIsValid("00:01:01"), true);
- BOOST_CHECK_EQUAL(durationIsValid("PT15M"), true);
-}
-
-BOOST_AUTO_TEST_CASE(common_durations_get_translated)
-{
- BOOST_CHECK_EQUAL(parseDuration("00:01"), 60);
- BOOST_CHECK_EQUAL(parseDuration("00:01:01"), 61);
- BOOST_CHECK_EQUAL(parseDuration("01:01"), 3660);
-
- // check all combinations of iso duration tokens
- BOOST_CHECK_EQUAL(parseDuration("PT1M1S"), 61);
- BOOST_CHECK_EQUAL(parseDuration("PT1H1S"), 3601);
- BOOST_CHECK_EQUAL(parseDuration("PT15M"), 900);
- BOOST_CHECK_EQUAL(parseDuration("PT15S"), 15);
- BOOST_CHECK_EQUAL(parseDuration("PT15H"), 54000);
- BOOST_CHECK_EQUAL(parseDuration("PT1H15M"), 4500);
- BOOST_CHECK_EQUAL(parseDuration("PT1H15M1S"), 4501);
-}
-
-BOOST_AUTO_TEST_CASE(iso_8601_durations_case_insensitive)
-{
- BOOST_CHECK_EQUAL(parseDuration("PT15m"), 900);
- BOOST_CHECK_EQUAL(parseDuration("PT1h15m"), 4500);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/algorithms/geometry_string.cpp b/unit_tests/algorithms/geometry_string.cpp
deleted file mode 100644
index ab9f357..0000000
--- a/unit_tests/algorithms/geometry_string.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include <boost/test/floating_point_comparison.hpp>
-#include <boost/test/unit_test.hpp>
-
-#include "../../algorithms/polyline_compressor.hpp"
-#include "../../algorithms/coordinate_calculation.hpp"
-
-#include <osrm/coordinate.hpp>
-
-#include <cmath>
-#include <vector>
-
-BOOST_AUTO_TEST_CASE(geometry_string)
-{
- // Polyline string for the 5 coordinates
- const std::string polyline = "_gjaR_gjaR_pR_ibE_pR_ibE_pR_ibE_pR_ibE";
- PolylineCompressor pc;
- std::vector<FixedPointCoordinate> coords = pc.decode_string(polyline);
-
- // Test coordinates; these would be the coordinates we give the loc parameter,
- // e.g. loc=10.00,10.0&loc=10.01,10.1...
- FixedPointCoordinate coord1(10.00 * COORDINATE_PRECISION, 10.0 * COORDINATE_PRECISION);
- FixedPointCoordinate coord2(10.01 * COORDINATE_PRECISION, 10.1 * COORDINATE_PRECISION);
- FixedPointCoordinate coord3(10.02 * COORDINATE_PRECISION, 10.2 * COORDINATE_PRECISION);
- FixedPointCoordinate coord4(10.03 * COORDINATE_PRECISION, 10.3 * COORDINATE_PRECISION);
- FixedPointCoordinate coord5(10.04 * COORDINATE_PRECISION, 10.4 * COORDINATE_PRECISION);
-
- // Put the test coordinates into the vector for comparison
- std::vector<FixedPointCoordinate> cmp_coords;
- cmp_coords.emplace_back(coord1);
- cmp_coords.emplace_back(coord2);
- cmp_coords.emplace_back(coord3);
- cmp_coords.emplace_back(coord4);
- cmp_coords.emplace_back(coord5);
-
- BOOST_CHECK_EQUAL(cmp_coords.size(), coords.size());
-
- for(unsigned i = 0; i < cmp_coords.size(); ++i)
- {
- const double cmp1_lat = coords.at(i).lat;
- const double cmp2_lat = cmp_coords.at(i).lat;
- BOOST_CHECK_CLOSE(cmp1_lat, cmp2_lat, 0.0001);
-
- const double cmp1_lon = coords.at(i).lon;
- const double cmp2_lon = cmp_coords.at(i).lon;
- BOOST_CHECK_CLOSE(cmp1_lon, cmp2_lon, 0.0001);
- }
-}
diff --git a/unit_tests/algorithms/string_util.cpp b/unit_tests/algorithms/string_util.cpp
deleted file mode 100644
index cf82eba..0000000
--- a/unit_tests/algorithms/string_util.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "../../util/string_util.hpp"
-
-#include <boost/test/unit_test.hpp>
-#include <boost/test/test_case_template.hpp>
-
-#include <iostream>
-
-BOOST_AUTO_TEST_SUITE(string_util)
-
-BOOST_AUTO_TEST_CASE(json_escaping)
-{
- std::string input{"\b\\"};
- std::string output{escape_JSON(input)};
-
- BOOST_CHECK_EQUAL(output, "\\b\\\\");
-
- input = "Aleja \"Solidarnosci\"";
- output = escape_JSON(input);
- BOOST_CHECK_EQUAL(output, "Aleja \\\"Solidarnosci\\\"");
-}
-
-BOOST_AUTO_TEST_CASE(print_int)
-{
- const std::string input{"\b\\"};
- char buffer[12];
- buffer[11] = 0; // zero termination
- std::string output = printInt<11, 8>(buffer, 314158976);
- BOOST_CHECK_EQUAL(output, "3.14158976");
-
- buffer[11] = 0;
- output = printInt<11, 8>(buffer, 0);
- BOOST_CHECK_EQUAL(output, "0.00000000");
-
- output = printInt<11, 8>(buffer, -314158976);
- BOOST_CHECK_EQUAL(output, "-3.14158976");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/data_structures/coordinate.cpp b/unit_tests/data_structures/coordinate.cpp
deleted file mode 100644
index e820976..0000000
--- a/unit_tests/data_structures/coordinate.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include <boost/test/unit_test.hpp>
-
-#include "../../algorithms/coordinate_calculation.hpp"
-
-#include <osrm/coordinate.hpp>
-
-#include <cmath>
-
-// Regression test for bug captured in #1347
-BOOST_AUTO_TEST_CASE(regression_test_1347)
-{
- FixedPointCoordinate u(10 * COORDINATE_PRECISION, -100 * COORDINATE_PRECISION);
- FixedPointCoordinate v(10.001 * COORDINATE_PRECISION, -100.002 * COORDINATE_PRECISION);
- FixedPointCoordinate q(10.002 * COORDINATE_PRECISION, -100.001 * COORDINATE_PRECISION);
-
- float d1 = coordinate_calculation::perpendicular_distance(u, v, q);
-
- float ratio;
- FixedPointCoordinate nearest_location;
- float d2 = coordinate_calculation::perpendicular_distance(u, v, q, nearest_location, ratio);
-
- BOOST_CHECK_LE(std::abs(d1 - d2), 0.01f);
-}
diff --git a/unit_tests/data_structures/dynamic_graph.cpp b/unit_tests/data_structures/dynamic_graph.cpp
deleted file mode 100644
index df8eb21..0000000
--- a/unit_tests/data_structures/dynamic_graph.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "../../data_structures/dynamic_graph.hpp"
-#include "../../typedefs.h"
-
-#include <boost/test/unit_test.hpp>
-#include <boost/test/test_case_template.hpp>
-
-#include <vector>
-
-BOOST_AUTO_TEST_SUITE(dynamic_graph)
-
-struct TestData
-{
- EdgeID id;
-};
-
-typedef DynamicGraph<TestData> TestDynamicGraph;
-typedef TestDynamicGraph::InputEdge TestInputEdge;
-
-BOOST_AUTO_TEST_CASE(find_test)
-{
- /*
- * (0) -1-> (1)
- * ^ ^
- * 2 5
- * | |
- * (3) -3-> (4)
- * <-4-
- */
- std::vector<TestInputEdge> input_edges = {
- TestInputEdge{0, 1, TestData{1}},
- TestInputEdge{3, 0, TestData{2}},
- TestInputEdge{3, 0, TestData{5}},
- TestInputEdge{3, 4, TestData{3}},
- TestInputEdge{4, 3, TestData{4}}
- };
- TestDynamicGraph simple_graph(5, input_edges);
-
- auto eit = simple_graph.FindEdge(0, 1);
- BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 1);
-
- eit = simple_graph.FindEdge(1, 0);
- BOOST_CHECK_EQUAL(eit, SPECIAL_EDGEID);
-
- eit = simple_graph.FindEdgeInEitherDirection(1, 0);
- BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 1);
-
- bool reverse = false;
- eit = simple_graph.FindEdgeIndicateIfReverse(1, 0, reverse);
- BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 1);
- BOOST_CHECK(reverse);
-
- eit = simple_graph.FindEdge(3, 1);
- BOOST_CHECK_EQUAL(eit, SPECIAL_EDGEID);
- eit = simple_graph.FindEdge(0, 4);
- BOOST_CHECK_EQUAL(eit, SPECIAL_EDGEID);
-
- eit = simple_graph.FindEdge(3, 4);
- BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 3);
- eit = simple_graph.FindEdgeInEitherDirection(3, 4);
- BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 3);
-
- eit = simple_graph.FindEdge(3, 0);
- BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 2);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/data_structures/static_rtree.cpp b/unit_tests/data_structures/static_rtree.cpp
deleted file mode 100644
index 2539d5f..0000000
--- a/unit_tests/data_structures/static_rtree.cpp
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "../../algorithms/coordinate_calculation.hpp"
-#include "../../algorithms/geospatial_query.hpp"
-#include "../../data_structures/static_rtree.hpp"
-#include "../../data_structures/query_node.hpp"
-#include "../../data_structures/edge_based_node.hpp"
-#include "../../util/floating_point.hpp"
-#include "../../typedefs.h"
-
-#include <boost/functional/hash.hpp>
-#include <boost/test/unit_test.hpp>
-#include <boost/test/test_case_template.hpp>
-
-#include <osrm/coordinate.hpp>
-
-#include <cstdint>
-#include <cmath>
-
-#include <algorithm>
-#include <memory>
-#include <random>
-#include <string>
-#include <utility>
-#include <unordered_set>
-#include <vector>
-
-BOOST_AUTO_TEST_SUITE(static_rtree)
-
-constexpr uint32_t TEST_BRANCHING_FACTOR = 8;
-constexpr uint32_t TEST_LEAF_NODE_SIZE = 64;
-
-typedef EdgeBasedNode TestData;
-using TestStaticRTree = StaticRTree<TestData,
- std::vector<FixedPointCoordinate>,
- false,
- TEST_BRANCHING_FACTOR,
- TEST_LEAF_NODE_SIZE>;
-using MiniStaticRTree = StaticRTree<TestData, std::vector<FixedPointCoordinate>, false, 2, 3>;
-
-// Choosen by a fair W20 dice roll (this value is completely arbitrary)
-constexpr unsigned RANDOM_SEED = 42;
-static const int32_t WORLD_MIN_LAT = -90 * COORDINATE_PRECISION;
-static const int32_t WORLD_MAX_LAT = 90 * COORDINATE_PRECISION;
-static const int32_t WORLD_MIN_LON = -180 * COORDINATE_PRECISION;
-static const int32_t WORLD_MAX_LON = 180 * COORDINATE_PRECISION;
-
-template <typename DataT> class LinearSearchNN
-{
- public:
- LinearSearchNN(const std::shared_ptr<std::vector<FixedPointCoordinate>> &coords,
- const std::vector<DataT> &edges)
- : coords(coords), edges(edges)
- {
- }
-
- std::vector<DataT> Nearest(const FixedPointCoordinate &input_coordinate,
- const unsigned num_results)
- {
- std::vector<DataT> local_edges(edges);
-
- std::nth_element(
- local_edges.begin(), local_edges.begin() + num_results, local_edges.end(),
- [this, &input_coordinate](const DataT &lhs, const DataT &rhs)
- {
- float current_ratio = 0.;
- FixedPointCoordinate nearest;
- const float lhs_dist = coordinate_calculation::perpendicular_distance(
- coords->at(lhs.u), coords->at(lhs.v), input_coordinate, nearest, current_ratio);
- const float rhs_dist = coordinate_calculation::perpendicular_distance(
- coords->at(rhs.u), coords->at(rhs.v), input_coordinate, nearest, current_ratio);
- return lhs_dist < rhs_dist;
- });
- local_edges.resize(num_results);
-
- return local_edges;
- }
-
- private:
- const std::shared_ptr<std::vector<FixedPointCoordinate>> &coords;
- const std::vector<TestData> &edges;
-};
-
-template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomGraphFixture
-{
- struct TupleHash
- {
- typedef std::pair<unsigned, unsigned> argument_type;
- typedef std::size_t result_type;
-
- result_type operator()(const argument_type &t) const
- {
- std::size_t val{0};
- boost::hash_combine(val, t.first);
- boost::hash_combine(val, t.second);
- return val;
- }
- };
-
- RandomGraphFixture() : coords(std::make_shared<std::vector<FixedPointCoordinate>>())
- {
- BOOST_TEST_MESSAGE("Constructing " << NUM_NODES << " nodes and " << NUM_EDGES << " edges.");
-
- std::mt19937 g(RANDOM_SEED);
-
- std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
- std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
-
- for (unsigned i = 0; i < NUM_NODES; i++)
- {
- int lat = lat_udist(g);
- int lon = lon_udist(g);
- nodes.emplace_back(QueryNode(lat, lon, OSMNodeID(i)));
- coords->emplace_back(FixedPointCoordinate(lat, lon));
- }
-
- std::uniform_int_distribution<> edge_udist(0, nodes.size() - 1);
-
- std::unordered_set<std::pair<unsigned, unsigned>, TupleHash> used_edges;
-
- while (edges.size() < NUM_EDGES)
- {
- TestData data;
- data.u = edge_udist(g);
- data.v = edge_udist(g);
- if (used_edges.find(std::pair<unsigned, unsigned>(
- std::min(data.u, data.v), std::max(data.u, data.v))) == used_edges.end())
- {
- data.component.id = 0;
- edges.emplace_back(data);
- used_edges.emplace(std::min(data.u, data.v), std::max(data.u, data.v));
- }
- }
- }
-
- std::vector<QueryNode> nodes;
- std::shared_ptr<std::vector<FixedPointCoordinate>> coords;
- std::vector<TestData> edges;
-};
-
-struct GraphFixture
-{
- GraphFixture(const std::vector<std::pair<float, float>> &input_coords,
- const std::vector<std::pair<unsigned, unsigned>> &input_edges)
- : coords(std::make_shared<std::vector<FixedPointCoordinate>>())
- {
-
- for (unsigned i = 0; i < input_coords.size(); i++)
- {
- FixedPointCoordinate c(input_coords[i].first * COORDINATE_PRECISION,
- input_coords[i].second * COORDINATE_PRECISION);
- coords->emplace_back(c);
- nodes.emplace_back(QueryNode(c.lat, c.lon, OSMNodeID(i)));
- }
-
- for (const auto &pair : input_edges)
- {
- TestData d;
- d.u = pair.first;
- d.v = pair.second;
- // We set the forward nodes to the target node-based-node IDs, just
- // so we have something to test against. Because this isn't a real
- // graph, the actual values aren't important, we just need something
- // to examine during tests.
- d.forward_edge_based_node_id = pair.second;
- d.reverse_edge_based_node_id = pair.first;
- edges.emplace_back(d);
- }
- }
-
- std::vector<QueryNode> nodes;
- std::shared_ptr<std::vector<FixedPointCoordinate>> coords;
- std::vector<TestData> edges;
-};
-
-typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 3, TEST_LEAF_NODE_SIZE / 2>
- TestRandomGraphFixture_LeafHalfFull;
-typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 5, TEST_LEAF_NODE_SIZE>
- TestRandomGraphFixture_LeafFull;
-typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 10, TEST_LEAF_NODE_SIZE * 2>
- TestRandomGraphFixture_TwoLeaves;
-typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 3,
- TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR>
- TestRandomGraphFixture_Branch;
-typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 3,
- TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 2>
- TestRandomGraphFixture_MultipleLevels;
-
-template <typename RTreeT>
-void simple_verify_rtree(RTreeT &rtree,
- const std::shared_ptr<std::vector<FixedPointCoordinate>> &coords,
- const std::vector<TestData> &edges)
-{
- BOOST_TEST_MESSAGE("Verify end points");
- for (const auto &e : edges)
- {
- const FixedPointCoordinate &pu = coords->at(e.u);
- const FixedPointCoordinate &pv = coords->at(e.v);
- auto result_u = rtree.Nearest(pu, 1);
- auto result_v = rtree.Nearest(pv, 1);
- BOOST_CHECK(result_u.size() == 1 && result_v.size() == 1);
- BOOST_CHECK(result_u.front().u == e.u || result_u.front().v == e.u);
- BOOST_CHECK(result_v.front().u == e.v || result_v.front().v == e.v);
- }
-}
-
-template <typename RTreeT>
-void sampling_verify_rtree(RTreeT &rtree, LinearSearchNN<TestData> &lsnn, const std::vector<FixedPointCoordinate>& coords, unsigned num_samples)
-{
- std::mt19937 g(RANDOM_SEED);
- std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
- std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
- std::vector<FixedPointCoordinate> queries;
- for (unsigned i = 0; i < num_samples; i++)
- {
- queries.emplace_back(FixedPointCoordinate(lat_udist(g), lon_udist(g)));
- }
-
- BOOST_TEST_MESSAGE("Sampling queries");
- for (const auto &q : queries)
- {
- auto result_rtree = rtree.Nearest(q, 1);
- auto result_lsnn = lsnn.Nearest(q, 1);
- BOOST_CHECK(result_rtree.size() == 1);
- BOOST_CHECK(result_lsnn.size() == 1);
- auto rtree_u = result_rtree.back().u;
- auto rtree_v = result_rtree.back().v;
- auto lsnn_u = result_lsnn.back().u;
- auto lsnn_v = result_lsnn.back().v;
-
- float current_ratio = 0.;
- FixedPointCoordinate nearest;
- const float rtree_dist = coordinate_calculation::perpendicular_distance(
- coords[rtree_u], coords[rtree_v], q, nearest, current_ratio);
- const float lsnn_dist = coordinate_calculation::perpendicular_distance(
- coords[lsnn_u], coords[lsnn_v], q, nearest, current_ratio);
- BOOST_CHECK_LE(std::abs(rtree_dist - lsnn_dist), std::numeric_limits<float>::epsilon());
- }
-}
-
-template <typename FixtureT, typename RTreeT = TestStaticRTree>
-void build_rtree(const std::string &prefix,
- FixtureT *fixture,
- std::string &leaves_path,
- std::string &nodes_path)
-{
- nodes_path = prefix + ".ramIndex";
- leaves_path = prefix + ".fileIndex";
- const std::string coords_path = prefix + ".nodes";
-
- boost::filesystem::ofstream node_stream(coords_path, std::ios::binary);
- const auto num_nodes = static_cast<unsigned>(fixture->nodes.size());
- node_stream.write((char *)&num_nodes, sizeof(unsigned));
- node_stream.write((char *)&(fixture->nodes[0]), num_nodes * sizeof(QueryNode));
- node_stream.close();
-
- RTreeT r(fixture->edges, nodes_path, leaves_path, fixture->nodes);
-}
-
-template <typename FixtureT, typename RTreeT = TestStaticRTree>
-void construction_test(const std::string &prefix, FixtureT *fixture)
-{
- std::string leaves_path;
- std::string nodes_path;
- build_rtree<FixtureT, RTreeT>(prefix, fixture, leaves_path, nodes_path);
- RTreeT rtree(nodes_path, leaves_path, fixture->coords);
- LinearSearchNN<TestData> lsnn(fixture->coords, fixture->edges);
-
- simple_verify_rtree(rtree, fixture->coords, fixture->edges);
- sampling_verify_rtree(rtree, lsnn, *fixture->coords, 100);
-}
-
-BOOST_FIXTURE_TEST_CASE(construct_half_leaf_test, TestRandomGraphFixture_LeafHalfFull)
-{
- construction_test("test_1", this);
-}
-
-BOOST_FIXTURE_TEST_CASE(construct_full_leaf_test, TestRandomGraphFixture_LeafFull)
-{
- construction_test("test_2", this);
-}
-
-BOOST_FIXTURE_TEST_CASE(construct_two_leaves_test, TestRandomGraphFixture_TwoLeaves)
-{
- construction_test("test_3", this);
-}
-
-BOOST_FIXTURE_TEST_CASE(construct_branch_test, TestRandomGraphFixture_Branch)
-{
- construction_test("test_4", this);
-}
-
-BOOST_FIXTURE_TEST_CASE(construct_multiple_levels_test, TestRandomGraphFixture_MultipleLevels)
-{
- construction_test("test_5", this);
-}
-
-// Bug: If you querry a point that lies between two BBs that have a gap,
-// one BB will be pruned, even if it could contain a nearer match.
-BOOST_AUTO_TEST_CASE(regression_test)
-{
- using Coord = std::pair<float, float>;
- using Edge = std::pair<unsigned, unsigned>;
- GraphFixture fixture(
- {
- Coord(40.0, 0.0), Coord(35.0, 5.0),
-
- Coord(5.0, 5.0), Coord(0.0, 10.0),
-
- Coord(20.0, 10.0), Coord(20.0, 5.0),
-
- Coord(40.0, 100.0), Coord(35.0, 105.0),
-
- Coord(5.0, 105.0), Coord(0.0, 110.0),
- },
- {Edge(0, 1), Edge(2, 3), Edge(4, 5), Edge(6, 7), Edge(8, 9)});
-
- std::string leaves_path;
- std::string nodes_path;
- build_rtree<GraphFixture, MiniStaticRTree>("test_regression", &fixture, leaves_path,
- nodes_path);
- MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords);
- LinearSearchNN<TestData> lsnn(fixture.coords, fixture.edges);
-
- // query a node just right of the center of the gap
- FixedPointCoordinate input(20.0 * COORDINATE_PRECISION, 55.1 * COORDINATE_PRECISION);
- auto result_rtree = rtree.Nearest(input, 1);
- auto result_ls = lsnn.Nearest(input, 1);
-
- BOOST_CHECK(result_rtree.size() == 1);
- BOOST_CHECK(result_ls.size() == 1);
-
- BOOST_CHECK_EQUAL(result_ls.front().u, result_rtree.front().u);
- BOOST_CHECK_EQUAL(result_ls.front().v, result_rtree.front().v);
-}
-
-void TestRectangle(double width, double height, double center_lat, double center_lon)
-{
- FixedPointCoordinate center(center_lat * COORDINATE_PRECISION,
- center_lon * COORDINATE_PRECISION);
-
- TestStaticRTree::Rectangle rect;
- rect.min_lat = center.lat - height / 2.0 * COORDINATE_PRECISION;
- rect.max_lat = center.lat + height / 2.0 * COORDINATE_PRECISION;
- rect.min_lon = center.lon - width / 2.0 * COORDINATE_PRECISION;
- rect.max_lon = center.lon + width / 2.0 * COORDINATE_PRECISION;
-
- unsigned offset = 5 * COORDINATE_PRECISION;
- FixedPointCoordinate north(rect.max_lat + offset, center.lon);
- FixedPointCoordinate south(rect.min_lat - offset, center.lon);
- FixedPointCoordinate west(center.lat, rect.min_lon - offset);
- FixedPointCoordinate east(center.lat, rect.max_lon + offset);
- FixedPointCoordinate north_east(rect.max_lat + offset, rect.max_lon + offset);
- FixedPointCoordinate north_west(rect.max_lat + offset, rect.min_lon - offset);
- FixedPointCoordinate south_east(rect.min_lat - offset, rect.max_lon + offset);
- FixedPointCoordinate south_west(rect.min_lat - offset, rect.min_lon - offset);
-
- /* Distance to line segments of rectangle */
- BOOST_CHECK_EQUAL(rect.GetMinDist(north),
- coordinate_calculation::great_circle_distance(
- north, FixedPointCoordinate(rect.max_lat, north.lon)));
- BOOST_CHECK_EQUAL(rect.GetMinDist(south),
- coordinate_calculation::great_circle_distance(
- south, FixedPointCoordinate(rect.min_lat, south.lon)));
- BOOST_CHECK_EQUAL(rect.GetMinDist(west),
- coordinate_calculation::great_circle_distance(
- west, FixedPointCoordinate(west.lat, rect.min_lon)));
- BOOST_CHECK_EQUAL(rect.GetMinDist(east),
- coordinate_calculation::great_circle_distance(
- east, FixedPointCoordinate(east.lat, rect.max_lon)));
-
- /* Distance to corner points */
- BOOST_CHECK_EQUAL(rect.GetMinDist(north_east),
- coordinate_calculation::great_circle_distance(
- north_east, FixedPointCoordinate(rect.max_lat, rect.max_lon)));
- BOOST_CHECK_EQUAL(rect.GetMinDist(north_west),
- coordinate_calculation::great_circle_distance(
- north_west, FixedPointCoordinate(rect.max_lat, rect.min_lon)));
- BOOST_CHECK_EQUAL(rect.GetMinDist(south_east),
- coordinate_calculation::great_circle_distance(
- south_east, FixedPointCoordinate(rect.min_lat, rect.max_lon)));
- BOOST_CHECK_EQUAL(rect.GetMinDist(south_west),
- coordinate_calculation::great_circle_distance(
- south_west, FixedPointCoordinate(rect.min_lat, rect.min_lon)));
-}
-
-BOOST_AUTO_TEST_CASE(rectangle_test)
-{
- TestRectangle(10, 10, 5, 5);
- TestRectangle(10, 10, -5, 5);
- TestRectangle(10, 10, 5, -5);
- TestRectangle(10, 10, -5, -5);
- TestRectangle(10, 10, 0, 0);
-}
-
-BOOST_AUTO_TEST_CASE(bearing_tests)
-{
- using Coord = std::pair<float, float>;
- using Edge = std::pair<unsigned, unsigned>;
- GraphFixture fixture(
- {
- Coord(0.0, 0.0), Coord(10.0, 10.0),
- },
- {Edge(0, 1), Edge(1, 0)});
-
- std::string leaves_path;
- std::string nodes_path;
- build_rtree<GraphFixture, MiniStaticRTree>("test_bearing", &fixture, leaves_path, nodes_path);
- MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords);
- GeospatialQuery<MiniStaticRTree> query(rtree, fixture.coords);
-
- FixedPointCoordinate input(5.0 * COORDINATE_PRECISION, 5.1 * COORDINATE_PRECISION);
-
- {
- auto results = query.NearestPhantomNodes(input, 5);
- BOOST_CHECK_EQUAL(results.size(), 2);
- BOOST_CHECK_EQUAL(results.back().phantom_node.forward_node_id, 0);
- BOOST_CHECK_EQUAL(results.back().phantom_node.reverse_node_id, 1);
- }
-
- {
- auto results = query.NearestPhantomNodes(input, 5, 270, 10);
- BOOST_CHECK_EQUAL(results.size(), 0);
- }
-
- {
- auto results = query.NearestPhantomNodes(input, 5, 45, 10);
- BOOST_CHECK_EQUAL(results.size(), 2);
- BOOST_CHECK_EQUAL(results[0].phantom_node.forward_node_id, 1);
- BOOST_CHECK_EQUAL(results[0].phantom_node.reverse_node_id, SPECIAL_NODEID);
- BOOST_CHECK_EQUAL(results[1].phantom_node.forward_node_id, SPECIAL_NODEID);
- BOOST_CHECK_EQUAL(results[1].phantom_node.reverse_node_id, 1);
- }
-
- {
- auto results = query.NearestPhantomNodesInRange(input, 11000);
- BOOST_CHECK_EQUAL(results.size(), 2);
- }
-
- {
- auto results = query.NearestPhantomNodesInRange(input, 11000, 270, 10);
- BOOST_CHECK_EQUAL(results.size(), 0);
- }
-
- {
- auto results = query.NearestPhantomNodesInRange(input, 11000, 45, 10);
- BOOST_CHECK_EQUAL(results.size(), 2);
- BOOST_CHECK_EQUAL(results[0].phantom_node.forward_node_id, 1);
- BOOST_CHECK_EQUAL(results[0].phantom_node.reverse_node_id, SPECIAL_NODEID);
- BOOST_CHECK_EQUAL(results[1].phantom_node.forward_node_id, SPECIAL_NODEID);
- BOOST_CHECK_EQUAL(results[1].phantom_node.reverse_node_id, 1);
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/engine/base64.cpp b/unit_tests/engine/base64.cpp
new file mode 100644
index 0000000..4896965
--- /dev/null
+++ b/unit_tests/engine/base64.cpp
@@ -0,0 +1,80 @@
+#include "engine/base64.hpp"
+#include "engine/hint.hpp"
+#include "mocks/mock_datafacade.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include <iostream>
+#include <algorithm>
+
+// RFC 4648 "The Base16, Base32, and Base64 Data Encodings"
+BOOST_AUTO_TEST_SUITE(base64)
+
+// For test vectors see section 10: https://tools.ietf.org/html/rfc4648#section-10
+BOOST_AUTO_TEST_CASE(rfc4648_test_vectors)
+{
+ using namespace osrm::engine;
+
+ BOOST_CHECK_EQUAL(encodeBase64(""), "");
+ BOOST_CHECK_EQUAL(encodeBase64("f"), "Zg==");
+ BOOST_CHECK_EQUAL(encodeBase64("fo"), "Zm8=");
+ BOOST_CHECK_EQUAL(encodeBase64("foo"), "Zm9v");
+ BOOST_CHECK_EQUAL(encodeBase64("foob"), "Zm9vYg==");
+ BOOST_CHECK_EQUAL(encodeBase64("fooba"), "Zm9vYmE=");
+ BOOST_CHECK_EQUAL(encodeBase64("foobar"), "Zm9vYmFy");
+}
+
+BOOST_AUTO_TEST_CASE(rfc4648_test_vectors_roundtrip)
+{
+ using namespace osrm::engine;
+
+ BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("")), "");
+ BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("f")), "f");
+ BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("fo")), "fo");
+ BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("foo")), "foo");
+ BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("foob")), "foob");
+ BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("fooba")), "fooba");
+ BOOST_CHECK_EQUAL(decodeBase64(encodeBase64("foobar")), "foobar");
+}
+
+BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip)
+{
+ using namespace osrm::engine;
+ using namespace osrm::util;
+
+ const Coordinate coordinate;
+ const PhantomNode phantom;
+ const osrm::test::MockDataFacade facade{};
+
+ const Hint hint{phantom, facade.GetCheckSum()};
+
+ const auto base64 = hint.ToBase64();
+
+ BOOST_CHECK(0 == std::count(begin(base64), end(base64), '+'));
+ BOOST_CHECK(0 == std::count(begin(base64), end(base64), '/'));
+
+ const auto decoded = Hint::FromBase64(base64);
+
+ BOOST_CHECK_EQUAL(hint, decoded);
+}
+
+BOOST_AUTO_TEST_CASE(hint_encoding_decoding_roundtrip_bytewise)
+{
+ using namespace osrm::engine;
+ using namespace osrm::util;
+
+ const Coordinate coordinate;
+ const PhantomNode phantom;
+ const osrm::test::MockDataFacade facade{};
+
+ const Hint hint{phantom, facade.GetCheckSum()};
+
+ const auto decoded = Hint::FromBase64(hint.ToBase64());
+
+ BOOST_CHECK(std::equal(reinterpret_cast<const unsigned char *>(&hint),
+ reinterpret_cast<const unsigned char *>(&hint) + sizeof(Hint),
+ reinterpret_cast<const unsigned char *>(&decoded)));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/engine/douglas_peucker.cpp b/unit_tests/engine/douglas_peucker.cpp
new file mode 100644
index 0000000..b280c13
--- /dev/null
+++ b/unit_tests/engine/douglas_peucker.cpp
@@ -0,0 +1,109 @@
+#include "engine/douglas_peucker.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include <osrm/coordinate.hpp>
+
+#include <vector>
+
+BOOST_AUTO_TEST_SUITE(douglas_peucker_simplification)
+
+using namespace osrm;
+using namespace osrm::engine;
+
+BOOST_AUTO_TEST_CASE(removed_middle_test)
+{
+ /*
+ x
+ / \
+ x \
+ / \
+ x x
+ */
+ std::vector<util::Coordinate> coordinates = {
+ util::Coordinate(util::FloatLongitude(5), util::FloatLatitude(5)),
+ util::Coordinate(util::FloatLongitude(5.995715), util::FloatLatitude(6)),
+ util::Coordinate(util::FloatLongitude(10), util::FloatLatitude(10)),
+ util::Coordinate(util::FloatLongitude(15), util::FloatLatitude(5))};
+
+ for (unsigned z = 0; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
+ {
+ auto result = douglasPeucker(coordinates, z);
+ BOOST_CHECK_EQUAL(result.size(), 3);
+ BOOST_CHECK_EQUAL(result[0], coordinates[0]);
+ BOOST_CHECK_EQUAL(result[1], coordinates[2]);
+ BOOST_CHECK_EQUAL(result[2], coordinates[3]);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(removed_middle_test_zoom_sensitive)
+{
+ /*
+ x
+ / \
+ x \
+ / \
+ x x
+ */
+ std::vector<util::Coordinate> coordinates = {
+ util::Coordinate(util::FloatLongitude(5), util::FloatLatitude(5)),
+ util::Coordinate(util::FloatLongitude(6), util::FloatLatitude(6)),
+ util::Coordinate(util::FloatLongitude(10), util::FloatLatitude(10)),
+ util::Coordinate(util::FloatLongitude(15), util::FloatLatitude(5))};
+
+ // Coordinate 6,6 should start getting included at Z12 and higher
+ // Note that 5,5->6,6->10,10 is *not* a straight line on the surface
+ // of the earth
+ for (unsigned z = 0; z < 11; z++)
+ {
+ auto result = douglasPeucker(coordinates, z);
+ BOOST_CHECK_EQUAL(result.size(), 3);
+ }
+ // From 12 to max zoom, we should get all coordinates
+ for (unsigned z = 12; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
+ {
+ auto result = douglasPeucker(coordinates, z);
+ BOOST_CHECK_EQUAL(result.size(), 4);
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE(remove_second_node_test)
+{
+ for (unsigned z = 0; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
+ {
+ /*
+ x--x
+ | \
+ x-x x
+ |
+ x
+ */
+ std::vector<util::Coordinate> input = {
+ util::Coordinate(util::FixedLongitude(5 * COORDINATE_PRECISION),
+ util::FixedLatitude(5 * COORDINATE_PRECISION)),
+ util::Coordinate(util::FixedLongitude(5 * COORDINATE_PRECISION),
+ util::FixedLatitude(5 * COORDINATE_PRECISION +
+ detail::DOUGLAS_PEUCKER_THRESHOLDS[z])),
+ util::Coordinate(util::FixedLongitude(10 * COORDINATE_PRECISION),
+ util::FixedLatitude(10 * COORDINATE_PRECISION)),
+ util::Coordinate(util::FixedLongitude(10 * COORDINATE_PRECISION),
+ util::FixedLatitude(10 + COORDINATE_PRECISION +
+ detail::DOUGLAS_PEUCKER_THRESHOLDS[z] * 2)),
+ util::Coordinate(util::FixedLongitude(5 * COORDINATE_PRECISION),
+ util::FixedLatitude(15 * COORDINATE_PRECISION)),
+ util::Coordinate(util::FixedLongitude(5 * COORDINATE_PRECISION +
+ detail::DOUGLAS_PEUCKER_THRESHOLDS[z]),
+ util::FixedLatitude(15 * COORDINATE_PRECISION))};
+ BOOST_TEST_MESSAGE("Threshold (" << z << "): " << detail::DOUGLAS_PEUCKER_THRESHOLDS[z]);
+ auto result = douglasPeucker(input, z);
+ BOOST_CHECK_EQUAL(result.size(), 4);
+ BOOST_CHECK_EQUAL(input[0], result[0]);
+ BOOST_CHECK_EQUAL(input[2], result[1]);
+ BOOST_CHECK_EQUAL(input[3], result[2]);
+ BOOST_CHECK_EQUAL(input[5], result[3]);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/engine/geometry_string.cpp b/unit_tests/engine/geometry_string.cpp
new file mode 100644
index 0000000..5209460
--- /dev/null
+++ b/unit_tests/engine/geometry_string.cpp
@@ -0,0 +1,45 @@
+#include <boost/test/floating_point_comparison.hpp>
+#include <boost/test/unit_test.hpp>
+
+#include "engine/polyline_compressor.hpp"
+#include "util/coordinate_calculation.hpp"
+
+#include <osrm/coordinate.hpp>
+
+#include <cmath>
+#include <vector>
+
+BOOST_AUTO_TEST_SUITE(polyline)
+
+using namespace osrm;
+using namespace osrm::engine;
+
+BOOST_AUTO_TEST_CASE(decode)
+{
+ // Polyline string for the 5 coordinates
+ const std::string polyline = "_c`|@_c`|@o}@_pRo}@_pRo}@_pRo}@_pR";
+ const auto coords = decodePolyline(polyline);
+
+ // Test coordinates; these would be the coordinates we give the loc parameter,
+ // e.g. loc=10.00,10.0&loc=10.01,10.1...
+ util::Coordinate coord1(util::FloatLongitude(10.0), util::FloatLatitude(10.00));
+ util::Coordinate coord2(util::FloatLongitude(10.1), util::FloatLatitude(10.01));
+ util::Coordinate coord3(util::FloatLongitude(10.2), util::FloatLatitude(10.02));
+ util::Coordinate coord4(util::FloatLongitude(10.3), util::FloatLatitude(10.03));
+ util::Coordinate coord5(util::FloatLongitude(10.4), util::FloatLatitude(10.04));
+
+ // Put the test coordinates into the vector for comparison
+ std::vector<util::Coordinate> cmp_coords = {coord1, coord2, coord3, coord4, coord5};
+
+ BOOST_CHECK_EQUAL(cmp_coords.size(), coords.size());
+
+ for (unsigned i = 0; i < cmp_coords.size(); ++i)
+ {
+ BOOST_CHECK_CLOSE(static_cast<double>(util::toFloating(coords[i].lat)),
+ static_cast<double>(util::toFloating(cmp_coords[i].lat)), 0.0001);
+ BOOST_CHECK_CLOSE(static_cast<double>(util::toFloating(coords[i].lon)),
+ static_cast<double>(util::toFloating(cmp_coords[i].lon)), 0.0001);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/engine/guidance_assembly.cpp b/unit_tests/engine/guidance_assembly.cpp
new file mode 100644
index 0000000..6f50529
--- /dev/null
+++ b/unit_tests/engine/guidance_assembly.cpp
@@ -0,0 +1,20 @@
+#include "engine/guidance/assemble_overview.hpp"
+#include "engine/guidance/assemble_geometry.hpp"
+#include "engine/guidance/assemble_steps.hpp"
+#include "engine/guidance/assemble_route.hpp"
+#include "engine/guidance/assemble_leg.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+BOOST_AUTO_TEST_SUITE(guidance_assembly)
+
+BOOST_AUTO_TEST_CASE(rfc4648_test_vectors)
+{
+ using namespace osrm::engine::guidance;
+ using namespace osrm::engine;
+
+ // TODO(daniel-j-h):
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/engine_tests.cpp b/unit_tests/engine_tests.cpp
new file mode 100644
index 0000000..8154f03
--- /dev/null
+++ b/unit_tests/engine_tests.cpp
@@ -0,0 +1,7 @@
+#define BOOST_TEST_MODULE engine tests
+
+#include <boost/test/unit_test.hpp>
+
+/*
+ * This file will contain an automatically generated main function.
+ */
diff --git a/unit_tests/data_structures/compressed_edge_container.cpp b/unit_tests/extractor/compressed_edge_container.cpp
similarity index 95%
rename from unit_tests/data_structures/compressed_edge_container.cpp
rename to unit_tests/extractor/compressed_edge_container.cpp
index 12d9d3f..593ec59 100644
--- a/unit_tests/data_structures/compressed_edge_container.cpp
+++ b/unit_tests/extractor/compressed_edge_container.cpp
@@ -1,11 +1,14 @@
-#include "../../data_structures/compressed_edge_container.hpp"
-#include "../../typedefs.h"
+#include "extractor/compressed_edge_container.hpp"
+#include "util/typedefs.hpp"
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
BOOST_AUTO_TEST_SUITE(compressed_edge_container)
+using namespace osrm;
+using namespace osrm::extractor;
+
BOOST_AUTO_TEST_CASE(long_road_test)
{
// 0 1 2 3
diff --git a/unit_tests/algorithms/graph_compressor.cpp b/unit_tests/extractor/graph_compressor.cpp
similarity index 71%
rename from unit_tests/algorithms/graph_compressor.cpp
rename to unit_tests/extractor/graph_compressor.cpp
index a3407c0..7a6da7a 100644
--- a/unit_tests/algorithms/graph_compressor.cpp
+++ b/unit_tests/extractor/graph_compressor.cpp
@@ -1,9 +1,8 @@
-#include "../../algorithms/graph_compressor.hpp"
-#include "../../data_structures/compressed_edge_container.hpp"
-#include "../../data_structures/restriction_map.hpp"
-#include "../../data_structures/node_based_graph.hpp"
-#include "../../extractor/speed_profile.hpp"
-#include "../../typedefs.h"
+#include "extractor/graph_compressor.hpp"
+#include "extractor/compressed_edge_container.hpp"
+#include "extractor/restriction_map.hpp"
+#include "util/node_based_graph.hpp"
+#include "util/typedefs.hpp"
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
@@ -12,37 +11,39 @@
BOOST_AUTO_TEST_SUITE(graph_compressor)
+using namespace osrm;
+using namespace osrm::extractor;
+using InputEdge = util::NodeBasedDynamicGraph::InputEdge;
+using Graph = util::NodeBasedDynamicGraph;
+
BOOST_AUTO_TEST_CASE(long_road_test)
{
//
// 0---1---2---3---4
//
- SpeedProfileProperties speed_profile;
- GraphCompressor compressor(speed_profile);
+ GraphCompressor compressor;
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
RestrictionMap map;
CompressedEdgeContainer container;
- using InputEdge = NodeBasedDynamicGraph::InputEdge;
std::vector<InputEdge> edges = {
- // source, target, distance, edge_id, name_id, access_restricted, reversed, roundabout, travel_mode
- {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {2, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {3, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {3, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {4, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT}
- };
+ // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode
+ {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {2, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {3, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {3, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {4, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE}};
BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[2].data));
BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[4].data));
BOOST_ASSERT(edges[4].data.IsCompatibleTo(edges[6].data));
- NodeBasedDynamicGraph graph(5, edges);
+ Graph graph(5, edges);
compressor.Compress(barrier_nodes, traffic_lights, map, graph, container);
BOOST_CHECK_EQUAL(graph.FindEdge(0, 1), SPECIAL_EDGEID);
@@ -59,29 +60,27 @@ BOOST_AUTO_TEST_CASE(loop_test)
// | |
// 5---4---3
//
- SpeedProfileProperties speed_profile;
- GraphCompressor compressor(speed_profile);
+ GraphCompressor compressor;
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
RestrictionMap map;
CompressedEdgeContainer container;
- using InputEdge = NodeBasedDynamicGraph::InputEdge;
std::vector<InputEdge> edges = {
- // source, target, distance, edge_id, name_id, access_restricted, forward, backward, roundabout, travel_mode
- {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {0, 5, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {2, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {3, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {3, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {4, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {4, 5, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {5, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {5, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
+ // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode
+ {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {0, 5, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {2, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {3, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {3, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {4, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {4, 5, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {5, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {5, 4, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
};
BOOST_ASSERT(edges.size() == 12);
@@ -97,7 +96,7 @@ BOOST_AUTO_TEST_CASE(loop_test)
BOOST_ASSERT(edges[9].data.IsCompatibleTo(edges[10].data));
BOOST_ASSERT(edges[10].data.IsCompatibleTo(edges[11].data));
- NodeBasedDynamicGraph graph(6, edges);
+ Graph graph(6, edges);
compressor.Compress(barrier_nodes, traffic_lights, map, graph, container);
BOOST_CHECK_EQUAL(graph.FindEdge(5, 0), SPECIAL_EDGEID);
@@ -116,23 +115,21 @@ BOOST_AUTO_TEST_CASE(t_intersection)
// |
// 3
//
- SpeedProfileProperties speed_profile;
- GraphCompressor compressor(speed_profile);
+ GraphCompressor compressor;
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
RestrictionMap map;
CompressedEdgeContainer container;
- using InputEdge = NodeBasedDynamicGraph::InputEdge;
std::vector<InputEdge> edges = {
- // source, target, distance, edge_id, name_id, access_restricted, reversed, roundabout, travel_mode
- {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {1, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {3, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
+ // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode
+ {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {1, 3, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {3, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
};
BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data));
@@ -141,7 +138,7 @@ BOOST_AUTO_TEST_CASE(t_intersection)
BOOST_ASSERT(edges[3].data.IsCompatibleTo(edges[4].data));
BOOST_ASSERT(edges[4].data.IsCompatibleTo(edges[5].data));
- NodeBasedDynamicGraph graph(4, edges);
+ Graph graph(4, edges);
compressor.Compress(barrier_nodes, traffic_lights, map, graph, container);
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
@@ -154,27 +151,25 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
//
// 0---1---2
//
- SpeedProfileProperties speed_profile;
- GraphCompressor compressor(speed_profile);
+ GraphCompressor compressor;
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
RestrictionMap map;
CompressedEdgeContainer container;
- using InputEdge = NodeBasedDynamicGraph::InputEdge;
std::vector<InputEdge> edges = {
- // source, target, distance, edge_id, name_id, access_restricted, forward, backward, roundabout, travel_mode
- {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {1, 2, 1, SPECIAL_EDGEID, 1, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {2, 1, 1, SPECIAL_EDGEID, 1, false, false, false, true, TRAVEL_MODE_DEFAULT},
+ // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode
+ {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {1, 0, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {1, 2, 1, SPECIAL_EDGEID, 1, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {2, 1, 1, SPECIAL_EDGEID, 1, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
};
BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data));
BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[3].data));
- NodeBasedDynamicGraph graph(5, edges);
+ Graph graph(5, edges);
compressor.Compress(barrier_nodes, traffic_lights, map, graph, container);
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
@@ -186,24 +181,22 @@ BOOST_AUTO_TEST_CASE(direction_changes)
//
// 0-->1---2
//
- SpeedProfileProperties speed_profile;
- GraphCompressor compressor(speed_profile);
+ GraphCompressor compressor;
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
RestrictionMap map;
CompressedEdgeContainer container;
- using InputEdge = NodeBasedDynamicGraph::InputEdge;
std::vector<InputEdge> edges = {
- // source, target, distance, edge_id, name_id, access_restricted, reverse, roundabout, travel_mode
- {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {1, 0, 1, SPECIAL_EDGEID, 0, false, true, false, true, TRAVEL_MODE_DEFAULT},
- {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
- {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_DEFAULT},
+ // src, tgt, dist, edge_id, name_id, access_restricted, fwd, bkwd, roundabout, travel_mode
+ {0, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {1, 0, 1, SPECIAL_EDGEID, 0, false, true, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {1, 2, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
+ {2, 1, 1, SPECIAL_EDGEID, 0, false, false, false, true, TRAVEL_MODE_INACCESSIBLE},
};
- NodeBasedDynamicGraph graph(5, edges);
+ Graph graph(5, edges);
compressor.Compress(barrier_nodes, traffic_lights, map, graph, container);
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
diff --git a/unit_tests/data_structures/raster_source.cpp b/unit_tests/extractor/raster_source.cpp
similarity index 63%
rename from unit_tests/data_structures/raster_source.cpp
rename to unit_tests/extractor/raster_source.cpp
index 691cba1..1c66f12 100644
--- a/unit_tests/data_structures/raster_source.cpp
+++ b/unit_tests/extractor/raster_source.cpp
@@ -1,33 +1,6 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "../../data_structures/raster_source.hpp"
-#include "../../typedefs.h"
-#include "../../util/osrm_exception.hpp"
+#include "extractor/raster_source.hpp"
+#include "util/typedefs.hpp"
+#include "util/exception.hpp"
#include <osrm/coordinate.hpp>
@@ -36,16 +9,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
BOOST_AUTO_TEST_SUITE(raster_source)
+using namespace osrm;
+using namespace osrm::extractor;
+
int normalize(double coord) { return static_cast<int>(coord * COORDINATE_PRECISION); }
#define CHECK_QUERY(source_id, lon, lat, expected) \
BOOST_CHECK_EQUAL( \
- sources.getRasterDataFromSource(source_id, normalize(lon), normalize(lat)).datum, \
+ sources.getRasterDataFromSource(source_id, lon, lat).datum, \
expected)
#define CHECK_INTERPOLATE(source_id, lon, lat, expected) \
BOOST_CHECK_EQUAL( \
- sources.getRasterInterpolateFromSource(source_id, normalize(lon), normalize(lat)).datum, \
+ sources.getRasterInterpolateFromSource(source_id, lon, lat).datum, \
expected)
BOOST_AUTO_TEST_CASE(raster_test)
@@ -100,11 +76,11 @@ BOOST_AUTO_TEST_CASE(raster_test)
BOOST_CHECK_EQUAL(source_already_loaded_id, 0);
BOOST_CHECK_THROW(sources.getRasterDataFromSource(1, normalize(0.02), normalize(0.02)),
- osrm::exception);
+ util::exception);
BOOST_CHECK_THROW(
sources.loadRasterSource("../unit_tests/fixtures/nonexistent.asc", 0, 0.1, 0, 0.1, 7, 7),
- osrm::exception);
+ util::exception);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/extractor_tests.cpp b/unit_tests/extractor_tests.cpp
new file mode 100644
index 0000000..f2b4745
--- /dev/null
+++ b/unit_tests/extractor_tests.cpp
@@ -0,0 +1,7 @@
+#define BOOST_TEST_MODULE extractor tests
+
+#include <boost/test/unit_test.hpp>
+
+/*
+ * This file will contain an automatically generated main function.
+ */
diff --git a/unit_tests/library/args.hpp b/unit_tests/library/args.hpp
new file mode 100644
index 0000000..b595e32
--- /dev/null
+++ b/unit_tests/library/args.hpp
@@ -0,0 +1,16 @@
+#ifndef OSRM_UNIT_TEST_ARGS
+#define OSRM_UNIT_TEST_ARGS
+
+#include <vector>
+#include <string>
+
+inline std::vector<std::string> get_args()
+{
+ // Split off argv[0], store actual positional arguments in args
+ const auto argc = boost::unit_test::framework::master_test_suite().argc - 1;
+ const auto argv = boost::unit_test::framework::master_test_suite().argv + 1;
+
+ return {argv, argv + argc};
+}
+
+#endif
diff --git a/unit_tests/library/coordinates.hpp b/unit_tests/library/coordinates.hpp
new file mode 100644
index 0000000..2ccc689
--- /dev/null
+++ b/unit_tests/library/coordinates.hpp
@@ -0,0 +1,28 @@
+#ifndef OSRM_UNIT_TEST_COORDINATES
+#define OSRM_UNIT_TEST_COORDINATES
+
+#include "osrm/coordinate.hpp"
+
+#include <vector>
+
+// Somewhere in 2b8dd9343d5e615afc9c67bcc7028a63 Monaco
+
+// Convenience aliases
+using Longitude = osrm::util::FloatLongitude;
+using Latitude = osrm::util::FloatLatitude;
+using Location = osrm::util::Coordinate;
+using Locations = std::vector<Location>;
+
+inline Location get_dummy_location()
+{
+ return {osrm::util::FloatLongitude{7.437069}, osrm::util::FloatLatitude{43.749249}};
+}
+
+inline Locations get_locations_in_small_component()
+{
+ return {{Longitude{7.438023}, Latitude{43.746465}},
+ {Longitude{7.439263}, Latitude{43.746543}},
+ {Longitude{7.438190}, Latitude{43.747560}}};
+}
+
+#endif
diff --git a/unit_tests/library/equal_json.hpp b/unit_tests/library/equal_json.hpp
new file mode 100644
index 0000000..8e2f9ac
--- /dev/null
+++ b/unit_tests/library/equal_json.hpp
@@ -0,0 +1,27 @@
+#ifndef UNIT_TESTS_JSON_EQUAL
+#define UNIT_TESTS_JSON_EQUAL
+
+#include <boost/test/included/unit_test.hpp>
+
+#include "util/json_deep_compare.hpp"
+
+boost::test_tools::predicate_result compareJSON(const osrm::util::json::Value &reference,
+ const osrm::util::json::Value &result)
+{
+ std::string reason;
+ auto is_same = osrm::util::json::compare(reference, result, reason);
+ if (!is_same)
+ {
+ boost::test_tools::predicate_result res(false);
+
+ res.message() << reason;
+
+ return res;
+ }
+
+ return true;
+}
+
+#define CHECK_EQUAL_JSON(reference, result) BOOST_CHECK(compareJSON(reference, result));
+
+#endif
diff --git a/unit_tests/library/fixture.hpp b/unit_tests/library/fixture.hpp
new file mode 100644
index 0000000..568593d
--- /dev/null
+++ b/unit_tests/library/fixture.hpp
@@ -0,0 +1,21 @@
+#ifndef OSRM_LIBRARY_TEST_FIXTURE
+#define OSRM_LIBRARY_TEST_FIXTURE
+
+#include "osrm/engine_config.hpp"
+#include "osrm/osrm.hpp"
+
+#include <string>
+
+// I couldn't get Boost.UnitTest to provide a test suite level fixture with custom
+// arguments per test suite (osrm base path from argv), so this has to suffice.
+
+inline osrm::OSRM getOSRM(const std::string &base_path)
+{
+ osrm::EngineConfig config;
+ config.storage_config = {base_path};
+ config.use_shared_memory = false;
+
+ return osrm::OSRM{config};
+}
+
+#endif
diff --git a/unit_tests/library/limits.cpp b/unit_tests/library/limits.cpp
new file mode 100644
index 0000000..8632171
--- /dev/null
+++ b/unit_tests/library/limits.cpp
@@ -0,0 +1,139 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include "args.hpp"
+
+#include "osrm/trip_parameters.hpp"
+#include "osrm/route_parameters.hpp"
+#include "osrm/table_parameters.hpp"
+#include "osrm/match_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+BOOST_AUTO_TEST_SUITE(limits)
+
+BOOST_AUTO_TEST_CASE(test_trip_limits)
+{
+ const auto args = get_args();
+ BOOST_REQUIRE_EQUAL(args.size(), 1);
+
+ using namespace osrm;
+
+ EngineConfig config;
+ config.storage_config = {args[0]};
+ config.use_shared_memory = false;
+ config.max_locations_trip = 2;
+
+ OSRM osrm{config};
+
+ TripParameters params;
+ params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+ params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+ params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+
+ json::Object result;
+
+ const auto rc = osrm.Trip(params, result);
+
+ BOOST_CHECK(rc == Status::Error);
+
+ // Make sure we're not accidentally hitting a guard code path before
+ const auto code = result.values["code"].get<json::String>().value;
+ BOOST_CHECK(code == "TooBig"); // per the New-Server API spec
+}
+
+BOOST_AUTO_TEST_CASE(test_route_limits)
+{
+ const auto args = get_args();
+ BOOST_REQUIRE_EQUAL(args.size(), 1);
+
+ using namespace osrm;
+
+ EngineConfig config;
+ config.storage_config = {args[0]};
+ config.use_shared_memory = false;
+ config.max_locations_viaroute = 2;
+
+ OSRM osrm{config};
+
+ RouteParameters params;
+ params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+ params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+ params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+
+ json::Object result;
+
+ const auto rc = osrm.Route(params, result);
+
+ BOOST_CHECK(rc == Status::Error);
+
+ // Make sure we're not accidentally hitting a guard code path before
+ const auto code = result.values["code"].get<json::String>().value;
+ BOOST_CHECK(code == "TooBig"); // per the New-Server API spec
+}
+
+BOOST_AUTO_TEST_CASE(test_table_limits)
+{
+ const auto args = get_args();
+ BOOST_REQUIRE_EQUAL(args.size(), 1);
+
+ using namespace osrm;
+
+ EngineConfig config;
+ config.storage_config = {args[0]};
+ config.use_shared_memory = false;
+ config.max_locations_distance_table = 2;
+
+ OSRM osrm{config};
+
+ TableParameters params;
+ params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+ params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+ params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+
+ json::Object result;
+
+ const auto rc = osrm.Table(params, result);
+
+ BOOST_CHECK(rc == Status::Error);
+
+ // Make sure we're not accidentally hitting a guard code path before
+ const auto code = result.values["code"].get<json::String>().value;
+ BOOST_CHECK(code == "TooBig"); // per the New-Server API spec
+}
+
+BOOST_AUTO_TEST_CASE(test_match_limits)
+{
+ const auto args = get_args();
+ BOOST_REQUIRE_EQUAL(args.size(), 1);
+
+ using namespace osrm;
+
+ EngineConfig config;
+ config.storage_config = {args[0]};
+ config.use_shared_memory = false;
+ config.max_locations_map_matching = 2;
+
+ OSRM osrm{config};
+
+ MatchParameters params;
+ params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+ params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+ params.coordinates.emplace_back(util::FloatLongitude{}, util::FloatLatitude{});
+
+ json::Object result;
+
+ const auto rc = osrm.Match(params, result);
+
+ BOOST_CHECK(rc == Status::Error);
+
+ // Make sure we're not accidentally hitting a guard code path before
+ const auto code = result.values["code"].get<json::String>().value;
+ BOOST_CHECK(code == "TooBig"); // per the New-Server API spec
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library/match.cpp b/unit_tests/library/match.cpp
new file mode 100644
index 0000000..5cd2739
--- /dev/null
+++ b/unit_tests/library/match.cpp
@@ -0,0 +1,37 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include "args.hpp"
+#include "fixture.hpp"
+
+#include "osrm/match_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+BOOST_AUTO_TEST_SUITE(match)
+
+BOOST_AUTO_TEST_CASE(test_match)
+{
+ const auto args = get_args();
+ BOOST_REQUIRE_EQUAL(args.size(), 1);
+
+ using namespace osrm;
+
+ auto osrm = getOSRM(args[0]);
+
+ /*
+ MatchParameters params;
+
+ json::Object result;
+
+ const auto rc = osrm.Match(params, result);
+
+ BOOST_CHECK(rc == Status::Ok || rc == Status::Error);
+ */
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library/nearest.cpp b/unit_tests/library/nearest.cpp
new file mode 100644
index 0000000..b56f0f7
--- /dev/null
+++ b/unit_tests/library/nearest.cpp
@@ -0,0 +1,116 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include "args.hpp"
+#include "fixture.hpp"
+#include "coordinates.hpp"
+
+#include "osrm/nearest_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+BOOST_AUTO_TEST_SUITE(nearest)
+
+BOOST_AUTO_TEST_CASE(test_nearest_response)
+{
+ const auto args = get_args();
+ auto osrm = getOSRM(args.at(0));
+
+ using namespace osrm;
+
+ NearestParameters params;
+ params.coordinates.push_back(get_dummy_location());
+
+ json::Object result;
+ const auto rc = osrm.Nearest(params, result);
+ BOOST_REQUIRE(rc == Status::Ok);
+
+ const auto code = result.values.at("code").get<json::String>().value;
+ BOOST_CHECK_EQUAL(code, "ok");
+
+ const auto &waypoints = result.values.at("waypoints").get<json::Array>().values;
+ BOOST_CHECK(!waypoints.empty()); // the dataset has at least one nearest coordinate
+
+ for (const auto &waypoint : waypoints)
+ {
+ const auto &waypoint_object = waypoint.get<json::Object>();
+ const auto distance = waypoint_object.values.at("distance").get<json::Number>().value;
+ BOOST_CHECK(distance >= 0);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_nearest_response_no_coordinates)
+{
+ const auto args = get_args();
+ auto osrm = getOSRM(args.at(0));
+
+ using namespace osrm;
+
+ NearestParameters params;
+
+ json::Object result;
+ const auto rc = osrm.Nearest(params, result);
+ BOOST_REQUIRE(rc == Status::Error);
+
+ const auto code = result.values.at("code").get<json::String>().value;
+ BOOST_CHECK_EQUAL(code, "InvalidOptions");
+}
+
+BOOST_AUTO_TEST_CASE(test_nearest_response_multiple_coordinates)
+{
+ const auto args = get_args();
+ auto osrm = getOSRM(args.at(0));
+
+ using namespace osrm;
+
+ NearestParameters params;
+ params.coordinates.push_back(get_dummy_location());
+ params.coordinates.push_back(get_dummy_location());
+
+ json::Object result;
+ const auto rc = osrm.Nearest(params, result);
+ BOOST_REQUIRE(rc == Status::Error);
+
+ const auto code = result.values.at("code").get<json::String>().value;
+ BOOST_CHECK_EQUAL(code, "InvalidOptions");
+}
+
+BOOST_AUTO_TEST_CASE(test_nearest_response_for_location_in_small_component)
+{
+ const auto args = get_args();
+ auto osrm = getOSRM(args.at(0));
+
+ using namespace osrm;
+
+ const auto locations = get_locations_in_small_component();
+
+ NearestParameters params;
+ params.coordinates.push_back(locations.at(0));
+ params.number_of_results = 3;
+
+ json::Object result;
+ const auto rc = osrm.Nearest(params, result);
+ BOOST_REQUIRE(rc == Status::Ok);
+
+ const auto code = result.values.at("code").get<json::String>().value;
+ BOOST_CHECK_EQUAL(code, "ok");
+
+ const auto &waypoints = result.values.at("waypoints").get<json::Array>().values;
+ BOOST_CHECK(!waypoints.empty());
+
+ for (const auto &waypoint : waypoints)
+ {
+ const auto &waypoint_object = waypoint.get<json::Object>();
+
+ // Everything within ~20m (actually more) is still in small component.
+ // Nearest service should snap to road network without considering components.
+ const auto distance = waypoint_object.values.at("distance").get<json::Number>().value;
+ BOOST_CHECK_LT(distance, 20);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library/route.cpp b/unit_tests/library/route.cpp
new file mode 100644
index 0000000..e93ceba
--- /dev/null
+++ b/unit_tests/library/route.cpp
@@ -0,0 +1,232 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include "args.hpp"
+#include "fixture.hpp"
+#include "equal_json.hpp"
+#include "coordinates.hpp"
+
+#include "osrm/route_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+BOOST_AUTO_TEST_SUITE(route)
+
+BOOST_AUTO_TEST_CASE(test_route_same_coordinates_fixture)
+{
+ const auto args = get_args();
+ auto osrm = getOSRM(args.at(0));
+
+ using namespace osrm;
+
+ RouteParameters params;
+ params.coordinates.push_back(get_dummy_location());
+ params.coordinates.push_back(get_dummy_location());
+
+ json::Object result;
+ const auto rc = osrm.Route(params, result);
+ BOOST_CHECK(rc == Status::Ok);
+
+ json::Object reference{
+ {{"code", "ok"},
+ {"waypoints",
+ json::Array{{json::Object{{{"name", ""}, {"location", json::Array{}}, {"hint", ""}}},
+ json::Object{{{"name", ""}, {"location", json::Array{}}, {"hint", ""}}}}}},
+ {"routes", json::Array{{json::Object{
+ {{"distance", 0.},
+ {"duration", 0.},
+ {"geometry", ""},
+ {"legs", json::Array{{json::Object{
+ {{"distance", 0.},
+ {"duration", 0.},
+ {"summary", ""},
+ {"steps", json::Array{{json::Object{
+ {{"duration", 0.},
+ {"distance", 0.},
+ {"geometry", ""},
+ {"name", ""},
+ {"mode", "driving"},
+ {"maneuver", json::Object{{
+ {"type", "depart"},
+ {"location", json::Array{}},
+ {"modifier", ""},
+ {"bearing_before", 0.},
+ {"bearing_after", 0.},
+ {"exit", 0},
+ }}}}}}}}}}}}}}}}}}}};
+
+ CHECK_EQUAL_JSON(reference, result);
+}
+
+BOOST_AUTO_TEST_CASE(test_route_same_coordinates)
+{
+ const auto args = get_args();
+ auto osrm = getOSRM(args.at(0));
+
+ using namespace osrm;
+
+ RouteParameters params;
+ params.coordinates.push_back(get_dummy_location());
+ params.coordinates.push_back(get_dummy_location());
+ params.coordinates.push_back(get_dummy_location());
+
+ json::Object result;
+ const auto rc = osrm.Route(params, result);
+ BOOST_CHECK(rc == Status::Ok);
+
+ const auto code = result.values.at("code").get<json::String>().value;
+ BOOST_CHECK_EQUAL(code, "ok");
+
+ const auto &waypoints = result.values.at("waypoints").get<json::Array>().values;
+ BOOST_CHECK(waypoints.size() == params.coordinates.size());
+
+ for (const auto &waypoint : waypoints)
+ {
+ const auto &waypoint_object = waypoint.get<json::Object>();
+
+ // nothing can be said about name, empty or contains name of the street
+ const auto name = waypoint_object.values.at("name").get<json::String>().value;
+ BOOST_CHECK(((void)name, true));
+
+ const auto location = waypoint_object.values.at("location").get<json::Array>().values;
+ const auto longitude = location[0].get<json::Number>().value;
+ const auto latitude = location[1].get<json::Number>().value;
+ BOOST_CHECK(longitude >= -180. && longitude <= 180.);
+ BOOST_CHECK(latitude >= -90. && latitude <= 90.);
+
+ const auto hint = waypoint_object.values.at("hint").get<json::String>().value;
+ BOOST_CHECK(!hint.empty());
+ }
+
+ // alternative=true by default
+ const auto &routes = result.values.at("routes").get<json::Array>().values;
+ BOOST_CHECK(!routes.empty());
+ BOOST_CHECK(routes.size() > 1);
+
+ for (const auto &route : routes)
+ {
+ const auto &route_object = route.get<json::Object>();
+
+ const auto distance = route_object.values.at("distance").get<json::Number>().value;
+ BOOST_CHECK_EQUAL(distance, 0);
+
+ const auto duration = route_object.values.at("duration").get<json::Number>().value;
+ BOOST_CHECK_EQUAL(duration, 0);
+
+ // geometries=polyline by default
+ const auto geometry = route_object.values.at("geometry").get<json::String>().value;
+ BOOST_CHECK(!geometry.empty());
+
+ const auto &legs = route_object.values.at("legs").get<json::Array>().values;
+ BOOST_CHECK(!legs.empty());
+
+ for (const auto &leg : legs)
+ {
+ const auto &leg_object = leg.get<json::Object>();
+
+ const auto distance = leg_object.values.at("distance").get<json::Number>().value;
+ BOOST_CHECK_EQUAL(distance, 0);
+
+ const auto duration = leg_object.values.at("duration").get<json::Number>().value;
+ BOOST_CHECK_EQUAL(duration, 0);
+
+ // nothing can be said about summary, empty or contains human readable summary
+ const auto summary = leg_object.values.at("summary").get<json::String>().value;
+ BOOST_CHECK(((void)summary, true));
+
+ // steps=true by default
+ const auto &steps = leg_object.values.at("steps").get<json::Array>().values;
+ BOOST_CHECK(!steps.empty());
+
+ for (const auto &step : steps)
+ {
+ const auto &step_object = step.get<json::Object>();
+
+ const auto distance = step_object.values.at("distance").get<json::Number>().value;
+ BOOST_CHECK_EQUAL(distance, 0);
+
+ const auto duration = step_object.values.at("duration").get<json::Number>().value;
+ BOOST_CHECK_EQUAL(duration, 0);
+
+ // geometries=polyline by default
+ const auto geometry = step_object.values.at("geometry").get<json::String>().value;
+ BOOST_CHECK(!geometry.empty());
+
+ // nothing can be said about name, empty or contains way name
+ const auto name = step_object.values.at("name").get<json::String>().value;
+ BOOST_CHECK(((void)name, true));
+
+ // nothing can be said about mode, contains mode of transportation
+ const auto mode = step_object.values.at("mode").get<json::String>().value;
+ BOOST_CHECK(!name.empty());
+
+ const auto &maneuver = step_object.values.at("maneuver").get<json::Object>().values;
+
+ const auto location = maneuver.at("location").get<json::Array>().values;
+ const auto longitude = location[0].get<json::Number>().value;
+ const auto latitude = location[1].get<json::Number>().value;
+ BOOST_CHECK(longitude >= -180. && longitude <= 180.);
+ BOOST_CHECK(latitude >= -90. && latitude <= 90.);
+
+ const auto bearing_before = maneuver.at("bearing_before").get<json::Number>().value;
+ const auto bearing_after = maneuver.at("bearing_after").get<json::Number>().value;
+ BOOST_CHECK(bearing_before >= 0. && bearing_before <= 360.);
+ BOOST_CHECK(bearing_after >= 0. && bearing_after <= 360.);
+
+ const auto type = maneuver.at("type").get<json::String>().value;
+ BOOST_CHECK(!type.empty());
+
+ // modifier is optional
+ // TODO(daniel-j-h):
+
+ // exit is optional
+ // TODO(daniel-j-h):
+ }
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_route_response_for_locations_in_small_component)
+{
+ const auto args = get_args();
+ auto osrm = getOSRM(args.at(0));
+
+ using namespace osrm;
+
+ const auto locations = get_locations_in_small_component();
+
+ RouteParameters params;
+ params.coordinates.push_back(locations.at(0));
+ params.coordinates.push_back(locations.at(1));
+ params.coordinates.push_back(locations.at(2));
+
+ json::Object result;
+ const auto rc = osrm.Route(params, result);
+ BOOST_CHECK(rc == Status::Ok);
+
+ const auto code = result.values.at("code").get<json::String>().value;
+ BOOST_CHECK_EQUAL(code, "ok");
+
+ const auto &waypoints = result.values.at("waypoints").get<json::Array>().values;
+ BOOST_CHECK_EQUAL(waypoints.size(), params.coordinates.size());
+
+ for (const auto &waypoint : waypoints)
+ {
+ const auto &waypoint_object = waypoint.get<json::Object>();
+
+ const auto location = waypoint_object.values.at("location").get<json::Array>().values;
+ const auto longitude = location[0].get<json::Number>().value;
+ const auto latitude = location[1].get<json::Number>().value;
+ BOOST_CHECK(longitude >= -180. && longitude <= 180.);
+ BOOST_CHECK(latitude >= -90. && latitude <= 90.);
+
+ // TODO(daniel-j-h): we could do a Nearest request for each waypoint, verifying
+ // that we did indeed not snap to the input locations inside the small component.
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library/table.cpp b/unit_tests/library/table.cpp
new file mode 100644
index 0000000..bab5312
--- /dev/null
+++ b/unit_tests/library/table.cpp
@@ -0,0 +1,37 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include "args.hpp"
+#include "fixture.hpp"
+
+#include "osrm/table_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+BOOST_AUTO_TEST_SUITE(table)
+
+BOOST_AUTO_TEST_CASE(test_table)
+{
+ const auto args = get_args();
+ BOOST_REQUIRE_EQUAL(args.size(), 1);
+
+ using namespace osrm;
+
+ auto osrm = getOSRM(args[0]);
+
+ /*
+ TableParameters params;
+
+ json::Object result;
+
+ const auto rc = osrm.Table(params, result);
+
+ BOOST_CHECK(rc == Status::Ok || rc == Status::Error);
+ */
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library/tile.cpp b/unit_tests/library/tile.cpp
new file mode 100644
index 0000000..2ca674b
--- /dev/null
+++ b/unit_tests/library/tile.cpp
@@ -0,0 +1,31 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include "args.hpp"
+#include "fixture.hpp"
+
+#include "osrm/tile_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+BOOST_AUTO_TEST_SUITE(tile)
+
+BOOST_AUTO_TEST_CASE(test_tile)
+{
+ const auto args = get_args();
+ auto osrm = getOSRM(args.at(0));
+
+ using namespace osrm;
+
+ TileParameters params{0, 0, 1};
+
+ std::string result;
+ const auto rc = osrm.Tile(params, result);
+ BOOST_CHECK(rc == Status::Ok);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library/trip.cpp b/unit_tests/library/trip.cpp
new file mode 100644
index 0000000..7bfd1c2
--- /dev/null
+++ b/unit_tests/library/trip.cpp
@@ -0,0 +1,37 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include "args.hpp"
+#include "fixture.hpp"
+
+#include "osrm/trip_parameters.hpp"
+
+#include "osrm/coordinate.hpp"
+#include "osrm/engine_config.hpp"
+#include "osrm/json_container.hpp"
+#include "osrm/status.hpp"
+#include "osrm/osrm.hpp"
+
+BOOST_AUTO_TEST_SUITE(trip)
+
+BOOST_AUTO_TEST_CASE(test_trip)
+{
+ const auto args = get_args();
+ BOOST_REQUIRE_EQUAL(args.size(), 1);
+
+ using namespace osrm;
+
+ auto osrm = getOSRM(args[0]);
+
+ /*
+ TripParameters params;
+
+ json::Object result;
+
+ const auto rc = osrm.Trip(params, result);
+
+ BOOST_CHECK(rc == Status::Ok || rc == Status::Error);
+ */
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/library_tests.cpp b/unit_tests/library_tests.cpp
new file mode 100644
index 0000000..6f75356
--- /dev/null
+++ b/unit_tests/library_tests.cpp
@@ -0,0 +1,7 @@
+#define BOOST_TEST_MODULE library tests
+
+#include <boost/test/unit_test.hpp>
+
+/*
+ * This file will contain an automatically generated main function.
+ */
diff --git a/unit_tests/mocks/mock_datafacade.hpp b/unit_tests/mocks/mock_datafacade.hpp
new file mode 100644
index 0000000..cb05a94
--- /dev/null
+++ b/unit_tests/mocks/mock_datafacade.hpp
@@ -0,0 +1,178 @@
+#ifndef MOCK_DATAFACADE_HPP
+#define MOCK_DATAFACADE_HPP
+
+// implements all data storage when shared memory _IS_ used
+
+#include "extractor/guidance/turn_instruction.hpp"
+#include "engine/datafacade/datafacade_base.hpp"
+#include "contractor/query_edge.hpp"
+
+namespace osrm
+{
+namespace test
+{
+
+class MockDataFacade final : public engine::datafacade::BaseDataFacade
+{
+ private:
+ EdgeData foo;
+
+ public:
+ unsigned GetNumberOfNodes() const override { return 0; }
+ unsigned GetNumberOfEdges() const override { return 0; }
+ unsigned GetOutDegree(const NodeID /* n */) const override { return 0; }
+ NodeID GetTarget(const EdgeID /* e */) const override { return SPECIAL_NODEID; }
+ const EdgeData &GetEdgeData(const EdgeID /* e */) const override { return foo; }
+ EdgeID BeginEdges(const NodeID /* n */) const override { return SPECIAL_EDGEID; }
+ EdgeID EndEdges(const NodeID /* n */) const override { return SPECIAL_EDGEID; }
+ osrm::engine::datafacade::EdgeRange GetAdjacentEdgeRange(const NodeID /* node */) const override
+ {
+ return util::irange(static_cast<EdgeID>(0), static_cast<EdgeID>(0));
+ }
+ EdgeID FindEdge(const NodeID /* from */, const NodeID /* to */) const override
+ {
+ return SPECIAL_EDGEID;
+ }
+ EdgeID FindEdgeInEitherDirection(const NodeID /* from */, const NodeID /* to */) const override
+ {
+ return SPECIAL_EDGEID;
+ }
+ EdgeID FindEdgeIndicateIfReverse(const NodeID /* from */,
+ const NodeID /* to */,
+ bool & /* result */) const override
+ {
+ return SPECIAL_EDGEID;
+ }
+ util::Coordinate GetCoordinateOfNode(const unsigned /* id */) const override
+ {
+ return {util::FixedLongitude{0}, util::FixedLatitude{0}};
+ }
+ bool EdgeIsCompressed(const unsigned /* id */) const { return false; }
+ unsigned GetGeometryIndexForEdgeID(const unsigned /* id */) const override
+ {
+ return SPECIAL_NODEID;
+ }
+ void GetUncompressedGeometry(const EdgeID /* id */,
+ std::vector<NodeID> & /* result_nodes */) const override
+ {
+ }
+ void GetUncompressedWeights(const EdgeID /* id */,
+ std::vector<EdgeWeight> & /* result_weights */) const override
+ {
+ }
+ void GetUncompressedDatasources(const EdgeID /*id*/,
+ std::vector<uint8_t> & /*data_sources*/) const override
+ {
+ }
+ std::string GetDatasourceName(const uint8_t /*datasource_name_id*/) const override
+ {
+ return "";
+ }
+ extractor::guidance::TurnInstruction
+ GetTurnInstructionForEdgeID(const unsigned /* id */) const override
+ {
+ return extractor::guidance::TurnInstruction::NO_TURN();
+ }
+ extractor::TravelMode GetTravelModeForEdgeID(const unsigned /* id */) const override
+ {
+ return TRAVEL_MODE_INACCESSIBLE;
+ }
+ std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate /* south_west */,
+ const util::Coordinate /*north_east */) override
+ {
+ return {};
+ }
+
+ std::vector<engine::PhantomNodeWithDistance>
+ NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
+ const float /*max_distance*/,
+ const int /*bearing*/,
+ const int /*bearing_range*/) override
+ {
+ return {};
+ }
+
+ std::vector<engine::PhantomNodeWithDistance>
+ NearestPhantomNodesInRange(const util::Coordinate /*input_coordinate*/,
+ const float /*max_distance*/) override
+ {
+ return {};
+ }
+
+ std::vector<engine::PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
+ const unsigned /*max_results*/,
+ const double /*max_distance*/,
+ const int /*bearing*/,
+ const int /*bearing_range*/) override
+ {
+ return {};
+ }
+
+ std::vector<engine::PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
+ const unsigned /*max_results*/,
+ const int /*bearing*/,
+ const int /*bearing_range*/) override
+ {
+ return {};
+ }
+
+ std::vector<engine::PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
+ const unsigned /*max_results*/) override
+ {
+ return {};
+ }
+
+ std::vector<engine::PhantomNodeWithDistance>
+ NearestPhantomNodes(const util::Coordinate /*input_coordinate*/,
+ const unsigned /*max_results*/,
+ const double /*max_distance*/) override
+ {
+ return {};
+ }
+
+ std::pair<engine::PhantomNode, engine::PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(
+ const util::Coordinate /*input_coordinate*/) override
+ {
+ return {};
+ }
+
+ std::pair<engine::PhantomNode, engine::PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
+ const double /*max_distance*/) override
+ {
+ return {};
+ }
+
+ std::pair<engine::PhantomNode, engine::PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
+ const double /*max_distance*/,
+ const int /*bearing*/,
+ const int /*bearing_range*/) override
+ {
+ return {};
+ }
+
+ std::pair<engine::PhantomNode, engine::PhantomNode>
+ NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/,
+ const int /*bearing*/,
+ const int /*bearing_range*/) override
+ {
+ return {};
+ };
+
+ unsigned GetCheckSum() const override { return 0; }
+ bool IsCoreNode(const NodeID /* id */) const override { return false; }
+ unsigned GetNameIndexFromEdgeID(const unsigned /* id */) const override { return 0; }
+ std::string GetNameForID(const unsigned /* name_id */) const override { return ""; }
+ std::size_t GetCoreSize() const override { return 0; }
+ std::string GetTimestamp() const override { return ""; }
+ bool GetUTurnsDefault() const override { return true; }
+};
+} // ns test
+} // ns osrm
+
+#endif // MOCK_DATAFACADE_HPP
diff --git a/unit_tests/server/parameters_parser.cpp b/unit_tests/server/parameters_parser.cpp
new file mode 100644
index 0000000..e6f2d82
--- /dev/null
+++ b/unit_tests/server/parameters_parser.cpp
@@ -0,0 +1,330 @@
+#include "server/api/parameters_parser.hpp"
+
+#include "engine/api/base_parameters.hpp"
+#include "engine/api/route_parameters.hpp"
+#include "engine/api/table_parameters.hpp"
+#include "engine/api/match_parameters.hpp"
+#include "engine/api/trip_parameters.hpp"
+#include "engine/api/tile_parameters.hpp"
+#include "engine/api/nearest_parameters.hpp"
+
+#include <fstream>
+
+namespace osrm
+{
+namespace engine
+{
+namespace api
+{
+std::ostream &operator<<(std::ostream &out, api::RouteParameters::GeometriesType geometries)
+{
+ switch (geometries)
+ {
+ case api::RouteParameters::GeometriesType::GeoJSON:
+ out << "GeoJSON";
+ break;
+ case api::RouteParameters::GeometriesType::Polyline:
+ out << "Polyline";
+ break;
+ default:
+ BOOST_ASSERT_MSG(false, "GeometriesType not fully captured");
+ }
+ return out;
+}
+std::ostream &operator<<(std::ostream &out, api::RouteParameters::OverviewType overview)
+{
+ switch (overview)
+ {
+ case api::RouteParameters::OverviewType::False:
+ out << "False";
+ break;
+ case api::RouteParameters::OverviewType::Full:
+ out << "Full";
+ break;
+ case api::RouteParameters::OverviewType::Simplified:
+ out << "Simplified";
+ break;
+ default:
+ BOOST_ASSERT_MSG(false, "OverviewType not fully captured");
+ }
+ return out;
+}
+}
+std::ostream &operator<<(std::ostream &out, Bearing bearing)
+{
+ out << bearing.bearing << "," << bearing.range;
+ return out;
+}
+}
+}
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+#include <boost/optional/optional_io.hpp>
+
+#define CHECK_EQUAL_RANGE(R1, R2) \
+ BOOST_CHECK_EQUAL_COLLECTIONS(R1.begin(), R1.end(), R2.begin(), R2.end());
+
+BOOST_AUTO_TEST_SUITE(api_parameters_parser)
+
+using namespace osrm;
+using namespace osrm::server;
+
+// returns distance to front
+template <typename ParameterT> std::size_t testInvalidOptions(std::string options)
+{
+ auto iter = options.begin();
+ auto result = api::parseParameters<ParameterT>(iter, options.end());
+ BOOST_CHECK(!result);
+ return std::distance(options.begin(), iter);
+}
+
+BOOST_AUTO_TEST_CASE(invalid_route_urls)
+{
+ BOOST_CHECK_EQUAL(
+ testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&bla=foo"), 22UL);
+ BOOST_CHECK_EQUAL(
+ testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&bearings=foo"),
+ 32UL);
+ BOOST_CHECK_EQUAL(
+ testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&uturns=foo"),
+ 30UL);
+ BOOST_CHECK_EQUAL(
+ testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&radiuses=foo"),
+ 32UL);
+ BOOST_CHECK_EQUAL(
+ testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&hints=foo"), 22UL);
+ BOOST_CHECK_EQUAL(
+ testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&geometries=foo"),
+ 22UL);
+ BOOST_CHECK_EQUAL(
+ testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&overview=foo"),
+ 22L);
+ BOOST_CHECK_EQUAL(
+ testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&alternatives=foo"),
+ 22UL);
+}
+
+BOOST_AUTO_TEST_CASE(invalid_table_urls)
+{
+ BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>("1,2;3,4?sources=1&bla=foo"),
+ 17UL);
+ BOOST_CHECK_EQUAL(
+ testInvalidOptions<engine::api::TableParameters>("1,2;3,4?destinations=1&bla=foo"), 22UL);
+ BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>(
+ "1,2;3,4?sources=1&destinations=1&bla=foo"),
+ 32UL);
+ BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>("1,2;3,4?sources=foo"), 7UL);
+ BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>("1,2;3,4?destinations=foo"),
+ 7UL);
+}
+
+BOOST_AUTO_TEST_CASE(valid_route_urls)
+{
+ std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)},
+ {util::FloatLongitude(3), util::FloatLatitude(4)}};
+
+ engine::api::RouteParameters reference_1{};
+ reference_1.coordinates = coords_1;
+ auto result_1 = api::parseParameters<engine::api::RouteParameters>("1,2;3,4");
+ BOOST_CHECK(result_1);
+ BOOST_CHECK_EQUAL(reference_1.steps, result_1->steps);
+ BOOST_CHECK_EQUAL(reference_1.alternatives, result_1->alternatives);
+ BOOST_CHECK_EQUAL(reference_1.geometries, result_1->geometries);
+ BOOST_CHECK_EQUAL(reference_1.overview, result_1->overview);
+ BOOST_CHECK_EQUAL(reference_1.uturns, result_1->uturns);
+ CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
+ CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
+ CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
+
+ engine::api::RouteParameters reference_2{};
+ reference_2.coordinates = coords_1;
+ auto result_2 = api::parseParameters<engine::api::RouteParameters>(
+ "1,2;3,4?steps=true&alternatives=true&geometries=polyline&overview=simplified");
+ BOOST_CHECK(result_2);
+ BOOST_CHECK_EQUAL(reference_2.steps, result_2->steps);
+ BOOST_CHECK_EQUAL(reference_2.alternatives, result_2->alternatives);
+ BOOST_CHECK_EQUAL(reference_2.geometries, result_2->geometries);
+ BOOST_CHECK_EQUAL(reference_2.overview, result_2->overview);
+ BOOST_CHECK_EQUAL(reference_2.uturns, result_2->uturns);
+ CHECK_EQUAL_RANGE(reference_2.bearings, result_2->bearings);
+ CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
+ CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
+
+ engine::api::RouteParameters reference_3{false,
+ false,
+ engine::api::RouteParameters::GeometriesType::GeoJSON,
+ engine::api::RouteParameters::OverviewType::False,
+ true};
+ reference_3.coordinates = coords_1;
+ auto result_3 = api::parseParameters<engine::api::RouteParameters>(
+ "1,2;3,4?steps=false&alternatives=false&geometries=geojson&overview=false&uturns=true"
+ "false;");
+ BOOST_CHECK(result_3);
+ BOOST_CHECK_EQUAL(reference_3.steps, result_3->steps);
+ BOOST_CHECK_EQUAL(reference_3.alternatives, result_3->alternatives);
+ BOOST_CHECK_EQUAL(reference_3.geometries, result_3->geometries);
+ BOOST_CHECK_EQUAL(reference_3.overview, result_3->overview);
+ BOOST_CHECK_EQUAL(reference_3.uturns, result_3->uturns);
+ CHECK_EQUAL_RANGE(reference_3.bearings, result_3->bearings);
+ CHECK_EQUAL_RANGE(reference_3.radiuses, result_3->radiuses);
+ CHECK_EQUAL_RANGE(reference_3.coordinates, result_3->coordinates);
+
+ std::vector<boost::optional<engine::Hint>> hints_4 = {
+ engine::Hint::FromBase64(
+ "rVghAzxMzABMAwAA5h4CAKMIAAAQAAAAGAAAAAYAAAAAAAAAch8BAJ4AAACpWCED_0vMAAEAAQGLSzmR"),
+ engine::Hint::FromBase64(
+ "_4ghA4JuzAD_IAAAo28BAOYAAAAzAAAAAgAAAEwAAAAAAAAAdIwAAJ4AAAAXiSEDfm7MAAEAAQGLSzmR"),
+ engine::Hint::FromBase64(
+ "03AhA0vnzAA_SAAA_____3wEAAAYAAAAQAAAAB4AAABAAAAAoUYBAJ4AAADlcCEDSefMAAMAAQGLSzmR")};
+ engine::api::RouteParameters reference_4{false,
+ true,
+ engine::api::RouteParameters::GeometriesType::Polyline,
+ engine::api::RouteParameters::OverviewType::Simplified,
+ boost::optional<bool>{},
+ coords_1,
+ hints_4,
+ std::vector<boost::optional<double>>{},
+ std::vector<boost::optional<engine::Bearing>>{}};
+ auto result_4 = api::parseParameters<engine::api::RouteParameters>(
+ "1,2;3,4?steps=false&hints="
+ "rVghAzxMzABMAwAA5h4CAKMIAAAQAAAAGAAAAAYAAAAAAAAAch8BAJ4AAACpWCED_"
+ "0vMAAEAAQGLSzmR;_4ghA4JuzAD_"
+ "IAAAo28BAOYAAAAzAAAAAgAAAEwAAAAAAAAAdIwAAJ4AAAAXiSEDfm7MAAEAAQGLSzmR;03AhA0vnzAA_SAAA_____"
+ "3wEAAAYAAAAQAAAAB4AAABAAAAAoUYBAJ4AAADlcCEDSefMAAMAAQGLSzmR");
+ BOOST_CHECK(result_4);
+ BOOST_CHECK_EQUAL(reference_4.steps, result_4->steps);
+ BOOST_CHECK_EQUAL(reference_4.alternatives, result_4->alternatives);
+ BOOST_CHECK_EQUAL(reference_4.geometries, result_4->geometries);
+ BOOST_CHECK_EQUAL(reference_4.overview, result_4->overview);
+ BOOST_CHECK_EQUAL(reference_4.uturns, result_4->uturns);
+ CHECK_EQUAL_RANGE(reference_4.bearings, result_4->bearings);
+ CHECK_EQUAL_RANGE(reference_4.radiuses, result_4->radiuses);
+ CHECK_EQUAL_RANGE(reference_4.coordinates, result_4->coordinates);
+
+ std::vector<boost::optional<engine::Bearing>> bearings_4 = {
+ boost::none, engine::Bearing{200, 10}, engine::Bearing{100, 5},
+ };
+ engine::api::RouteParameters reference_5{false,
+ true,
+ engine::api::RouteParameters::GeometriesType::Polyline,
+ engine::api::RouteParameters::OverviewType::Simplified,
+ boost::optional<bool>{},
+ coords_1,
+ std::vector<boost::optional<engine::Hint>>{},
+ std::vector<boost::optional<double>>{},
+ bearings_4};
+ auto result_5 = api::parseParameters<engine::api::RouteParameters>(
+ "1,2;3,4?steps=false&bearings=;200,10;100,5");
+ BOOST_CHECK(result_5);
+ BOOST_CHECK_EQUAL(reference_5.steps, result_5->steps);
+ BOOST_CHECK_EQUAL(reference_5.alternatives, result_5->alternatives);
+ BOOST_CHECK_EQUAL(reference_5.geometries, result_5->geometries);
+ BOOST_CHECK_EQUAL(reference_5.overview, result_5->overview);
+ BOOST_CHECK_EQUAL(reference_5.uturns, result_5->uturns);
+ CHECK_EQUAL_RANGE(reference_5.bearings, result_5->bearings);
+ CHECK_EQUAL_RANGE(reference_5.radiuses, result_5->radiuses);
+ CHECK_EQUAL_RANGE(reference_5.coordinates, result_5->coordinates);
+
+ std::vector<util::Coordinate> coords_2 = {{util::FloatLongitude(0), util::FloatLatitude(1)},
+ {util::FloatLongitude(2), util::FloatLatitude(3)},
+ {util::FloatLongitude(4), util::FloatLatitude(5)}};
+
+ engine::api::RouteParameters reference_6{};
+ reference_6.coordinates = coords_2;
+ auto result_6 =
+ api::parseParameters<engine::api::RouteParameters>("polyline(_ibE?_seK_seK_seK_seK)");
+ BOOST_CHECK(result_6);
+ BOOST_CHECK_EQUAL(reference_6.steps, result_6->steps);
+ BOOST_CHECK_EQUAL(reference_6.alternatives, result_6->alternatives);
+ BOOST_CHECK_EQUAL(reference_6.geometries, result_6->geometries);
+ BOOST_CHECK_EQUAL(reference_6.overview, result_6->overview);
+ BOOST_CHECK_EQUAL(reference_6.uturns, result_6->uturns);
+ CHECK_EQUAL_RANGE(reference_6.bearings, result_6->bearings);
+ CHECK_EQUAL_RANGE(reference_6.radiuses, result_6->radiuses);
+ CHECK_EQUAL_RANGE(reference_6.coordinates, result_6->coordinates);
+}
+
+BOOST_AUTO_TEST_CASE(valid_table_urls)
+{
+ std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)},
+ {util::FloatLongitude(3), util::FloatLatitude(4)}};
+
+ engine::api::TableParameters reference_1{};
+ reference_1.coordinates = coords_1;
+ auto result_1 = api::parseParameters<engine::api::TableParameters>("1,2;3,4");
+ BOOST_CHECK(result_1);
+ CHECK_EQUAL_RANGE(reference_1.sources, result_1->sources);
+ CHECK_EQUAL_RANGE(reference_1.destinations, result_1->destinations);
+ CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
+ CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
+ CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
+
+ std::vector<std::size_t> sources_2 = {1, 2, 3};
+ std::vector<std::size_t> destinations_2 = {4, 5};
+ engine::api::TableParameters reference_2{sources_2, destinations_2};
+ reference_2.coordinates = coords_1;
+ auto result_2 = api::parseParameters<engine::api::TableParameters>(
+ "1,2;3,4?sources=1;2;3&destinations=4;5");
+ BOOST_CHECK(result_2);
+ CHECK_EQUAL_RANGE(reference_2.sources, result_2->sources);
+ CHECK_EQUAL_RANGE(reference_2.destinations, result_2->destinations);
+ CHECK_EQUAL_RANGE(reference_2.bearings, result_2->bearings);
+ CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
+ CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
+}
+
+BOOST_AUTO_TEST_CASE(valid_match_urls)
+{
+ std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)},
+ {util::FloatLongitude(3), util::FloatLatitude(4)}};
+
+ engine::api::MatchParameters reference_1{};
+ reference_1.coordinates = coords_1;
+ auto result_1 = api::parseParameters<engine::api::MatchParameters>("1,2;3,4");
+ BOOST_CHECK(result_1);
+ CHECK_EQUAL_RANGE(reference_1.timestamps, result_1->timestamps);
+ CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
+ CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
+ CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
+}
+
+BOOST_AUTO_TEST_CASE(valid_nearest_urls)
+{
+ std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)}};
+
+ engine::api::NearestParameters reference_1{};
+ reference_1.coordinates = coords_1;
+ auto result_1 = api::parseParameters<engine::api::NearestParameters>("1,2");
+ BOOST_CHECK(result_1);
+ BOOST_CHECK_EQUAL(reference_1.number_of_results, result_1->number_of_results);
+ CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
+ CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
+ CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
+}
+
+BOOST_AUTO_TEST_CASE(valid_tile_urls)
+{
+ engine::api::TileParameters reference_1{1, 2, 3};
+ auto result_1 = api::parseParameters<engine::api::TileParameters>("tile(1,2,3).mvt");
+ BOOST_CHECK(result_1);
+ BOOST_CHECK_EQUAL(reference_1.x, result_1->x);
+ BOOST_CHECK_EQUAL(reference_1.y, result_1->y);
+ BOOST_CHECK_EQUAL(reference_1.z, result_1->z);
+}
+
+BOOST_AUTO_TEST_CASE(valid_trip_urls)
+{
+ std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)},
+ {util::FloatLongitude(3), util::FloatLatitude(4)}};
+
+ engine::api::TripParameters reference_1{};
+ reference_1.coordinates = coords_1;
+ auto result_1 = api::parseParameters<engine::api::TripParameters>("1,2;3,4");
+ BOOST_CHECK(result_1);
+ CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
+ CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
+ CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/server/url_parser.cpp b/unit_tests/server/url_parser.cpp
new file mode 100644
index 0000000..1405674
--- /dev/null
+++ b/unit_tests/server/url_parser.cpp
@@ -0,0 +1,102 @@
+#include "server/api/url_parser.hpp"
+
+#include <fstream>
+
+// needed for BOOST_CHECK_EQUAL
+namespace osrm
+{
+namespace server
+{
+namespace api
+{
+std::ostream &operator<<(std::ostream &out, const osrm::server::api::ParsedURL &url)
+{
+ out << url.service << ", " << url.version << ", " << url.profile << ", " << url.query;
+
+ return out;
+}
+}
+}
+}
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define CHECK_EQUAL_RANGE(R1, R2) \
+ BOOST_CHECK_EQUAL_COLLECTIONS(R1.begin(), R1.end(), R2.begin(), R2.end());
+
+BOOST_AUTO_TEST_SUITE(api_url_parser)
+
+using namespace osrm;
+using namespace osrm::server;
+
+// returns distance to front
+std::size_t testInvalidURL(std::string url)
+{
+ auto iter = url.begin();
+ auto result = api::parseURL(iter, url.end());
+ BOOST_CHECK(!result);
+ return std::distance(url.begin(), iter);
+}
+
+BOOST_AUTO_TEST_CASE(invalid_urls)
+{
+ BOOST_CHECK_EQUAL(testInvalidURL("/route/"), 0UL);
+ BOOST_CHECK_EQUAL(testInvalidURL("/route/bla"), 0UL);
+ BOOST_CHECK_EQUAL(testInvalidURL("/route/1/1,2;3;4"), 0UL);
+ BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/pro_file/1,2;3,4"), 0UL);
+ BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/profile"), 0UL);
+ BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/profile/"), 0UL);
+}
+
+BOOST_AUTO_TEST_CASE(valid_urls)
+{
+ api::ParsedURL reference_1{"route", 1, "profile", "0,1;2,3;4,5?options=value&foo=bar"};
+ auto result_1 = api::parseURL("/route/v1/profile/0,1;2,3;4,5?options=value&foo=bar");
+ BOOST_CHECK(result_1);
+ BOOST_CHECK_EQUAL(reference_1.service, result_1->service);
+ BOOST_CHECK_EQUAL(reference_1.version, result_1->version);
+ BOOST_CHECK_EQUAL(reference_1.profile, result_1->profile);
+ CHECK_EQUAL_RANGE(reference_1.query, result_1->query);
+
+ // no options
+ api::ParsedURL reference_2{"route", 1, "profile", "0,1;2,3;4,5"};
+ auto result_2 = api::parseURL("/route/v1/profile/0,1;2,3;4,5");
+ BOOST_CHECK(result_2);
+ BOOST_CHECK_EQUAL(reference_2.service, result_2->service);
+ BOOST_CHECK_EQUAL(reference_2.version, result_2->version);
+ BOOST_CHECK_EQUAL(reference_2.profile, result_2->profile);
+ CHECK_EQUAL_RANGE(reference_2.query, result_2->query);
+
+ // one coordinate
+ std::vector<util::Coordinate> coords_3 = {
+ util::Coordinate(util::FloatLongitude(0), util::FloatLatitude(1)),
+ };
+ api::ParsedURL reference_3{"route", 1, "profile", "0,1"};
+ auto result_3 = api::parseURL("/route/v1/profile/0,1");
+ BOOST_CHECK(result_3);
+ BOOST_CHECK_EQUAL(reference_3.service, result_3->service);
+ BOOST_CHECK_EQUAL(reference_3.version, result_3->version);
+ BOOST_CHECK_EQUAL(reference_3.profile, result_3->profile);
+ CHECK_EQUAL_RANGE(reference_3.query, result_3->query);
+
+ // polyline
+ api::ParsedURL reference_5{"route", 1, "profile", "polyline(_ibE?_seK_seK_seK_seK)?"};
+ auto result_5 = api::parseURL("/route/v1/profile/polyline(_ibE?_seK_seK_seK_seK)?");
+ BOOST_CHECK(result_5);
+ BOOST_CHECK_EQUAL(reference_5.service, result_5->service);
+ BOOST_CHECK_EQUAL(reference_5.version, result_5->version);
+ BOOST_CHECK_EQUAL(reference_5.profile, result_5->profile);
+ CHECK_EQUAL_RANGE(reference_5.query, result_5->query);
+
+ // tile
+ api::ParsedURL reference_6{"route", 1, "profile", "tile(1,2,3).mvt"};
+ auto result_6 = api::parseURL("/route/v1/profile/tile(1,2,3).mvt");
+ BOOST_CHECK(result_5);
+ BOOST_CHECK_EQUAL(reference_6.service, result_6->service);
+ BOOST_CHECK_EQUAL(reference_6.version, result_6->version);
+ BOOST_CHECK_EQUAL(reference_6.profile, result_6->profile);
+ CHECK_EQUAL_RANGE(reference_6.query, result_6->query);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/server_tests.cpp b/unit_tests/server_tests.cpp
new file mode 100644
index 0000000..c1edf06
--- /dev/null
+++ b/unit_tests/server_tests.cpp
@@ -0,0 +1,7 @@
+#define BOOST_TEST_MODULE server tests
+
+#include <boost/test/unit_test.hpp>
+
+/*
+ * This file will contain an automatically generated main function.
+ */
diff --git a/unit_tests/util/bearing.cpp b/unit_tests/util/bearing.cpp
index f0866de..77e2ede 100644
--- a/unit_tests/util/bearing.cpp
+++ b/unit_tests/util/bearing.cpp
@@ -1,38 +1,14 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "../../util/bearing.hpp"
-#include "../../typedefs.h"
+#include "util/bearing.hpp"
+#include "util/typedefs.hpp"
#include <boost/functional/hash.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
-BOOST_AUTO_TEST_SUITE(bearing)
+BOOST_AUTO_TEST_SUITE(bearing_test)
+
+using namespace osrm;
+using namespace osrm::util;
// Verify that the bearing-bounds checking function behaves as expected
BOOST_AUTO_TEST_CASE(bearing_range_test)
@@ -56,7 +32,6 @@ BOOST_AUTO_TEST_CASE(bearing_range_test)
BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(354, 5, 10));
BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(16, 5, 10));
-
// Checking other cases of wraparound
BOOST_CHECK_EQUAL(true, bearing::CheckInBounds(359, -5, 10));
BOOST_CHECK_EQUAL(false, bearing::CheckInBounds(344, -5, 10));
diff --git a/unit_tests/data_structures/binary_heap.cpp b/unit_tests/util/binary_heap.cpp
similarity index 74%
rename from unit_tests/data_structures/binary_heap.cpp
rename to unit_tests/util/binary_heap.cpp
index ee22a1f..44aef13 100644
--- a/unit_tests/data_structures/binary_heap.cpp
+++ b/unit_tests/util/binary_heap.cpp
@@ -1,32 +1,5 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "../../data_structures/binary_heap.hpp"
-#include "../../typedefs.h"
+#include "util/binary_heap.hpp"
+#include "util/typedefs.hpp"
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
@@ -39,6 +12,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
BOOST_AUTO_TEST_SUITE(binary_heap)
+using namespace osrm;
+using namespace osrm::util;
+
struct TestData
{
unsigned value;
diff --git a/unit_tests/util/coordinate_calculation.cpp b/unit_tests/util/coordinate_calculation.cpp
new file mode 100644
index 0000000..d159441
--- /dev/null
+++ b/unit_tests/util/coordinate_calculation.cpp
@@ -0,0 +1,191 @@
+#include <boost/test/unit_test.hpp>
+
+#include "util/coordinate_calculation.hpp"
+
+#include <osrm/coordinate.hpp>
+
+#include <cmath>
+
+using namespace osrm;
+using namespace osrm::util;
+
+BOOST_AUTO_TEST_SUITE(coordinate_calculation_tests)
+
+// Regression test for bug captured in #1347
+BOOST_AUTO_TEST_CASE(regression_test_1347)
+{
+ Coordinate u(FloatLongitude(-100), FloatLatitude(10));
+ Coordinate v(FloatLongitude(-100.002), FloatLatitude(10.001));
+ Coordinate q(FloatLongitude(-100.001), FloatLatitude(10.002));
+
+ double d1 = coordinate_calculation::perpendicularDistance(u, v, q);
+
+ double ratio;
+ Coordinate nearest_location;
+ double d2 = coordinate_calculation::perpendicularDistance(u, v, q, nearest_location, ratio);
+
+ BOOST_CHECK_LE(std::abs(d1 - d2), 0.01);
+}
+
+BOOST_AUTO_TEST_CASE(lon_to_pixel)
+{
+ using namespace coordinate_calculation;
+ BOOST_CHECK_CLOSE(7.416042 * mercator::DEGREE_TO_PX, 825550.019142, 0.1);
+ BOOST_CHECK_CLOSE(7.415892 * mercator::DEGREE_TO_PX, 825533.321218, 0.1);
+ BOOST_CHECK_CLOSE(7.416016 * mercator::DEGREE_TO_PX, 825547.124835, 0.1);
+ BOOST_CHECK_CLOSE(7.41577 * mercator::DEGREE_TO_PX, 825519.74024, 0.1);
+ BOOST_CHECK_CLOSE(7.415808 * mercator::DEGREE_TO_PX, 825523.970381, 0.1);
+}
+
+BOOST_AUTO_TEST_CASE(lat_to_pixel)
+{
+ using namespace coordinate_calculation;
+ BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733947)) * mercator::DEGREE_TO_PX,
+ 5424361.75863, 0.1);
+ BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733799)) * mercator::DEGREE_TO_PX,
+ 5424338.95731, 0.1);
+ BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733922)) * mercator::DEGREE_TO_PX,
+ 5424357.90705, 0.1);
+ BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733697)) * mercator::DEGREE_TO_PX,
+ 5424323.24293, 0.1);
+ BOOST_CHECK_CLOSE(mercator::latToY(util::FloatLatitude(43.733729)) * mercator::DEGREE_TO_PX,
+ 5424328.17293, 0.1);
+}
+
+BOOST_AUTO_TEST_CASE(xyz_to_wgs84)
+{
+ using namespace coordinate_calculation;
+
+ double minx_1;
+ double miny_1;
+ double maxx_1;
+ double maxy_1;
+ mercator::xyzToWGS84(2, 2, 1, minx_1, miny_1, maxx_1, maxy_1);
+ BOOST_CHECK_CLOSE(minx_1, 180, 0.0001);
+ BOOST_CHECK_CLOSE(miny_1, -85.0511, 0.0001);
+ BOOST_CHECK_CLOSE(maxx_1, 360, 0.0001);
+ BOOST_CHECK_CLOSE(maxy_1, -85.0511, 0.0001);
+
+ double minx_2;
+ double miny_2;
+ double maxx_2;
+ double maxy_2;
+ mercator::xyzToWGS84(100, 0, 13, minx_2, miny_2, maxx_2, maxy_2);
+ BOOST_CHECK_CLOSE(minx_2, -175.6054, 0.0001);
+ BOOST_CHECK_CLOSE(miny_2, 85.0473, 0.0001);
+ BOOST_CHECK_CLOSE(maxx_2, -175.5615, 0.0001);
+ BOOST_CHECK_CLOSE(maxy_2, 85.0511, 0.0001);
+}
+
+BOOST_AUTO_TEST_CASE(xyz_to_mercator)
+{
+ using namespace coordinate_calculation;
+
+ double minx;
+ double miny;
+ double maxx;
+ double maxy;
+ mercator::xyzToMercator(100, 0, 13, minx, miny, maxx, maxy);
+
+ BOOST_CHECK_CLOSE(minx, -19548311.361764118075, 0.0001);
+ BOOST_CHECK_CLOSE(miny, 20032616.372979003936, 0.0001);
+ BOOST_CHECK_CLOSE(maxx, -19543419.391953866929, 0.0001);
+ BOOST_CHECK_CLOSE(maxy, 20037508.342789277434, 0.0001);
+}
+
+BOOST_AUTO_TEST_CASE(regression_point_on_segment)
+{
+ // ^
+ // | t
+ // |
+ // | i
+ // |
+ // |---|---|---|---|---|---|---|--->
+ // |
+ // |
+ // |
+ // |
+ // |
+ // |
+ // |
+ // |
+ // | s
+ FloatCoordinate input{FloatLongitude{55.995715}, FloatLatitude{48.332711}};
+ FloatCoordinate start{FloatLongitude{74.140427}, FloatLatitude{-180}};
+ FloatCoordinate target{FloatLongitude{53.041084}, FloatLatitude{77.21011}};
+
+ FloatCoordinate nearest;
+ double ratio;
+ std::tie(ratio, nearest) = coordinate_calculation::projectPointOnSegment(start, target, input);
+
+ FloatCoordinate diff{target.lon - start.lon, target.lat - start.lat};
+
+ BOOST_CHECK_CLOSE(static_cast<double>(start.lon + FloatLongitude(ratio) * diff.lon), static_cast<double>(nearest.lon), 0.1);
+ BOOST_CHECK_CLOSE(static_cast<double>(start.lat + FloatLatitude(ratio) * diff.lat), static_cast<double>(nearest.lat), 0.1);
+}
+
+BOOST_AUTO_TEST_CASE(point_on_segment)
+{
+ // t
+ // |
+ // |---- i
+ // |
+ // s
+ auto result_1 = coordinate_calculation::projectPointOnSegment(
+ {FloatLongitude{0}, FloatLatitude{0}}, {FloatLongitude{0}, FloatLatitude{2}},
+ {FloatLongitude{2}, FloatLatitude{1}});
+ auto reference_ratio_1 = 0.5;
+ auto reference_point_1 = FloatCoordinate{FloatLongitude{0}, FloatLatitude{1}};
+ BOOST_CHECK_EQUAL(result_1.first, reference_ratio_1);
+ BOOST_CHECK_EQUAL(result_1.second.lon, reference_point_1.lon);
+ BOOST_CHECK_EQUAL(result_1.second.lat, reference_point_1.lat);
+
+ // i
+ // :
+ // t
+ // |
+ // |
+ // |
+ // s
+ auto result_2 = coordinate_calculation::projectPointOnSegment(
+ {FloatLongitude{0.}, FloatLatitude{0.}}, {FloatLongitude{0}, FloatLatitude{2}},
+ {FloatLongitude{0}, FloatLatitude{3}});
+ auto reference_ratio_2 = 1.;
+ auto reference_point_2 = FloatCoordinate{FloatLongitude{0}, FloatLatitude{2}};
+ BOOST_CHECK_EQUAL(result_2.first, reference_ratio_2);
+ BOOST_CHECK_EQUAL(result_2.second.lon, reference_point_2.lon);
+ BOOST_CHECK_EQUAL(result_2.second.lat, reference_point_2.lat);
+
+ // t
+ // |
+ // |
+ // |
+ // s
+ // :
+ // i
+ auto result_3 = coordinate_calculation::projectPointOnSegment(
+ {FloatLongitude{0.}, FloatLatitude{0.}}, {FloatLongitude{0}, FloatLatitude{2}},
+ {FloatLongitude{0}, FloatLatitude{-1}});
+ auto reference_ratio_3 = 0.;
+ auto reference_point_3 = FloatCoordinate{FloatLongitude{0}, FloatLatitude{0}};
+ BOOST_CHECK_EQUAL(result_3.first, reference_ratio_3);
+ BOOST_CHECK_EQUAL(result_3.second.lon, reference_point_3.lon);
+ BOOST_CHECK_EQUAL(result_3.second.lat, reference_point_3.lat);
+
+ // t
+ // /
+ // /.
+ // / i
+ // s
+ //
+ auto result_4 = coordinate_calculation::projectPointOnSegment(
+ {FloatLongitude{0}, FloatLatitude{0}}, {FloatLongitude{1}, FloatLatitude{1}},
+ {FloatLongitude{0.5 + 0.1}, FloatLatitude{0.5 - 0.1}});
+ auto reference_ratio_4 = 0.5;
+ auto reference_point_4 = FloatCoordinate{FloatLongitude{0.5}, FloatLatitude{0.5}};
+ BOOST_CHECK_EQUAL(result_4.first, reference_ratio_4);
+ BOOST_CHECK_EQUAL(result_4.second.lon, reference_point_4.lon);
+ BOOST_CHECK_EQUAL(result_4.second.lat, reference_point_4.lat);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/util/duration_parsing.cpp b/unit_tests/util/duration_parsing.cpp
new file mode 100644
index 0000000..72a5b63
--- /dev/null
+++ b/unit_tests/util/duration_parsing.cpp
@@ -0,0 +1,40 @@
+#include "extractor/extraction_helper_functions.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+BOOST_AUTO_TEST_SUITE(durations_are_valid)
+
+using namespace osrm;
+using namespace osrm::util;
+
+BOOST_AUTO_TEST_CASE(all_necessary_test)
+{
+ BOOST_CHECK_EQUAL(extractor::durationIsValid("00:01"), true);
+ BOOST_CHECK_EQUAL(extractor::durationIsValid("00:01:01"), true);
+ BOOST_CHECK_EQUAL(extractor::durationIsValid("PT15M"), true);
+}
+
+BOOST_AUTO_TEST_CASE(common_durations_get_translated)
+{
+ BOOST_CHECK_EQUAL(extractor::parseDuration("00:01"), 60);
+ BOOST_CHECK_EQUAL(extractor::parseDuration("00:01:01"), 61);
+ BOOST_CHECK_EQUAL(extractor::parseDuration("01:01"), 3660);
+
+ // check all combinations of iso duration tokens
+ BOOST_CHECK_EQUAL(extractor::parseDuration("PT1M1S"), 61);
+ BOOST_CHECK_EQUAL(extractor::parseDuration("PT1H1S"), 3601);
+ BOOST_CHECK_EQUAL(extractor::parseDuration("PT15M"), 900);
+ BOOST_CHECK_EQUAL(extractor::parseDuration("PT15S"), 15);
+ BOOST_CHECK_EQUAL(extractor::parseDuration("PT15H"), 54000);
+ BOOST_CHECK_EQUAL(extractor::parseDuration("PT1H15M"), 4500);
+ BOOST_CHECK_EQUAL(extractor::parseDuration("PT1H15M1S"), 4501);
+}
+
+BOOST_AUTO_TEST_CASE(iso_8601_durations_case_insensitive)
+{
+ BOOST_CHECK_EQUAL(extractor::parseDuration("PT15m"), 900);
+ BOOST_CHECK_EQUAL(extractor::parseDuration("PT1h15m"), 4500);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/util/dynamic_graph.cpp b/unit_tests/util/dynamic_graph.cpp
new file mode 100644
index 0000000..263b60c
--- /dev/null
+++ b/unit_tests/util/dynamic_graph.cpp
@@ -0,0 +1,66 @@
+#include "util/dynamic_graph.hpp"
+#include "util/typedefs.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include <vector>
+
+BOOST_AUTO_TEST_SUITE(dynamic_graph)
+
+using namespace osrm;
+using namespace osrm::util;
+
+struct TestData
+{
+ EdgeID id;
+};
+
+typedef DynamicGraph<TestData> TestDynamicGraph;
+typedef TestDynamicGraph::InputEdge TestInputEdge;
+
+BOOST_AUTO_TEST_CASE(find_test)
+{
+ /*
+ * (0) -1-> (1)
+ * ^ ^
+ * 2 5
+ * | |
+ * (3) -3-> (4)
+ * <-4-
+ */
+ std::vector<TestInputEdge> input_edges = {
+ TestInputEdge{0, 1, TestData{1}}, TestInputEdge{3, 0, TestData{2}},
+ TestInputEdge{3, 0, TestData{5}}, TestInputEdge{3, 4, TestData{3}},
+ TestInputEdge{4, 3, TestData{4}}};
+ TestDynamicGraph simple_graph(5, input_edges);
+
+ auto eit = simple_graph.FindEdge(0, 1);
+ BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 1);
+
+ eit = simple_graph.FindEdge(1, 0);
+ BOOST_CHECK_EQUAL(eit, SPECIAL_EDGEID);
+
+ eit = simple_graph.FindEdgeInEitherDirection(1, 0);
+ BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 1);
+
+ bool reverse = false;
+ eit = simple_graph.FindEdgeIndicateIfReverse(1, 0, reverse);
+ BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 1);
+ BOOST_CHECK(reverse);
+
+ eit = simple_graph.FindEdge(3, 1);
+ BOOST_CHECK_EQUAL(eit, SPECIAL_EDGEID);
+ eit = simple_graph.FindEdge(0, 4);
+ BOOST_CHECK_EQUAL(eit, SPECIAL_EDGEID);
+
+ eit = simple_graph.FindEdge(3, 4);
+ BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 3);
+ eit = simple_graph.FindEdgeInEitherDirection(3, 4);
+ BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 3);
+
+ eit = simple_graph.FindEdge(3, 0);
+ BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 2);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/util/io.cpp b/unit_tests/util/io.cpp
new file mode 100644
index 0000000..e37fa13
--- /dev/null
+++ b/unit_tests/util/io.cpp
@@ -0,0 +1,42 @@
+#include "util/io.hpp"
+#include "util/typedefs.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include <string>
+
+const static std::string IO_TMP_FILE = "test_io.tmp";
+
+BOOST_AUTO_TEST_SUITE(osrm_io)
+
+BOOST_AUTO_TEST_CASE(io_flags)
+{
+ std::vector<bool> flags_in, flags_out;
+ flags_in.resize(53);
+ for (std::size_t i = 0; i < flags_in.size(); ++i)
+ flags_in[i] = ((i % 2) == 1);
+
+ osrm::util::serializeFlags(IO_TMP_FILE, flags_in);
+ osrm::util::deserializeFlags(IO_TMP_FILE, flags_out);
+
+ BOOST_REQUIRE_EQUAL(flags_in.size(), flags_out.size());
+ BOOST_CHECK_EQUAL_COLLECTIONS(flags_out.begin(), flags_out.end(), flags_in.begin(),
+ flags_in.end());
+}
+
+BOOST_AUTO_TEST_CASE(io_data)
+{
+ std::vector<int> data_in, data_out;
+ data_in.resize(53);
+ for (std::size_t i = 0; i < data_in.size(); ++i)
+ data_in[i] = i;
+
+ osrm::util::serializeVector(IO_TMP_FILE, data_in);
+ osrm::util::deserializeVector(IO_TMP_FILE, data_out);
+
+ BOOST_REQUIRE_EQUAL(data_in.size(), data_out.size());
+ BOOST_CHECK_EQUAL_COLLECTIONS(data_out.begin(), data_out.end(), data_in.begin(), data_in.end());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/data_structures/range_table.cpp b/unit_tests/util/range_table.cpp
similarity index 72%
rename from unit_tests/data_structures/range_table.cpp
rename to unit_tests/util/range_table.cpp
index 065840b..a5db4c5 100644
--- a/unit_tests/data_structures/range_table.cpp
+++ b/unit_tests/util/range_table.cpp
@@ -1,32 +1,5 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "../../data_structures/range_table.hpp"
-#include "../../typedefs.h"
+#include "util/range_table.hpp"
+#include "util/typedefs.hpp"
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
@@ -34,11 +7,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <numeric>
#include <stxxl/vector>
+BOOST_AUTO_TEST_SUITE(range_table)
+
+using namespace osrm;
+using namespace osrm::util;
+
constexpr unsigned BLOCK_SIZE = 16;
typedef RangeTable<BLOCK_SIZE, false> TestRangeTable;
-BOOST_AUTO_TEST_SUITE(range_table)
-
void ConstructionTest(stxxl::vector<unsigned> lengths, std::vector<unsigned> offsets)
{
BOOST_ASSERT(lengths.size() == offsets.size() - 1);
diff --git a/unit_tests/util/rectangle.cpp b/unit_tests/util/rectangle.cpp
new file mode 100644
index 0000000..f85d073
--- /dev/null
+++ b/unit_tests/util/rectangle.cpp
@@ -0,0 +1,107 @@
+#include "util/rectangle.hpp"
+#include "util/typedefs.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+BOOST_AUTO_TEST_SUITE(rectangle_test)
+
+using namespace osrm;
+using namespace osrm::util;
+
+// Verify that the bearing-bounds checking function behaves as expected
+BOOST_AUTO_TEST_CASE(get_min_dist_test)
+{
+ // ^
+ // |
+ // +- 80
+ // |
+ // |
+ // +- 10
+ // |
+ //--|-----|--+--|-----|-->
+ // -100 -10 | 10 100
+ // +- -10
+ // |
+ // |
+ // +- -80
+ // |
+ RectangleInt2D ne{FloatLongitude(10), FloatLongitude(100), FloatLatitude(10),
+ FloatLatitude(80)};
+ RectangleInt2D nw{FloatLongitude(-100), FloatLongitude(-10), FloatLatitude(10),
+ FloatLatitude(80)};
+ RectangleInt2D se{FloatLongitude(10), FloatLongitude(100), FloatLatitude(-80),
+ FloatLatitude(-10)};
+ RectangleInt2D sw{FloatLongitude(-100), FloatLongitude(-10), FloatLatitude(-80),
+ FloatLatitude(-10)};
+
+ Coordinate nw_sw{FloatLongitude(-100.1), FloatLatitude(9.9)};
+ Coordinate nw_se{FloatLongitude(-9.9), FloatLatitude(9.9)};
+ Coordinate nw_ne{FloatLongitude(-9.9), FloatLatitude(80.1)};
+ Coordinate nw_nw{FloatLongitude(-100.1), FloatLatitude(80.1)};
+ Coordinate nw_s{FloatLongitude(-55), FloatLatitude(9.9)};
+ Coordinate nw_e{FloatLongitude(-9.9), FloatLatitude(45.0)};
+ Coordinate nw_w{FloatLongitude(-100.1), FloatLatitude(45.0)};
+ Coordinate nw_n{FloatLongitude(-55), FloatLatitude(80.1)};
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_sw), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_se), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_ne), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_nw), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_s), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_e), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_w), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(nw.GetMinSquaredDist(nw_n), 0.01, 0.1);
+
+ Coordinate ne_sw{FloatLongitude(9.9), FloatLatitude(9.9)};
+ Coordinate ne_se{FloatLongitude(100.1), FloatLatitude(9.9)};
+ Coordinate ne_ne{FloatLongitude(100.1), FloatLatitude(80.1)};
+ Coordinate ne_nw{FloatLongitude(9.9), FloatLatitude(80.1)};
+ Coordinate ne_s{FloatLongitude(55), FloatLatitude(9.9)};
+ Coordinate ne_e{FloatLongitude(100.1), FloatLatitude(45.0)};
+ Coordinate ne_w{FloatLongitude(9.9), FloatLatitude(45.0)};
+ Coordinate ne_n{FloatLongitude(55), FloatLatitude(80.1)};
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_sw), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_se), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_ne), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_nw), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_s), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_e), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_w), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(ne.GetMinSquaredDist(ne_n), 0.01, 0.1);
+
+ Coordinate se_ne{FloatLongitude(100.1), FloatLatitude(-9.9)};
+ Coordinate se_nw{FloatLongitude(9.9), FloatLatitude(-9.9)};
+ Coordinate se_sw{FloatLongitude(9.9), FloatLatitude(-80.1)};
+ Coordinate se_se{FloatLongitude(100.1), FloatLatitude(-80.1)};
+ Coordinate se_n{FloatLongitude(55), FloatLatitude(-9.9)};
+ Coordinate se_w{FloatLongitude(9.9), FloatLatitude(-45.0)};
+ Coordinate se_e{FloatLongitude(100.1), FloatLatitude(-45.0)};
+ Coordinate se_s{FloatLongitude(55), FloatLatitude(-80.1)};
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_sw), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_se), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_ne), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_nw), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_s), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_e), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_w), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(se.GetMinSquaredDist(se_n), 0.01, 0.1);
+
+ Coordinate sw_ne{FloatLongitude(-9.9), FloatLatitude(-9.9)};
+ Coordinate sw_nw{FloatLongitude(-100.1), FloatLatitude(-9.9)};
+ Coordinate sw_sw{FloatLongitude(-100.1), FloatLatitude(-80.1)};
+ Coordinate sw_se{FloatLongitude(-9.9), FloatLatitude(-80.1)};
+ Coordinate sw_n{FloatLongitude(-55), FloatLatitude(-9.9)};
+ Coordinate sw_w{FloatLongitude(-100.1), FloatLatitude(-45.0)};
+ Coordinate sw_e{FloatLongitude(-9.9), FloatLatitude(-45.0)};
+ Coordinate sw_s{FloatLongitude(-55), FloatLatitude(-80.1)};
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_sw), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_se), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_ne), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_nw), 0.02, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_s), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_e), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_w), 0.01, 0.1);
+ BOOST_CHECK_CLOSE(sw.GetMinSquaredDist(sw_n), 0.01, 0.1);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/data_structures/static_graph.cpp b/unit_tests/util/static_graph.cpp
similarity index 71%
rename from unit_tests/data_structures/static_graph.cpp
rename to unit_tests/util/static_graph.cpp
index ddadd7f..c975401 100644
--- a/unit_tests/data_structures/static_graph.cpp
+++ b/unit_tests/util/static_graph.cpp
@@ -1,32 +1,5 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "../../data_structures/static_graph.hpp"
-#include "../../typedefs.h"
+#include "util/static_graph.hpp"
+#include "util/typedefs.hpp"
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
@@ -37,6 +10,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
BOOST_AUTO_TEST_SUITE(static_graph)
+using namespace osrm;
+using namespace osrm::util;
+
struct TestData
{
EdgeID id;
@@ -118,6 +94,16 @@ BOOST_FIXTURE_TEST_CASE(array_test, TestRandomArrayEntryFixture)
}
}
+BOOST_AUTO_TEST_CASE(target_test)
+{
+ std::vector<TestInputEdge> input_edges = {TestInputEdge{0, 1, TestData{1}},
+ TestInputEdge{3, 0, TestData{2}}};
+ TestStaticGraph simple_graph = TestStaticGraph(4, input_edges);
+
+ auto target = simple_graph.GetTarget(simple_graph.FindEdge(3, 0));
+ BOOST_CHECK_EQUAL(target, 0);
+}
+
BOOST_AUTO_TEST_CASE(find_test)
{
/*
@@ -129,12 +115,9 @@ BOOST_AUTO_TEST_CASE(find_test)
* <-4-
*/
std::vector<TestInputEdge> input_edges = {
- TestInputEdge{0, 1, TestData{1}},
- TestInputEdge{3, 0, TestData{2}},
- TestInputEdge{3, 0, TestData{5}},
- TestInputEdge{3, 4, TestData{3}},
- TestInputEdge{4, 3, TestData{4}}
- };
+ TestInputEdge{0, 1, TestData{1}}, TestInputEdge{3, 0, TestData{2}},
+ TestInputEdge{3, 0, TestData{5}}, TestInputEdge{3, 4, TestData{3}},
+ TestInputEdge{4, 3, TestData{4}}};
TestStaticGraph simple_graph(5, input_edges);
auto eit = simple_graph.FindEdge(0, 1);
diff --git a/unit_tests/util/static_rtree.cpp b/unit_tests/util/static_rtree.cpp
new file mode 100644
index 0000000..a9170be
--- /dev/null
+++ b/unit_tests/util/static_rtree.cpp
@@ -0,0 +1,456 @@
+#include "extractor/edge_based_node.hpp"
+#include "engine/geospatial_query.hpp"
+#include "util/typedefs.hpp"
+#include "util/rectangle.hpp"
+#include "util/exception.hpp"
+#include "util/coordinate_calculation.hpp"
+#include "util/coordinate.hpp"
+#include "util/static_rtree.hpp"
+
+#include "mocks/mock_datafacade.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/functional/hash.hpp>
+
+#include <cstdint>
+#include <cmath>
+
+#include <algorithm>
+#include <memory>
+#include <random>
+#include <string>
+#include <utility>
+#include <unordered_set>
+#include <vector>
+
+BOOST_AUTO_TEST_SUITE(static_rtree)
+
+using namespace osrm;
+using namespace osrm::util;
+using namespace osrm::test;
+
+constexpr uint32_t TEST_BRANCHING_FACTOR = 8;
+constexpr uint32_t TEST_LEAF_NODE_SIZE = 64;
+
+using TestData = extractor::EdgeBasedNode;
+using TestStaticRTree = StaticRTree<TestData,
+ std::vector<Coordinate>,
+ false,
+ TEST_BRANCHING_FACTOR,
+ TEST_LEAF_NODE_SIZE>;
+using MiniStaticRTree = StaticRTree<TestData, std::vector<Coordinate>, false, 2, 3>;
+
+// Choosen by a fair W20 dice roll (this value is completely arbitrary)
+constexpr unsigned RANDOM_SEED = 42;
+static const int32_t WORLD_MIN_LAT = -85 * COORDINATE_PRECISION;
+static const int32_t WORLD_MAX_LAT = 85 * COORDINATE_PRECISION;
+static const int32_t WORLD_MIN_LON = -180 * COORDINATE_PRECISION;
+static const int32_t WORLD_MAX_LON = 180 * COORDINATE_PRECISION;
+
+template <typename DataT> class LinearSearchNN
+{
+ public:
+ LinearSearchNN(const std::shared_ptr<std::vector<Coordinate>> &coords,
+ const std::vector<DataT> &edges)
+ : coords(coords), edges(edges)
+ {
+ }
+
+ std::vector<DataT> Nearest(const Coordinate &input_coordinate, const unsigned num_results)
+ {
+ std::vector<DataT> local_edges(edges);
+
+ auto projected_input = coordinate_calculation::mercator::fromWGS84(input_coordinate);
+ const auto segment_comparator = [this, &projected_input](const DataT &lhs, const DataT &rhs)
+ {
+ using coordinate_calculation::mercator::fromWGS84;
+ const auto lhs_result = coordinate_calculation::projectPointOnSegment(
+ fromWGS84(coords->at(lhs.u)), fromWGS84(coords->at(lhs.v)), projected_input);
+ const auto rhs_result = coordinate_calculation::projectPointOnSegment(
+ fromWGS84(coords->at(rhs.u)), fromWGS84(coords->at(rhs.v)), projected_input);
+ const auto lhs_squared_dist = coordinate_calculation::squaredEuclideanDistance(
+ lhs_result.second, projected_input);
+ const auto rhs_squared_dist = coordinate_calculation::squaredEuclideanDistance(
+ rhs_result.second, projected_input);
+ return lhs_squared_dist < rhs_squared_dist;
+ };
+
+ std::nth_element(local_edges.begin(), local_edges.begin() + num_results, local_edges.end(),
+ segment_comparator);
+ local_edges.resize(num_results);
+
+ return local_edges;
+ }
+
+ private:
+ const std::shared_ptr<std::vector<Coordinate>> &coords;
+ const std::vector<TestData> &edges;
+};
+
+template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomGraphFixture
+{
+ struct TupleHash
+ {
+ typedef std::pair<unsigned, unsigned> argument_type;
+ typedef std::size_t result_type;
+
+ result_type operator()(const argument_type &t) const
+ {
+ std::size_t val{0};
+ boost::hash_combine(val, t.first);
+ boost::hash_combine(val, t.second);
+ return val;
+ }
+ };
+
+ RandomGraphFixture() : coords(std::make_shared<std::vector<Coordinate>>())
+ {
+ std::mt19937 g(RANDOM_SEED);
+
+ std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
+ std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
+
+ for (unsigned i = 0; i < NUM_NODES; i++)
+ {
+ int lon = lon_udist(g);
+ int lat = lat_udist(g);
+ coords->emplace_back(Coordinate(FixedLongitude(lon), FixedLatitude(lat)));
+ }
+
+ std::uniform_int_distribution<> edge_udist(0, coords->size() - 1);
+
+ std::unordered_set<std::pair<unsigned, unsigned>, TupleHash> used_edges;
+
+ while (edges.size() < NUM_EDGES)
+ {
+ TestData data;
+ data.u = edge_udist(g);
+ data.v = edge_udist(g);
+ if (used_edges.find(std::pair<unsigned, unsigned>(
+ std::min(data.u, data.v), std::max(data.u, data.v))) == used_edges.end())
+ {
+ data.component.id = 0;
+ edges.emplace_back(data);
+ used_edges.emplace(std::min(data.u, data.v), std::max(data.u, data.v));
+ }
+ }
+ }
+
+ std::shared_ptr<std::vector<Coordinate>> coords;
+ std::vector<TestData> edges;
+};
+
+struct GraphFixture
+{
+ GraphFixture(const std::vector<std::pair<FloatLongitude, FloatLatitude>> &input_coords,
+ const std::vector<std::pair<unsigned, unsigned>> &input_edges)
+ : coords(std::make_shared<std::vector<Coordinate>>())
+ {
+
+ for (unsigned i = 0; i < input_coords.size(); i++)
+ {
+ coords->emplace_back(input_coords[i].first, input_coords[i].second);
+ }
+
+ for (const auto &pair : input_edges)
+ {
+ TestData d;
+ d.u = pair.first;
+ d.v = pair.second;
+ // We set the forward nodes to the target node-based-node IDs, just
+ // so we have something to test against. Because this isn't a real
+ // graph, the actual values aren't important, we just need something
+ // to examine during tests.
+ d.forward_segment_id = {pair.second, true};
+ d.reverse_segment_id = {pair.first, true};
+ edges.emplace_back(d);
+ }
+ }
+
+ std::shared_ptr<std::vector<Coordinate>> coords;
+ std::vector<TestData> edges;
+};
+
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 3, TEST_LEAF_NODE_SIZE / 2>
+ TestRandomGraphFixture_LeafHalfFull;
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 5, TEST_LEAF_NODE_SIZE>
+ TestRandomGraphFixture_LeafFull;
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 10, TEST_LEAF_NODE_SIZE * 2>
+ TestRandomGraphFixture_TwoLeaves;
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 3,
+ TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR>
+ TestRandomGraphFixture_Branch;
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 3,
+ TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 2>
+ TestRandomGraphFixture_MultipleLevels;
+typedef RandomGraphFixture<10, 30> TestRandomGraphFixture_10_30;
+
+template <typename RTreeT>
+void simple_verify_rtree(RTreeT &rtree,
+ const std::shared_ptr<std::vector<Coordinate>> &coords,
+ const std::vector<TestData> &edges)
+{
+ for (const auto &e : edges)
+ {
+ const Coordinate &pu = coords->at(e.u);
+ const Coordinate &pv = coords->at(e.v);
+ auto result_u = rtree.Nearest(pu, 1);
+ auto result_v = rtree.Nearest(pv, 1);
+ BOOST_CHECK(result_u.size() == 1 && result_v.size() == 1);
+ BOOST_CHECK(result_u.front().u == e.u || result_u.front().v == e.u);
+ BOOST_CHECK(result_v.front().u == e.v || result_v.front().v == e.v);
+ }
+}
+
+template <typename RTreeT>
+void sampling_verify_rtree(RTreeT &rtree,
+ LinearSearchNN<TestData> &lsnn,
+ const std::vector<Coordinate> &coords,
+ unsigned num_samples)
+{
+ std::mt19937 g(RANDOM_SEED);
+ std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
+ std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
+ std::vector<Coordinate> queries;
+ for (unsigned i = 0; i < num_samples; i++)
+ {
+ queries.emplace_back(FixedLongitude(lon_udist(g)), FixedLatitude(lat_udist(g)));
+ }
+
+ for (const auto &q : queries)
+ {
+ auto result_rtree = rtree.Nearest(q, 1);
+ auto result_lsnn = lsnn.Nearest(q, 1);
+ BOOST_CHECK(result_rtree.size() == 1);
+ BOOST_CHECK(result_lsnn.size() == 1);
+ auto rtree_u = result_rtree.back().u;
+ auto rtree_v = result_rtree.back().v;
+ auto lsnn_u = result_lsnn.back().u;
+ auto lsnn_v = result_lsnn.back().v;
+
+ Coordinate rtree_nearest;
+ Coordinate lsnn_nearest;
+ double ratio;
+ const double rtree_dist = coordinate_calculation::perpendicularDistance(
+ coords[rtree_u], coords[rtree_v], q, rtree_nearest, ratio);
+ const double lsnn_dist = coordinate_calculation::perpendicularDistance(
+ coords[lsnn_u], coords[lsnn_v], q, lsnn_nearest, ratio);
+
+ BOOST_CHECK_CLOSE(rtree_dist, lsnn_dist, 0.0001);
+ }
+}
+
+template <typename FixtureT, typename RTreeT = TestStaticRTree>
+void build_rtree(const std::string &prefix,
+ FixtureT *fixture,
+ std::string &leaves_path,
+ std::string &nodes_path)
+{
+ nodes_path = prefix + ".ramIndex";
+ leaves_path = prefix + ".fileIndex";
+
+ RTreeT r(fixture->edges, nodes_path, leaves_path, *fixture->coords);
+}
+
+template <typename RTreeT = TestStaticRTree, typename FixtureT>
+void construction_test(const std::string &prefix, FixtureT *fixture)
+{
+ std::string leaves_path;
+ std::string nodes_path;
+ build_rtree<FixtureT, RTreeT>(prefix, fixture, leaves_path, nodes_path);
+ RTreeT rtree(nodes_path, leaves_path, fixture->coords);
+ LinearSearchNN<TestData> lsnn(fixture->coords, fixture->edges);
+
+ simple_verify_rtree(rtree, fixture->coords, fixture->edges);
+ sampling_verify_rtree(rtree, lsnn, *fixture->coords, 100);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_tiny, TestRandomGraphFixture_10_30)
+{
+ using TinyTestTree = StaticRTree<TestData, std::vector<Coordinate>, false, 2, 1>;
+ construction_test<TinyTestTree>("test_tiny", this);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_half_leaf_test, TestRandomGraphFixture_LeafHalfFull)
+{
+ construction_test("test_1", this);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_full_leaf_test, TestRandomGraphFixture_LeafFull)
+{
+ construction_test("test_2", this);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_two_leaves_test, TestRandomGraphFixture_TwoLeaves)
+{
+ construction_test("test_3", this);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_branch_test, TestRandomGraphFixture_Branch)
+{
+ construction_test("test_4", this);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_multiple_levels_test, TestRandomGraphFixture_MultipleLevels)
+{
+ construction_test("test_5", this);
+}
+
+// Bug: If you querry a point that lies between two BBs that have a gap,
+// one BB will be pruned, even if it could contain a nearer match.
+BOOST_AUTO_TEST_CASE(regression_test)
+{
+ using Coord = std::pair<FloatLongitude, FloatLatitude>;
+ using Edge = std::pair<unsigned, unsigned>;
+ GraphFixture fixture(
+ {
+ Coord{FloatLongitude{0.0}, FloatLatitude{40.0}}, //
+ Coord{FloatLongitude{5.0}, FloatLatitude{35.0}}, //
+ Coord{FloatLongitude{5.0}, FloatLatitude{5.0}}, //
+ Coord{FloatLongitude{10.0}, FloatLatitude{0.0}}, //
+ Coord{FloatLongitude{10.0}, FloatLatitude{20.0}}, //
+ Coord{FloatLongitude{5.0}, FloatLatitude{20.0}}, //
+ Coord{FloatLongitude{100.0}, FloatLatitude{40.0}}, //
+ Coord{FloatLongitude{105.0}, FloatLatitude{35.0}}, //
+ Coord{FloatLongitude{105.0}, FloatLatitude{5.0}}, //
+ Coord{FloatLongitude{110.0}, FloatLatitude{0.0}}, //
+ },
+ {Edge(0, 1), Edge(2, 3), Edge(4, 5), Edge(6, 7), Edge(8, 9)});
+
+ std::string leaves_path;
+ std::string nodes_path;
+ build_rtree<GraphFixture, MiniStaticRTree>("test_regression", &fixture, leaves_path,
+ nodes_path);
+ MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords);
+ LinearSearchNN<TestData> lsnn(fixture.coords, fixture.edges);
+
+ // query a node just right of the center of the gap
+ Coordinate input(FloatLongitude(55.1), FloatLatitude(20.0));
+ auto result_rtree = rtree.Nearest(input, 1);
+ auto result_ls = lsnn.Nearest(input, 1);
+
+ auto distance_rtree = coordinate_calculation::perpendicularDistance(
+ fixture.coords->at(result_rtree.front().u), fixture.coords->at(result_rtree.front().v),
+ input);
+
+ auto distance_lsnn = coordinate_calculation::perpendicularDistance(
+ fixture.coords->at(result_ls.front().u), fixture.coords->at(result_ls.front().v), input);
+
+ BOOST_CHECK(result_rtree.size() == 1);
+ BOOST_CHECK(result_ls.size() == 1);
+
+ BOOST_CHECK_EQUAL(result_ls.front().u, result_rtree.front().u);
+ BOOST_CHECK_EQUAL(result_ls.front().v, result_rtree.front().v);
+}
+
+BOOST_AUTO_TEST_CASE(bearing_tests)
+{
+ using Coord = std::pair<FloatLongitude, FloatLatitude>;
+ using Edge = std::pair<unsigned, unsigned>;
+ GraphFixture fixture(
+ {
+ Coord(FloatLongitude(0.0), FloatLatitude(0.0)),
+ Coord(FloatLongitude(10.0), FloatLatitude(10.0)),
+ },
+ {Edge(0, 1), Edge(1, 0)});
+
+ std::string leaves_path;
+ std::string nodes_path;
+ build_rtree<GraphFixture, MiniStaticRTree>("test_bearing", &fixture, leaves_path, nodes_path);
+ MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords);
+ MockDataFacade mockfacade;
+ engine::GeospatialQuery<MiniStaticRTree, MockDataFacade> query(rtree, fixture.coords,
+ mockfacade);
+
+ Coordinate input(FloatLongitude(5.1), FloatLatitude(5.0));
+
+ {
+ auto results = query.NearestPhantomNodes(input, 5);
+ BOOST_CHECK_EQUAL(results.size(), 2);
+ BOOST_CHECK_EQUAL(results.back().phantom_node.forward_segment_id.id, 0);
+ BOOST_CHECK_EQUAL(results.back().phantom_node.reverse_segment_id.id, 1);
+ }
+
+ {
+ auto results = query.NearestPhantomNodes(input, 5, 270, 10);
+ BOOST_CHECK_EQUAL(results.size(), 0);
+ }
+
+ {
+ auto results = query.NearestPhantomNodes(input, 5, 45, 10);
+ BOOST_CHECK_EQUAL(results.size(), 2);
+
+ BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled);
+ BOOST_CHECK(!results[0].phantom_node.reverse_segment_id.enabled);
+ BOOST_CHECK_EQUAL(results[0].phantom_node.forward_segment_id.id, 1);
+
+ BOOST_CHECK(!results[1].phantom_node.forward_segment_id.enabled);
+ BOOST_CHECK(results[1].phantom_node.reverse_segment_id.enabled);
+ BOOST_CHECK_EQUAL(results[1].phantom_node.reverse_segment_id.id, 1);
+ }
+
+ {
+ auto results = query.NearestPhantomNodesInRange(input, 11000);
+ BOOST_CHECK_EQUAL(results.size(), 2);
+ }
+
+ {
+ auto results = query.NearestPhantomNodesInRange(input, 11000, 270, 10);
+ BOOST_CHECK_EQUAL(results.size(), 0);
+ }
+
+ {
+ auto results = query.NearestPhantomNodesInRange(input, 11000, 45, 10);
+ BOOST_CHECK_EQUAL(results.size(), 2);
+
+ BOOST_CHECK(results[0].phantom_node.forward_segment_id.enabled);
+ BOOST_CHECK(!results[0].phantom_node.reverse_segment_id.enabled);
+ BOOST_CHECK_EQUAL(results[0].phantom_node.forward_segment_id.id, 1);
+
+ BOOST_CHECK(!results[1].phantom_node.forward_segment_id.enabled);
+ BOOST_CHECK(results[1].phantom_node.reverse_segment_id.enabled);
+ BOOST_CHECK_EQUAL(results[1].phantom_node.reverse_segment_id.id, 1);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(bbox_search_tests)
+{
+ using Coord = std::pair<FloatLongitude, FloatLatitude>;
+ using Edge = std::pair<unsigned, unsigned>;
+
+ GraphFixture fixture(
+ {
+ Coord(FloatLongitude(0.0), FloatLatitude(0.0)),
+ Coord(FloatLongitude(1.0), FloatLatitude(1.0)),
+ Coord(FloatLongitude(2.0), FloatLatitude(2.0)),
+ Coord(FloatLongitude(3.0), FloatLatitude(3.0)),
+ Coord(FloatLongitude(4.0), FloatLatitude(4.0)),
+ },
+ {Edge(0, 1), Edge(1, 2), Edge(2, 3), Edge(3, 4)});
+
+ std::string leaves_path;
+ std::string nodes_path;
+ build_rtree<GraphFixture, MiniStaticRTree>("test_bbox", &fixture, leaves_path, nodes_path);
+ MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords);
+ MockDataFacade mockfacade;
+ engine::GeospatialQuery<MiniStaticRTree, MockDataFacade> query(rtree, fixture.coords,
+ mockfacade);
+
+ {
+ RectangleInt2D bbox = {FloatLongitude(0.5), FloatLongitude(1.5), FloatLatitude(0.5),
+ FloatLatitude(1.5)};
+ auto results = query.Search(bbox);
+ BOOST_CHECK_EQUAL(results.size(), 2);
+ }
+
+ {
+ RectangleInt2D bbox = {FloatLongitude(1.5), FloatLongitude(3.5), FloatLatitude(1.5),
+ FloatLatitude(3.5)};
+ auto results = query.Search(bbox);
+ BOOST_CHECK_EQUAL(results.size(), 3);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/util/string_util.cpp b/unit_tests/util/string_util.cpp
new file mode 100644
index 0000000..e3a7204
--- /dev/null
+++ b/unit_tests/util/string_util.cpp
@@ -0,0 +1,41 @@
+#include "util/string_util.hpp"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include <iostream>
+
+BOOST_AUTO_TEST_SUITE(string_util)
+
+using namespace osrm;
+using namespace osrm::util;
+
+BOOST_AUTO_TEST_CASE(json_escaping)
+{
+ std::string input{"\b\\"};
+ std::string output{escape_JSON(input)};
+
+ BOOST_CHECK_EQUAL(output, "\\b\\\\");
+
+ input = "Aleja \"Solidarnosci\"";
+ output = escape_JSON(input);
+ BOOST_CHECK_EQUAL(output, "Aleja \\\"Solidarnosci\\\"");
+}
+
+BOOST_AUTO_TEST_CASE(print_int)
+{
+ const std::string input{"\b\\"};
+ char buffer[12];
+ buffer[11] = 0; // zero termination
+ std::string output = printInt<11, 8>(buffer, 314158976);
+ BOOST_CHECK_EQUAL(output, "3.14158976");
+
+ buffer[11] = 0;
+ output = printInt<11, 8>(buffer, 0);
+ BOOST_CHECK_EQUAL(output, "0.00000000");
+
+ output = printInt<11, 8>(buffer, -314158976);
+ BOOST_CHECK_EQUAL(output, "-3.14158976");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/util/viewport.cpp b/unit_tests/util/viewport.cpp
new file mode 100644
index 0000000..f5f4f9a
--- /dev/null
+++ b/unit_tests/util/viewport.cpp
@@ -0,0 +1,25 @@
+#include "util/viewport.hpp"
+
+using namespace osrm::util;
+
+#include <boost/functional/hash.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include <iostream>
+
+BOOST_AUTO_TEST_SUITE(viewport_test)
+
+using namespace osrm;
+using namespace osrm::util;
+
+BOOST_AUTO_TEST_CASE(zoom_level_test)
+{
+ BOOST_CHECK_EQUAL(
+ viewport::getFittedZoom(
+ Coordinate(FloatLongitude{5.668343999999995}, FloatLatitude{45.111511000000014}),
+ Coordinate(FloatLongitude{5.852471999999996}, FloatLatitude{45.26800200000002})),
+ 12);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/unit_tests/util_tests.cpp b/unit_tests/util_tests.cpp
index 26275ab..7b641fa 100644
--- a/unit_tests/util_tests.cpp
+++ b/unit_tests/util_tests.cpp
@@ -1,30 +1,3 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
#define BOOST_TEST_MODULE util tests
#include <boost/test/unit_test.hpp>
diff --git a/util/cast.hpp b/util/cast.hpp
deleted file mode 100644
index a9e97d6..0000000
--- a/util/cast.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef CAST_HPP
-#define CAST_HPP
-
-#include <string>
-#include <sstream>
-#include <iomanip>
-#include <type_traits>
-
-#include <boost/algorithm/string/classification.hpp>
-#include <boost/algorithm/string/trim.hpp>
-
-namespace cast
-{
-template <typename Enumeration>
-inline auto enum_to_underlying(Enumeration const value) ->
- typename std::underlying_type<Enumeration>::type
-{
- return static_cast<typename std::underlying_type<Enumeration>::type>(value);
-}
-
-template <typename T, int Precision = 6> inline std::string to_string_with_precision(const T x)
-{
- static_assert(std::is_arithmetic<T>::value, "integral or floating point type required");
-
- std::ostringstream out;
- out << std::fixed << std::setprecision(Precision) << x;
- auto rv = out.str();
-
- // Javascript has no separation of float / int, digits without a '.' are integral typed
- // X.Y.0 -> X.Y
- // X.0 -> X
- boost::trim_right_if(rv, boost::is_any_of("0"));
- boost::trim_right_if(rv, boost::is_any_of("."));
- // Note:
- // - assumes the locale to use '.' as digit separator
- // - this is not identical to: trim_right_if(rv, is_any_of('0 .'))
-
- return rv;
-}
-}
-
-#endif // CAST_HPP
diff --git a/util/compute_angle.cpp b/util/compute_angle.cpp
deleted file mode 100644
index 8cd8aa4..0000000
--- a/util/compute_angle.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "compute_angle.hpp"
-
-#include "trigonometry_table.hpp"
-#include "../util/mercator.hpp"
-
-#include <osrm/coordinate.hpp>
-
-#include <cmath>
-
-double ComputeAngle::OfThreeFixedPointCoordinates(const FixedPointCoordinate &first,
- const FixedPointCoordinate &second,
- const FixedPointCoordinate &third) noexcept
-{
- const double v1x = (first.lon - second.lon) / COORDINATE_PRECISION;
- const double v1y = mercator::lat2y(first.lat / COORDINATE_PRECISION) -
- mercator::lat2y(second.lat / COORDINATE_PRECISION);
- const double v2x = (third.lon - second.lon) / COORDINATE_PRECISION;
- const double v2y = mercator::lat2y(third.lat / COORDINATE_PRECISION) -
- mercator::lat2y(second.lat / COORDINATE_PRECISION);
-
- double angle = (atan2_lookup(v2y, v2x) - atan2_lookup(v1y, v1x)) * 180. / M_PI;
- while (angle < 0.)
- {
- angle += 360.;
- }
- return angle;
-}
diff --git a/util/compute_angle.hpp b/util/compute_angle.hpp
deleted file mode 100644
index da84caf..0000000
--- a/util/compute_angle.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef COMPUTE_ANGLE_HPP
-#define COMPUTE_ANGLE_HPP
-
-struct FixedPointCoordinate;
-
-struct ComputeAngle
-{
- // Get angle of line segment (A,C)->(C,B)
- // atan2 magic, formerly cosine theorem
- static double OfThreeFixedPointCoordinates(const FixedPointCoordinate &first,
- const FixedPointCoordinate &second,
- const FixedPointCoordinate &third) noexcept;
-};
-
-#endif // COMPUTE_ANGLE_HPP
diff --git a/util/container.hpp b/util/container.hpp
deleted file mode 100644
index 14b88ee..0000000
--- a/util/container.hpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef CONTAINER_HPP
-#define CONTAINER_HPP
-
-#include <algorithm>
-#include <iterator>
-#include <vector>
-
-namespace osrm
-{
-namespace detail
-{
-// Culled by SFINAE if reserve does not exist or is not accessible
-template <typename T>
-constexpr auto has_resize_method(T &t) noexcept -> decltype(t.resize(0), bool())
-{
- return true;
-}
-
-// Used as fallback when SFINAE culls the template method
-constexpr bool has_resize_method(...) noexcept { return false; }
-}
-
-template <typename Container> void sort_unique_resize(Container &vector) noexcept
-{
- std::sort(std::begin(vector), std::end(vector));
- const auto number_of_unique_elements =
- std::unique(std::begin(vector), std::end(vector)) - std::begin(vector);
- if (detail::has_resize_method(vector))
- {
- vector.resize(number_of_unique_elements);
- }
-}
-
-// template <typename T> inline void sort_unique_resize_shrink_vector(std::vector<T> &vector)
-// {
-// sort_unique_resize(vector);
-// vector.shrink_to_fit();
-// }
-
-// template <typename T> inline void remove_consecutive_duplicates_from_vector(std::vector<T>
-// &vector)
-// {
-// const auto number_of_unique_elements = std::unique(vector.begin(), vector.end()) -
-// vector.begin();
-// vector.resize(number_of_unique_elements);
-// }
-
-template <typename ForwardIterator, typename Function>
-Function for_each_pair(ForwardIterator begin, ForwardIterator end, Function function)
-{
- if (begin == end)
- {
- return function;
- }
-
- auto next = begin;
- next = std::next(next);
-
- while (next != end)
- {
- function(*begin, *next);
- begin = std::next(begin);
- next = std::next(next);
- }
- return function;
-}
-
-template <class ContainerT, typename Function>
-Function for_each_pair(ContainerT &container, Function function)
-{
- return for_each_pair(std::begin(container), std::end(container), function);
-}
-
-template <class Container> void append_to_container(Container &&) {}
-
-template <class Container, typename T, typename... Args>
-void append_to_container(Container &&container, T value, Args &&... args)
-{
- container.emplace_back(value);
- append_to_container(std::forward<Container>(container), std::forward<Args>(args)...);
-}
-
-} // namespace osrm
-#endif /* CONTAINER_HPP */
diff --git a/util/datastore_options.hpp b/util/datastore_options.hpp
deleted file mode 100644
index 4a8320c..0000000
--- a/util/datastore_options.hpp
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef DATASTORE_OPTIONS_HPP
-#define DATASTORE_OPTIONS_HPP
-
-#include "util/version.hpp"
-#include "ini_file.hpp"
-#include "osrm_exception.hpp"
-#include "simple_logger.hpp"
-
-#include <boost/any.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/program_options.hpp>
-
-#include <string>
-#include <unordered_map>
-
-// generate boost::program_options object for the routing part
-bool GenerateDataStoreOptions(const int argc, const char *argv[], std::unordered_map<std::string, boost::filesystem::path> &paths)
-{
- // declare a group of options that will be allowed only on command line
- boost::program_options::options_description generic_options("Options");
- generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
- "springclean,s", "Remove all regions in shared memory")(
- "config,c", boost::program_options::value<boost::filesystem::path>(&paths["config"])
- ->default_value("server.ini"),
- "Path to a configuration file");
-
- // declare a group of options that will be allowed both on command line
- // as well as in a config file
- boost::program_options::options_description config_options("Configuration");
- config_options.add_options()(
- "hsgrdata", boost::program_options::value<boost::filesystem::path>(&paths["hsgrdata"]),
- ".hsgr file")("nodesdata",
- boost::program_options::value<boost::filesystem::path>(&paths["nodesdata"]),
- ".nodes file")(
- "edgesdata", boost::program_options::value<boost::filesystem::path>(&paths["edgesdata"]),
- ".edges file")("geometry",
- boost::program_options::value<boost::filesystem::path>(&paths["geometry"]),
- ".geometry file")(
- "ramindex", boost::program_options::value<boost::filesystem::path>(&paths["ramindex"]),
- ".ramIndex file")(
- "fileindex", boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
- ".fileIndex file")("core",
- boost::program_options::value<boost::filesystem::path>(&paths["core"]),
- ".core file")(
- "namesdata", boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
- ".names file")("timestamp",
- boost::program_options::value<boost::filesystem::path>(&paths["timestamp"]),
- ".timestamp file");
-
- // hidden options, will be allowed both on command line and in config
- // file, but will not be shown to the user
- boost::program_options::options_description hidden_options("Hidden options");
- hidden_options.add_options()(
- "base,b", boost::program_options::value<boost::filesystem::path>(&paths["base"]),
- "base path to .osrm file");
-
- // positional option
- boost::program_options::positional_options_description positional_options;
- positional_options.add("base", 1);
-
- // combine above options for parsing
- boost::program_options::options_description cmdline_options;
- cmdline_options.add(generic_options).add(config_options).add(hidden_options);
-
- boost::program_options::options_description config_file_options;
- config_file_options.add(config_options).add(hidden_options);
-
- boost::program_options::options_description visible_options(
- boost::filesystem::basename(argv[0]) + " [<options>] <configuration>");
- visible_options.add(generic_options).add(config_options);
-
- // parse command line options
- boost::program_options::variables_map option_variables;
- boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
- .options(cmdline_options)
- .positional(positional_options)
- .run(),
- option_variables);
-
- if (option_variables.count("version"))
- {
- SimpleLogger().Write() << OSRM_VERSION;
- return false;
- }
-
- if (option_variables.count("help"))
- {
- SimpleLogger().Write() << visible_options;
- return false;
- }
-
- boost::program_options::notify(option_variables);
-
- const bool parameter_present =
- (paths.find("hsgrdata") != paths.end() &&
- !paths.find("hsgrdata")->second.string().empty()) ||
- (paths.find("nodesdata") != paths.end() &&
- !paths.find("nodesdata")->second.string().empty()) ||
- (paths.find("edgesdata") != paths.end() &&
- !paths.find("edgesdata")->second.string().empty()) ||
- (paths.find("geometry") != paths.end() &&
- !paths.find("geometry")->second.string().empty()) ||
- (paths.find("ramindex") != paths.end() &&
- !paths.find("ramindex")->second.string().empty()) ||
- (paths.find("fileindex") != paths.end() &&
- !paths.find("fileindex")->second.string().empty()) ||
- (paths.find("core") != paths.end() && !paths.find("core")->second.string().empty()) ||
- (paths.find("timestamp") != paths.end() &&
- !paths.find("timestamp")->second.string().empty());
-
- if (parameter_present)
- {
- if ((paths.find("config") != paths.end() &&
- boost::filesystem::is_regular_file(paths.find("config")->second)) ||
- option_variables.count("base"))
- {
- SimpleLogger().Write(logWARNING) << "conflicting parameters";
- SimpleLogger().Write() << visible_options;
- return false;
- }
- }
-
- // parse config file
- auto path_iterator = paths.find("config");
- if (path_iterator != paths.end() && boost::filesystem::is_regular_file(path_iterator->second) &&
- !option_variables.count("base"))
- {
- SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
- std::string ini_file_contents = read_file_lower_content(path_iterator->second);
- std::stringstream config_stream(ini_file_contents);
- boost::program_options::store(parse_config_file(config_stream, config_file_options),
- option_variables);
- boost::program_options::notify(option_variables);
- }
- else if (option_variables.count("base"))
- {
- path_iterator = paths.find("base");
- BOOST_ASSERT(paths.end() != path_iterator);
- std::string base_string = path_iterator->second.string();
-
- path_iterator = paths.find("hsgrdata");
- if (path_iterator != paths.end())
- {
- path_iterator->second = base_string + ".hsgr";
- }
-
- path_iterator = paths.find("nodesdata");
- if (path_iterator != paths.end())
- {
- path_iterator->second = base_string + ".nodes";
- }
-
- path_iterator = paths.find("edgesdata");
- if (path_iterator != paths.end())
- {
- path_iterator->second = base_string + ".edges";
- }
-
- path_iterator = paths.find("geometry");
- if (path_iterator != paths.end())
- {
- path_iterator->second = base_string + ".geometry";
- }
-
- path_iterator = paths.find("ramindex");
- if (path_iterator != paths.end())
- {
- path_iterator->second = base_string + ".ramIndex";
- }
-
- path_iterator = paths.find("fileindex");
- if (path_iterator != paths.end())
- {
- path_iterator->second = base_string + ".fileIndex";
- }
-
- path_iterator = paths.find("core");
- if (path_iterator != paths.end())
- {
- path_iterator->second = base_string + ".core";
- }
-
- path_iterator = paths.find("namesdata");
- if (path_iterator != paths.end())
- {
- path_iterator->second = base_string + ".names";
- }
-
- path_iterator = paths.find("timestamp");
- if (path_iterator != paths.end())
- {
- path_iterator->second = base_string + ".timestamp";
- }
- }
-
- path_iterator = paths.find("hsgrdata");
- if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception("valid .hsgr file must be specified");
- }
-
- path_iterator = paths.find("nodesdata");
- if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception("valid .nodes file must be specified");
- }
-
- path_iterator = paths.find("edgesdata");
- if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception("valid .edges file must be specified");
- }
-
- path_iterator = paths.find("geometry");
- if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception("valid .geometry file must be specified");
- }
-
- path_iterator = paths.find("ramindex");
- if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception("valid .ramindex file must be specified");
- }
-
- path_iterator = paths.find("fileindex");
- if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception("valid .fileindex file must be specified");
- }
-
- path_iterator = paths.find("namesdata");
- if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception("valid .names file must be specified");
- }
-
- path_iterator = paths.find("timestamp");
- if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception("valid .timestamp file must be specified");
- }
-
- return true;
-}
-
-#endif /* DATASTORE_OPTIONS_HPP */
diff --git a/util/debug_geometry.hpp b/util/debug_geometry.hpp
deleted file mode 100644
index daa7e10..0000000
--- a/util/debug_geometry.hpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef DEBUG_GEOMETRY_H
-#define DEBUG_GEOMETRY_H
-
-#include "../contractor/contractor_options.hpp"
-#include "../data_structures/query_node.hpp"
-
-#ifndef DEBUG_GEOMETRY
-
-inline void DEBUG_GEOMETRY_START(ContractorConfig & /* config */) {}
-inline void DEBUG_GEOMETRY_EDGE(int /* new_segment_weight */ , double /* segment_length */,
- OSMNodeID /* previous_osm_node_id */, OSMNodeID /* this_osm_node_id */) {}
-inline void DEBUG_GEOMETRY_STOP() {}
-
-inline void DEBUG_TURNS_START(const std::string & /* debug_turns_filename */) {}
-inline void DEBUG_TURN( const NodeID /* node */, const std::vector<QueryNode>& /* m_node_info_list */,
- const FixedPointCoordinate & /* first_coordinate */, const int /* turn_angle */,
- const int /* turn_penalty */) {}
-inline void DEBUG_UTURN( const NodeID /* node */, const std::vector<QueryNode>& /* m_node_info_list */,
- const int /* uturn_penalty */ ) {}
-inline void DEBUG_SIGNAL( const NodeID /* node */, const std::vector<QueryNode>& /* m_node_info_list */,
- const int /* signal_penalty */ ) {}
-
-inline void DEBUG_TURNS_STOP() {}
-
-#else // DEBUG_GEOMETRY
-
-#include <boost/filesystem.hpp>
-#include <ctime>
-#include <string>
-#include <iomanip>
-#include <iostream>
-
-#include "../include/osrm/coordinate.hpp"
-#include "../algorithms/coordinate_calculation.hpp"
-
-boost::filesystem::ofstream debug_geometry_file;
-bool dg_output_debug_geometry = false;
-bool dg_first_debug_geometry = true;
-char dg_time_buffer[80];
-
-boost::filesystem::ofstream dg_debug_turns_file;
-bool dg_output_turn_debug = false;
-bool dg_first_turn_debug = true;
-
-inline void DEBUG_GEOMETRY_START(const ContractorConfig &config)
-{
- time_t raw_time;
- struct tm *timeinfo;
- time(&raw_time);
- timeinfo = localtime(&raw_time);
- strftime(dg_time_buffer, 80, "%Y-%m-%d %H:%M %Z", timeinfo);
-
- dg_output_debug_geometry = config.debug_geometry_path != "";
-
- if (dg_output_debug_geometry)
- {
- debug_geometry_file.open(config.debug_geometry_path, std::ios::binary);
- debug_geometry_file << "{\"type\":\"FeatureCollection\", \"features\":[" << std::endl;
- }
-}
-
-inline void DEBUG_GEOMETRY_EDGE(int new_segment_weight, double segment_length, OSMNodeID previous_osm_node_id, OSMNodeID this_osm_node_id)
-{
- if (dg_output_debug_geometry)
- {
- if (!dg_first_debug_geometry)
- debug_geometry_file << "," << std::endl;
- debug_geometry_file
- << "{ \"type\":\"Feature\",\"properties\":{\"original\":false, "
- "\"weight\":"
- << new_segment_weight / 10.0 << ",\"speed\":"
- << static_cast<int>(
- std::floor((segment_length / new_segment_weight) * 10. * 3.6))
- << ",";
- debug_geometry_file << "\"from_node\": " << previous_osm_node_id
- << ", \"to_node\": " << this_osm_node_id << ",";
- debug_geometry_file << "\"timestamp\": \"" << dg_time_buffer << "\"},";
- debug_geometry_file
- << "\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[!!"
- << previous_osm_node_id << "!!],[!!" << this_osm_node_id << "!!]]}}"
- << std::endl;
- dg_first_debug_geometry = false;
- }
-}
-
-inline void DEBUG_GEOMETRY_STOP()
-{
- if (dg_output_debug_geometry)
- {
- debug_geometry_file << std::endl << "]}" << std::endl;
- debug_geometry_file.close();
- }
-}
-
-
-inline void DEBUG_TURNS_START(const std::string & debug_turns_path)
-{
- dg_output_turn_debug = debug_turns_path != "";
- if (dg_output_turn_debug)
- {
- dg_debug_turns_file.open(debug_turns_path);
- dg_debug_turns_file << "{\"type\":\"FeatureCollection\", \"features\":[" << std::endl;
- }
-}
-
-inline void DEBUG_SIGNAL(
- const NodeID node,
- const std::vector<QueryNode>& m_node_info_list,
- const int traffic_signal_penalty)
-{
- if (dg_output_turn_debug)
- {
- const QueryNode &nodeinfo = m_node_info_list[node];
- if (!dg_first_turn_debug) dg_debug_turns_file << "," << std::endl;
- dg_debug_turns_file << "{ \"type\":\"Feature\",\"properties\":{\"type\":\"trafficlights\",\"cost\":" << traffic_signal_penalty/10. << "},";
- dg_debug_turns_file << " \"geometry\":{\"type\":\"Point\",\"coordinates\":[" << std::setprecision(12) << nodeinfo.lon/COORDINATE_PRECISION << "," << nodeinfo.lat/COORDINATE_PRECISION << "]}}";
- dg_first_turn_debug = false;
- }
-}
-
-inline void DEBUG_UTURN(
- const NodeID node,
- const std::vector<QueryNode>& m_node_info_list,
- const int traffic_signal_penalty)
-{
- if (dg_output_turn_debug)
- {
- const QueryNode &nodeinfo = m_node_info_list[node];
- if (!dg_first_turn_debug) dg_debug_turns_file << "," << std::endl;
- dg_debug_turns_file << "{ \"type\":\"Feature\",\"properties\":{\"type\":\"trafficlights\",\"cost\":" << traffic_signal_penalty/10. << "},";
- dg_debug_turns_file << " \"geometry\":{\"type\":\"Point\",\"coordinates\":[" << std::setprecision(12) << nodeinfo.lon/COORDINATE_PRECISION << "," << nodeinfo.lat/COORDINATE_PRECISION << "]}}";
- dg_first_turn_debug = false;
- }
-}
-
-
-inline void DEBUG_TURN(
- const NodeID node,
- const std::vector<QueryNode>& m_node_info_list,
- const FixedPointCoordinate & first_coordinate,
- const int turn_angle,
- const int turn_penalty)
-{
- if (turn_penalty > 0 && dg_output_turn_debug)
- {
- const QueryNode &v = m_node_info_list[node];
-
- const float bearing_uv = coordinate_calculation::bearing(first_coordinate,v);
- float uvw_normal = bearing_uv + turn_angle/2;
- while (uvw_normal >= 360.) { uvw_normal -= 360.; }
-
- if (!dg_first_turn_debug) dg_debug_turns_file << "," << std::endl;
- dg_debug_turns_file << "{ \"type\":\"Feature\",\"properties\":{\"type\":\"turn\",\"cost\":" << turn_penalty/10. << ",\"turn_angle\":" << static_cast<int>(turn_angle) << ",\"normal\":" << static_cast<int>(uvw_normal) << "},";
- dg_debug_turns_file << " \"geometry\":{\"type\":\"Point\",\"coordinates\":[" << std::setprecision(12) << v.lon/COORDINATE_PRECISION << "," << v.lat/COORDINATE_PRECISION << "]}}";
- dg_first_turn_debug = false;
- }
-}
-
-inline void DEBUG_TURNS_STOP()
-{
- if (dg_output_turn_debug)
- {
- dg_debug_turns_file << std::endl << "]}" << std::endl;
- dg_debug_turns_file.close();
- }
-}
-
-#endif // DEBUG_GEOMETRY
-
-
-#endif // DEBUG_GEOMETRY_H
diff --git a/util/fingerprint.hpp b/util/fingerprint.hpp
deleted file mode 100644
index 99576f9..0000000
--- a/util/fingerprint.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef FINGERPRINT_H
-#define FINGERPRINT_H
-
-#include <boost/uuid/uuid.hpp>
-#include <type_traits>
-
-// implements a singleton, i.e. there is one and only one conviguration object
-class FingerPrint
-{
- public:
- static FingerPrint GetValid();
- const boost::uuids::uuid &GetFingerPrint() const;
- bool IsMagicNumberOK(const FingerPrint &other) const;
- bool TestGraphUtil(const FingerPrint &other) const;
- bool TestPrepare(const FingerPrint &other) const;
- bool TestRTree(const FingerPrint &other) const;
- bool TestQueryObjects(const FingerPrint &other) const;
-
- private:
- unsigned magic_number;
- char md5_prepare[33];
- char md5_tree[33];
- char md5_graph[33];
- char md5_objects[33];
-
- // initialize to {6ba7b810-9dad-11d1-80b4-00c04fd430c8}
- boost::uuids::uuid named_uuid;
-
-};
-
-static_assert(std::is_trivial<FingerPrint>::value, "FingerPrint needs to be trivial.");
-
-
-#endif /* FingerPrint_H */
diff --git a/util/ini_file.hpp b/util/ini_file.hpp
deleted file mode 100644
index b42f9ae..0000000
--- a/util/ini_file.hpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef INI_FILE_HPP
-#define INI_FILE_HPP
-
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-
-#include <algorithm>
-#include <string>
-
-namespace
-{
-
-// support old capitalized option names by down-casing them with a regex replace
-std::string read_file_lower_content(const boost::filesystem::path &path)
-{
- boost::filesystem::fstream config_stream(path);
- std::string ini_file_content((std::istreambuf_iterator<char>(config_stream)),
- std::istreambuf_iterator<char>());
- std::transform(std::begin(ini_file_content), std::end(ini_file_content),
- std::begin(ini_file_content), ::tolower);
- return ini_file_content;
-}
-}
-#endif // INI_FILE_HPP
diff --git a/util/integer_range.hpp b/util/integer_range.hpp
deleted file mode 100644
index 02de7f8..0000000
--- a/util/integer_range.hpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef INTEGER_RANGE_HPP
-#define INTEGER_RANGE_HPP
-
-#include <boost/assert.hpp>
-
-#include <type_traits>
-
-#include <cstdint>
-
-namespace osrm
-{
-
-template <typename Integer> class range
-{
- private:
- const Integer last;
- Integer iter;
-
- public:
- range(Integer start, Integer end) noexcept : last(end), iter(start)
- {
- BOOST_ASSERT_MSG(start <= end, "backwards counting ranges not suppoted");
- static_assert(std::is_integral<Integer>::value, "range type must be integral");
- }
-
- // Iterable functions
- const range &begin() const noexcept { return *this; }
- const range &end() const noexcept { return *this; }
- Integer front() const noexcept { return iter; }
- Integer back() const noexcept { return last - 1; }
- std::size_t size() const noexcept
- {
- return static_cast<std::size_t>(last - iter);
- }
-
- // Iterator functions
- bool operator!=(const range &) const noexcept { return iter < last; }
- void operator++() noexcept { ++iter; }
- Integer operator*() const noexcept { return iter; }
-};
-
-// convenience function to construct an integer range with type deduction
-template <typename Integer>
-range<Integer>
-irange(const Integer first,
- const Integer last,
- typename std::enable_if<std::is_integral<Integer>::value>::type * = 0) noexcept
-{
- return range<Integer>(first, last);
-}
-}
-
-#endif // INTEGER_RANGE_HPP
diff --git a/util/json_util.hpp b/util/json_util.hpp
deleted file mode 100644
index bfb8a8b..0000000
--- a/util/json_util.hpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef JSON_UTIL_HPP
-#define JSON_UTIL_HPP
-
-#include <osrm/json_container.hpp>
-
-#include <cmath>
-#include <limits>
-
-namespace osrm
-{
-namespace json
-{
-
-// Make sure we don't have inf and NaN values
-template <typename T> T clamp_float(T d)
-{
- if (std::isnan(d) || std::numeric_limits<T>::infinity() == d)
- {
- return std::numeric_limits<T>::max();
- }
- if (-std::numeric_limits<T>::infinity() == d)
- {
- return std::numeric_limits<T>::lowest();
- }
-
- return d;
-}
-
-template <typename... Args> osrm::json::Array make_array(Args... args)
-{
- osrm::json::Array a;
- append_to_container(a.values, args...);
- return a;
-}
-
-template <typename T> osrm::json::Array make_array(const std::vector<T> &vector)
-{
- osrm::json::Array a;
- for (const auto &v : vector)
- {
- a.values.emplace_back(v);
- }
- return a;
-}
-
-// template specialization needed as clang does not play nice
-template <> osrm::json::Array make_array(const std::vector<bool> &vector)
-{
- osrm::json::Array a;
- for (const bool v : vector)
- {
- a.values.emplace_back(v);
- }
- return a;
-}
-
-// Easy acces to object hierachies
-osrm::json::Value &get(osrm::json::Value &value) { return value; }
-
-template <typename... Keys>
-osrm::json::Value &get(osrm::json::Value &value, const char *key, Keys... keys)
-{
- using recursive_object_t = mapbox::util::recursive_wrapper<osrm::json::Object>;
- return get(value.get<recursive_object_t>().get().values[key], keys...);
-}
-
-template <typename... Keys>
-osrm::json::Value &get(osrm::json::Value &value, unsigned key, Keys... keys)
-{
- using recursive_array_t = mapbox::util::recursive_wrapper<osrm::json::Array>;
- return get(value.get<recursive_array_t>().get().values[key], keys...);
-}
-
-} // namespace json
-} // namespace osrm
-#endif // JSON_UTIL_HPP
diff --git a/util/lua_util.hpp b/util/lua_util.hpp
deleted file mode 100644
index 6dbdc8b..0000000
--- a/util/lua_util.hpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef LUA_UTIL_HPP
-#define LUA_UTIL_HPP
-
-extern "C" {
-#include <lua.h>
-#include <lauxlib.h>
-#include <lualib.h>
-}
-
-#include <boost/filesystem/convenience.hpp>
-#include <luabind/luabind.hpp>
-
-#include <iostream>
-#include <string>
-
-template <typename T> void LUA_print(T output) { std::cout << "[LUA] " << output << std::endl; }
-
-// Check if the lua function <name> is defined
-inline bool lua_function_exists(lua_State *lua_state, const char *name)
-{
- luabind::object globals_table = luabind::globals(lua_state);
- luabind::object lua_function = globals_table[name];
- return lua_function && (luabind::type(lua_function) == LUA_TFUNCTION);
-}
-
-// Add the folder contain the script to the lua load path, so script can easily require() other lua
-// scripts inside that folder, or subfolders.
-// See http://lua-users.org/wiki/PackagePath for details on the package.path syntax.
-inline void luaAddScriptFolderToLoadPath(lua_State *lua_state, const char *file_name)
-{
- boost::filesystem::path profile_path = boost::filesystem::canonical(file_name);
- std::string folder = profile_path.parent_path().string();
- // TODO: This code is most probably not Windows safe since it uses UNIX'ish path delimiters
- const std::string lua_code = "package.path = \"" + folder + "/?.lua;\" .. package.path";
- luaL_dostring(lua_state, lua_code.c_str());
-}
-
-#endif // LUA_UTIL_HPP
diff --git a/util/matching_debug_info.hpp b/util/matching_debug_info.hpp
deleted file mode 100644
index 28bc6ee..0000000
--- a/util/matching_debug_info.hpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef MATCHING_DEBUG_INFO_HPP
-#define MATCHING_DEBUG_INFO_HPP
-
-#include "json_logger.hpp"
-#include "json_util.hpp"
-#include "../data_structures/hidden_markov_model.hpp"
-
-#include <osrm/coordinate.hpp>
-
-// Provides the debug interface for introspection tools
-struct MatchingDebugInfo
-{
- MatchingDebugInfo(const osrm::json::Logger *logger) : logger(logger)
- {
- if (logger)
- {
- object = &logger->map->at("matching");
- }
- }
-
- template <class CandidateLists> void initialize(const CandidateLists &candidates_list)
- {
- // json logger not enabled
- if (!logger)
- {
- return;
- }
-
- osrm::json::Array states;
- for (auto &elem : candidates_list)
- {
- osrm::json::Array timestamps;
- for (auto &elem_s : elem)
- {
- osrm::json::Object state;
- state.values["transitions"] = osrm::json::Array();
- state.values["coordinate"] =
- osrm::json::make_array(elem_s.phantom_node.location.lat / COORDINATE_PRECISION,
- elem_s.phantom_node.location.lon / COORDINATE_PRECISION);
- state.values["viterbi"] =
- osrm::json::clamp_float(osrm::matching::IMPOSSIBLE_LOG_PROB);
- state.values["pruned"] = 0u;
- timestamps.values.push_back(state);
- }
- states.values.push_back(timestamps);
- }
- osrm::json::get(*object, "states") = states;
- }
-
- void add_transition_info(const unsigned prev_t,
- const unsigned current_t,
- const unsigned prev_state,
- const unsigned current_state,
- const double prev_viterbi,
- const double emission_pr,
- const double transition_pr,
- const double network_distance,
- const double haversine_distance)
- {
- // json logger not enabled
- if (!logger)
- {
- return;
- }
-
- osrm::json::Object transistion;
- transistion.values["to"] = osrm::json::make_array(current_t, current_state);
- transistion.values["properties"] = osrm::json::make_array(
- osrm::json::clamp_float(prev_viterbi), osrm::json::clamp_float(emission_pr),
- osrm::json::clamp_float(transition_pr), network_distance, haversine_distance);
-
- osrm::json::get(*object, "states", prev_t, prev_state, "transitions")
- .get<mapbox::util::recursive_wrapper<osrm::json::Array>>()
- .get()
- .values.push_back(transistion);
- }
-
- void set_viterbi(const std::vector<std::vector<double>> &viterbi,
- const std::vector<std::vector<bool>> &pruned,
- const std::vector<std::vector<bool>> &suspicious)
- {
- // json logger not enabled
- if (!logger)
- {
- return;
- }
-
- for (auto t = 0u; t < viterbi.size(); t++)
- {
- for (auto s_prime = 0u; s_prime < viterbi[t].size(); ++s_prime)
- {
- osrm::json::get(*object, "states", t, s_prime, "viterbi") =
- osrm::json::clamp_float(viterbi[t][s_prime]);
- osrm::json::get(*object, "states", t, s_prime, "pruned") =
- static_cast<unsigned>(pruned[t][s_prime]);
- osrm::json::get(*object, "states", t, s_prime, "suspicious") =
- static_cast<unsigned>(suspicious[t][s_prime]);
- }
- }
- }
-
- void add_chosen(const unsigned t, const unsigned s)
- {
- // json logger not enabled
- if (!logger)
- {
- return;
- }
-
- osrm::json::get(*object, "states", t, s, "chosen") = true;
- }
-
- void add_breakage(const std::vector<bool> &breakage)
- {
- // json logger not enabled
- if (!logger)
- {
- return;
- }
-
- osrm::json::get(*object, "breakage") = osrm::json::make_array(breakage);
- }
-
- const osrm::json::Logger *logger;
- osrm::json::Value *object;
-};
-
-#endif // MATCHING_DEBUG_INFO_HPP
diff --git a/util/mercator.cpp b/util/mercator.cpp
deleted file mode 100644
index 0ccd999..0000000
--- a/util/mercator.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "mercator.hpp"
-
-#include <cmath>
-
-double mercator::y2lat(const double value) noexcept
-{
- return 180. * M_1_PI * (2. * std::atan(std::exp(value * M_PI / 180.)) - M_PI_2);
-}
-
-double mercator::lat2y(const double latitude) noexcept
-{
- return 180. * M_1_PI * std::log(std::tan(M_PI_4 + latitude * (M_PI / 180.) / 2.));
-}
diff --git a/util/mercator.hpp b/util/mercator.hpp
deleted file mode 100644
index e994c84..0000000
--- a/util/mercator.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef MERCATOR_HPP
-#define MERCATOR_HPP
-
-struct mercator
-{
- static double y2lat(const double value) noexcept;
-
- static double lat2y(const double latitude) noexcept;
-};
-
-#endif // MERCATOR_HPP
diff --git a/util/osrm_exception.cpp b/util/osrm_exception.cpp
deleted file mode 100644
index 9738b8e..0000000
--- a/util/osrm_exception.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#include "osrm_exception.hpp"
-
-namespace osrm
-{
-// This function exists to 'anchor' the class, and stop the compiler from
-// copying vtable and RTTI info into every object file that includes
-// this header. (Caught by -Wweak-vtables under Clang.)
-
-// More information from the LLVM Coding Standards:
-// If a class is defined in a header file and has a vtable (either it has
-// virtual methods or it derives from classes with virtual methods), it must
-// always have at least one out-of-line virtual method in the class. Without
-// this, the compiler will copy the vtable and RTTI into every .o file that
-// #includes the header, bloating .o file sizes and increasing link times.
-void exception::anchor() const {}
-}
diff --git a/util/routed_options.hpp b/util/routed_options.hpp
deleted file mode 100644
index bfe8e5c..0000000
--- a/util/routed_options.hpp
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef ROUTED_OPTIONS_HPP
-#define ROUTED_OPTIONS_HPP
-
-#include "util/version.hpp"
-#include "ini_file.hpp"
-#include "osrm_exception.hpp"
-#include "simple_logger.hpp"
-
-#include <boost/any.hpp>
-#include <boost/program_options.hpp>
-
-#include <unordered_map>
-#include <fstream>
-#include <string>
-const static unsigned INIT_OK_START_ENGINE = 0;
-const static unsigned INIT_OK_DO_NOT_START_ENGINE = 1;
-const static unsigned INIT_FAILED = -1;
-
-inline void
-populate_base_path(std::unordered_map<std::string, boost::filesystem::path> &server_paths)
-{
- // populate the server_path object
- auto path_iterator = server_paths.find("base");
-
- // if a base path has been set, we populate it.
- if (path_iterator != server_paths.end())
- {
- const std::string base_string = path_iterator->second.string();
- SimpleLogger().Write() << "populating base path: " << base_string;
-
- server_paths["hsgrdata"] = base_string + ".hsgr";
- BOOST_ASSERT(server_paths.find("hsgrdata") != server_paths.end());
- server_paths["nodesdata"] = base_string + ".nodes";
- BOOST_ASSERT(server_paths.find("nodesdata") != server_paths.end());
- server_paths["coredata"] = base_string + ".core";
- BOOST_ASSERT(server_paths.find("coredata") != server_paths.end());
- server_paths["edgesdata"] = base_string + ".edges";
- BOOST_ASSERT(server_paths.find("edgesdata") != server_paths.end());
- server_paths["geometries"] = base_string + ".geometry";
- BOOST_ASSERT(server_paths.find("geometries") != server_paths.end());
- server_paths["ramindex"] = base_string + ".ramIndex";
- BOOST_ASSERT(server_paths.find("ramindex") != server_paths.end());
- server_paths["fileindex"] = base_string + ".fileIndex";
- BOOST_ASSERT(server_paths.find("fileindex") != server_paths.end());
- server_paths["namesdata"] = base_string + ".names";
- BOOST_ASSERT(server_paths.find("namesdata") != server_paths.end());
- server_paths["timestamp"] = base_string + ".timestamp";
- BOOST_ASSERT(server_paths.find("timestamp") != server_paths.end());
- }
-
- // check if files are give and whether they exist at all
- path_iterator = server_paths.find("hsgrdata");
- if (path_iterator == server_paths.end() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception(".hsgr not found");
- }
-
- path_iterator = server_paths.find("nodesdata");
- if (path_iterator == server_paths.end() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception(".nodes not found");
- }
-
- path_iterator = server_paths.find("edgesdata");
- if (path_iterator == server_paths.end() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception(".edges not found");
- }
-
- path_iterator = server_paths.find("geometries");
- if (path_iterator == server_paths.end() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception(".geometry not found");
- }
-
- path_iterator = server_paths.find("ramindex");
- if (path_iterator == server_paths.end() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception(".ramIndex not found");
- }
-
- path_iterator = server_paths.find("fileindex");
- if (path_iterator == server_paths.end() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception(".fileIndex not found");
- }
-
- path_iterator = server_paths.find("namesdata");
- if (path_iterator == server_paths.end() ||
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- throw osrm::exception(".namesIndex not found");
- }
-
- SimpleLogger().Write() << "HSGR file:\t" << server_paths["hsgrdata"];
- SimpleLogger().Write(logDEBUG) << "Nodes file:\t" << server_paths["nodesdata"];
- SimpleLogger().Write(logDEBUG) << "Edges file:\t" << server_paths["edgesdata"];
- SimpleLogger().Write(logDEBUG) << "Geometry file:\t" << server_paths["geometries"];
- SimpleLogger().Write(logDEBUG) << "RAM file:\t" << server_paths["ramindex"];
- SimpleLogger().Write(logDEBUG) << "Index file:\t" << server_paths["fileindex"];
- SimpleLogger().Write(logDEBUG) << "Names file:\t" << server_paths["namesdata"];
- SimpleLogger().Write(logDEBUG) << "Timestamp file:\t" << server_paths["timestamp"];
-}
-
-// generate boost::program_options object for the routing part
-inline unsigned
-GenerateServerProgramOptions(const int argc,
- const char *argv[],
- std::unordered_map<std::string, boost::filesystem::path> &paths,
- std::string &ip_address,
- int &ip_port,
- int &requested_num_threads,
- bool &use_shared_memory,
- bool &trial,
- int &max_locations_trip,
- int &max_locations_viaroute,
- int &max_locations_distance_table,
- int &max_locations_map_matching)
-{
- using boost::program_options::value;
- using boost::filesystem::path;
-
- // declare a group of options that will be allowed only on command line
- boost::program_options::options_description generic_options("Options");
- generic_options.add_options() //
- ("version,v", "Show version")("help,h", "Show this help message") //
- ("config,c", value<boost::filesystem::path>(&paths["config"])->default_value("server.ini"),
- "Path to a configuration file") //
- ("trial", value<bool>(&trial)->implicit_value(true), "Quit after initialization");
-
- // declare a group of options that will be allowed both on command line
- // as well as in a config file
- boost::program_options::options_description config_options("Configuration");
- config_options.add_options() //
- ("hsgrdata", value<boost::filesystem::path>(&paths["hsgrdata"]), ".hsgr file") //
- ("nodesdata", value<boost::filesystem::path>(&paths["nodesdata"]), ".nodes file") //
- ("edgesdata", value<boost::filesystem::path>(&paths["edgesdata"]), ".edges file") //
- ("geometry", value<boost::filesystem::path>(&paths["geometries"]), ".geometry file") //
- ("ramindex", value<boost::filesystem::path>(&paths["ramindex"]), ".ramIndex file") //
- ("fileindex", value<boost::filesystem::path>(&paths["fileindex"]),
- "File index file") //
- ("namesdata", value<boost::filesystem::path>(&paths["namesdata"]),
- ".names file") //
- ("timestamp", value<boost::filesystem::path>(&paths["timestamp"]),
- ".timestamp file") //
- ("ip,i", value<std::string>(&ip_address)->default_value("0.0.0.0"),
- "IP address") //
- ("port,p", value<int>(&ip_port)->default_value(5000),
- "TCP/IP port") //
- ("threads,t", value<int>(&requested_num_threads)->default_value(8),
- "Number of threads to use") //
- ("shared-memory,s",
- value<bool>(&use_shared_memory)->implicit_value(true)->default_value(false),
- "Load data from shared memory") //
- ("max-viaroute-size", value<int>(&max_locations_viaroute)->default_value(500),
- "Max. locations supported in viaroute query") //
- ("max-trip-size", value<int>(&max_locations_trip)->default_value(100),
- "Max. locations supported in trip query") //
- ("max-table-size", value<int>(&max_locations_distance_table)->default_value(100),
- "Max. locations supported in distance table query") //
- ("max-matching-size", value<int>(&max_locations_map_matching)->default_value(100),
- "Max. locations supported in map matching query");
-
- // hidden options, will be allowed both on command line and in config
- // file, but will not be shown to the user
- boost::program_options::options_description hidden_options("Hidden options");
- hidden_options.add_options()("base,b", value<boost::filesystem::path>(&paths["base"]),
- "base path to .osrm file");
-
- // positional option
- boost::program_options::positional_options_description positional_options;
- positional_options.add("base", 1);
-
- // combine above options for parsing
- boost::program_options::options_description cmdline_options;
- cmdline_options.add(generic_options).add(config_options).add(hidden_options);
-
- boost::program_options::options_description config_file_options;
- config_file_options.add(config_options).add(hidden_options);
-
- boost::program_options::options_description visible_options(
- boost::filesystem::basename(argv[0]) + " <base.osrm> [<options>]");
- visible_options.add(generic_options).add(config_options);
-
- // parse command line options
- boost::program_options::variables_map option_variables;
- boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
- .options(cmdline_options)
- .positional(positional_options)
- .run(),
- option_variables);
-
- if (option_variables.count("version"))
- {
- SimpleLogger().Write() << OSRM_VERSION;
- return INIT_OK_DO_NOT_START_ENGINE;
- }
-
- if (option_variables.count("help"))
- {
- SimpleLogger().Write() << visible_options;
- return INIT_OK_DO_NOT_START_ENGINE;
- }
-
- boost::program_options::notify(option_variables);
-
- // parse config file
- auto path_iterator = paths.find("config");
- if (path_iterator != paths.end() && boost::filesystem::is_regular_file(path_iterator->second) &&
- !option_variables.count("base"))
- {
- SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
- std::string ini_file_contents = read_file_lower_content(path_iterator->second);
- std::stringstream config_stream(ini_file_contents);
- boost::program_options::store(parse_config_file(config_stream, config_file_options),
- option_variables);
- boost::program_options::notify(option_variables);
- return INIT_OK_START_ENGINE;
- }
-
- if (1 > requested_num_threads)
- {
- throw osrm::exception("Number of threads must be a positive number");
- }
- if (2 > max_locations_distance_table)
- {
- throw osrm::exception("Max location for distance table must be at least two");
- }
- if (2 > max_locations_map_matching)
- {
- throw osrm::exception("Max location for map matching must be at least two");
- }
-
- if (!use_shared_memory && option_variables.count("base"))
- {
- return INIT_OK_START_ENGINE;
- }
- else if (use_shared_memory && !option_variables.count("base"))
- {
- return INIT_OK_START_ENGINE;
- }
- else if (use_shared_memory && option_variables.count("base"))
- {
- SimpleLogger().Write(logWARNING) << "Shared memory settings conflict with path settings.";
- }
-
- SimpleLogger().Write() << visible_options;
- return INIT_OK_DO_NOT_START_ENGINE;
-}
-
-#endif // ROUTED_OPTIONS_HPP
diff --git a/util/simple_logger.hpp b/util/simple_logger.hpp
deleted file mode 100644
index df61a9d..0000000
--- a/util/simple_logger.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef SIMPLE_LOGGER_HPP
-#define SIMPLE_LOGGER_HPP
-
-#include <atomic>
-#include <mutex>
-#include <sstream>
-
-enum LogLevel
-{
- logINFO,
- logWARNING,
- logDEBUG
-};
-
-class LogPolicy
-{
- public:
- void Unmute();
-
- void Mute();
-
- bool IsMute() const;
-
- static LogPolicy &GetInstance();
-
- LogPolicy(const LogPolicy &) = delete;
-
- private:
- LogPolicy() : m_is_mute(true) {}
- std::atomic<bool> m_is_mute;
-};
-
-class SimpleLogger
-{
- public:
- SimpleLogger();
-
- virtual ~SimpleLogger();
- std::mutex &get_mutex();
- std::ostringstream &Write(LogLevel l = logINFO) noexcept;
-
- private:
- std::ostringstream os;
- LogLevel level;
-};
-
-#endif /* SIMPLE_LOGGER_HPP */
diff --git a/util/std_hash.hpp b/util/std_hash.hpp
deleted file mode 100644
index 9e78fcc..0000000
--- a/util/std_hash.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef STD_HASH_HPP
-#define STD_HASH_HPP
-
-#include <functional>
-
-// this is largely inspired by boost's hash combine as can be found in
-// "The C++ Standard Library" 2nd Edition. Nicolai M. Josuttis. 2012.
-
-namespace
-{
-
-template <typename T> void hash_combine(std::size_t &seed, const T &val)
-{
- seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
-}
-
-template <typename T> void hash_val(std::size_t &seed, const T &val) { hash_combine(seed, val); }
-
-template <typename T, typename... Types>
-void hash_val(std::size_t &seed, const T &val, const Types &... args)
-{
- hash_combine(seed, val);
- hash_val(seed, args...);
-}
-
-template <typename... Types> std::size_t hash_val(const Types &... args)
-{
- std::size_t seed = 0;
- hash_val(seed, args...);
- return seed;
-}
-}
-
-namespace std
-{
-template <typename T1, typename T2> struct hash<std::pair<T1, T2>>
-{
- size_t operator()(const std::pair<T1, T2> &pair) const
- {
- return hash_val(pair.first, pair.second);
- }
-};
-}
-
-#endif // STD_HASH_HPP
diff --git a/util/version.hpp.in b/util/version.hpp.in
deleted file mode 100644
index 2eafd48..0000000
--- a/util/version.hpp.in
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-
-Copyright (c) 2015, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef VERSION_HPP
-#define VERSION_HPP
-
-#define OSRM_VERSION_MAJOR "@OSRM_VERSION_MAJOR@"
-#define OSRM_VERSION_MINOR "@OSRM_VERSION_MINOR@"
-#define OSRM_VERSION_PATCH "@OSRM_VERSION_PATCH@"
-
-#define OSRM_VERSION "v" OSRM_VERSION_MAJOR "." OSRM_VERSION_MINOR "." OSRM_VERSION_PATCH
-
-#endif // VERSION_HPP
diff --git a/util/xml_renderer.hpp b/util/xml_renderer.hpp
deleted file mode 100644
index 44f7c2d..0000000
--- a/util/xml_renderer.hpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
-
-Copyright (c) 2014, Project OSRM contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef XML_RENDERER_HPP
-#define XML_RENDERER_HPP
-
-#include "cast.hpp"
-
-#include <osrm/json_container.hpp>
-
-namespace osrm
-{
-namespace json
-{
-
-struct XMLToArrayRenderer : mapbox::util::static_visitor<>
-{
- explicit XMLToArrayRenderer(std::vector<char> &_out) : out(_out) {}
-
- void operator()(const String &string) const
- {
- out.push_back('\"');
- out.insert(out.end(), string.value.begin(), string.value.end());
- out.push_back('\"');
- }
-
- void operator()(const Number &number) const
- {
- const std::string number_string = cast::to_string_with_precision(number.value);
- out.insert(out.end(), number_string.begin(), number_string.end());
- }
-
- void operator()(const Object &object) const
- {
- for (auto &&each : object.values)
- {
- if (each.first.at(0) != '_')
- {
- out.push_back('<');
- out.insert(out.end(), each.first.begin(), each.first.end());
- }
- else
- {
- out.push_back(' ');
- out.insert(out.end(), ++(each).first.begin(), each.first.end());
- out.push_back('=');
- }
- mapbox::util::apply_visitor(XMLToArrayRenderer(out), each.second);
- if (each.first.at(0) != '_')
- {
- out.push_back('/');
- out.push_back('>');
- }
- }
- }
-
- void operator()(const Array &array) const
- {
- for (auto &&each : array.values)
- {
- mapbox::util::apply_visitor(XMLToArrayRenderer(out), each);
- }
- }
-
- void operator()(const True &) const
- {
- const std::string temp("true");
- out.insert(out.end(), temp.begin(), temp.end());
- }
-
- void operator()(const False &) const
- {
- const std::string temp("false");
- out.insert(out.end(), temp.begin(), temp.end());
- }
-
- void operator()(const Null &) const
- {
- const std::string temp("null");
- out.insert(out.end(), temp.begin(), temp.end());
- }
-
- private:
- std::vector<char> &out;
-};
-
-template <class JSONObject> inline void xml_render(std::vector<char> &out, const JSONObject &object)
-{
- Value value = object;
- mapbox::util::apply_visitor(XMLToArrayRenderer(out), value);
-}
-
-template <class JSONObject> inline void gpx_render(std::vector<char> &out, const JSONObject &object)
-{
- // add header
-
- const std::string header{
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><gpx creator=\"OSRM Routing Engine\""
- " version=\"1.1\" xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xsi=\"http:"
- "//www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topogr"
- "afix.com/GPX/1/1 gpx.xsd\"><metadata><copyright author=\"Project OSRM\"><lice"
- "nse>Data (c) OpenStreetMap contributors (ODbL)</license></copyright></metadat"
- "a><rte>"};
- out.insert(out.end(), header.begin(), header.end());
-
- xml_render(out, object);
-
- const std::string footer{"</rte></gpx>"};
- out.insert(out.end(), footer.begin(), footer.end());
-}
-} // namespace json
-} // namespace osrm
-#endif // XML_RENDERER_HPP
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/osrm.git
More information about the Pkg-grass-devel
mailing list