[osrm] 01/08: Imported Upstream version 4.6.0
Sebastiaan Couwenberg
sebastic at moszumanska.debian.org
Sat May 9 23:08:43 UTC 2015
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository osrm.
commit 5d6067d4db0d111d22e79ecce371a059e553ee65
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Sat May 9 23:32:16 2015 +0200
Imported Upstream version 4.6.0
---
.gitignore | 23 +-
.travis.yml | 10 +-
CMakeLists.txt | 155 +-
Gemfile | 2 +-
Include/osrm/Coordinate.h | 113 -
Include/osrm/Reply.h | 74 -
LICENCE.TXT | 2 +-
Server/APIGrammar.h | 74 -
Server/RequestHandler.cpp | 143 -
Server/RequestParser.cpp | 310 -
Util/TrigonometryTables.h | 790 --
Util/graph_loader.hpp | 325 -
Util/range_algorithms.hpp | 42 -
algorithms/bayes_classifier.hpp | 117 +
algorithms/bfs_components.hpp | 8 +-
algorithms/crc32_processor.hpp | 15 +-
algorithms/douglas_peucker.cpp | 14 +-
algorithms/douglas_peucker.hpp | 11 +-
algorithms/object_encoder.hpp | 17 +-
algorithms/polyline_compressor.cpp | 12 +-
algorithms/polyline_compressor.hpp | 2 +-
algorithms/polyline_formatter.cpp | 14 +-
algorithms/polyline_formatter.hpp | 8 +-
algorithms/route_name_extraction.hpp | 65 +-
algorithms/tiny_components.hpp | 64 +-
appveyor.yml | 3 -
benchmarks/static_rtree.cpp | 21 +-
cmake/FingerPrint-Config.cmake | 8 +-
contractor/contractor.hpp | 202 +-
contractor/edge_based_graph_factory.cpp | 272 +-
contractor/geometry_compressor.cpp | 41 +-
contractor/geometry_compressor.hpp | 2 +
contractor/processing_chain.cpp | 82 +-
data_structures/Coordinate.cpp | 483 --
data_structures/InputReaderFactory.h | 123 -
data_structures/binary_heap.hpp | 58 +-
data_structures/concurrent_queue.hpp | 16 +-
data_structures/coordinate.cpp | 87 +
data_structures/coordinate_calculation.cpp | 268 +
data_structures/coordinate_calculation.hpp | 82 +
data_structures/deallocating_vector.hpp | 75 +-
data_structures/dynamic_graph.hpp | 132 +-
data_structures/edge_based_node.hpp | 120 +-
data_structures/external_memory_node.cpp | 10 +-
data_structures/external_memory_node.hpp | 4 +-
data_structures/fixed_point_number.hpp | 2 +-
data_structures/hidden_markov_model.hpp | 158 +
data_structures/hilbert_value.cpp | 4 +-
data_structures/hilbert_value.hpp | 2 +-
data_structures/import_edge.cpp | 9 +-
data_structures/import_edge.hpp | 2 +-
...aw_route_data.hpp => internal_route_result.hpp} | 27 +-
data_structures/lru_cache.hpp | 4 +-
data_structures/node_based_graph.hpp | 62 +-
data_structures/node_id.hpp | 2 +-
data_structures/original_edge_data.hpp | 7 +-
data_structures/percent.hpp | 4 +-
data_structures/phantom_node.cpp | 114 +-
data_structures/phantom_node.hpp | 59 +-
data_structures/query_edge.hpp | 18 +-
data_structures/query_node.hpp | 8 +-
data_structures/range_table.hpp | 81 +-
data_structures/rectangle.hpp | 150 +-
data_structures/restriction.hpp | 16 +-
data_structures/restriction_map.cpp | 92 +-
data_structures/restriction_map.hpp | 36 +-
data_structures/route_parameters.cpp | 32 +-
data_structures/search_engine.hpp | 14 +-
data_structures/search_engine_data.cpp | 38 +-
data_structures/search_engine_data.hpp | 14 +-
data_structures/segment_information.hpp | 10 +-
data_structures/shared_memory_factory.hpp | 55 +-
data_structures/shared_memory_vector_wrapper.hpp | 6 +-
data_structures/static_graph.hpp | 34 +-
data_structures/static_kdtree.hpp | 6 +-
data_structures/static_rtree.hpp | 594 +-
data_structures/travel_mode.hpp | 5 +-
Util/git_sha.cpp.in => data_structures/tribool.hpp | 17 +-
data_structures/turn_instructions.hpp | 29 +-
.../upper_bound.hpp | 67 +-
data_structures/xor_fast_hash.hpp | 14 +-
data_structures/xor_fast_hash_storage.hpp | 32 +-
datastore.cpp | 35 +-
descriptors/description_factory.cpp | 164 +-
descriptors/description_factory.hpp | 144 +-
descriptors/descriptor_base.hpp | 24 +-
descriptors/gpx_descriptor.hpp | 38 +-
descriptors/json_descriptor.hpp | 785 +-
extract.cpp | 51 +-
extractor/extraction_containers.cpp | 182 +-
extractor/extraction_containers.hpp | 20 +-
extractor/extraction_helper_functions.hpp | 103 +-
extractor/extraction_node.hpp | 9 +-
extractor/extraction_way.hpp | 23 +-
extractor/extractor.cpp | 149 +-
extractor/extractor.hpp | 36 +-
extractor/extractor_callbacks.cpp | 94 +-
extractor/extractor_callbacks.hpp | 2 +-
extractor/extractor_options.cpp | 97 +-
extractor/extractor_options.hpp | 18 +-
extractor/first_and_last_segment_of_way.hpp | 2 +-
extractor/internal_extractor_edge.hpp | 34 +-
extractor/restriction_parser.cpp | 62 +-
extractor/restriction_parser.hpp | 5 +-
extractor/scripting_environment.cpp | 83 +-
extractor/scripting_environment.hpp | 6 +-
features/bicycle/bridge.feature | 47 +
features/car/access.feature | 2 +
features/car/barrier.feature | 1 +
features/car/bridge.feature | 47 +
features/car/ferry.feature | 21 +-
features/car/maxspeed.feature | 20 +
features/options/routed/help.feature | 18 +-
features/step_definitions/matching.rb | 96 +
features/support/env.rb | 18 +-
features/support/launch.rb | 4 +-
features/support/match.rb | 26 +
features/testbot/loop.feature | 14 +-
features/testbot/matching.feature | 55 +
.../osrm/coordinate.hpp | 57 +-
.../osrm}/json_container.hpp | 14 +-
prepare.cpp => include/osrm/libosrm_config.hpp | 41 +-
.../osrm/route_parameters.hpp | 26 +-
.../ServerPaths.h => include/osrm/server_paths.hpp | 4 +-
Library/OSRM.h => library/osrm.hpp | 21 +-
Library/OSRM_impl.cpp => library/osrm_impl.cpp | 154 +-
Library/OSRM_impl.h => library/osrm_impl.hpp | 23 +-
plugins/distance_table.hpp | 52 +-
plugins/hello_world.hpp | 40 +-
plugins/locate.hpp | 33 +-
plugins/match.hpp | 314 +
plugins/nearest.hpp | 52 +-
plugins/plugin_base.hpp | 32 +-
plugins/timestamp.hpp | 16 +-
plugins/viaroute.hpp | 26 +-
prepare.cpp | 8 +-
profiles/bicycle.lua | 22 +-
profiles/car.lua | 54 +-
routed.cpp | 43 +-
routing_algorithms/alternative_path.hpp | 233 +-
routing_algorithms/many_to_many.hpp | 25 +-
routing_algorithms/map_matching.hpp | 344 +
routing_algorithms/routing_base.hpp | 179 +-
routing_algorithms/shortest_path.hpp | 114 +-
server/api_grammar.hpp | 101 +
Server/Connection.cpp => server/connection.cpp | 93 +-
Server/Connection.h => server/connection.hpp | 48 +-
.../data_structures/datafacade_base.hpp | 39 +-
.../data_structures/internal_datafacade.hpp | 140 +-
.../data_structures/shared_barriers.hpp | 8 +-
.../data_structures/shared_datafacade.hpp | 154 +-
.../data_structures/shared_datatype.hpp | 164 +-
.../http/compression_type.hpp | 19 +-
Include/osrm/Header.h => server/http/header.hpp | 19 +-
Server/Http/Reply.cpp => server/http/reply.cpp | 68 +-
Server/Http/Request.h => server/http/reply.hpp | 43 +-
Server/Http/Request.h => server/http/request.hpp | 10 +-
server/request_handler.cpp | 175 +
.../RequestHandler.h => server/request_handler.hpp | 14 +-
server/request_parser.cpp | 323 +
.../RequestParser.h => server/request_parser.hpp | 94 +-
Server/Server.h => server/server.hpp | 24 +-
third_party/libosmium/.gitignore | 2 +
third_party/libosmium/.travis.yml | 51 +
third_party/libosmium/.ycm_extra_conf.py | 48 +
third_party/libosmium/CHANGELOG.md | 31 +
third_party/libosmium/CMakeLists.txt | 333 +
third_party/libosmium/CONTRIBUTING.md | 132 +
.../io/xml_input.hpp => libosmium/LICENSE.txt} | 16 -
third_party/libosmium/Makefile | 25 +
third_party/libosmium/README.md | 104 +
third_party/libosmium/appveyor.yml | 77 +
third_party/libosmium/benchmarks/CMakeLists.txt | 48 +
third_party/libosmium/benchmarks/README.md | 41 +
third_party/libosmium/benchmarks/download_data.sh | 12 +
.../benchmarks/osmium_benchmark_count.cpp | 54 +
.../benchmarks/osmium_benchmark_count_tag.cpp | 55 +
.../benchmarks/osmium_benchmark_index_map.cpp | 41 +
.../osmium_benchmark_static_vs_dynamic_index.cpp | 136 +
.../libosmium/benchmarks/run_benchmark_count.sh | 22 +
.../benchmarks/run_benchmark_count_tag.sh | 22 +
.../benchmarks/run_benchmark_index_map.sh | 27 +
.../run_benchmark_static_vs_dynamic_index.sh | 21 +
third_party/libosmium/benchmarks/run_benchmarks.sh | 15 +
third_party/libosmium/benchmarks/setup.sh | 34 +
third_party/libosmium/cmake/FindGem.cmake | 153 +
third_party/libosmium/cmake/FindOSMPBF.cmake | 50 +
third_party/libosmium/cmake/FindOsmium.cmake | 340 +
third_party/libosmium/cmake/README | 3 +
third_party/libosmium/cmake/build.bat | 15 +
third_party/libosmium/cmake/iwyu.sh | 43 +
third_party/libosmium/doc/CMakeLists.txt | 35 +
third_party/libosmium/doc/Doxyfile.in | 2313 +++++
third_party/libosmium/doc/README.md | 8 +
third_party/libosmium/doc/doc.txt | 26 +
third_party/libosmium/doc/header.html | 56 +
third_party/libosmium/doc/osmium.css | 22 +
third_party/libosmium/examples/CMakeLists.txt | 115 +
.../libosmium/examples/osmium_area_test.cpp | 138 +
third_party/libosmium/examples/osmium_convert.cpp | 112 +
third_party/libosmium/examples/osmium_count.cpp | 57 +
.../examples/osmium_create_node_cache.cpp | 58 +
third_party/libosmium/examples/osmium_debug.cpp | 52 +
third_party/libosmium/examples/osmium_index.cpp | 237 +
third_party/libosmium/examples/osmium_read.cpp | 32 +
third_party/libosmium/examples/osmium_serdump.cpp | 209 +
third_party/libosmium/examples/osmium_toogr.cpp | 246 +
third_party/libosmium/examples/osmium_toogr2.cpp | 333 +
.../libosmium/examples/osmium_toogr2_exp.cpp | 307 +
.../libosmium/examples/osmium_use_node_cache.cpp | 71 +
.../libosmium/include/boost_unicode_iterator.hpp | 776 ++
third_party/libosmium/include/mmap_for_windows.hpp | 103 +
.../include}/osmium/area/assembler.hpp | 8 +-
.../osmium/area/detail/node_ref_segment.hpp | 2 +-
.../include}/osmium/area/detail/proto_ring.hpp | 4 +-
.../include}/osmium/area/detail/segment_list.hpp | 4 +-
.../osmium/area/multipolygon_collector.hpp | 4 +-
.../include}/osmium/area/problem_reporter.hpp | 2 +-
.../osmium/area/problem_reporter_exception.hpp | 2 +-
.../include}/osmium/area/problem_reporter_ogr.hpp | 45 +-
.../osmium/area/problem_reporter_stream.hpp | 2 +-
.../include}/osmium/builder/builder.hpp | 19 +-
.../include}/osmium/builder/builder_helper.hpp | 2 +-
.../include}/osmium/builder/osm_object_builder.hpp | 17 +-
.../include}/osmium/diff_handler.hpp | 2 +-
.../include}/osmium/diff_iterator.hpp | 2 +-
.../include}/osmium/diff_visitor.hpp | 2 +-
.../include}/osmium/dynamic_handler.hpp | 2 +-
.../include}/osmium/experimental/flex_reader.hpp | 42 +-
.../include}/osmium/geom/coordinates.hpp | 2 +-
.../include}/osmium/geom/factory.hpp | 4 +-
.../include}/osmium/geom/geojson.hpp | 10 +-
.../{ => libosmium/include}/osmium/geom/geos.hpp | 12 +-
.../include}/osmium/geom/haversine.hpp | 4 +-
.../include}/osmium/geom/mercator_projection.hpp | 2 +-
.../{ => libosmium/include}/osmium/geom/ogr.hpp | 47 +-
.../include}/osmium/geom/projection.hpp | 28 +-
.../include}/osmium/geom/relations.hpp | 2 +-
.../{ => libosmium/include}/osmium/geom/util.hpp | 2 +-
.../{ => libosmium/include}/osmium/geom/wkb.hpp | 12 +-
.../{ => libosmium/include}/osmium/geom/wkt.hpp | 8 +-
.../{ => libosmium/include}/osmium/handler.hpp | 2 +-
.../include}/osmium/handler/chain.hpp | 2 +-
.../include}/osmium/handler/disk_store.hpp | 2 +-
.../include}/osmium/handler/dump.hpp | 4 +-
.../osmium/handler/node_locations_for_ways.hpp | 13 +-
.../include}/osmium/handler/object_relations.hpp | 2 +-
.../osmium/index/detail/create_map_with_fd.hpp} | 45 +-
.../osmium/index/detail/mmap_vector_anon.hpp | 12 +-
.../osmium/index/detail/mmap_vector_base.hpp | 9 +-
.../osmium/index/detail/mmap_vector_file.hpp | 21 +-
.../include}/osmium/index/detail/tmpfile.hpp | 8 +-
.../include}/osmium/index/detail/typed_mmap.hpp | 8 +-
.../include/osmium/index/detail/vector_map.hpp} | 40 +-
.../osmium/index/detail/vector_multimap.hpp} | 11 +-
.../{ => libosmium/include}/osmium/index/index.hpp | 2 +-
.../{ => libosmium/include}/osmium/index/map.hpp | 109 +-
.../include/osmium/index/map/all.hpp} | 25 +-
.../include/osmium/index/map/dense_file_array.hpp} | 24 +-
.../include/osmium/index/map/dense_mem_array.hpp} | 21 +-
.../include/osmium/index/map/dense_mmap_array.hpp} | 17 +-
.../include}/osmium/index/map/dummy.hpp | 3 +-
.../osmium/index/map/sparse_file_array.hpp} | 24 +-
.../include/osmium/index/map/sparse_mem_array.hpp} | 17 +-
.../include/osmium/index/map/sparse_mem_map.hpp} | 21 +-
.../include/osmium/index/map/sparse_mem_table.hpp} | 32 +-
.../osmium/index/map/sparse_mmap_array.hpp} | 23 +-
.../include}/osmium/index/multimap.hpp | 10 +-
.../include/osmium/index/multimap/all.hpp} | 18 +-
.../include}/osmium/index/multimap/hybrid.hpp | 17 +-
.../osmium/index/multimap/sparse_file_array.hpp} | 12 +-
.../osmium/index/multimap/sparse_mem_array.hpp} | 12 +-
.../osmium/index/multimap/sparse_mem_multimap.hpp} | 18 +-
.../osmium/index/multimap/sparse_mmap_array.hpp} | 12 +-
.../include/osmium/index/node_locations_map.hpp | 70 +
.../include}/osmium/io/any_compression.hpp | 11 +-
.../include}/osmium/io/any_input.hpp | 12 +-
.../include}/osmium/io/any_output.hpp | 12 +-
.../include}/osmium/io/bzip2_compression.hpp | 110 +-
.../include}/osmium/io/compression.hpp | 24 +-
.../include}/osmium/io/detail/input_format.hpp | 8 +-
.../osmium/io/detail/opl_output_format.hpp | 82 +-
.../include}/osmium/io/detail/output_format.hpp | 2 +-
.../include}/osmium/io/detail/pbf.hpp | 4 +-
.../include}/osmium/io/detail/pbf_input_format.hpp | 52 +-
.../osmium/io/detail/pbf_output_format.hpp | 52 +-
.../include}/osmium/io/detail/pbf_parser.hpp | 46 +-
.../include}/osmium/io/detail/pbf_stringtable.hpp | 44 +-
.../include}/osmium/io/detail/read_thread.hpp | 2 +-
.../include}/osmium/io/detail/read_write.hpp | 10 +-
.../include}/osmium/io/detail/write_thread.hpp | 2 +-
.../include}/osmium/io/detail/xml_input_format.hpp | 28 +-
.../osmium/io/detail/xml_output_format.hpp | 153 +-
.../include}/osmium/io/detail/zlib.hpp | 42 +-
.../{ => libosmium/include}/osmium/io/error.hpp | 3 +-
.../{ => libosmium/include}/osmium/io/file.hpp | 3 +-
.../include}/osmium/io/file_compression.hpp | 2 +-
.../include}/osmium/io/file_format.hpp | 2 +-
.../include}/osmium/io/gzip_compression.hpp | 50 +-
.../{ => libosmium/include}/osmium/io/header.hpp | 2 +-
.../include}/osmium/io/input_iterator.hpp | 3 +-
.../include}/osmium/io/opl_output.hpp | 2 +-
.../include}/osmium/io/output_iterator.hpp | 10 +-
.../include}/osmium/io/overwrite.hpp | 2 +-
.../include}/osmium/io/pbf_input.hpp | 12 +-
.../include}/osmium/io/pbf_output.hpp | 12 +-
.../{ => libosmium/include}/osmium/io/reader.hpp | 21 +-
.../include}/osmium/io/reader_iterator.hpp | 2 +-
.../{ => libosmium/include}/osmium/io/writer.hpp | 4 +-
.../include}/osmium/io/xml_input.hpp | 11 +-
.../include}/osmium/io/xml_output.hpp | 10 +-
.../include}/osmium/memory/buffer.hpp | 13 +-
.../include}/osmium/memory/collection.hpp | 3 +-
.../{ => libosmium/include}/osmium/memory/item.hpp | 7 +-
.../include}/osmium/memory/item_iterator.hpp | 2 +-
.../include}/osmium/object_pointer_collection.hpp | 2 +-
third_party/{ => libosmium/include}/osmium/osm.hpp | 2 +-
.../{ => libosmium/include}/osmium/osm/area.hpp | 41 +-
.../{ => libosmium/include}/osmium/osm/box.hpp | 81 +-
.../include}/osmium/osm/changeset.hpp | 5 +-
.../include}/osmium/osm/diff_object.hpp | 2 +-
.../{ => libosmium/include}/osmium/osm/entity.hpp | 7 +-
.../include}/osmium/osm/entity_bits.hpp | 8 +-
.../include}/osmium/osm/item_type.hpp | 2 +-
.../include}/osmium/osm/location.hpp | 2 +-
.../{ => libosmium/include}/osmium/osm/node.hpp | 2 +-
.../include}/osmium/osm/node_ref.hpp | 4 +-
.../include}/osmium/osm/node_ref_list.hpp | 97 +-
.../{ => libosmium/include}/osmium/osm/object.hpp | 2 +-
.../include}/osmium/osm/object_comparisons.hpp | 2 +-
.../include}/osmium/osm/relation.hpp | 4 +-
.../{ => libosmium/include}/osmium/osm/segment.hpp | 2 +-
.../{ => libosmium/include}/osmium/osm/tag.hpp | 2 +-
.../include}/osmium/osm/timestamp.hpp | 38 +-
.../{ => libosmium/include}/osmium/osm/types.hpp | 2 +-
.../include}/osmium/osm/undirected_segment.hpp | 2 +-
.../{ => libosmium/include}/osmium/osm/way.hpp | 8 +-
.../include}/osmium/relations/collector.hpp | 6 +-
.../osmium/relations/detail/member_meta.hpp | 2 +-
.../osmium/relations/detail/relation_meta.hpp | 2 +-
.../{ => libosmium/include}/osmium/tags/filter.hpp | 16 +-
.../include}/osmium/tags/regex_filter.hpp | 2 +-
.../include}/osmium/tags/taglist.hpp | 8 +-
.../include}/osmium/thread/function_wrapper.hpp | 5 +-
.../{ => libosmium/include}/osmium/thread/pool.hpp | 8 +-
.../include}/osmium/thread/queue.hpp | 13 +-
.../include}/osmium/thread/sorted_queue.hpp | 6 +-
.../{ => libosmium/include}/osmium/thread/util.hpp | 2 +-
third_party/libosmium/include/osmium/util/cast.hpp | 103 +
.../include}/osmium/util/compatibility.hpp | 2 +-
.../{ => libosmium/include}/osmium/util/config.hpp | 7 +-
.../{ => libosmium/include}/osmium/util/double.hpp | 4 +-
.../include}/osmium/util/options.hpp | 2 +-
.../include/osmium/util/string.hpp} | 51 +-
.../include}/osmium/util/verbose_output.hpp | 4 +-
.../{ => libosmium/include}/osmium/visitor.hpp | 2 +-
third_party/libosmium/osmium.imp | 11 +
third_party/libosmium/test/CMakeLists.txt | 165 +
third_party/libosmium/test/README | 13 +
third_party/libosmium/test/data-tests/.gitignore | 1 +
.../libosmium/test/data-tests/CMakeLists.txt | 118 +
third_party/libosmium/test/data-tests/README.md | 10 +
.../data-tests/include/check_basics_handler.hpp | 92 +
.../test/data-tests/include/check_wkt_handler.hpp | 86 +
.../libosmium/test/data-tests/include/common.hpp | 22 +
.../test/data-tests/include/testdata-testcases.hpp | 10 +
.../libosmium/test/data-tests/multipolygon.qgs | 880 ++
.../data-tests/run-testdata-multipolygon.cmake | 46 +
.../test/data-tests/testcases/test-100.cpp | 41 +
.../test/data-tests/testcases/test-101.cpp | 43 +
.../test/data-tests/testcases/test-110.cpp | 58 +
.../test/data-tests/testdata-multipolygon.cpp | 291 +
.../test/data-tests/testdata-overview.cpp | 197 +
.../test/data-tests/testdata-testcases.cpp | 27 +
.../libosmium/test/data-tests/testdata-xml.cpp | 462 +
third_party/libosmium/test/include/catch.hpp | 9003 ++++++++++++++++++++
third_party/libosmium/test/include/catch_orig.hpp | 8997 +++++++++++++++++++
third_party/libosmium/test/include/utils.hpp | 18 +
third_party/libosmium/test/include/win_mkstemp.hpp | 42 +
third_party/libosmium/test/t/area/test_area_id.cpp | 25 +
.../test/t/area/test_node_ref_segment.cpp | 115 +
third_party/libosmium/test/t/basic/helper.hpp | 97 +
third_party/libosmium/test/t/basic/test_box.cpp | 91 +
.../libosmium/test/t/basic/test_changeset.cpp | 57 +
.../libosmium/test/t/basic/test_entity_bits.cpp | 31 +
.../libosmium/test/t/basic/test_location.cpp | 154 +
third_party/libosmium/test/t/basic/test_node.cpp | 117 +
.../libosmium/test/t/basic/test_node_ref.cpp | 57 +
.../test/t/basic/test_object_comparisons.cpp | 147 +
.../libosmium/test/t/basic/test_relation.cpp | 60 +
.../libosmium/test/t/basic/test_timestamp.cpp | 58 +
third_party/libosmium/test/t/basic/test_way.cpp | 82 +
.../libosmium/test/t/buffer/test_buffer_node.cpp | 135 +
.../libosmium/test/t/buffer/test_buffer_purge.cpp | 186 +
third_party/libosmium/test/t/geom/helper.hpp | 15 +
.../test/t/geom/test_factory_with_projection.cpp | 41 +
third_party/libosmium/test/t/geom/test_geojson.cpp | 236 +
third_party/libosmium/test/t/geom/test_geos.cpp | 198 +
.../libosmium/test/t/geom/test_geos_wkb.cpp | 156 +
.../libosmium/test/t/geom/test_mercator.cpp | 37 +
third_party/libosmium/test/t/geom/test_ogr.cpp | 185 +
.../libosmium/test/t/geom/test_projection.cpp | 131 +
third_party/libosmium/test/t/geom/test_wkb.cpp | 133 +
third_party/libosmium/test/t/geom/test_wkt.cpp | 198 +
.../libosmium/test/t/index/test_id_to_location.cpp | 170 +
.../libosmium/test/t/index/test_typed_mmap.cpp | 76 +
.../test/t/index/test_typed_mmap_grow.cpp | 34 +
third_party/libosmium/test/t/io/data.osm | 4 +
third_party/libosmium/test/t/io/data.osm.bz2 | Bin 0 -> 200 bytes
third_party/libosmium/test/t/io/data.osm.gz | Bin 0 -> 187 bytes
third_party/libosmium/test/t/io/data_bzip2.txt | 1 +
third_party/libosmium/test/t/io/data_bzip2.txt.bz2 | Bin 0 -> 45 bytes
third_party/libosmium/test/t/io/test_bzip2.cpp | 33 +
.../libosmium/test/t/io/test_file_formats.cpp | 251 +
.../libosmium/test/t/io/test_output_iterator.cpp | 37 +
third_party/libosmium/test/t/io/test_reader.cpp | 117 +
third_party/libosmium/test/t/tags/test_filter.cpp | 216 +
.../libosmium/test/t/tags/test_operators.cpp | 61 +
.../libosmium/test/t/tags/test_tag_list.cpp | 76 +
third_party/libosmium/test/t/thread/test_pool.cpp | 69 +
.../test/t/util/test_cast_with_assert.cpp | 89 +
third_party/libosmium/test/t/util/test_double.cpp | 33 +
third_party/libosmium/test/t/util/test_options.cpp | 48 +
third_party/libosmium/test/t/util/test_string.cpp | 57 +
third_party/libosmium/test/test_main.cpp | 2 +
third_party/libosmium/test/valgrind.supp | 47 +
third_party/osmium/thread/checked_task.hpp | 106 -
third_party/osmium/thread/name.hpp | 61 -
third_party/osmium/util/cast.hpp | 72 -
third_party/variant/.gitignore | 3 +
third_party/variant/.travis.yml | 22 +
third_party/variant/Jamroot | 75 +
Util/git_sha.cpp.in => third_party/variant/LICENSE | 26 +-
third_party/variant/Makefile | 100 +
third_party/variant/README.md | 67 +
third_party/variant/appveyor.yml | 27 +
third_party/variant/common.gypi | 143 +
third_party/variant/scripts/linux.sh | 59 +
third_party/variant/scripts/osx.sh | 20 +
third_party/variant/test/bench_variant.cpp | 204 +
third_party/variant/test/binary_visitor_test.cpp | 136 +
.../variant/test/boost_variant_hello_world.cpp | 19 +
third_party/variant/test/catch.hpp | 8683 +++++++++++++++++++
third_party/variant/test/optional_unit.cpp | 82 +
.../variant/test/recursive_wrapper_test.cpp | 132 +
.../variant/test/reference_wrapper_test.cpp | 74 +
third_party/variant/test/unique_ptr_test.cpp | 128 +
third_party/variant/test/unit.cpp | 314 +
third_party/variant/test/variant_hello_world.cpp | 22 +
third_party/variant/variant.gyp | 21 +
third_party/variant/variant.hpp | 282 +-
third_party/variant/variant_io.hpp | 39 +
third_party/variant/vcbuild.bat | 8 +
tools/check-hsgr.cpp | 22 +-
tools/components.cpp | 120 +-
tools/graph_compare.cpp | 199 +
tools/io-benchmark.cpp | 24 +-
tools/simpleclient.cpp | 93 +-
tools/springclean.cpp | 12 +-
tools/unlock_all_mutexes.cpp | 8 +-
{UnitTests => unit_tests}/algorithm_tests.cpp | 3 +-
.../algorithms/douglas_peucker.cpp | 36 +-
.../algorithms/duration_parsing.cpp | 39 +-
.../algorithms/string_util.cpp | 50 +-
.../data_structures/binary_heap.cpp | 2 +-
.../data_structures/coordinate.cpp | 27 +-
unit_tests/data_structures/dynamic_graph.cpp | 96 +
.../data_structures/range_table.cpp | 7 +-
.../data_structures/static_graph.cpp | 63 +-
.../data_structures/static_rtree.cpp | 86 +-
{UnitTests => unit_tests}/datastructure_tests.cpp | 2 +-
{Util => util}/bearing.cpp | 42 +-
{Util => util}/bearing.hpp | 12 +-
.../boost_filesystem_2_fix.hpp | 2 +-
{Util => util}/cast.hpp | 17 +-
{Util => util}/compute_angle.cpp | 25 +-
{Util => util}/compute_angle.hpp | 13 +-
{Util => util}/container.hpp | 51 +-
.../datastore_options.hpp | 42 +-
Util/git_sha.hpp => util/fingerprint.cpp | 8 +-
Util/FingerPrint.h => util/fingerprint.hpp | 4 +-
.../fingerprint_impl.hpp.in | 6 +-
{Util => util}/floating_point.hpp | 2 +-
{Util => util}/git_sha.cpp.in | 2 +-
{Util => util}/git_sha.hpp | 4 +-
util/graph_loader.hpp | 539 ++
Util/IniFileUtil.h => util/ini_file.hpp | 26 +-
{Util => util}/integer_range.hpp | 26 +-
util/iso_8601_duration_parser.hpp | 102 +
{Util => util}/iterator_range.hpp | 37 +-
Util/bearing.cpp => util/json_logger.hpp | 79 +-
{Util => util}/json_renderer.hpp | 25 +-
util/json_util.hpp | 103 +
{Util => util}/lua_util.hpp | 2 +-
{Util => util}/make_unique.hpp | 44 +-
util/matching_debug_info.hpp | 155 +
Util/MercatorUtil.h => util/mercator.cpp | 15 +-
Util/bearing.hpp => util/mercator.hpp | 16 +-
{Util => util}/osrm_exception.cpp | 24 +-
{Util => util}/osrm_exception.hpp | 2 +-
.../range_algorithms.hpp | 27 +-
Util/ProgramOptions.h => util/routed_options.hpp | 76 +-
{Util => util}/simple_logger.cpp | 58 +-
{Util => util}/simple_logger.hpp | 4 +-
{Util => util}/std_hash.hpp | 23 +-
{Util => util}/string_util.hpp | 54 +-
{Util => util}/timing_util.hpp | 36 +-
util/trigonometry_table.hpp | 448 +
{Util => util}/xml_renderer.hpp | 36 +-
509 files changed, 52877 insertions(+), 7892 deletions(-)
diff --git a/.gitignore b/.gitignore
index b905eea..6ed5d2a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,8 +36,8 @@ Thumbs.db
# build related files #
#######################
/build/
-/Util/finger_print.cpp
-/Util/git_sha.cpp
+/util/fingerprint_impl.hpp
+/util/git_sha.cpp
/cmake/postinst
# Eclipse related files #
@@ -53,25 +53,8 @@ Thumbs.db
stxxl.log
stxxl.errlog
-# compiled protobuffers #
-#########################
-/DataStructures/pbf-proto/*.pb.h
-/DataStructures/pbf-proto/*.pb.cc
-
-# External Libs #
-#################
-/lib/
-/win/lib
-
-# Visual Studio Temp + build Files #
+# Compiled Binary Files #
####################################
-/win/*.user
-/win/*.ncb
-/win/*.suo
-/win/Debug/
-/win/Release/
-/win/bin/
-/win/bin-debug/
/osrm-extract
/osrm-io-benchmark
/osrm-components
diff --git a/.travis.yml b/.travis.yml
index 643e00d..ed023e4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,6 +10,7 @@ install:
- sudo apt-get -q install protobuf-compiler libprotoc-dev libprotobuf7 libprotobuf-dev libbz2-dev libstxxl-dev libstxxl1 libxml2-dev libzip-dev lua5.1 liblua5.1-0-dev rubygems libtbb-dev
- sudo apt-get -q install g++-4.8
- sudo apt-get install libboost1.54-all-dev
+ - sudo apt-get install libgdal-dev
# luabind
- curl https://gist.githubusercontent.com/DennisOSRM/f2eb7b948e6fe1ae319e/raw/install-luabind.sh | sudo bash
# osmosis
@@ -24,10 +25,11 @@ before_script:
- bundle install
- mkdir build
- cd build
- - cmake .. $CMAKEOPTIONS
+ - cmake .. $CMAKEOPTIONS -DBUILD_TOOLS=1
script:
- - make -j 2
- - make -j 2 tests
+ - make
+ - make tests
+ - make benchmarks
- ./datastructure-tests
- cd ..
- cucumber -p verify
@@ -44,7 +46,9 @@ cache:
env:
- CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-4.8" OSRM_PORT=5000 OSRM_TIMEOUT=60
- CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=g++-4.8" OSRM_PORT=5010 OSRM_TIMEOUT=60
+ - CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DCMAKE_CXX_COMPILER=g++-4.8" OSRM_PORT=5020 OSRM_TIMEOUT=60
notifications:
+ slack: mapbox:4A6euphDwfxAQnhLurXbu6A1
irc:
channels:
- irc.oftc.net#osrm
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b6a40f9..503171a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,17 +1,17 @@
cmake_minimum_required(VERSION 2.8.8)
-if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR AND NOT MSVC_IDE)
+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)
+project(OSRM C CXX)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
include(CheckCXXCompilerFlag)
include(FindPackageHandleStandardArgs)
-list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(GetGitRevisionDescription)
git_describe(GIT_DESCRIPTION)
@@ -23,85 +23,89 @@ else()
message(WARNING "Building on a 32 bit system is unsupported")
endif()
-if (WIN32 AND MSVC_VERSION LESS 1800)
+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(WITH_TOOLS "Build OSRM tools" OFF)
-OPTION(BUILD_TOOLS "Build OSRM tools" OFF)
+option(ENABLE_JSON_LOGGING "Adds additional JSON debug logging to the response" OFF)
+option(WITH_TOOLS "Build OSRM tools" OFF)
+option(BUILD_TOOLS "Build OSRM tools" OFF)
-include_directories(${CMAKE_SOURCE_DIR}/Include/)
-include_directories(${CMAKE_SOURCE_DIR}/third_party/)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third_party/)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include/)
-add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/finger_print.cpp finger_print.cpp.alwaysbuild
- COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR}
+add_custom_target(FingerPrintConfigure ALL
+ ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR}
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FingerPrint-Config.cmake
- DEPENDS
- ${CMAKE_SOURCE_DIR}/Util/finger_print.cpp.in
- COMMENT "Configuring finger_print.cpp"
+ COMMENT "Configuring revision fingerprint"
VERBATIM)
-add_custom_target(FingerPrintConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/finger_print.cpp)
add_custom_target(tests DEPENDS datastructure-tests algorithm-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_SOURCE_DIR}/Util/git_sha.cpp.in
- ${CMAKE_SOURCE_DIR}/Util/git_sha.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/util/git_sha.cpp.in
+ ${CMAKE_CURRENT_SOURCE_DIR}/util/git_sha.cpp
)
file(GLOB ExtractorGlob extractor/*.cpp)
file(GLOB ImporterGlob data_structures/import_edge.cpp data_structures/external_memory_node.cpp)
add_library(IMPORT OBJECT ${ImporterGlob})
-add_library(LOGGER OBJECT Util/simple_logger.cpp)
+add_library(LOGGER OBJECT util/simple_logger.cpp)
add_library(PHANTOMNODE OBJECT data_structures/phantom_node.cpp)
-add_library(EXCEPTION OBJECT Util/osrm_exception.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:GITDESCRIPTION> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION>)
+add_executable(osrm-extract ${ExtractorSources} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
add_library(RESTRICTION OBJECT data_structures/restriction_map.cpp)
-file(GLOB PrepareGlob contractor/*.cpp data_structures/hilbert_value.cpp Util/compute_angle.cpp {RestrictionMapGlob})
+file(GLOB PrepareGlob contractor/*.cpp data_structures/hilbert_value.cpp {RestrictionMapGlob})
set(PrepareSources prepare.cpp ${PrepareGlob})
-add_executable(osrm-prepare ${PrepareSources} $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:EXCEPTION>)
+add_executable(osrm-prepare ${PrepareSources} $<TARGET_OBJECTS:ANGLE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
-file(GLOB ServerGlob Server/*.cpp)
+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 DatastructureGlob data_structures/search_engine_data.cpp data_structures/route_parameters.cpp util/bearing.cpp)
list(REMOVE_ITEM DatastructureGlob data_structures/Coordinate.cpp)
-file(GLOB CoordinateGlob data_structures/Coordinate.cpp)
+file(GLOB CoordinateGlob data_structures/coordinate*.cpp)
file(GLOB AlgorithmGlob algorithms/*.cpp)
-file(GLOB HttpGlob Server/Http/*.cpp)
-file(GLOB LibOSRMGlob Library/*.cpp)
-file(GLOB DataStructureTestsGlob UnitTests/data_structures/*.cpp data_structures/hilbert_value.cpp)
-file(GLOB AlgorithmTestsGlob UnitTests/Algorithms/*.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)
set(
OSRMSources
${LibOSRMGlob}
${DescriptorGlob}
${DatastructureGlob}
- ${CoordinateGlob}
${AlgorithmGlob}
${HttpGlob}
)
+
add_library(COORDINATE OBJECT ${CoordinateGlob})
-add_library(FINGERPRINT OBJECT Util/finger_print.cpp)
-add_library(GITDESCRIPTION OBJECT Util/git_sha.cpp)
-add_library(OSRM ${OSRMSources} $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION>)
+add_library(GITDESCRIPTION OBJECT util/git_sha.cpp)
+add_library(OSRM ${OSRMSources} $<TARGET_OBJECTS:ANGLE> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
+
+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:GITDESCRIPTION> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION>)
+add_executable(osrm-datastore datastore.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
# Unit tests
-add_executable(datastructure-tests EXCLUDE_FROM_ALL UnitTests/datastructure_tests.cpp ${DataStructureTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION>)
-add_executable(algorithm-tests EXCLUDE_FROM_ALL UnitTests/algorithm_tests.cpp ${AlgorithmTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION>)
+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>)
+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>)
# Benchmarks
-add_executable(rtree-bench EXCLUDE_FROM_ALL benchmarks/static_rtree.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION>)
+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>)
# Check the release mode
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
@@ -109,7 +113,7 @@ if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
endif()
if(CMAKE_BUILD_TYPE MATCHES Debug)
message(STATUS "Configuring OSRM in debug mode")
- if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+ if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
message(STATUS "adding profiling flags")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline")
set(CMAKE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline")
@@ -119,46 +123,54 @@ if(CMAKE_BUILD_TYPE MATCHES Release)
message(STATUS "Configuring OSRM in release mode")
# Check if LTO is available
set(LTO_FLAGS "")
- CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG)
- if (HAS_LTO_FLAG)
- set(LTO_FLAGS "${LTO_FLAGS} -flto")
+ check_cxx_compiler_flag("-flto" LTO_AVAILABLE)
+ if(LTO_AVAILABLE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
+ set(CHECK_LTO_SRC "int main(){return 0;}")
+ check_cxx_source_compiles("${CHECK_LTO_SRC}" LTO_WORKS)
+ if(LTO_WORKS)
+ message(STATUS "LTO working")
+ else()
+ message(STATUS "LTO broken")
+ set(CMAKE_CXX_FLAGS "${OLD_CXX_FLAGS}")
+ endif()
# Since gcc 4.9 the LTO format is non-standart ('slim'), so we need to use the build-in tools
- if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND
+ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND
NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0" AND NOT MINGW)
message(STATUS "Using gcc specific binutils for LTO.")
set(CMAKE_AR "/usr/bin/gcc-ar")
set(CMAKE_RANLIB "/usr/bin/gcc-ranlib")
endif()
- endif (HAS_LTO_FLAG)
+ endif()
endif()
-if (NOT WIN32)
-add_definitions(-DBOOST_TEST_DYN_LINK)
+if(NOT WIN32)
+ add_definitions(-DBOOST_TEST_DYN_LINK)
endif()
# Configuring compilers
-if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
# using Clang
# -Weverything -Wno-c++98-compat -Wno-shadow -Wno-exit-time-destructors
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wunreachable-code -pedantic -fPIC")
-elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
set(COLOR_FLAG "-fdiagnostics-color=auto")
- CHECK_CXX_COMPILER_FLAG("-fdiagnostics-color=auto" HAS_COLOR_FLAG)
+ check_cxx_compiler_flag("-fdiagnostics-color=auto" HAS_COLOR_FLAG)
if(NOT HAS_COLOR_FLAG)
set(COLOR_FLAG "")
endif()
# using GCC
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -fPIC ${COLOR_FLAG}")
- if (WIN32) # using mingw
+ 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)
+ set(OPTIONAL_SOCKET_LIBS ws2_32 wsock32)
endif()
-elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
+elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel")
# using Intel C++
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-intel -wd10237 -Wall -ipo -fPIC")
-elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
# using Visual Studio C++
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} date_time chrono zlib)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
@@ -171,8 +183,8 @@ elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
endif()
# Activate C++11
-if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
- ADD_DEFINITIONS(-std=c++11)
+if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ")
endif()
# Configuring other platform dependencies
@@ -242,7 +254,7 @@ include_directories(${LUABIND_INCLUDE_DIR})
target_link_libraries(osrm-extract ${LUABIND_LIBRARY})
target_link_libraries(osrm-prepare ${LUABIND_LIBRARY})
-if( LUAJIT_FOUND )
+if(LUAJIT_FOUND)
target_link_libraries(osrm-extract ${LUAJIT_LIBRARIES})
target_link_libraries(osrm-prepare ${LUAJIT_LIBRARIES})
else()
@@ -255,18 +267,20 @@ find_package(EXPAT REQUIRED)
include_directories(${EXPAT_INCLUDE_DIRS})
target_link_libraries(osrm-extract ${EXPAT_LIBRARIES})
-find_package( STXXL REQUIRED )
+find_package(STXXL REQUIRED)
include_directories(${STXXL_INCLUDE_DIR})
target_link_libraries(OSRM ${STXXL_LIBRARY})
target_link_libraries(osrm-extract ${STXXL_LIBRARY})
target_link_libraries(osrm-prepare ${STXXL_LIBRARY})
-if(MINGW)
- # STXXL needs OpenMP library
- target_link_libraries(osrm-extract gomp)
+set(OpenMP_FIND_QUIETLY ON)
+find_package(OpenMP)
+if(OPENMP_FOUND)
+ message(STATUS "OpenMP support found. Linking just in case for stxxl")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
endif()
-find_package( OSMPBF REQUIRED )
+find_package(OSMPBF REQUIRED)
include_directories(${OSMPBF_INCLUDE_DIR})
target_link_libraries(osrm-extract ${OSMPBF_LIBRARY})
target_link_libraries(osrm-prepare ${OSMPBF_LIBRARY})
@@ -285,11 +299,16 @@ include_directories(${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(WITH_TOOLS OR BUILD_TOOLS)
message(STATUS "Activating OSRM internal tools")
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>)
+ 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>)
target_link_libraries(osrm-components ${TBB_LIBRARIES})
include_directories(${GDAL_INCLUDE_DIR})
target_link_libraries(
@@ -299,7 +318,7 @@ if(WITH_TOOLS OR BUILD_TOOLS)
else()
message(FATAL_ERROR "libgdal and/or development headers not found")
endif()
- add_executable(osrm-cli tools/simpleclient.cpp $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER>)
+ 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:GITDESCRIPTION> $<TARGET_OBJECTS:LOGGER>)
@@ -309,10 +328,12 @@ if(WITH_TOOLS OR BUILD_TOOLS)
if(UNIX AND NOT APPLE)
target_link_libraries(osrm-unlock-all rt)
endif()
- add_executable(osrm-check-hsgr tools/check-hsgr.cpp $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER>)
+ add_executable(osrm-check-hsgr tools/check-hsgr.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER>)
target_link_libraries(osrm-check-hsgr ${Boost_LIBRARIES})
add_executable(osrm-springclean tools/springclean.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:EXCEPTION>)
target_link_libraries(osrm-springclean ${Boost_LIBRARIES})
+ add_executable(osrm-graph-compare tools/graph_compare.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
+ target_link_libraries(osrm-graph-compare ${Boost_LIBRARIES} ${TBB_LIBRARIES})
install(TARGETS osrm-cli DESTINATION bin)
install(TARGETS osrm-io-benchmark DESTINATION bin)
@@ -321,7 +342,8 @@ if(WITH_TOOLS OR BUILD_TOOLS)
install(TARGETS osrm-springclean DESTINATION bin)
endif()
-file(GLOB InstallGlob Include/osrm/*.h Library/OSRM.h)
+file(GLOB InstallGlob include/osrm/*.hpp library/osrm.hpp)
+file(GLOB VariantGlob third_party/variant/*.hpp)
# 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
@@ -332,6 +354,7 @@ 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)
+install(FILES ${VariantGlob} DESTINATION include/variant)
install(TARGETS osrm-extract DESTINATION bin)
install(TARGETS osrm-prepare DESTINATION bin)
install(TARGETS osrm-datastore DESTINATION bin)
@@ -340,13 +363,13 @@ 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})
+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 ()
+endforeach()
-configure_file(${CMAKE_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION lib/pkgconfig)
if(BUILD_DEBIAN_PACKAGE)
diff --git a/Gemfile b/Gemfile
index 114808e..31d044b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -4,4 +4,4 @@ gem "cucumber"
gem "rake"
gem "osmlib-base"
gem "sys-proctable"
-gem "rspec-expectations"
\ No newline at end of file
+gem "rspec-expectations"
diff --git a/Include/osrm/Coordinate.h b/Include/osrm/Coordinate.h
deleted file mode 100644
index baac61f..0000000
--- a/Include/osrm/Coordinate.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
-
-Copyright (c) 2013, 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 FIXED_POINT_COORDINATE_H_
-#define FIXED_POINT_COORDINATE_H_
-
-#include <iosfwd> //for std::ostream
-#include <string>
-#include <type_traits>
-
-namespace
-{
-constexpr float COORDINATE_PRECISION = 1000000.f;
-}
-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");
- }
-
- void Reset();
- bool isSet() const;
- bool is_valid() const;
- bool operator==(const FixedPointCoordinate &other) const;
-
- static double
- ApproximateDistance(const int lat1, const int lon1, const int lat2, const int lon2);
-
- static double ApproximateDistance(const FixedPointCoordinate &first_coordinate,
- const FixedPointCoordinate &second_coordinate);
-
- static float ApproximateEuclideanDistance(const FixedPointCoordinate &first_coordinate,
- const FixedPointCoordinate &second_coordinate);
-
- static float
- ApproximateEuclideanDistance(const int lat1, const int lon1, const int lat2, const int lon2);
-
- static float ApproximateSquaredEuclideanDistance(const FixedPointCoordinate &first_coordinate,
- const FixedPointCoordinate &second_coordinate);
-
- static void convertInternalLatLonToString(const int value, std::string &output);
-
- static void convertInternalCoordinateToString(const FixedPointCoordinate &coordinate,
- std::string &output);
-
- static void convertInternalReversedCoordinateToString(const FixedPointCoordinate &coordinate,
- std::string &output);
-
- static float ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
- const FixedPointCoordinate &segment_target,
- const FixedPointCoordinate &query_location);
-
- static float ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
- const FixedPointCoordinate &segment_target,
- const FixedPointCoordinate &query_location,
- FixedPointCoordinate &nearest_location,
- float &ratio);
-
- static int
- OrderedPerpendicularDistanceApproximation(const FixedPointCoordinate &segment_source,
- const FixedPointCoordinate &segment_target,
- const FixedPointCoordinate &query_location);
-
- static float GetBearing(const FixedPointCoordinate &A, const FixedPointCoordinate &B);
-
- float GetBearing(const FixedPointCoordinate &other) const;
-
- void Output(std::ostream &out) const;
-
- static float DegreeToRadian(const float degree);
- static float RadianToDegree(const float radian);
-};
-
-inline std::ostream &operator<<(std::ostream &out_stream, FixedPointCoordinate const &coordinate)
-{
- coordinate.Output(out_stream);
- return out_stream;
-}
-
-#endif /* FIXED_POINT_COORDINATE_H_ */
diff --git a/Include/osrm/Reply.h b/Include/osrm/Reply.h
deleted file mode 100644
index a2ee1f4..0000000
--- a/Include/osrm/Reply.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-
-Copyright (c) 2013, 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 REPLY_H
-#define REPLY_H
-
-#include "Header.h"
-
-#include <boost/asio.hpp>
-
-#include <vector>
-
-namespace http
-{
-
-const char okHTML[] = "";
-const char badRequestHTML[] = "{\"status\": 400,\"status_message\":\"Bad Request\"}";
-const char internalServerErrorHTML[] =
- "{\"status\": 500,\"status_message\":\"Internal Server Error\"}";
-const char seperators[] = {':', ' '};
-const char crlf[] = {'\r', '\n'};
-const std::string okString = "HTTP/1.0 200 OK\r\n";
-const std::string badRequestString = "HTTP/1.0 400 Bad Request\r\n";
-const std::string internalServerErrorString = "HTTP/1.0 500 Internal Server Error\r\n";
-
-class Reply
-{
- public:
- enum status_type
- { ok = 200,
- badRequest = 400,
- internalServerError = 500 } status;
-
- std::vector<Header> headers;
- std::vector<boost::asio::const_buffer> ToBuffers();
- std::vector<boost::asio::const_buffer> HeaderstoBuffers();
- std::vector<char> content;
- static Reply StockReply(status_type status);
- void SetSize(const unsigned size);
- void SetUncompressedSize();
-
- Reply();
-
- private:
- std::string ToString(Reply::status_type status);
- boost::asio::const_buffer ToBuffer(Reply::status_type status);
-};
-}
-
-#endif // REPLY_H
diff --git a/LICENCE.TXT b/LICENCE.TXT
index 28fe97b..c77e5cd 100644
--- a/LICENCE.TXT
+++ b/LICENCE.TXT
@@ -1,4 +1,4 @@
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/Server/APIGrammar.h b/Server/APIGrammar.h
deleted file mode 100644
index 83a5cd0..0000000
--- a/Server/APIGrammar.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-
-Copyright (c) 2013, 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 APIGRAMMAR_H_
-#define APIGRAMMAR_H_
-
-#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) >> -(uturns);
- query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | u | cmp | language | instruction | geometry | alt_route | old_API | num_results) ) ;
-
- 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)];
- hint = (-qi::lit('&')) >> qi::lit("hint") >> '=' >> stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
- 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)];
-
- 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") ));
- }
-
- qi::rule<Iterator> api_call, query;
- qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location, hint,
- stringwithDot, stringwithPercent, language, instruction, geometry,
- cmp, alt_route, u, uturns, old_API, num_results;
-
- HandlerT * handler;
-};
-
-#endif /* APIGRAMMAR_H_ */
diff --git a/Server/RequestHandler.cpp b/Server/RequestHandler.cpp
deleted file mode 100644
index b1178ba..0000000
--- a/Server/RequestHandler.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
-
-Copyright (c) 2013, 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 "RequestHandler.h"
-
-#include "APIGrammar.h"
-#include "Http/Request.h"
-
-#include "../data_structures/json_container.hpp"
-#include "../Library/OSRM.h"
-#include "../Util/json_renderer.hpp"
-#include "../Util/simple_logger.hpp"
-#include "../Util/string_util.hpp"
-#include "../typedefs.h"
-
-#include <osrm/Reply.h>
-#include <osrm/RouteParameters.h>
-
-#include <ctime>
-
-#include <algorithm>
-#include <iostream>
-
-RequestHandler::RequestHandler() : routing_machine(nullptr) {}
-
-void RequestHandler::handle_request(const http::Request &req, http::Reply &reply)
-{
- // parse command
- try
- {
- std::string request;
- URIDecode(req.uri, request);
-
- // 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") <<
- // " " << req.endpoint.to_string() << " " <<
- // req.referrer << ( 0 == req.referrer.length() ? "- " :" ") <<
- // req.agent << ( 0 == req.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 << " "
- << req.endpoint.to_string() << " " << req.referrer
- << (0 == req.referrer.length() ? "- " : " ") << req.agent
- << (0 == req.agent.length() ? "- " : " ") << request;
-
- RouteParameters route_parameters;
- APIGrammarParser api_parser(&route_parameters);
-
- auto iter = request.begin();
- const bool result = boost::spirit::qi::parse(iter, request.end(), api_parser);
-
- // check if the was an error with the request
- if (!result || (iter != request.end()))
- {
- reply = http::Reply::StockReply(http::Reply::badRequest);
- reply.content.clear();
- const auto position = std::distance(request.begin(), iter);
- JSON::Object json_result;
- json_result.values["status"] = 400;
- std::string message = "Query string malformed close to position ";
- message += cast::integral_to_string(position);
- json_result.values["status_message"] = message;
- JSON::render(reply.content, json_result);
- return;
- }
-
- // 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 + "(");
- reply.content.insert(reply.content.end(), json_p.begin(), json_p.end());
- }
- routing_machine->RunQuery(route_parameters, reply);
- if (!route_parameters.jsonp_parameter.empty())
- { // append brace to jsonp response
- reply.content.push_back(')');
- }
-
- // set headers
- reply.headers.emplace_back("Content-Length", cast::integral_to_string(reply.content.size()));
- if ("gpx" == route_parameters.output_format)
- { // gpx file
- reply.headers.emplace_back("Content-Type", "application/gpx+xml; charset=UTF-8");
- reply.headers.emplace_back("Content-Disposition", "attachment; filename=\"route.gpx\"");
- }
- else if (route_parameters.jsonp_parameter.empty())
- { // json file
- reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
- reply.headers.emplace_back("Content-Disposition", "inline; filename=\"response.json\"");
- }
- else
- { // jsonp
- reply.headers.emplace_back("Content-Type", "text/javascript; charset=UTF-8");
- reply.headers.emplace_back("Content-Disposition", "inline; filename=\"response.js\"");
- }
- }
- catch (const std::exception &e)
- {
- reply = http::Reply::StockReply(http::Reply::internalServerError);
- SimpleLogger().Write(logWARNING) << "[server error] code: " << e.what()
- << ", uri: " << req.uri;
- return;
- }
-}
-
-void RequestHandler::RegisterRoutingMachine(OSRM *osrm) { routing_machine = osrm; }
diff --git a/Server/RequestParser.cpp b/Server/RequestParser.cpp
deleted file mode 100644
index a599381..0000000
--- a/Server/RequestParser.cpp
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
-
-Copyright (c) 2013, 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 "RequestParser.h"
-
-#include "Http/Request.h"
-
-namespace http
-{
-
-RequestParser::RequestParser() : state_(method_start), header({"", ""}) {}
-
-void RequestParser::Reset() { state_ = method_start; }
-
-boost::tuple<boost::tribool, char *>
-RequestParser::Parse(Request &req, char *begin, char *end, http::CompressionType &compression_type)
-{
- while (begin != end)
- {
- boost::tribool result = consume(req, *begin++, compression_type);
- if (result || !result)
- {
- return boost::make_tuple(result, begin);
- }
- }
- boost::tribool result = boost::indeterminate;
- return boost::make_tuple(result, begin);
-}
-
-boost::tribool
-RequestParser::consume(Request &req, char input, http::CompressionType &compression_type)
-{
- switch (state_)
- {
- case method_start:
- if (!isChar(input) || isCTL(input) || isTSpecial(input))
- {
- return false;
- }
- state_ = method;
- return boost::indeterminate;
- case method:
- if (input == ' ')
- {
- state_ = uri;
- return boost::indeterminate;
- }
- if (!isChar(input) || isCTL(input) || isTSpecial(input))
- {
- return false;
- }
- return boost::indeterminate;
- case uri_start:
- if (isCTL(input))
- {
- return false;
- }
- state_ = uri;
- req.uri.push_back(input);
- return boost::indeterminate;
- case uri:
- if (input == ' ')
- {
- state_ = http_version_h;
- return boost::indeterminate;
- }
- if (isCTL(input))
- {
- return false;
- }
- req.uri.push_back(input);
- return boost::indeterminate;
- case http_version_h:
- if (input == 'H')
- {
- state_ = http_version_t_1;
- return boost::indeterminate;
- }
- return false;
- case http_version_t_1:
- if (input == 'T')
- {
- state_ = http_version_t_2;
- return boost::indeterminate;
- }
- return false;
- case http_version_t_2:
- if (input == 'T')
- {
- state_ = http_version_p;
- return boost::indeterminate;
- }
- return false;
- case http_version_p:
- if (input == 'P')
- {
- state_ = http_version_slash;
- return boost::indeterminate;
- }
- return false;
- case http_version_slash:
- if (input == '/')
- {
- state_ = http_version_major_start;
- return boost::indeterminate;
- }
- return false;
- case http_version_major_start:
- if (isDigit(input))
- {
- state_ = http_version_major;
- return boost::indeterminate;
- }
- return false;
- case http_version_major:
- if (input == '.')
- {
- state_ = http_version_minor_start;
- return boost::indeterminate;
- }
- if (isDigit(input))
- {
- return boost::indeterminate;
- }
- return false;
- case http_version_minor_start:
- if (isDigit(input))
- {
- state_ = http_version_minor;
- return boost::indeterminate;
- }
- return false;
- case http_version_minor:
- if (input == '\r')
- {
- state_ = expecting_newline_1;
- return boost::indeterminate;
- }
- if (isDigit(input))
- {
- return boost::indeterminate;
- }
- return false;
- case expecting_newline_1:
- if (input == '\n')
- {
- state_ = header_line_start;
- return boost::indeterminate;
- }
- return false;
- case header_line_start:
- if (header.name == "Accept-Encoding")
- {
- /* giving gzip precedence over deflate */
- if (header.value.find("deflate") != std::string::npos)
- {
- compression_type = deflateRFC1951;
- }
- if (header.value.find("gzip") != std::string::npos)
- {
- compression_type = gzipRFC1952;
- }
- }
-
- if ("Referer" == header.name)
- {
- req.referrer = header.value;
- }
-
- if ("User-Agent" == header.name)
- {
- req.agent = header.value;
- }
-
- if (input == '\r')
- {
- state_ = expecting_newline_3;
- return boost::indeterminate;
- }
- if (!isChar(input) || isCTL(input) || isTSpecial(input))
- {
- return false;
- }
- state_ = header_name;
- header.Clear();
- header.name.push_back(input);
- return boost::indeterminate;
- case header_lws:
- if (input == '\r')
- {
- state_ = expecting_newline_2;
- return boost::indeterminate;
- }
- if (input == ' ' || input == '\t')
- {
- return boost::indeterminate;
- }
- if (isCTL(input))
- {
- return false;
- }
- state_ = header_value;
- return boost::indeterminate;
- case header_name:
- if (input == ':')
- {
- state_ = space_before_header_value;
- return boost::indeterminate;
- }
- if (!isChar(input) || isCTL(input) || isTSpecial(input))
- {
- return false;
- }
- header.name.push_back(input);
- return boost::indeterminate;
- case space_before_header_value:
- if (input == ' ')
- {
- state_ = header_value;
- return boost::indeterminate;
- }
- return false;
- case header_value:
- if (input == '\r')
- {
- state_ = expecting_newline_2;
- return boost::indeterminate;
- }
- if (isCTL(input))
- {
- return false;
- }
- header.value.push_back(input);
- return boost::indeterminate;
- case expecting_newline_2:
- if (input == '\n')
- {
- state_ = header_line_start;
- return boost::indeterminate;
- }
- return false;
- default: // expecting_newline_3:
- return (input == '\n');
- // default:
- // return false;
- }
-}
-
-inline bool RequestParser::isChar(int character) { return character >= 0 && character <= 127; }
-
-inline bool RequestParser::isCTL(int character)
-{
- return (character >= 0 && character <= 31) || (character == 127);
-}
-
-inline bool RequestParser::isTSpecial(int character)
-{
- 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;
- }
-}
-
-inline bool RequestParser::isDigit(int character) { return character >= '0' && character <= '9'; }
-}
diff --git a/Util/TrigonometryTables.h b/Util/TrigonometryTables.h
deleted file mode 100644
index d145404..0000000
--- a/Util/TrigonometryTables.h
+++ /dev/null
@@ -1,790 +0,0 @@
-/*
-
-Copyright (c) 2013, 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 TRIGONOMETRY_TABLES_H
-#define TRIGONOMETRY_TABLES_H
-
-#include "../typedefs.h"
-#include <cmath>
-
-#include <limits>
-
-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,
-0x01e9, 0x01fd, 0x0211, 0x0226, 0x023a, 0x024e,
-0x0263, 0x0277, 0x028c, 0x02a0, 0x02b4, 0x02c9,
-0x02dd, 0x02f1, 0x0306, 0x031a, 0x032f, 0x0343,
-0x0357, 0x036c, 0x0380, 0x0394, 0x03a9, 0x03bd,
-0x03d2, 0x03e6, 0x03fa, 0x040f, 0x0423, 0x0437,
-0x044c, 0x0460, 0x0475, 0x0489, 0x049d, 0x04b2,
-0x04c6, 0x04da, 0x04ef, 0x0503, 0x0517, 0x052c,
-0x0540, 0x0555, 0x0569, 0x057d, 0x0592, 0x05a6,
-0x05ba, 0x05cf, 0x05e3, 0x05f8, 0x060c, 0x0620,
-0x0635, 0x0649, 0x065d, 0x0672, 0x0686, 0x069b,
-0x06af, 0x06c3, 0x06d8, 0x06ec, 0x0700, 0x0715,
-0x0729, 0x073d, 0x0752, 0x0766, 0x077b, 0x078f,
-0x07a3, 0x07b8, 0x07cc, 0x07e0, 0x07f5, 0x0809,
-0x081d, 0x0832, 0x0846, 0x085b, 0x086f, 0x0883,
-0x0898, 0x08ac, 0x08c0, 0x08d5, 0x08e9, 0x08fd,
-0x0912, 0x0926, 0x093b, 0x094f, 0x0963, 0x0978,
-0x098c, 0x09a0, 0x09b5, 0x09c9, 0x09dd, 0x09f2,
-0x0a06, 0x0a1a, 0x0a2f, 0x0a43, 0x0a58, 0x0a6c,
-0x0a80, 0x0a95, 0x0aa9, 0x0abd, 0x0ad2, 0x0ae6,
-0x0afa, 0x0b0f, 0x0b23, 0x0b37, 0x0b4c, 0x0b60,
-0x0b75, 0x0b89, 0x0b9d, 0x0bb2, 0x0bc6, 0x0bda,
-0x0bef, 0x0c03, 0x0c17, 0x0c2c, 0x0c40, 0x0c54,
-0x0c69, 0x0c7d, 0x0c91, 0x0ca6, 0x0cba, 0x0cce,
-0x0ce3, 0x0cf7, 0x0d0b, 0x0d20, 0x0d34, 0x0d48,
-0x0d5d, 0x0d71, 0x0d86, 0x0d9a, 0x0dae, 0x0dc3,
-0x0dd7, 0x0deb, 0x0e00, 0x0e14, 0x0e28, 0x0e3d,
-0x0e51, 0x0e65, 0x0e7a, 0x0e8e, 0x0ea2, 0x0eb7,
-0x0ecb, 0x0edf, 0x0ef4, 0x0f08, 0x0f1c, 0x0f31,
-0x0f45, 0x0f59, 0x0f6e, 0x0f82, 0x0f96, 0x0fab,
-0x0fbf, 0x0fd3, 0x0fe8, 0x0ffc, 0x1010, 0x1025,
-0x1039, 0x104d, 0x1062, 0x1076, 0x108a, 0x109e,
-0x10b3, 0x10c7, 0x10db, 0x10f0, 0x1104, 0x1118,
-0x112d, 0x1141, 0x1155, 0x116a, 0x117e, 0x1192,
-0x11a7, 0x11bb, 0x11cf, 0x11e4, 0x11f8, 0x120c,
-0x1221, 0x1235, 0x1249, 0x125d, 0x1272, 0x1286,
-0x129a, 0x12af, 0x12c3, 0x12d7, 0x12ec, 0x1300,
-0x1314, 0x1329, 0x133d, 0x1351, 0x1365, 0x137a,
-0x138e, 0x13a2, 0x13b7, 0x13cb, 0x13df, 0x13f4,
-0x1408, 0x141c, 0x1431, 0x1445, 0x1459, 0x146d,
-0x1482, 0x1496, 0x14aa, 0x14bf, 0x14d3, 0x14e7,
-0x14fb, 0x1510, 0x1524, 0x1538, 0x154d, 0x1561,
-0x1575, 0x1589, 0x159e, 0x15b2, 0x15c6, 0x15db,
-0x15ef, 0x1603, 0x1617, 0x162c, 0x1640, 0x1654,
-0x1669, 0x167d, 0x1691, 0x16a5, 0x16ba, 0x16ce,
-0x16e2, 0x16f7, 0x170b, 0x171f, 0x1733, 0x1748,
-0x175c, 0x1770, 0x1784, 0x1799, 0x17ad, 0x17c1,
-0x17d6, 0x17ea, 0x17fe, 0x1812, 0x1827, 0x183b,
-0x184f, 0x1863, 0x1878, 0x188c, 0x18a0, 0x18b4,
-0x18c9, 0x18dd, 0x18f1, 0x1905, 0x191a, 0x192e,
-0x1942, 0x1957, 0x196b, 0x197f, 0x1993, 0x19a8,
-0x19bc, 0x19d0, 0x19e4, 0x19f9, 0x1a0d, 0x1a21,
-0x1a35, 0x1a49, 0x1a5e, 0x1a72, 0x1a86, 0x1a9a,
-0x1aaf, 0x1ac3, 0x1ad7, 0x1aeb, 0x1b00, 0x1b14,
-0x1b28, 0x1b3c, 0x1b51, 0x1b65, 0x1b79, 0x1b8d,
-0x1ba2, 0x1bb6, 0x1bca, 0x1bde, 0x1bf2, 0x1c07,
-0x1c1b, 0x1c2f, 0x1c43, 0x1c58, 0x1c6c, 0x1c80,
-0x1c94, 0x1ca8, 0x1cbd, 0x1cd1, 0x1ce5, 0x1cf9,
-0x1d0e, 0x1d22, 0x1d36, 0x1d4a, 0x1d5e, 0x1d73,
-0x1d87, 0x1d9b, 0x1daf, 0x1dc3, 0x1dd8, 0x1dec,
-0x1e00, 0x1e14, 0x1e28, 0x1e3d, 0x1e51, 0x1e65,
-0x1e79, 0x1e8d, 0x1ea2, 0x1eb6, 0x1eca, 0x1ede,
-0x1ef2, 0x1f07, 0x1f1b, 0x1f2f, 0x1f43, 0x1f57,
-0x1f6c, 0x1f80, 0x1f94, 0x1fa8, 0x1fbc, 0x1fd1,
-0x1fe5, 0x1ff9, 0x200d, 0x2021, 0x2035, 0x204a,
-0x205e, 0x2072, 0x2086, 0x209a, 0x20ae, 0x20c3,
-0x20d7, 0x20eb, 0x20ff, 0x2113, 0x2127, 0x213c,
-0x2150, 0x2164, 0x2178, 0x218c, 0x21a0, 0x21b5,
-0x21c9, 0x21dd, 0x21f1, 0x2205, 0x2219, 0x222e,
-0x2242, 0x2256, 0x226a, 0x227e, 0x2292, 0x22a6,
-0x22bb, 0x22cf, 0x22e3, 0x22f7, 0x230b, 0x231f,
-0x2333, 0x2348, 0x235c, 0x2370, 0x2384, 0x2398,
-0x23ac, 0x23c0, 0x23d5, 0x23e9, 0x23fd, 0x2411,
-0x2425, 0x2439, 0x244d, 0x2461, 0x2476, 0x248a,
-0x249e, 0x24b2, 0x24c6, 0x24da, 0x24ee, 0x2502,
-0x2517, 0x252b, 0x253f, 0x2553, 0x2567, 0x257b,
-0x258f, 0x25a3, 0x25b7, 0x25cb, 0x25e0, 0x25f4,
-0x2608, 0x261c, 0x2630, 0x2644, 0x2658, 0x266c,
-0x2680, 0x2694, 0x26a9, 0x26bd, 0x26d1, 0x26e5,
-0x26f9, 0x270d, 0x2721, 0x2735, 0x2749, 0x275d,
-0x2771, 0x2785, 0x279a, 0x27ae, 0x27c2, 0x27d6,
-0x27ea, 0x27fe, 0x2812, 0x2826, 0x283a, 0x284e,
-0x2862, 0x2876, 0x288a, 0x289e, 0x28b3, 0x28c7,
-0x28db, 0x28ef, 0x2903, 0x2917, 0x292b, 0x293f,
-0x2953, 0x2967, 0x297b, 0x298f, 0x29a3, 0x29b7,
-0x29cb, 0x29df, 0x29f3, 0x2a07, 0x2a1b, 0x2a2f,
-0x2a43, 0x2a58, 0x2a6c, 0x2a80, 0x2a94, 0x2aa8,
-0x2abc, 0x2ad0, 0x2ae4, 0x2af8, 0x2b0c, 0x2b20,
-0x2b34, 0x2b48, 0x2b5c, 0x2b70, 0x2b84, 0x2b98,
-0x2bac, 0x2bc0, 0x2bd4, 0x2be8, 0x2bfc, 0x2c10,
-0x2c24, 0x2c38, 0x2c4c, 0x2c60, 0x2c74, 0x2c88,
-0x2c9c, 0x2cb0, 0x2cc4, 0x2cd8, 0x2cec, 0x2d00,
-0x2d14, 0x2d28, 0x2d3c, 0x2d50, 0x2d64, 0x2d78,
-0x2d8c, 0x2da0, 0x2db4, 0x2dc8, 0x2ddc, 0x2df0,
-0x2e04, 0x2e18, 0x2e2c, 0x2e40, 0x2e54, 0x2e68,
-0x2e7c, 0x2e90, 0x2ea3, 0x2eb7, 0x2ecb, 0x2edf,
-0x2ef3, 0x2f07, 0x2f1b, 0x2f2f, 0x2f43, 0x2f57,
-0x2f6b, 0x2f7f, 0x2f93, 0x2fa7, 0x2fbb, 0x2fcf,
-0x2fe3, 0x2ff7, 0x300b, 0x301e, 0x3032, 0x3046,
-0x305a, 0x306e, 0x3082, 0x3096, 0x30aa, 0x30be,
-0x30d2, 0x30e6, 0x30fa, 0x310e, 0x3122, 0x3135,
-0x3149, 0x315d, 0x3171, 0x3185, 0x3199, 0x31ad,
-0x31c1, 0x31d5, 0x31e9, 0x31fd, 0x3210, 0x3224,
-0x3238, 0x324c, 0x3260, 0x3274, 0x3288, 0x329c,
-0x32b0, 0x32c3, 0x32d7, 0x32eb, 0x32ff, 0x3313,
-0x3327, 0x333b, 0x334f, 0x3363, 0x3376, 0x338a,
-0x339e, 0x33b2, 0x33c6, 0x33da, 0x33ee, 0x3401,
-0x3415, 0x3429, 0x343d, 0x3451, 0x3465, 0x3479,
-0x348c, 0x34a0, 0x34b4, 0x34c8, 0x34dc, 0x34f0,
-0x3504, 0x3517, 0x352b, 0x353f, 0x3553, 0x3567,
-0x357b, 0x358e, 0x35a2, 0x35b6, 0x35ca, 0x35de,
-0x35f2, 0x3605, 0x3619, 0x362d, 0x3641, 0x3655,
-0x3668, 0x367c, 0x3690, 0x36a4, 0x36b8, 0x36cb,
-0x36df, 0x36f3, 0x3707, 0x371b, 0x372f, 0x3742,
-0x3756, 0x376a, 0x377e, 0x3791, 0x37a5, 0x37b9,
-0x37cd, 0x37e1, 0x37f4, 0x3808, 0x381c, 0x3830,
-0x3844, 0x3857, 0x386b, 0x387f, 0x3893, 0x38a6,
-0x38ba, 0x38ce, 0x38e2, 0x38f5, 0x3909, 0x391d,
-0x3931, 0x3944, 0x3958, 0x396c, 0x3980, 0x3993,
-0x39a7, 0x39bb, 0x39cf, 0x39e2, 0x39f6, 0x3a0a,
-0x3a1e, 0x3a31, 0x3a45, 0x3a59, 0x3a6d, 0x3a80,
-0x3a94, 0x3aa8, 0x3abb, 0x3acf, 0x3ae3, 0x3af7,
-0x3b0a, 0x3b1e, 0x3b32, 0x3b45, 0x3b59, 0x3b6d,
-0x3b81, 0x3b94, 0x3ba8, 0x3bbc, 0x3bcf, 0x3be3,
-0x3bf7, 0x3c0b, 0x3c1e, 0x3c32, 0x3c46, 0x3c59,
-0x3c6d, 0x3c81, 0x3c94, 0x3ca8, 0x3cbc, 0x3ccf,
-0x3ce3, 0x3cf7, 0x3d0a, 0x3d1e, 0x3d32, 0x3d45,
-0x3d59, 0x3d6d, 0x3d80, 0x3d94, 0x3da8, 0x3dbb,
-0x3dcf, 0x3de3, 0x3df6, 0x3e0a, 0x3e1e, 0x3e31,
-0x3e45, 0x3e59, 0x3e6c, 0x3e80, 0x3e93, 0x3ea7,
-0x3ebb, 0x3ece, 0x3ee2, 0x3ef6, 0x3f09, 0x3f1d,
-0x3f30, 0x3f44, 0x3f58, 0x3f6b, 0x3f7f, 0x3f93,
-0x3fa6, 0x3fba, 0x3fcd, 0x3fe1, 0x3ff5, 0x4008,
-0x401c, 0x402f, 0x4043, 0x4057, 0x406a, 0x407e,
-0x4091, 0x40a5, 0x40b8, 0x40cc, 0x40e0, 0x40f3,
-0x4107, 0x411a, 0x412e, 0x4142, 0x4155, 0x4169,
-0x417c, 0x4190, 0x41a3, 0x41b7, 0x41ca, 0x41de,
-0x41f2, 0x4205, 0x4219, 0x422c, 0x4240, 0x4253,
-0x4267, 0x427a, 0x428e, 0x42a1, 0x42b5, 0x42c9,
-0x42dc, 0x42f0, 0x4303, 0x4317, 0x432a, 0x433e,
-0x4351, 0x4365, 0x4378, 0x438c, 0x439f, 0x43b3,
-0x43c6, 0x43da, 0x43ed, 0x4401, 0x4414, 0x4428,
-0x443b, 0x444f, 0x4462, 0x4476, 0x4489, 0x449d,
-0x44b0, 0x44c4, 0x44d7, 0x44eb, 0x44fe, 0x4512,
-0x4525, 0x4539, 0x454c, 0x4560, 0x4573, 0x4586,
-0x459a, 0x45ad, 0x45c1, 0x45d4, 0x45e8, 0x45fb,
-0x460f, 0x4622, 0x4636, 0x4649, 0x465c, 0x4670,
-0x4683, 0x4697, 0x46aa, 0x46be, 0x46d1, 0x46e5,
-0x46f8, 0x470b, 0x471f, 0x4732, 0x4746, 0x4759,
-0x476c, 0x4780, 0x4793, 0x47a7, 0x47ba, 0x47cd,
-0x47e1, 0x47f4, 0x4808, 0x481b, 0x482e, 0x4842,
-0x4855, 0x4869, 0x487c, 0x488f, 0x48a3, 0x48b6,
-0x48ca, 0x48dd, 0x48f0, 0x4904, 0x4917, 0x492a,
-0x493e, 0x4951, 0x4965, 0x4978, 0x498b, 0x499f,
-0x49b2, 0x49c5, 0x49d9, 0x49ec, 0x49ff, 0x4a13,
-0x4a26, 0x4a39, 0x4a4d, 0x4a60, 0x4a73, 0x4a87,
-0x4a9a, 0x4aad, 0x4ac1, 0x4ad4, 0x4ae7, 0x4afb,
-0x4b0e, 0x4b21, 0x4b35, 0x4b48, 0x4b5b, 0x4b6f,
-0x4b82, 0x4b95, 0x4ba8, 0x4bbc, 0x4bcf, 0x4be2,
-0x4bf6, 0x4c09, 0x4c1c, 0x4c2f, 0x4c43, 0x4c56,
-0x4c69, 0x4c7d, 0x4c90, 0x4ca3, 0x4cb6, 0x4cca,
-0x4cdd, 0x4cf0, 0x4d03, 0x4d17, 0x4d2a, 0x4d3d,
-0x4d50, 0x4d64, 0x4d77, 0x4d8a, 0x4d9d, 0x4db1,
-0x4dc4, 0x4dd7, 0x4dea, 0x4dfe, 0x4e11, 0x4e24,
-0x4e37, 0x4e4b, 0x4e5e, 0x4e71, 0x4e84, 0x4e97,
-0x4eab, 0x4ebe, 0x4ed1, 0x4ee4, 0x4ef7, 0x4f0b,
-0x4f1e, 0x4f31, 0x4f44, 0x4f57, 0x4f6b, 0x4f7e,
-0x4f91, 0x4fa4, 0x4fb7, 0x4fcb, 0x4fde, 0x4ff1,
-0x5004, 0x5017, 0x502a, 0x503e, 0x5051, 0x5064,
-0x5077, 0x508a, 0x509d, 0x50b1, 0x50c4, 0x50d7,
-0x50ea, 0x50fd, 0x5110, 0x5123, 0x5137, 0x514a,
-0x515d, 0x5170, 0x5183, 0x5196, 0x51a9, 0x51bc,
-0x51d0, 0x51e3, 0x51f6, 0x5209, 0x521c, 0x522f,
-0x5242, 0x5255, 0x5268, 0x527c, 0x528f, 0x52a2,
-0x52b5, 0x52c8, 0x52db, 0x52ee, 0x5301, 0x5314,
-0x5327, 0x533a, 0x534e, 0x5361, 0x5374, 0x5387,
-0x539a, 0x53ad, 0x53c0, 0x53d3, 0x53e6, 0x53f9,
-0x540c, 0x541f, 0x5432, 0x5445, 0x5458, 0x546b,
-0x547e, 0x5491, 0x54a5, 0x54b8, 0x54cb, 0x54de,
-0x54f1, 0x5504, 0x5517, 0x552a, 0x553d, 0x5550,
-0x5563, 0x5576, 0x5589, 0x559c, 0x55af, 0x55c2,
-0x55d5, 0x55e8, 0x55fb, 0x560e, 0x5621, 0x5634,
-0x5647, 0x565a, 0x566d, 0x5680, 0x5693, 0x56a6,
-0x56b9, 0x56cb, 0x56de, 0x56f1, 0x5704, 0x5717,
-0x572a, 0x573d, 0x5750, 0x5763, 0x5776, 0x5789,
-0x579c, 0x57af, 0x57c2, 0x57d5, 0x57e8, 0x57fb,
-0x580e, 0x5820, 0x5833, 0x5846, 0x5859, 0x586c,
-0x587f, 0x5892, 0x58a5, 0x58b8, 0x58cb, 0x58de,
-0x58f0, 0x5903, 0x5916, 0x5929, 0x593c, 0x594f,
-0x5962, 0x5975, 0x5988, 0x599a, 0x59ad, 0x59c0,
-0x59d3, 0x59e6, 0x59f9, 0x5a0c, 0x5a1f, 0x5a31,
-0x5a44, 0x5a57, 0x5a6a, 0x5a7d, 0x5a90, 0x5aa2,
-0x5ab5, 0x5ac8, 0x5adb, 0x5aee, 0x5b01, 0x5b13,
-0x5b26, 0x5b39, 0x5b4c, 0x5b5f, 0x5b72, 0x5b84,
-0x5b97, 0x5baa, 0x5bbd, 0x5bd0, 0x5be2, 0x5bf5,
-0x5c08, 0x5c1b, 0x5c2e, 0x5c40, 0x5c53, 0x5c66,
-0x5c79, 0x5c8c, 0x5c9e, 0x5cb1, 0x5cc4, 0x5cd7,
-0x5ce9, 0x5cfc, 0x5d0f, 0x5d22, 0x5d34, 0x5d47,
-0x5d5a, 0x5d6d, 0x5d7f, 0x5d92, 0x5da5, 0x5db8,
-0x5dca, 0x5ddd, 0x5df0, 0x5e03, 0x5e15, 0x5e28,
-0x5e3b, 0x5e4d, 0x5e60, 0x5e73, 0x5e86, 0x5e98,
-0x5eab, 0x5ebe, 0x5ed0, 0x5ee3, 0x5ef6, 0x5f09,
-0x5f1b, 0x5f2e, 0x5f41, 0x5f53, 0x5f66, 0x5f79,
-0x5f8b, 0x5f9e, 0x5fb1, 0x5fc3, 0x5fd6, 0x5fe9,
-0x5ffb, 0x600e, 0x6021, 0x6033, 0x6046, 0x6059,
-0x606b, 0x607e, 0x6091, 0x60a3, 0x60b6, 0x60c8,
-0x60db, 0x60ee, 0x6100, 0x6113, 0x6126, 0x6138,
-0x614b, 0x615d, 0x6170, 0x6183, 0x6195, 0x61a8,
-0x61ba, 0x61cd, 0x61e0, 0x61f2, 0x6205, 0x6217,
-0x622a, 0x623d, 0x624f, 0x6262, 0x6274, 0x6287,
-0x6299, 0x62ac, 0x62bf, 0x62d1, 0x62e4, 0x62f6,
-0x6309, 0x631b, 0x632e, 0x6340, 0x6353, 0x6366,
-0x6378, 0x638b, 0x639d, 0x63b0, 0x63c2, 0x63d5,
-0x63e7, 0x63fa, 0x640c, 0x641f, 0x6431, 0x6444,
-0x6456, 0x6469, 0x647b, 0x648e, 0x64a0, 0x64b3,
-0x64c5, 0x64d8, 0x64ea, 0x64fd, 0x650f, 0x6522,
-0x6534, 0x6547, 0x6559, 0x656c, 0x657e, 0x6591,
-0x65a3, 0x65b5, 0x65c8, 0x65da, 0x65ed, 0x65ff,
-0x6612, 0x6624, 0x6637, 0x6649, 0x665b, 0x666e,
-0x6680, 0x6693, 0x66a5, 0x66b8, 0x66ca, 0x66dc,
-0x66ef, 0x6701, 0x6714, 0x6726, 0x6738, 0x674b,
-0x675d, 0x6770, 0x6782, 0x6794, 0x67a7, 0x67b9,
-0x67cc, 0x67de, 0x67f0, 0x6803, 0x6815, 0x6827,
-0x683a, 0x684c, 0x685e, 0x6871, 0x6883, 0x6896,
-0x68a8, 0x68ba, 0x68cd, 0x68df, 0x68f1, 0x6904,
-0x6916, 0x6928, 0x693b, 0x694d, 0x695f, 0x6972,
-0x6984, 0x6996, 0x69a8, 0x69bb, 0x69cd, 0x69df,
-0x69f2, 0x6a04, 0x6a16, 0x6a29, 0x6a3b, 0x6a4d,
-0x6a5f, 0x6a72, 0x6a84, 0x6a96, 0x6aa9, 0x6abb,
-0x6acd, 0x6adf, 0x6af2, 0x6b04, 0x6b16, 0x6b28,
-0x6b3b, 0x6b4d, 0x6b5f, 0x6b71, 0x6b84, 0x6b96,
-0x6ba8, 0x6bba, 0x6bcd, 0x6bdf, 0x6bf1, 0x6c03,
-0x6c15, 0x6c28, 0x6c3a, 0x6c4c, 0x6c5e, 0x6c70,
-0x6c83, 0x6c95, 0x6ca7, 0x6cb9, 0x6ccb, 0x6cde,
-0x6cf0, 0x6d02, 0x6d14, 0x6d26, 0x6d39, 0x6d4b,
-0x6d5d, 0x6d6f, 0x6d81, 0x6d93, 0x6da6, 0x6db8,
-0x6dca, 0x6ddc, 0x6dee, 0x6e00, 0x6e12, 0x6e25,
-0x6e37, 0x6e49, 0x6e5b, 0x6e6d, 0x6e7f, 0x6e91,
-0x6ea3, 0x6eb6, 0x6ec8, 0x6eda, 0x6eec, 0x6efe,
-0x6f10, 0x6f22, 0x6f34, 0x6f46, 0x6f58, 0x6f6b,
-0x6f7d, 0x6f8f, 0x6fa1, 0x6fb3, 0x6fc5, 0x6fd7,
-0x6fe9, 0x6ffb, 0x700d, 0x701f, 0x7031, 0x7043,
-0x7055, 0x7068, 0x707a, 0x708c, 0x709e, 0x70b0,
-0x70c2, 0x70d4, 0x70e6, 0x70f8, 0x710a, 0x711c,
-0x712e, 0x7140, 0x7152, 0x7164, 0x7176, 0x7188,
-0x719a, 0x71ac, 0x71be, 0x71d0, 0x71e2, 0x71f4,
-0x7206, 0x7218, 0x722a, 0x723c, 0x724e, 0x7260,
-0x7272, 0x7284, 0x7296, 0x72a8, 0x72ba, 0x72cc,
-0x72dd, 0x72ef, 0x7301, 0x7313, 0x7325, 0x7337,
-0x7349, 0x735b, 0x736d, 0x737f, 0x7391, 0x73a3,
-0x73b5, 0x73c7, 0x73d8, 0x73ea, 0x73fc, 0x740e,
-0x7420, 0x7432, 0x7444, 0x7456, 0x7468, 0x747a,
-0x748b, 0x749d, 0x74af, 0x74c1, 0x74d3, 0x74e5,
-0x74f7, 0x7509, 0x751a, 0x752c, 0x753e, 0x7550,
-0x7562, 0x7574, 0x7585, 0x7597, 0x75a9, 0x75bb,
-0x75cd, 0x75df, 0x75f0, 0x7602, 0x7614, 0x7626,
-0x7638, 0x764a, 0x765b, 0x766d, 0x767f, 0x7691,
-0x76a3, 0x76b4, 0x76c6, 0x76d8, 0x76ea, 0x76fb,
-0x770d, 0x771f, 0x7731, 0x7743, 0x7754, 0x7766,
-0x7778, 0x778a, 0x779b, 0x77ad, 0x77bf, 0x77d1,
-0x77e2, 0x77f4, 0x7806, 0x7818, 0x7829, 0x783b,
-0x784d, 0x785e, 0x7870, 0x7882, 0x7894, 0x78a5,
-0x78b7, 0x78c9, 0x78da, 0x78ec, 0x78fe, 0x7910,
-0x7921, 0x7933, 0x7945, 0x7956, 0x7968, 0x797a,
-0x798b, 0x799d, 0x79af, 0x79c0, 0x79d2, 0x79e4,
-0x79f5, 0x7a07, 0x7a19, 0x7a2a, 0x7a3c, 0x7a4e,
-0x7a5f, 0x7a71, 0x7a82, 0x7a94, 0x7aa6, 0x7ab7,
-0x7ac9, 0x7adb, 0x7aec, 0x7afe, 0x7b0f, 0x7b21,
-0x7b33, 0x7b44, 0x7b56, 0x7b67, 0x7b79, 0x7b8b,
-0x7b9c, 0x7bae, 0x7bbf, 0x7bd1, 0x7be2, 0x7bf4,
-0x7c06, 0x7c17, 0x7c29, 0x7c3a, 0x7c4c, 0x7c5d,
-0x7c6f, 0x7c81, 0x7c92, 0x7ca4, 0x7cb5, 0x7cc7,
-0x7cd8, 0x7cea, 0x7cfb, 0x7d0d, 0x7d1e, 0x7d30,
-0x7d41, 0x7d53, 0x7d64, 0x7d76, 0x7d87, 0x7d99,
-0x7daa, 0x7dbc, 0x7dcd, 0x7ddf, 0x7df0, 0x7e02,
-0x7e13, 0x7e25, 0x7e36, 0x7e48, 0x7e59, 0x7e6b,
-0x7e7c, 0x7e8e, 0x7e9f, 0x7eb0, 0x7ec2, 0x7ed3,
-0x7ee5, 0x7ef6, 0x7f08, 0x7f19, 0x7f2b, 0x7f3c,
-0x7f4d, 0x7f5f, 0x7f70, 0x7f82, 0x7f93, 0x7fa4,
-0x7fb6, 0x7fc7, 0x7fd9, 0x7fea, 0x7ffb, 0x800d,
-0x801e, 0x8030, 0x8041, 0x8052, 0x8064, 0x8075,
-0x8086, 0x8098, 0x80a9, 0x80bb, 0x80cc, 0x80dd,
-0x80ef, 0x8100, 0x8111, 0x8123, 0x8134, 0x8145,
-0x8157, 0x8168, 0x8179, 0x818b, 0x819c, 0x81ad,
-0x81bf, 0x81d0, 0x81e1, 0x81f3, 0x8204, 0x8215,
-0x8226, 0x8238, 0x8249, 0x825a, 0x826c, 0x827d,
-0x828e, 0x829f, 0x82b1, 0x82c2, 0x82d3, 0x82e5,
-0x82f6, 0x8307, 0x8318, 0x832a, 0x833b, 0x834c,
-0x835d, 0x836f, 0x8380, 0x8391, 0x83a2, 0x83b3,
-0x83c5, 0x83d6, 0x83e7, 0x83f8, 0x840a, 0x841b,
-0x842c, 0x843d, 0x844e, 0x8460, 0x8471, 0x8482,
-0x8493, 0x84a4, 0x84b6, 0x84c7, 0x84d8, 0x84e9,
-0x84fa, 0x850b, 0x851d, 0x852e, 0x853f, 0x8550,
-0x8561, 0x8572, 0x8584, 0x8595, 0x85a6, 0x85b7,
-0x85c8, 0x85d9, 0x85ea, 0x85fb, 0x860d, 0x861e,
-0x862f, 0x8640, 0x8651, 0x8662, 0x8673, 0x8684,
-0x8695, 0x86a7, 0x86b8, 0x86c9, 0x86da, 0x86eb,
-0x86fc, 0x870d, 0x871e, 0x872f, 0x8740, 0x8751,
-0x8762, 0x8773, 0x8784, 0x8796, 0x87a7, 0x87b8,
-0x87c9, 0x87da, 0x87eb, 0x87fc, 0x880d, 0x881e,
-0x882f, 0x8840, 0x8851, 0x8862, 0x8873, 0x8884,
-0x8895, 0x88a6, 0x88b7, 0x88c8, 0x88d9, 0x88ea,
-0x88fb, 0x890c, 0x891d, 0x892e, 0x893f, 0x8950,
-0x8961, 0x8972, 0x8983, 0x8994, 0x89a5, 0x89b6,
-0x89c6, 0x89d7, 0x89e8, 0x89f9, 0x8a0a, 0x8a1b,
-0x8a2c, 0x8a3d, 0x8a4e, 0x8a5f, 0x8a70, 0x8a81,
-0x8a92, 0x8aa3, 0x8ab3, 0x8ac4, 0x8ad5, 0x8ae6,
-0x8af7, 0x8b08, 0x8b19, 0x8b2a, 0x8b3b, 0x8b4b,
-0x8b5c, 0x8b6d, 0x8b7e, 0x8b8f, 0x8ba0, 0x8bb1,
-0x8bc1, 0x8bd2, 0x8be3, 0x8bf4, 0x8c05, 0x8c16,
-0x8c27, 0x8c37, 0x8c48, 0x8c59, 0x8c6a, 0x8c7b,
-0x8c8c, 0x8c9c, 0x8cad, 0x8cbe, 0x8ccf, 0x8ce0,
-0x8cf0, 0x8d01, 0x8d12, 0x8d23, 0x8d34, 0x8d44,
-0x8d55, 0x8d66, 0x8d77, 0x8d87, 0x8d98, 0x8da9,
-0x8dba, 0x8dca, 0x8ddb, 0x8dec, 0x8dfd, 0x8e0d,
-0x8e1e, 0x8e2f, 0x8e40, 0x8e50, 0x8e61, 0x8e72,
-0x8e83, 0x8e93, 0x8ea4, 0x8eb5, 0x8ec5, 0x8ed6,
-0x8ee7, 0x8ef8, 0x8f08, 0x8f19, 0x8f2a, 0x8f3a,
-0x8f4b, 0x8f5c, 0x8f6c, 0x8f7d, 0x8f8e, 0x8f9e,
-0x8faf, 0x8fc0, 0x8fd0, 0x8fe1, 0x8ff2, 0x9002,
-0x9013, 0x9024, 0x9034, 0x9045, 0x9056, 0x9066,
-0x9077, 0x9088, 0x9098, 0x90a9, 0x90b9, 0x90ca,
-0x90db, 0x90eb, 0x90fc, 0x910c, 0x911d, 0x912e,
-0x913e, 0x914f, 0x915f, 0x9170, 0x9181, 0x9191,
-0x91a2, 0x91b2, 0x91c3, 0x91d3, 0x91e4, 0x91f5,
-0x9205, 0x9216, 0x9226, 0x9237, 0x9247, 0x9258,
-0x9268, 0x9279, 0x9289, 0x929a, 0x92aa, 0x92bb,
-0x92cc, 0x92dc, 0x92ed, 0x92fd, 0x930e, 0x931e,
-0x932f, 0x933f, 0x9350, 0x9360, 0x9370, 0x9381,
-0x9391, 0x93a2, 0x93b2, 0x93c3, 0x93d3, 0x93e4,
-0x93f4, 0x9405, 0x9415, 0x9426, 0x9436, 0x9447,
-0x9457, 0x9467, 0x9478, 0x9488, 0x9499, 0x94a9,
-0x94ba, 0x94ca, 0x94da, 0x94eb, 0x94fb, 0x950c,
-0x951c, 0x952c, 0x953d, 0x954d, 0x955e, 0x956e,
-0x957e, 0x958f, 0x959f, 0x95af, 0x95c0, 0x95d0,
-0x95e1, 0x95f1, 0x9601, 0x9612, 0x9622, 0x9632,
-0x9643, 0x9653, 0x9663, 0x9674, 0x9684, 0x9694,
-0x96a5, 0x96b5, 0x96c5, 0x96d6, 0x96e6, 0x96f6,
-0x9707, 0x9717, 0x9727, 0x9738, 0x9748, 0x9758,
-0x9768, 0x9779, 0x9789, 0x9799, 0x97aa, 0x97ba,
-0x97ca, 0x97da, 0x97eb, 0x97fb, 0x980b, 0x981b,
-0x982c, 0x983c, 0x984c, 0x985c, 0x986d, 0x987d,
-0x988d, 0x989d, 0x98ad, 0x98be, 0x98ce, 0x98de,
-0x98ee, 0x98ff, 0x990f, 0x991f, 0x992f, 0x993f,
-0x9950, 0x9960, 0x9970, 0x9980, 0x9990, 0x99a0,
-0x99b1, 0x99c1, 0x99d1, 0x99e1, 0x99f1, 0x9a01,
-0x9a12, 0x9a22, 0x9a32, 0x9a42, 0x9a52, 0x9a62,
-0x9a72, 0x9a83, 0x9a93, 0x9aa3, 0x9ab3, 0x9ac3,
-0x9ad3, 0x9ae3, 0x9af3, 0x9b04, 0x9b14, 0x9b24,
-0x9b34, 0x9b44, 0x9b54, 0x9b64, 0x9b74, 0x9b84,
-0x9b94, 0x9ba4, 0x9bb5, 0x9bc5, 0x9bd5, 0x9be5,
-0x9bf5, 0x9c05, 0x9c15, 0x9c25, 0x9c35, 0x9c45,
-0x9c55, 0x9c65, 0x9c75, 0x9c85, 0x9c95, 0x9ca5,
-0x9cb5, 0x9cc5, 0x9cd5, 0x9ce5, 0x9cf5, 0x9d05,
-0x9d15, 0x9d25, 0x9d35, 0x9d45, 0x9d55, 0x9d65,
-0x9d75, 0x9d85, 0x9d95, 0x9da5, 0x9db5, 0x9dc5,
-0x9dd5, 0x9de5, 0x9df5, 0x9e05, 0x9e15, 0x9e25,
-0x9e35, 0x9e45, 0x9e55, 0x9e65, 0x9e74, 0x9e84,
-0x9e94, 0x9ea4, 0x9eb4, 0x9ec4, 0x9ed4, 0x9ee4,
-0x9ef4, 0x9f04, 0x9f14, 0x9f23, 0x9f33, 0x9f43,
-0x9f53, 0x9f63, 0x9f73, 0x9f83, 0x9f93, 0x9fa3,
-0x9fb2, 0x9fc2, 0x9fd2, 0x9fe2, 0x9ff2, 0xa002,
-0xa012, 0xa021, 0xa031, 0xa041, 0xa051, 0xa061,
-0xa071, 0xa080, 0xa090, 0xa0a0, 0xa0b0, 0xa0c0,
-0xa0cf, 0xa0df, 0xa0ef, 0xa0ff, 0xa10f, 0xa11e,
-0xa12e, 0xa13e, 0xa14e, 0xa15e, 0xa16d, 0xa17d,
-0xa18d, 0xa19d, 0xa1ac, 0xa1bc, 0xa1cc, 0xa1dc,
-0xa1eb, 0xa1fb, 0xa20b, 0xa21b, 0xa22a, 0xa23a,
-0xa24a, 0xa25a, 0xa269, 0xa279, 0xa289, 0xa298,
-0xa2a8, 0xa2b8, 0xa2c8, 0xa2d7, 0xa2e7, 0xa2f7,
-0xa306, 0xa316, 0xa326, 0xa335, 0xa345, 0xa355,
-0xa364, 0xa374, 0xa384, 0xa393, 0xa3a3, 0xa3b3,
-0xa3c2, 0xa3d2, 0xa3e2, 0xa3f1, 0xa401, 0xa411,
-0xa420, 0xa430, 0xa440, 0xa44f, 0xa45f, 0xa46e,
-0xa47e, 0xa48e, 0xa49d, 0xa4ad, 0xa4bc, 0xa4cc,
-0xa4dc, 0xa4eb, 0xa4fb, 0xa50a, 0xa51a, 0xa52a,
-0xa539, 0xa549, 0xa558, 0xa568, 0xa577, 0xa587,
-0xa597, 0xa5a6, 0xa5b6, 0xa5c5, 0xa5d5, 0xa5e4,
-0xa5f4, 0xa603, 0xa613, 0xa622, 0xa632, 0xa641,
-0xa651, 0xa660, 0xa670, 0xa67f, 0xa68f, 0xa69e,
-0xa6ae, 0xa6bd, 0xa6cd, 0xa6dc, 0xa6ec, 0xa6fb,
-0xa70b, 0xa71a, 0xa72a, 0xa739, 0xa749, 0xa758,
-0xa768, 0xa777, 0xa787, 0xa796, 0xa7a5, 0xa7b5,
-0xa7c4, 0xa7d4, 0xa7e3, 0xa7f3, 0xa802, 0xa812,
-0xa821, 0xa830, 0xa840, 0xa84f, 0xa85f, 0xa86e,
-0xa87d, 0xa88d, 0xa89c, 0xa8ac, 0xa8bb, 0xa8ca,
-0xa8da, 0xa8e9, 0xa8f8, 0xa908, 0xa917, 0xa927,
-0xa936, 0xa945, 0xa955, 0xa964, 0xa973, 0xa983,
-0xa992, 0xa9a1, 0xa9b1, 0xa9c0, 0xa9cf, 0xa9df,
-0xa9ee, 0xa9fd, 0xaa0d, 0xaa1c, 0xaa2b, 0xaa3b,
-0xaa4a, 0xaa59, 0xaa69, 0xaa78, 0xaa87, 0xaa96,
-0xaaa6, 0xaab5, 0xaac4, 0xaad4, 0xaae3, 0xaaf2,
-0xab01, 0xab11, 0xab20, 0xab2f, 0xab3e, 0xab4e,
-0xab5d, 0xab6c, 0xab7b, 0xab8b, 0xab9a, 0xaba9,
-0xabb8, 0xabc7, 0xabd7, 0xabe6, 0xabf5, 0xac04,
-0xac14, 0xac23, 0xac32, 0xac41, 0xac50, 0xac60,
-0xac6f, 0xac7e, 0xac8d, 0xac9c, 0xacab, 0xacbb,
-0xacca, 0xacd9, 0xace8, 0xacf7, 0xad06, 0xad16,
-0xad25, 0xad34, 0xad43, 0xad52, 0xad61, 0xad70,
-0xad80, 0xad8f, 0xad9e, 0xadad, 0xadbc, 0xadcb,
-0xadda, 0xade9, 0xadf8, 0xae08, 0xae17, 0xae26,
-0xae35, 0xae44, 0xae53, 0xae62, 0xae71, 0xae80,
-0xae8f, 0xae9e, 0xaead, 0xaebd, 0xaecc, 0xaedb,
-0xaeea, 0xaef9, 0xaf08, 0xaf17, 0xaf26, 0xaf35,
-0xaf44, 0xaf53, 0xaf62, 0xaf71, 0xaf80, 0xaf8f,
-0xaf9e, 0xafad, 0xafbc, 0xafcb, 0xafda, 0xafe9,
-0xaff8, 0xb007, 0xb016, 0xb025, 0xb034, 0xb043,
-0xb052, 0xb061, 0xb070, 0xb07f, 0xb08e, 0xb09d,
-0xb0ac, 0xb0bb, 0xb0ca, 0xb0d9, 0xb0e8, 0xb0f6,
-0xb105, 0xb114, 0xb123, 0xb132, 0xb141, 0xb150,
-0xb15f, 0xb16e, 0xb17d, 0xb18c, 0xb19b, 0xb1aa,
-0xb1b8, 0xb1c7, 0xb1d6, 0xb1e5, 0xb1f4, 0xb203,
-0xb212, 0xb221, 0xb22f, 0xb23e, 0xb24d, 0xb25c,
-0xb26b, 0xb27a, 0xb289, 0xb297, 0xb2a6, 0xb2b5,
-0xb2c4, 0xb2d3, 0xb2e2, 0xb2f1, 0xb2ff, 0xb30e,
-0xb31d, 0xb32c, 0xb33b, 0xb349, 0xb358, 0xb367,
-0xb376, 0xb385, 0xb393, 0xb3a2, 0xb3b1, 0xb3c0,
-0xb3cf, 0xb3dd, 0xb3ec, 0xb3fb, 0xb40a, 0xb418,
-0xb427, 0xb436, 0xb445, 0xb453, 0xb462, 0xb471,
-0xb480, 0xb48e, 0xb49d, 0xb4ac, 0xb4bb, 0xb4c9,
-0xb4d8, 0xb4e7, 0xb4f6, 0xb504, 0xb513, 0xb522,
-0xb530, 0xb53f, 0xb54e, 0xb55c, 0xb56b, 0xb57a,
-0xb588, 0xb597, 0xb5a6, 0xb5b5, 0xb5c3, 0xb5d2,
-0xb5e1, 0xb5ef, 0xb5fe, 0xb60d, 0xb61b, 0xb62a,
-0xb638, 0xb647, 0xb656, 0xb664, 0xb673, 0xb682,
-0xb690, 0xb69f, 0xb6ae, 0xb6bc, 0xb6cb, 0xb6d9,
-0xb6e8, 0xb6f7, 0xb705, 0xb714, 0xb722, 0xb731,
-0xb740, 0xb74e, 0xb75d, 0xb76b, 0xb77a, 0xb788,
-0xb797, 0xb7a6, 0xb7b4, 0xb7c3, 0xb7d1, 0xb7e0,
-0xb7ee, 0xb7fd, 0xb80b, 0xb81a, 0xb829, 0xb837,
-0xb846, 0xb854, 0xb863, 0xb871, 0xb880, 0xb88e,
-0xb89d, 0xb8ab, 0xb8ba, 0xb8c8, 0xb8d7, 0xb8e5,
-0xb8f4, 0xb902, 0xb911, 0xb91f, 0xb92e, 0xb93c,
-0xb94b, 0xb959, 0xb968, 0xb976, 0xb984, 0xb993,
-0xb9a1, 0xb9b0, 0xb9be, 0xb9cd, 0xb9db, 0xb9ea,
-0xb9f8, 0xba06, 0xba15, 0xba23, 0xba32, 0xba40,
-0xba4f, 0xba5d, 0xba6b, 0xba7a, 0xba88, 0xba97,
-0xbaa5, 0xbab3, 0xbac2, 0xbad0, 0xbade, 0xbaed,
-0xbafb, 0xbb0a, 0xbb18, 0xbb26, 0xbb35, 0xbb43,
-0xbb51, 0xbb60, 0xbb6e, 0xbb7c, 0xbb8b, 0xbb99,
-0xbba8, 0xbbb6, 0xbbc4, 0xbbd3, 0xbbe1, 0xbbef,
-0xbbfd, 0xbc0c, 0xbc1a, 0xbc28, 0xbc37, 0xbc45,
-0xbc53, 0xbc62, 0xbc70, 0xbc7e, 0xbc8c, 0xbc9b,
-0xbca9, 0xbcb7, 0xbcc6, 0xbcd4, 0xbce2, 0xbcf0,
-0xbcff, 0xbd0d, 0xbd1b, 0xbd29, 0xbd38, 0xbd46,
-0xbd54, 0xbd62, 0xbd71, 0xbd7f, 0xbd8d, 0xbd9b,
-0xbdaa, 0xbdb8, 0xbdc6, 0xbdd4, 0xbde2, 0xbdf1,
-0xbdff, 0xbe0d, 0xbe1b, 0xbe29, 0xbe38, 0xbe46,
-0xbe54, 0xbe62, 0xbe70, 0xbe7f, 0xbe8d, 0xbe9b,
-0xbea9, 0xbeb7, 0xbec5, 0xbed4, 0xbee2, 0xbef0,
-0xbefe, 0xbf0c, 0xbf1a, 0xbf28, 0xbf37, 0xbf45,
-0xbf53, 0xbf61, 0xbf6f, 0xbf7d, 0xbf8b, 0xbf99,
-0xbfa7, 0xbfb6, 0xbfc4, 0xbfd2, 0xbfe0, 0xbfee,
-0xbffc, 0xc00a, 0xc018, 0xc026, 0xc034, 0xc042,
-0xc051, 0xc05f, 0xc06d, 0xc07b, 0xc089, 0xc097,
-0xc0a5, 0xc0b3, 0xc0c1, 0xc0cf, 0xc0dd, 0xc0eb,
-0xc0f9, 0xc107, 0xc115, 0xc123, 0xc131, 0xc13f,
-0xc14d, 0xc15b, 0xc169, 0xc177, 0xc185, 0xc193,
-0xc1a1, 0xc1af, 0xc1bd, 0xc1cb, 0xc1d9, 0xc1e7,
-0xc1f5, 0xc203, 0xc211, 0xc21f, 0xc22d, 0xc23b,
-0xc249, 0xc257, 0xc265, 0xc273, 0xc281, 0xc28f,
-0xc29d, 0xc2ab, 0xc2b8, 0xc2c6, 0xc2d4, 0xc2e2,
-0xc2f0, 0xc2fe, 0xc30c, 0xc31a, 0xc328, 0xc336,
-0xc344, 0xc352, 0xc35f, 0xc36d, 0xc37b, 0xc389,
-0xc397, 0xc3a5, 0xc3b3, 0xc3c1, 0xc3ce, 0xc3dc,
-0xc3ea, 0xc3f8, 0xc406, 0xc414, 0xc422, 0xc42f,
-0xc43d, 0xc44b, 0xc459, 0xc467, 0xc475, 0xc482,
-0xc490, 0xc49e, 0xc4ac, 0xc4ba, 0xc4c7, 0xc4d5,
-0xc4e3, 0xc4f1, 0xc4ff, 0xc50d, 0xc51a, 0xc528,
-0xc536, 0xc544, 0xc551, 0xc55f, 0xc56d, 0xc57b,
-0xc589, 0xc596, 0xc5a4, 0xc5b2, 0xc5c0, 0xc5cd,
-0xc5db, 0xc5e9, 0xc5f7, 0xc604, 0xc612, 0xc620,
-0xc62d, 0xc63b, 0xc649, 0xc657, 0xc664, 0xc672,
-0xc680, 0xc68d, 0xc69b, 0xc6a9, 0xc6b7, 0xc6c4,
-0xc6d2, 0xc6e0, 0xc6ed, 0xc6fb, 0xc709, 0xc716,
-0xc724, 0xc732, 0xc73f, 0xc74d, 0xc75b, 0xc768,
-0xc776, 0xc784, 0xc791, 0xc79f, 0xc7ad, 0xc7ba,
-0xc7c8, 0xc7d6, 0xc7e3, 0xc7f1, 0xc7fe, 0xc80c,
-0xc81a, 0xc827, 0xc835, 0xc842, 0xc850, 0xc85e,
-0xc86b, 0xc879, 0xc886, 0xc894, 0xc8a2, 0xc8af,
-0xc8bd, 0xc8ca, 0xc8d8, 0xc8e5, 0xc8f3, 0xc901,
-0xc90e, 0xc91c, 0xc929, 0xc937, 0xc944, 0xc952,
-0xc95f, 0xc96d, 0xc97b, 0xc988, 0xc996, 0xc9a3,
-0xc9b1, 0xc9be, 0xc9cc, 0xc9d9, 0xc9e7, 0xc9f4,
-0xca02, 0xca0f, 0xca1d, 0xca2a, 0xca38, 0xca45,
-0xca53, 0xca60, 0xca6e, 0xca7b, 0xca89, 0xca96,
-0xcaa4, 0xcab1, 0xcabe, 0xcacc, 0xcad9, 0xcae7,
-0xcaf4, 0xcb02, 0xcb0f, 0xcb1d, 0xcb2a, 0xcb37,
-0xcb45, 0xcb52, 0xcb60, 0xcb6d, 0xcb7b, 0xcb88,
-0xcb95, 0xcba3, 0xcbb0, 0xcbbe, 0xcbcb, 0xcbd8,
-0xcbe6, 0xcbf3, 0xcc01, 0xcc0e, 0xcc1b, 0xcc29,
-0xcc36, 0xcc43, 0xcc51, 0xcc5e, 0xcc6c, 0xcc79,
-0xcc86, 0xcc94, 0xcca1, 0xccae, 0xccbc, 0xccc9,
-0xccd6, 0xcce4, 0xccf1, 0xccfe, 0xcd0c, 0xcd19,
-0xcd26, 0xcd34, 0xcd41, 0xcd4e, 0xcd5b, 0xcd69,
-0xcd76, 0xcd83, 0xcd91, 0xcd9e, 0xcdab, 0xcdb9,
-0xcdc6, 0xcdd3, 0xcde0, 0xcdee, 0xcdfb, 0xce08,
-0xce15, 0xce23, 0xce30, 0xce3d, 0xce4a, 0xce58,
-0xce65, 0xce72, 0xce7f, 0xce8d, 0xce9a, 0xcea7,
-0xceb4, 0xcec2, 0xcecf, 0xcedc, 0xcee9, 0xcef6,
-0xcf04, 0xcf11, 0xcf1e, 0xcf2b, 0xcf38, 0xcf46,
-0xcf53, 0xcf60, 0xcf6d, 0xcf7a, 0xcf87, 0xcf95,
-0xcfa2, 0xcfaf, 0xcfbc, 0xcfc9, 0xcfd6, 0xcfe4,
-0xcff1, 0xcffe, 0xd00b, 0xd018, 0xd025, 0xd032,
-0xd040, 0xd04d, 0xd05a, 0xd067, 0xd074, 0xd081,
-0xd08e, 0xd09b, 0xd0a9, 0xd0b6, 0xd0c3, 0xd0d0,
-0xd0dd, 0xd0ea, 0xd0f7, 0xd104, 0xd111, 0xd11e,
-0xd12b, 0xd139, 0xd146, 0xd153, 0xd160, 0xd16d,
-0xd17a, 0xd187, 0xd194, 0xd1a1, 0xd1ae, 0xd1bb,
-0xd1c8, 0xd1d5, 0xd1e2, 0xd1ef, 0xd1fc, 0xd209,
-0xd216, 0xd223, 0xd230, 0xd23d, 0xd24a, 0xd257,
-0xd264, 0xd271, 0xd27e, 0xd28b, 0xd298, 0xd2a5,
-0xd2b2, 0xd2bf, 0xd2cc, 0xd2d9, 0xd2e6, 0xd2f3,
-0xd300, 0xd30d, 0xd31a, 0xd327, 0xd334, 0xd341,
-0xd34e, 0xd35b, 0xd368, 0xd375, 0xd382, 0xd38f,
-0xd39c, 0xd3a8, 0xd3b5, 0xd3c2, 0xd3cf, 0xd3dc,
-0xd3e9, 0xd3f6, 0xd403, 0xd410, 0xd41d, 0xd42a,
-0xd436, 0xd443, 0xd450, 0xd45d, 0xd46a, 0xd477,
-0xd484, 0xd491, 0xd49e, 0xd4aa, 0xd4b7, 0xd4c4,
-0xd4d1, 0xd4de, 0xd4eb, 0xd4f8, 0xd504, 0xd511,
-0xd51e, 0xd52b, 0xd538, 0xd545, 0xd551, 0xd55e,
-0xd56b, 0xd578, 0xd585, 0xd591, 0xd59e, 0xd5ab,
-0xd5b8, 0xd5c5, 0xd5d1, 0xd5de, 0xd5eb, 0xd5f8,
-0xd605, 0xd611, 0xd61e, 0xd62b, 0xd638, 0xd645,
-0xd651, 0xd65e, 0xd66b, 0xd678, 0xd684, 0xd691,
-0xd69e, 0xd6ab, 0xd6b7, 0xd6c4, 0xd6d1, 0xd6de,
-0xd6ea, 0xd6f7, 0xd704, 0xd710, 0xd71d, 0xd72a,
-0xd737, 0xd743, 0xd750, 0xd75d, 0xd769, 0xd776,
-0xd783, 0xd78f, 0xd79c, 0xd7a9, 0xd7b6, 0xd7c2,
-0xd7cf, 0xd7dc, 0xd7e8, 0xd7f5, 0xd802, 0xd80e,
-0xd81b, 0xd828, 0xd834, 0xd841, 0xd84e, 0xd85a,
-0xd867, 0xd873, 0xd880, 0xd88d, 0xd899, 0xd8a6,
-0xd8b3, 0xd8bf, 0xd8cc, 0xd8d8, 0xd8e5, 0xd8f2,
-0xd8fe, 0xd90b, 0xd917, 0xd924, 0xd931, 0xd93d,
-0xd94a, 0xd956, 0xd963, 0xd970, 0xd97c, 0xd989,
-0xd995, 0xd9a2, 0xd9ae, 0xd9bb, 0xd9c8, 0xd9d4,
-0xd9e1, 0xd9ed, 0xd9fa, 0xda06, 0xda13, 0xda1f,
-0xda2c, 0xda38, 0xda45, 0xda51, 0xda5e, 0xda6a,
-0xda77, 0xda84, 0xda90, 0xda9d, 0xdaa9, 0xdab6,
-0xdac2, 0xdacf, 0xdadb, 0xdae7, 0xdaf4, 0xdb00,
-0xdb0d, 0xdb19, 0xdb26, 0xdb32, 0xdb3f, 0xdb4b,
-0xdb58, 0xdb64, 0xdb71, 0xdb7d, 0xdb8a, 0xdb96,
-0xdba2, 0xdbaf, 0xdbbb, 0xdbc8, 0xdbd4, 0xdbe1,
-0xdbed, 0xdbf9, 0xdc06, 0xdc12, 0xdc1f, 0xdc2b,
-0xdc38, 0xdc44, 0xdc50, 0xdc5d, 0xdc69, 0xdc76,
-0xdc82, 0xdc8e, 0xdc9b, 0xdca7, 0xdcb3, 0xdcc0,
-0xdccc, 0xdcd9, 0xdce5, 0xdcf1, 0xdcfe, 0xdd0a,
-0xdd16, 0xdd23, 0xdd2f, 0xdd3b, 0xdd48, 0xdd54,
-0xdd60, 0xdd6d, 0xdd79, 0xdd85, 0xdd92, 0xdd9e,
-0xddaa, 0xddb7, 0xddc3, 0xddcf, 0xdddc, 0xdde8,
-0xddf4, 0xde01, 0xde0d, 0xde19, 0xde25, 0xde32,
-0xde3e, 0xde4a, 0xde57, 0xde63, 0xde6f, 0xde7b,
-0xde88, 0xde94, 0xdea0, 0xdeac, 0xdeb9, 0xdec5,
-0xded1, 0xdedd, 0xdeea, 0xdef6, 0xdf02, 0xdf0e,
-0xdf1b, 0xdf27, 0xdf33, 0xdf3f, 0xdf4c, 0xdf58,
-0xdf64, 0xdf70, 0xdf7c, 0xdf89, 0xdf95, 0xdfa1,
-0xdfad, 0xdfb9, 0xdfc6, 0xdfd2, 0xdfde, 0xdfea,
-0xdff6, 0xe003, 0xe00f, 0xe01b, 0xe027, 0xe033,
-0xe03f, 0xe04c, 0xe058, 0xe064, 0xe070, 0xe07c,
-0xe088, 0xe094, 0xe0a1, 0xe0ad, 0xe0b9, 0xe0c5,
-0xe0d1, 0xe0dd, 0xe0e9, 0xe0f5, 0xe102, 0xe10e,
-0xe11a, 0xe126, 0xe132, 0xe13e, 0xe14a, 0xe156,
-0xe162, 0xe16e, 0xe17b, 0xe187, 0xe193, 0xe19f,
-0xe1ab, 0xe1b7, 0xe1c3, 0xe1cf, 0xe1db, 0xe1e7,
-0xe1f3, 0xe1ff, 0xe20b, 0xe217, 0xe223, 0xe22f,
-0xe23c, 0xe248, 0xe254, 0xe260, 0xe26c, 0xe278,
-0xe284, 0xe290, 0xe29c, 0xe2a8, 0xe2b4, 0xe2c0,
-0xe2cc, 0xe2d8, 0xe2e4, 0xe2f0, 0xe2fc, 0xe308,
-0xe314, 0xe320, 0xe32c, 0xe338, 0xe344, 0xe350,
-0xe35c, 0xe368, 0xe374, 0xe380, 0xe38b, 0xe397,
-0xe3a3, 0xe3af, 0xe3bb, 0xe3c7, 0xe3d3, 0xe3df,
-0xe3eb, 0xe3f7, 0xe403, 0xe40f, 0xe41b, 0xe427,
-0xe433, 0xe43f, 0xe44a, 0xe456, 0xe462, 0xe46e,
-0xe47a, 0xe486, 0xe492, 0xe49e, 0xe4aa, 0xe4b6,
-0xe4c1, 0xe4cd, 0xe4d9, 0xe4e5, 0xe4f1, 0xe4fd,
-0xe509, 0xe515, 0xe520, 0xe52c, 0xe538, 0xe544,
-0xe550, 0xe55c, 0xe567, 0xe573, 0xe57f, 0xe58b,
-0xe597, 0xe5a3, 0xe5af, 0xe5ba, 0xe5c6, 0xe5d2,
-0xe5de, 0xe5ea, 0xe5f5, 0xe601, 0xe60d, 0xe619,
-0xe625, 0xe630, 0xe63c, 0xe648, 0xe654, 0xe660,
-0xe66b, 0xe677, 0xe683, 0xe68f, 0xe69a, 0xe6a6,
-0xe6b2, 0xe6be, 0xe6ca, 0xe6d5, 0xe6e1, 0xe6ed,
-0xe6f9, 0xe704, 0xe710, 0xe71c, 0xe727, 0xe733,
-0xe73f, 0xe74b, 0xe756, 0xe762, 0xe76e, 0xe77a,
-0xe785, 0xe791, 0xe79d, 0xe7a8, 0xe7b4, 0xe7c0,
-0xe7cb, 0xe7d7, 0xe7e3, 0xe7ef, 0xe7fa, 0xe806,
-0xe812, 0xe81d, 0xe829, 0xe835, 0xe840, 0xe84c,
-0xe858, 0xe863, 0xe86f, 0xe87b, 0xe886, 0xe892,
-0xe89e, 0xe8a9, 0xe8b5, 0xe8c0, 0xe8cc, 0xe8d8,
-0xe8e3, 0xe8ef, 0xe8fb, 0xe906, 0xe912, 0xe91d,
-0xe929, 0xe935, 0xe940, 0xe94c, 0xe958, 0xe963,
-0xe96f, 0xe97a, 0xe986, 0xe991, 0xe99d, 0xe9a9,
-0xe9b4, 0xe9c0, 0xe9cb, 0xe9d7, 0xe9e3, 0xe9ee,
-0xe9fa, 0xea05, 0xea11, 0xea1c, 0xea28, 0xea33,
-0xea3f, 0xea4a, 0xea56, 0xea62, 0xea6d, 0xea79,
-0xea84, 0xea90, 0xea9b, 0xeaa7, 0xeab2, 0xeabe,
-0xeac9, 0xead5, 0xeae0, 0xeaec, 0xeaf7, 0xeb03,
-0xeb0e, 0xeb1a, 0xeb25, 0xeb31, 0xeb3c, 0xeb48,
-0xeb53, 0xeb5f, 0xeb6a, 0xeb76, 0xeb81, 0xeb8d,
-0xeb98, 0xeba3, 0xebaf, 0xebba, 0xebc6, 0xebd1,
-0xebdd, 0xebe8, 0xebf4, 0xebff, 0xec0a, 0xec16,
-0xec21, 0xec2d, 0xec38, 0xec44, 0xec4f, 0xec5a,
-0xec66, 0xec71, 0xec7d, 0xec88, 0xec93, 0xec9f,
-0xecaa, 0xecb6, 0xecc1, 0xeccc, 0xecd8, 0xece3,
-0xecef, 0xecfa, 0xed05, 0xed11, 0xed1c, 0xed27,
-0xed33, 0xed3e, 0xed4a, 0xed55, 0xed60, 0xed6c,
-0xed77, 0xed82, 0xed8e, 0xed99, 0xeda4, 0xedb0,
-0xedbb, 0xedc6, 0xedd2, 0xeddd, 0xede8, 0xedf4,
-0xedff, 0xee0a, 0xee15, 0xee21, 0xee2c, 0xee37,
-0xee43, 0xee4e, 0xee59, 0xee65, 0xee70, 0xee7b,
-0xee86, 0xee92, 0xee9d, 0xeea8, 0xeeb3, 0xeebf,
-0xeeca, 0xeed5, 0xeee1, 0xeeec, 0xeef7, 0xef02,
-0xef0e, 0xef19, 0xef24, 0xef2f, 0xef3a, 0xef46,
-0xef51, 0xef5c, 0xef67, 0xef73, 0xef7e, 0xef89,
-0xef94, 0xef9f, 0xefab, 0xefb6, 0xefc1, 0xefcc,
-0xefd7, 0xefe3, 0xefee, 0xeff9, 0xf004, 0xf00f,
-0xf01b, 0xf026, 0xf031, 0xf03c, 0xf047, 0xf052,
-0xf05e, 0xf069, 0xf074, 0xf07f, 0xf08a, 0xf095,
-0xf0a1, 0xf0ac, 0xf0b7, 0xf0c2, 0xf0cd, 0xf0d8,
-0xf0e3, 0xf0ef, 0xf0fa, 0xf105, 0xf110, 0xf11b,
-0xf126, 0xf131, 0xf13c, 0xf147, 0xf153, 0xf15e,
-0xf169, 0xf174, 0xf17f, 0xf18a, 0xf195, 0xf1a0,
-0xf1ab, 0xf1b6, 0xf1c2, 0xf1cd, 0xf1d8, 0xf1e3,
-0xf1ee, 0xf1f9, 0xf204, 0xf20f, 0xf21a, 0xf225,
-0xf230, 0xf23b, 0xf246, 0xf251, 0xf25c, 0xf267,
-0xf272, 0xf27d, 0xf288, 0xf293, 0xf29f, 0xf2aa,
-0xf2b5, 0xf2c0, 0xf2cb, 0xf2d6, 0xf2e1, 0xf2ec,
-0xf2f7, 0xf302, 0xf30d, 0xf318, 0xf323, 0xf32e,
-0xf339, 0xf344, 0xf34f, 0xf35a, 0xf364, 0xf36f,
-0xf37a, 0xf385, 0xf390, 0xf39b, 0xf3a6, 0xf3b1,
-0xf3bc, 0xf3c7, 0xf3d2, 0xf3dd, 0xf3e8, 0xf3f3,
-0xf3fe, 0xf409, 0xf414, 0xf41f, 0xf42a, 0xf435,
-0xf43f, 0xf44a, 0xf455, 0xf460, 0xf46b, 0xf476,
-0xf481, 0xf48c, 0xf497, 0xf4a2, 0xf4ad, 0xf4b7,
-0xf4c2, 0xf4cd, 0xf4d8, 0xf4e3, 0xf4ee, 0xf4f9,
-0xf504, 0xf50f, 0xf519, 0xf524, 0xf52f, 0xf53a,
-0xf545, 0xf550, 0xf55b, 0xf565, 0xf570, 0xf57b,
-0xf586, 0xf591, 0xf59c, 0xf5a6, 0xf5b1, 0xf5bc,
-0xf5c7, 0xf5d2, 0xf5dd, 0xf5e7, 0xf5f2, 0xf5fd,
-0xf608, 0xf613, 0xf61d, 0xf628, 0xf633, 0xf63e,
-0xf649, 0xf653, 0xf65e, 0xf669, 0xf674, 0xf67f,
-0xf689, 0xf694, 0xf69f, 0xf6aa, 0xf6b4, 0xf6bf,
-0xf6ca, 0xf6d5, 0xf6e0, 0xf6ea, 0xf6f5, 0xf700,
-0xf70b, 0xf715, 0xf720, 0xf72b, 0xf736, 0xf740,
-0xf74b, 0xf756, 0xf760, 0xf76b, 0xf776, 0xf781,
-0xf78b, 0xf796, 0xf7a1, 0xf7ab, 0xf7b6, 0xf7c1,
-0xf7cc, 0xf7d6, 0xf7e1, 0xf7ec, 0xf7f6, 0xf801,
-0xf80c, 0xf816, 0xf821, 0xf82c, 0xf836, 0xf841,
-0xf84c, 0xf856, 0xf861, 0xf86c, 0xf876, 0xf881,
-0xf88c, 0xf896, 0xf8a1, 0xf8ac, 0xf8b6, 0xf8c1,
-0xf8cc, 0xf8d6, 0xf8e1, 0xf8ec, 0xf8f6, 0xf901,
-0xf90b, 0xf916, 0xf921, 0xf92b, 0xf936, 0xf941,
-0xf94b, 0xf956, 0xf960, 0xf96b, 0xf976, 0xf980,
-0xf98b, 0xf995, 0xf9a0, 0xf9aa, 0xf9b5, 0xf9c0,
-0xf9ca, 0xf9d5, 0xf9df, 0xf9ea, 0xf9f4, 0xf9ff,
-0xfa0a, 0xfa14, 0xfa1f, 0xfa29, 0xfa34, 0xfa3e,
-0xfa49, 0xfa53, 0xfa5e, 0xfa69, 0xfa73, 0xfa7e,
-0xfa88, 0xfa93, 0xfa9d, 0xfaa8, 0xfab2, 0xfabd,
-0xfac7, 0xfad2, 0xfadc, 0xfae7, 0xfaf1, 0xfafc,
-0xfb06, 0xfb11, 0xfb1b, 0xfb26, 0xfb30, 0xfb3b,
-0xfb45, 0xfb50, 0xfb5a, 0xfb65, 0xfb6f, 0xfb7a,
-0xfb84, 0xfb8f, 0xfb99, 0xfba4, 0xfbae, 0xfbb8,
-0xfbc3, 0xfbcd, 0xfbd8, 0xfbe2, 0xfbed, 0xfbf7,
-0xfc02, 0xfc0c, 0xfc16, 0xfc21, 0xfc2b, 0xfc36,
-0xfc40, 0xfc4b, 0xfc55, 0xfc5f, 0xfc6a, 0xfc74,
-0xfc7f, 0xfc89, 0xfc93, 0xfc9e, 0xfca8, 0xfcb3,
-0xfcbd, 0xfcc7, 0xfcd2, 0xfcdc, 0xfce7, 0xfcf1,
-0xfcfb, 0xfd06, 0xfd10, 0xfd1a, 0xfd25, 0xfd2f,
-0xfd3a, 0xfd44, 0xfd4e, 0xfd59, 0xfd63, 0xfd6d,
-0xfd78, 0xfd82, 0xfd8c, 0xfd97, 0xfda1, 0xfdab,
-0xfdb6, 0xfdc0, 0xfdca, 0xfdd5, 0xfddf, 0xfde9,
-0xfdf4, 0xfdfe, 0xfe08, 0xfe13, 0xfe1d, 0xfe27,
-0xfe32, 0xfe3c, 0xfe46, 0xfe50, 0xfe5b, 0xfe65,
-0xfe6f, 0xfe7a, 0xfe84, 0xfe8e, 0xfe98, 0xfea3,
-0xfead, 0xfeb7, 0xfec1, 0xfecc, 0xfed6, 0xfee0,
-0xfeeb, 0xfef5, 0xfeff, 0xff09, 0xff14, 0xff1e,
-0xff28, 0xff32, 0xff3c, 0xff47, 0xff51, 0xff5b,
-0xff65, 0xff70, 0xff7a, 0xff84, 0xff8e, 0xff98,
-0xffa3, 0xffad, 0xffb7, 0xffc1, 0xffcc, 0xffd6,
-0xffe0, 0xffea, 0xfff4, 0xffff
-};
-
-// max value is pi/4
-constexpr double SCALING_FACTOR = 4. / M_PI * 0xFFFF;
-
-inline double atan2_lookup(double y, double x)
-{
- if (std::abs(x) < std::numeric_limits<double>::epsilon())
- {
- if (y >= 0.)
- {
- return M_PI / 2.;
- }
- else
- {
- return -M_PI / 2.;
- }
- }
-
- unsigned octant = 0;
-
- if (x < 0.)
- {
- octant = 1;
- x = -x;
- }
- if (y < 0.)
- {
- octant |= 2;
- y = -y;
- }
-
- double t = y / x;
- if (t > 1.0)
- {
- octant |= 4;
- t = 1.0 / t;
- }
-
- double angle = atan_table[(unsigned)(t * 4095)] / SCALING_FACTOR;
-
- switch (octant)
- {
- case 0:
- break;
- case 1:
- angle = M_PI - angle;
- break;
- case 2:
- angle = -angle;
- break;
- case 3:
- angle = -M_PI + angle;
- break;
- case 4:
- angle = M_PI / 2.0 - angle;
- break;
- case 5:
- angle = M_PI / 2.0 + angle;
- break;
- case 6:
- angle = -M_PI / 2.0 + angle;
- break;
- case 7:
- angle = -M_PI / 2.0 - angle;
- break;
- }
- return angle;
-}
-
-#endif // TRIGONOMETRY_TABLES_H
diff --git a/Util/graph_loader.hpp b/Util/graph_loader.hpp
deleted file mode 100644
index 5ab8eba..0000000
--- a/Util/graph_loader.hpp
+++ /dev/null
@@ -1,325 +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.
-
-*/
-
-#ifndef GRAPHLOADER_H
-#define GRAPHLOADER_H
-
-#include "osrm_exception.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 "../Util/simple_logger.hpp"
-#include "../Util/FingerPrint.h"
-#include "../typedefs.h"
-
-#include <boost/assert.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-
-#include <tbb/parallel_sort.h>
-
-#include <cmath>
-
-#include <algorithm>
-#include <fstream>
-#include <iostream>
-#include <iomanip>
-#include <unordered_map>
-#include <vector>
-
-template <typename EdgeT>
-NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
- std::vector<EdgeT> &edge_list,
- std::vector<NodeID> &barrier_node_list,
- std::vector<NodeID> &traffic_light_node_list,
- std::vector<QueryNode> *int_to_ext_node_id_map,
- std::vector<TurnRestriction> &restriction_list)
-{
- const FingerPrint fingerprint_orig;
- FingerPrint fingerprint_loaded;
- input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
-
- if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
- {
- SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n"
- "Reprocess to get rid of this warning.";
- }
-
- std::unordered_map<NodeID, NodeID> ext_to_int_id_map;
-
- NodeID n;
- input_stream.read((char *)&n, sizeof(NodeID));
- SimpleLogger().Write() << "Importing n = " << n << " nodes ";
-
- ExternalMemoryNode current_node;
- for (NodeID i = 0; i < n; ++i)
- {
- input_stream.read((char *)¤t_node, sizeof(ExternalMemoryNode));
- int_to_ext_node_id_map->emplace_back(current_node.lat, current_node.lon, current_node.node_id);
- ext_to_int_id_map.emplace(current_node.node_id, i);
- if (current_node.barrier)
- {
- barrier_node_list.emplace_back(i);
- }
- if (current_node.traffic_lights)
- {
- traffic_light_node_list.emplace_back(i);
- }
- }
-
- // tighten vector sizes
- barrier_node_list.shrink_to_fit();
- traffic_light_node_list.shrink_to_fit();
-
- // renumber nodes in turn restrictions
- for (TurnRestriction ¤t_restriction : restriction_list)
- {
- auto internal_id_iter = ext_to_int_id_map.find(current_restriction.from.node);
- if (internal_id_iter == ext_to_int_id_map.end())
- {
- SimpleLogger().Write(logDEBUG) << "Unmapped from Node of restriction";
- continue;
- }
- current_restriction.from.node = internal_id_iter->second;
-
- internal_id_iter = ext_to_int_id_map.find(current_restriction.via.node);
- if (internal_id_iter == ext_to_int_id_map.end())
- {
- SimpleLogger().Write(logDEBUG) << "Unmapped via node of restriction";
- continue;
- }
- current_restriction.via.node = internal_id_iter->second;
-
- internal_id_iter = ext_to_int_id_map.find(current_restriction.to.node);
- if (internal_id_iter == ext_to_int_id_map.end())
- {
- SimpleLogger().Write(logDEBUG) << "Unmapped to node of restriction";
- continue;
- }
- current_restriction.to.node = internal_id_iter->second;
- }
-
- EdgeWeight weight;
- NodeID source, target;
- unsigned nameID;
- int length;
- short dir; // direction (0 = open, 1 = forward, 2+ = open)
- bool is_roundabout, ignore_in_grid, is_access_restricted, is_split;
- TravelMode travel_mode;
-
- EdgeID m;
- input_stream.read((char *)&m, sizeof(unsigned));
- edge_list.reserve(m);
- SimpleLogger().Write() << " and " << m << " edges ";
-
- for (EdgeID i = 0; i < m; ++i)
- {
- input_stream.read((char *)&source, sizeof(unsigned));
- input_stream.read((char *)&target, sizeof(unsigned));
- input_stream.read((char *)&length, sizeof(int));
- input_stream.read((char *)&dir, sizeof(short));
- input_stream.read((char *)&weight, sizeof(int));
- input_stream.read((char *)&nameID, sizeof(unsigned));
- input_stream.read((char *)&is_roundabout, sizeof(bool));
- input_stream.read((char *)&ignore_in_grid, sizeof(bool));
- input_stream.read((char *)&is_access_restricted, sizeof(bool));
- input_stream.read((char *)&travel_mode, sizeof(TravelMode));
- input_stream.read((char *)&is_split, sizeof(bool));
-
- BOOST_ASSERT_MSG(length > 0, "loaded null length edge");
- BOOST_ASSERT_MSG(weight > 0, "loaded null weight");
- BOOST_ASSERT_MSG(0 <= dir && dir <= 2, "loaded bogus direction");
-
- bool forward = true;
- bool backward = true;
- if (1 == dir)
- {
- backward = false;
- }
- if (2 == dir)
- {
- forward = false;
- }
-
- // translate the external NodeIDs to internal IDs
- auto internal_id_iter = ext_to_int_id_map.find(source);
- if (ext_to_int_id_map.find(source) == ext_to_int_id_map.end())
- {
-#ifndef NDEBUG
- SimpleLogger().Write(logWARNING) << " unresolved source NodeID: " << source;
-#endif
- continue;
- }
- source = internal_id_iter->second;
- internal_id_iter = ext_to_int_id_map.find(target);
- if (ext_to_int_id_map.find(target) == ext_to_int_id_map.end())
- {
-#ifndef NDEBUG
- SimpleLogger().Write(logWARNING) << "unresolved target NodeID : " << target;
-#endif
- continue;
- }
- target = internal_id_iter->second;
- BOOST_ASSERT_MSG(source != SPECIAL_NODEID && target != SPECIAL_NODEID,
- "nonexisting source or target");
-
- if (source > target)
- {
- std::swap(source, target);
- std::swap(forward, backward);
- }
-
- edge_list.emplace_back(source,
- target,
- nameID,
- weight,
- forward,
- backward,
- is_roundabout,
- ignore_in_grid,
- is_access_restricted,
- travel_mode,
- is_split);
- }
- ext_to_int_id_map.clear();
-
- tbb::parallel_sort(edge_list.begin(), edge_list.end());
-
- for (unsigned i = 1; i < edge_list.size(); ++i)
- {
- if ((edge_list[i - 1].target == edge_list[i].target) &&
- (edge_list[i - 1].source == edge_list[i].source))
- {
- const bool edge_flags_equivalent =
- (edge_list[i - 1].forward == edge_list[i].forward) &&
- (edge_list[i - 1].backward == edge_list[i].backward);
- const bool edge_flags_are_superset1 =
- (edge_list[i - 1].forward && edge_list[i - 1].backward) &&
- (edge_list[i].forward != edge_list[i].backward);
- const bool edge_flags_are_superset_2 =
- (edge_list[i].forward && edge_list[i].backward) &&
- (edge_list[i - 1].forward != edge_list[i - 1].backward);
-
- if (edge_flags_equivalent)
- {
- edge_list[i].weight = std::min(edge_list[i - 1].weight, edge_list[i].weight);
- edge_list[i - 1].source = SPECIAL_NODEID;
- }
- else if (edge_flags_are_superset1)
- {
- if (edge_list[i - 1].weight <= edge_list[i].weight)
- {
- // edge i-1 is smaller and goes in both directions. Throw away the other edge
- edge_list[i].source = SPECIAL_NODEID;
- }
- else
- {
- // edge i-1 is open in both directions, but edge i is smaller in one direction.
- // Close edge i-1 in this direction
- edge_list[i - 1].forward = !edge_list[i].forward;
- edge_list[i - 1].backward = !edge_list[i].backward;
- }
- }
- else if (edge_flags_are_superset_2)
- {
- if (edge_list[i - 1].weight <= edge_list[i].weight)
- {
- // edge i-1 is smaller for one direction. edge i is open in both. close edge i
- // in the other direction
- edge_list[i].forward = !edge_list[i - 1].forward;
- edge_list[i].backward = !edge_list[i - 1].backward;
- }
- else
- {
- // edge i is smaller and goes in both direction. Throw away edge i-1
- edge_list[i - 1].source = SPECIAL_NODEID;
- }
- }
- }
- }
- const auto new_end_iter = std::remove_if(edge_list.begin(), edge_list.end(), [] (const EdgeT &edge)
- {
- return edge.source == SPECIAL_NODEID ||
- edge.target == SPECIAL_NODEID;
- });
- edge_list.erase(new_end_iter, edge_list.end()); // remove excess candidates.
- edge_list.shrink_to_fit();
- SimpleLogger().Write() << "Graph loaded ok and has " << edge_list.size() << " edges";
- return n;
-}
-
-template <typename NodeT, typename EdgeT>
-unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
- std::vector<NodeT> &node_list,
- std::vector<EdgeT> &edge_list,
- unsigned *check_sum)
-{
- if (!boost::filesystem::exists(hsgr_file))
- {
- throw osrm::exception("hsgr file does not exist");
- }
- if (0 == boost::filesystem::file_size(hsgr_file))
- {
- throw osrm::exception("hsgr file is empty");
- }
-
- boost::filesystem::ifstream hsgr_input_stream(hsgr_file, std::ios::binary);
-
- FingerPrint fingerprint_loaded, fingerprint_orig;
- hsgr_input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
- if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
- {
- SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build.\n"
- "Reprocess to get rid of this warning.";
- }
-
- unsigned number_of_nodes = 0;
- unsigned number_of_edges = 0;
- hsgr_input_stream.read((char *)check_sum, sizeof(unsigned));
- hsgr_input_stream.read((char *)&number_of_nodes, sizeof(unsigned));
- BOOST_ASSERT_MSG(0 != number_of_nodes, "number of nodes is zero");
- hsgr_input_stream.read((char *)&number_of_edges, sizeof(unsigned));
-
- SimpleLogger().Write() << "number_of_nodes: " << number_of_nodes
- << ", number_of_edges: " << number_of_edges;
-
- // BOOST_ASSERT_MSG( 0 != number_of_edges, "number of edges is zero");
- node_list.resize(number_of_nodes);
- hsgr_input_stream.read((char *)&(node_list[0]), number_of_nodes * sizeof(NodeT));
-
- edge_list.resize(number_of_edges);
- if (number_of_edges > 0)
- {
- hsgr_input_stream.read((char *)&(edge_list[0]), number_of_edges * sizeof(EdgeT));
- }
- hsgr_input_stream.close();
-
- return number_of_nodes;
-}
-
-#endif // GRAPHLOADER_H
diff --git a/Util/range_algorithms.hpp b/Util/range_algorithms.hpp
deleted file mode 100644
index 208236e..0000000
--- a/Util/range_algorithms.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- open source routing machine
- Copyright (C) Dennis Luxen, others 2010
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU AFFERO General Public License as published by
-the Free Software Foundation; either version 3 of the License, or
-any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-or see http://www.gnu.org/licenses/agpl.txt.
- */
-
-#ifndef RANGE_ALGORITHMS_HPP
-#define RANGE_ALGORITHMS_HPP
-
-#include <algorithm>
-
-namespace osrm {
-
-template<class Container>
-auto max_element(const Container & c) -> decltype(std::max_element(c.begin(), c.end()))
-{
- return std::max_element(c.begin(), c.end());
-}
-
-template<class Container>
-auto max_element(const Container & c) -> decltype(std::max_element(c.cbegin(), c.cend()))
-{
- return std::max_element(c.cbegin(), c.cend());
-}
-
-}
-
-#endif // RANGE_ALGORITHMS_HPP
diff --git a/algorithms/bayes_classifier.hpp b/algorithms/bayes_classifier.hpp
new file mode 100644
index 0000000..3358144
--- /dev/null
+++ b/algorithms/bayes_classifier.hpp
@@ -0,0 +1,117 @@
+/*
+
+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
+
+#include <cmath>
+
+#include <vector>
+
+struct NormalDistribution
+{
+ NormalDistribution(const double mean, const double standard_deviation)
+ : mean(mean), standard_deviation(standard_deviation)
+ {
+ }
+
+ // FIXME implement log-probability version since its faster
+ double density_function(const double val) const
+ {
+ const double x = val - mean;
+ return 1.0 / (std::sqrt(2. * M_PI) * standard_deviation) *
+ std::exp(-x * x / (standard_deviation * standard_deviation));
+ }
+
+ double mean;
+ double standard_deviation;
+};
+
+struct LaplaceDistribution
+{
+ LaplaceDistribution(const double location, const double scale)
+ : location(location), scale(scale)
+ {
+ }
+
+ // FIXME implement log-probability version since its faster
+ double density_function(const double val) const
+ {
+ const double x = std::abs(val - location);
+ return 1.0 / (2. * scale) * std::exp(-x / scale);
+ }
+
+ double location;
+ double scale;
+};
+
+template <typename PositiveDistributionT, typename NegativeDistributionT, typename ValueT>
+class BayesClassifier
+{
+ public:
+ enum class ClassLabel : unsigned
+ {
+ NEGATIVE,
+ POSITIVE
+ };
+ using ClassificationT = std::pair<ClassLabel, double>;
+
+ BayesClassifier(const PositiveDistributionT &positive_distribution,
+ const NegativeDistributionT &negative_distribution,
+ const double positive_apriori_probability)
+ : positive_distribution(positive_distribution),
+ negative_distribution(negative_distribution),
+ positive_apriori_probability(positive_apriori_probability),
+ negative_apriori_probability(1. - positive_apriori_probability)
+ {
+ }
+
+ // Returns label and the probability of the label.
+ ClassificationT classify(const ValueT &v) const
+ {
+ const double positive_postpriori =
+ positive_apriori_probability * positive_distribution.density_function(v);
+ const double negative_postpriori =
+ negative_apriori_probability * negative_distribution.density_function(v);
+ const double norm = positive_postpriori + negative_postpriori;
+
+ if (positive_postpriori > negative_postpriori)
+ {
+ return std::make_pair(ClassLabel::POSITIVE, positive_postpriori / norm);
+ }
+
+ return std::make_pair(ClassLabel::NEGATIVE, negative_postpriori / norm);
+ }
+
+ private:
+ PositiveDistributionT positive_distribution;
+ NegativeDistributionT negative_distribution;
+ double positive_apriori_probability;
+ double negative_apriori_probability;
+};
+
+#endif // BAYES_CLASSIFIER_HPP
diff --git a/algorithms/bfs_components.hpp b/algorithms/bfs_components.hpp
index 57be635..b3f5364 100644
--- a/algorithms/bfs_components.hpp
+++ b/algorithms/bfs_components.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -95,8 +95,8 @@ template <typename GraphT> class BFSComponentExplorer
* 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)
+ NodeID node,
+ unsigned current_component)
{
/*
Graphical representation of variables:
@@ -118,7 +118,7 @@ template <typename GraphT> class BFSComponentExplorer
std::pair<NodeID, NodeID> current_queue_item = bfs_queue.front();
bfs_queue.pop();
- const NodeID v = current_queue_item.first; // current node
+ 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;
diff --git a/algorithms/crc32_processor.hpp b/algorithms/crc32_processor.hpp
index a68514d..a31b4ad 100644
--- a/algorithms/crc32_processor.hpp
+++ b/algorithms/crc32_processor.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -49,7 +49,7 @@ class IteratorbasedCRC32
while (iter != end)
{
using value_type = typename std::iterator_traits<Iterator>::value_type;
- char *data = (char *)(&(*iter));
+ const char *data = reinterpret_cast<const char *>(&(*iter));
if (use_hardware_implementation)
{
@@ -73,14 +73,14 @@ class IteratorbasedCRC32
return sse42_found;
}
- unsigned compute_in_software(char *str, unsigned len)
+ unsigned compute_in_software(const char *str, unsigned len)
{
crc_processor.process_bytes(str, len);
return crc_processor.checksum();
}
// adapted from http://byteworm.com/2010/10/13/crc32/
- unsigned compute_in_hardware(char *str, unsigned len)
+ unsigned compute_in_hardware(const char *str, unsigned len)
{
#if defined(__x86_64__)
unsigned q = len / sizeof(unsigned);
@@ -96,7 +96,7 @@ class IteratorbasedCRC32
++p;
}
- str = (char *)p;
+ str = reinterpret_cast<char *>(p);
while (r--)
{
__asm__ __volatile__(".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
@@ -116,7 +116,7 @@ class IteratorbasedCRC32
return ecx;
}
-#if defined(__MINGW64__) || defined(_MSC_VER)
+#if defined(__MINGW64__) || defined(_MSC_VER) || !defined(__x86_64__)
inline void
__get_cpuid(int param, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx) const
{
@@ -131,8 +131,7 @@ class IteratorbasedCRC32
struct RangebasedCRC32
{
- template<typename Iteratable>
- unsigned operator()(const Iteratable &iterable)
+ template <typename Iteratable> unsigned operator()(const Iteratable &iterable)
{
return crc32(std::begin(iterable), std::end(iterable));
}
diff --git a/algorithms/douglas_peucker.cpp b/algorithms/douglas_peucker.cpp
index 362f0a5..fa7d782 100644
--- a/algorithms/douglas_peucker.cpp
+++ b/algorithms/douglas_peucker.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,15 +28,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "douglas_peucker.hpp"
#include "../data_structures/segment_information.hpp"
-#include "../Util/integer_range.hpp"
-
-#include <osrm/Coordinate.h>
#include <boost/assert.hpp>
+#include <osrm/coordinate.hpp>
#include <cmath>
-
#include <algorithm>
+#include <iterator>
namespace
{
@@ -65,12 +63,12 @@ struct CoordinatePairCalculator
// 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 = sqrt(std::pow(x_value_1, 2) + std::pow(y_value_1, 2)) * earth_radius;
+ 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 = sqrt(std::pow(x_value_2, 2) + std::pow(y_value_2, 2)) * earth_radius;
+ const float dist2 = std::hypot(x_value_2, y_value_2) * earth_radius;
// return the minimum
return static_cast<int>(std::min(dist1, dist2));
@@ -90,7 +88,7 @@ void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const
void DouglasPeucker::Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level)
{
- unsigned size = std::distance(begin, end);
+ const auto size = std::distance(begin, end);
if (size < 2)
{
return;
diff --git a/algorithms/douglas_peucker.hpp b/algorithms/douglas_peucker.hpp
index 417e80a..da02982 100644
--- a/algorithms/douglas_peucker.hpp
+++ b/algorithms/douglas_peucker.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,9 +28,12 @@ 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>
-#include <array>
/* This class object computes the bitvector of indicating generalized input
* points according to the (Ramer-)Douglas-Peucker algorithm.
@@ -39,9 +42,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* bit indicating if the points is present in the generalization.
* Note: points may also be pre-selected*/
-struct SegmentInformation;
-
-static const std::array<int, 19> DOUGLAS_PEUCKER_THRESHOLDS {{
+static const std::array<int, 19> DOUGLAS_PEUCKER_THRESHOLDS{{
512440, // z0
256720, // z1
122560, // z2
diff --git a/algorithms/object_encoder.hpp b/algorithms/object_encoder.hpp
index af6e0d9..e880496 100644
--- a/algorithms/object_encoder.hpp
+++ b/algorithms/object_encoder.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,7 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef OBJECT_ENCODER_HPP
#define OBJECT_ENCODER_HPP
-#include "../Util/string_util.hpp"
+#include "../util/string_util.hpp"
#include <boost/assert.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
@@ -49,10 +49,9 @@ struct ObjectEncoder
8,
6>;
- template <class ObjectT>
- static void EncodeToBase64(const ObjectT &object, std::string &encoded)
+ template <class ObjectT> static void EncodeToBase64(const ObjectT &object, std::string &encoded)
{
- const char *char_ptr_to_object = (const char *)&object;
+ 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());
@@ -71,8 +70,7 @@ struct ObjectEncoder
replaceAll(encoded, "/", "_");
}
- template <class ObjectT>
- static void DecodeFromBase64(const std::string &input, ObjectT &object)
+ template <class ObjectT> static void DecodeFromBase64(const std::string &input, ObjectT &object)
{
try
{
@@ -81,9 +79,8 @@ struct ObjectEncoder
replaceAll(encoded, "-", "+");
replaceAll(encoded, "_", "/");
- std::copy(binary_t(encoded.begin()),
- binary_t(encoded.begin() + encoded.length() - 1),
- (char *)&object);
+ std::copy(binary_t(encoded.begin()), binary_t(encoded.begin() + encoded.length() - 1),
+ reinterpret_cast<char *>(&object));
}
catch (...)
{
diff --git a/algorithms/polyline_compressor.cpp b/algorithms/polyline_compressor.cpp
index 2f2972b..d5fd582 100644
--- a/algorithms/polyline_compressor.cpp
+++ b/algorithms/polyline_compressor.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,7 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "polyline_compressor.hpp"
#include "../data_structures/segment_information.hpp"
-#include <osrm/Coordinate.h>
+#include <osrm/coordinate.hpp>
std::string PolylineCompressor::encode_vector(std::vector<int> &numbers) const
{
@@ -56,19 +56,11 @@ std::string PolylineCompressor::encode_number(int number_to_encode) const
{
const int next_value = (0x20 | (number_to_encode & 0x1f)) + 63;
output += static_cast<char>(next_value);
- if (92 == next_value)
- {
- output += static_cast<char>(next_value);
- }
number_to_encode >>= 5;
}
number_to_encode += 63;
output += static_cast<char>(number_to_encode);
- if (92 == number_to_encode)
- {
- output += static_cast<char>(number_to_encode);
- }
return output;
}
diff --git a/algorithms/polyline_compressor.hpp b/algorithms/polyline_compressor.hpp
index 8bff4a0..933ac7a 100644
--- a/algorithms/polyline_compressor.hpp
+++ b/algorithms/polyline_compressor.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/algorithms/polyline_formatter.cpp b/algorithms/polyline_formatter.cpp
index d72496a..670a612 100644
--- a/algorithms/polyline_formatter.cpp
+++ b/algorithms/polyline_formatter.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,23 +30,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "polyline_compressor.hpp"
#include "../data_structures/segment_information.hpp"
-#include <osrm/Coordinate.h>
+#include <osrm/coordinate.hpp>
-JSON::String
+osrm::json::String
PolylineFormatter::printEncodedString(const std::vector<SegmentInformation> &polyline) const
{
- return JSON::String(PolylineCompressor().get_encoded_string(polyline));
+ return osrm::json::String(PolylineCompressor().get_encoded_string(polyline));
}
-JSON::Array
+osrm::json::Array
PolylineFormatter::printUnencodedString(const std::vector<SegmentInformation> &polyline) const
{
- JSON::Array json_geometry_array;
+ osrm::json::Array json_geometry_array;
for (const auto &segment : polyline)
{
if (segment.necessary)
{
- JSON::Array json_coordinate;
+ 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);
diff --git a/algorithms/polyline_formatter.hpp b/algorithms/polyline_formatter.hpp
index 1d4744d..68cc702 100644
--- a/algorithms/polyline_formatter.hpp
+++ b/algorithms/polyline_formatter.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,16 +30,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct SegmentInformation;
-#include "../data_structures/json_container.hpp"
+#include <osrm/json_container.hpp>
#include <string>
#include <vector>
struct PolylineFormatter
{
- JSON::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
+ osrm::json::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
- JSON::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
+ osrm::json::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
};
#endif /* POLYLINE_FORMATTER_HPP */
diff --git a/algorithms/route_name_extraction.hpp b/algorithms/route_name_extraction.hpp
index 519452f..00dae89 100644
--- a/algorithms/route_name_extraction.hpp
+++ b/algorithms/route_name_extraction.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -54,7 +54,8 @@ template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
for (const SegmentT &segment : segment_list)
{
- if (segment.name_id != blocked_name_id && segment.length > result_segment.length && segment.name_id != 0)
+ if (segment.name_id != blocked_name_id && segment.length > result_segment.length &&
+ segment.name_id != 0)
{
result_segment = segment;
}
@@ -73,9 +74,13 @@ template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
SegmentT alternative_segment_1, alternative_segment_2;
auto length_comperator = [](const SegmentT &a, const SegmentT &b)
- { return a.length > b.length; };
+ {
+ return a.length > b.length;
+ };
auto name_id_comperator = [](const SegmentT &a, const SegmentT &b)
- { return a.name_id < b.name_id; };
+ {
+ return a.name_id < b.name_id;
+ };
if (shortest_path_segments.empty())
{
@@ -87,8 +92,7 @@ template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
shortest_segment_1 = shortest_path_segments[0];
if (!alternative_path_segments.empty())
{
- std::sort(alternative_path_segments.begin(),
- alternative_path_segments.end(),
+ std::sort(alternative_path_segments.begin(), alternative_path_segments.end(),
length_comperator);
// also pick the longest segment for the alternative path
@@ -99,16 +103,13 @@ template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
// 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(),
+ 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);
@@ -116,29 +117,23 @@ template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
// 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(),
+ 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));
+ 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(),
+ 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);
+ alternative_segment_1.name_id);
}
// move the segments into the order in which they occur.
@@ -152,15 +147,13 @@ template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
}
// fetching names for the selected segments
- route_names.shortest_path_name_1 =
- facade->GetEscapedNameForNameID(shortest_segment_1.name_id);
- route_names.shortest_path_name_2 =
- facade->GetEscapedNameForNameID(shortest_segment_2.name_id);
+ 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->GetEscapedNameForNameID(alternative_segment_1.name_id);
+ facade->get_name_for_id(alternative_segment_1.name_id);
route_names.alternative_path_name_2 =
- facade->GetEscapedNameForNameID(alternative_segment_2.name_id);
+ facade->get_name_for_id(alternative_segment_2.name_id);
return route_names;
}
diff --git a/algorithms/tiny_components.hpp b/algorithms/tiny_components.hpp
index 5cf5a75..8eb61a9 100644
--- a/algorithms/tiny_components.hpp
+++ b/algorithms/tiny_components.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -37,18 +37,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../data_structures/restriction_map.hpp"
#include "../data_structures/turn_instructions.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.h>
+#include <osrm/coordinate.hpp>
#include <boost/assert.hpp>
#include <tbb/parallel_sort.h>
-
#include <cstdint>
#include <memory>
@@ -57,8 +56,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unordered_set>
#include <vector>
-template <typename GraphT>
-class TarjanSCC
+template <typename GraphT> class TarjanSCC
{
struct TarjanStackFrame
{
@@ -80,16 +78,15 @@ class TarjanSCC
std::shared_ptr<GraphT> m_node_based_graph;
std::unordered_set<NodeID> barrier_node_set;
RestrictionMap m_restriction_map;
- unsigned size_one_counter;
+ std::size_t size_one_counter;
public:
- template<class ContainerT>
+ template <class ContainerT>
TarjanSCC(std::shared_ptr<GraphT> graph,
const RestrictionMap &restrictions,
const ContainerT &barrier_node_list)
- : components_index(graph->GetNumberOfNodes(), SPECIAL_NODEID),
- m_node_based_graph(graph), m_restriction_map(restrictions),
- size_one_counter(0)
+ : components_index(graph->GetNumberOfNodes(), SPECIAL_NODEID), m_node_based_graph(graph),
+ m_restriction_map(restrictions), size_one_counter(0)
{
barrier_node_set.insert(std::begin(barrier_node_list), std::end(barrier_node_list));
BOOST_ASSERT(m_node_based_graph->GetNumberOfNodes() > 0);
@@ -98,17 +95,18 @@ class TarjanSCC
void run()
{
TIMER_START(SCC_RUN);
+ const NodeID max_node_id = m_node_based_graph->GetNumberOfNodes();
+
// The following is a hack to distinguish between stuff that happens
// before the recursive call and stuff that happens after
std::stack<TarjanStackFrame> recursion_stack;
// true = stuff before, false = stuff after call
std::stack<NodeID> tarjan_stack;
- std::vector<TarjanNode> tarjan_node_list(m_node_based_graph->GetNumberOfNodes());
+ std::vector<TarjanNode> tarjan_node_list(max_node_id);
unsigned component_index = 0, size_of_current_component = 0;
- int index = 0;
- const NodeID last_node = m_node_based_graph->GetNumberOfNodes();
- std::vector<bool> processing_node_before_recursion(m_node_based_graph->GetNumberOfNodes(), true);
- for(const NodeID node : osrm::irange(0u, last_node))
+ unsigned index = 0;
+ std::vector<bool> processing_node_before_recursion(max_node_id, true);
+ for (const NodeID node : osrm::irange(0u, max_node_id))
{
if (SPECIAL_NODEID == components_index[node])
{
@@ -150,13 +148,11 @@ class TarjanSCC
const auto vprime = m_node_based_graph->GetTarget(current_edge);
// Traverse outgoing edges
- if (barrier_node_set.find(v) != barrier_node_set.end() &&
- u != vprime)
+ if (barrier_node_set.find(v) != barrier_node_set.end() && u != vprime)
{
// continue;
}
-
if (to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
vprime == to_node_of_only_restriction)
{
@@ -219,35 +215,25 @@ class TarjanSCC
}
TIMER_STOP(SCC_RUN);
- SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN)/1000. << "s";
+ 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(),
+ size_one_counter = std::count_if(component_size_vector.begin(), component_size_vector.end(),
[](unsigned value)
{
- return 1 == value;
- });
+ return 1 == value;
+ });
}
- std::size_t get_number_of_components() const
- {
- return component_size_vector.size();
- }
+ std::size_t get_number_of_components() const { return component_size_vector.size(); }
- unsigned get_size_one_count() const
- {
- return size_one_counter;
- }
+ std::size_t get_size_one_count() const { return size_one_counter; }
unsigned get_component_size(const NodeID node) const
{
return component_size_vector[components_index[node]];
}
- unsigned get_component_id(const NodeID node) const
- {
- return components_index[node];
- }
+ unsigned get_component_id(const NodeID node) const { return components_index[node]; }
};
#endif /* TINY_COMPONENTS_HPP */
diff --git a/appveyor.yml b/appveyor.yml
index e650e1a..afb8dd4 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -9,9 +9,6 @@ branches:
only:
- develop
-# Operating system (build VM template)
-os: Windows Server 2012 R2
-
# scripts that are called at very beginning, before repo cloning
init:
- git config --global core.autocrlf input
diff --git a/benchmarks/static_rtree.cpp b/benchmarks/static_rtree.cpp
index 7a24cfc..9d88331 100644
--- a/benchmarks/static_rtree.cpp
+++ b/benchmarks/static_rtree.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -29,10 +29,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../data_structures/query_node.hpp"
#include "../data_structures/shared_memory_vector_wrapper.hpp"
#include "../data_structures/static_rtree.hpp"
+#include "../util/boost_filesystem_2_fix.hpp"
#include "../data_structures/edge_based_node.hpp"
-#include "../Util/BoostFileSystemFix.h"
-#include <osrm/Coordinate.h>
+#include <osrm/coordinate.hpp>
#include <random>
@@ -88,11 +88,9 @@ void Benchmark(BenchStaticRTree &rtree, unsigned num_queries)
for (const auto &q : queries)
{
phantom_node_vector.clear();
- rtree.IncrementalFindPhantomNodeForCoordinate(
- q, phantom_node_vector, 3, num_results);
+ rtree.IncrementalFindPhantomNodeForCoordinate(q, phantom_node_vector, 3, num_results);
phantom_node_vector.clear();
- rtree.IncrementalFindPhantomNodeForCoordinate(
- q, phantom_node_vector, 17, num_results);
+ rtree.IncrementalFindPhantomNodeForCoordinate(q, phantom_node_vector, 17, num_results);
}
TIMER_STOP(query_phantom);
@@ -130,8 +128,7 @@ void Benchmark(BenchStaticRTree &rtree, unsigned num_queries)
}
TIMER_STOP(query_node);
- std::cout << "Took " << TIMER_MSEC(query_node) << " msec for " << num_queries
- << " queries."
+ std::cout << "Took " << TIMER_MSEC(query_node) << " msec for " << num_queries << " queries."
<< "\n";
std::cout << TIMER_MSEC(query_node) / ((double)num_queries) << " msec/query."
<< "\n";
@@ -147,11 +144,9 @@ void Benchmark(BenchStaticRTree &rtree, unsigned num_queries)
for (const auto &q : queries)
{
phantom_node_vector.clear();
- rtree.IncrementalFindPhantomNodeForCoordinate(
- q, phantom_node_vector, 3, num_results);
+ rtree.IncrementalFindPhantomNodeForCoordinate(q, phantom_node_vector, 3, num_results);
phantom_node_vector.clear();
- rtree.IncrementalFindPhantomNodeForCoordinate(
- q, phantom_node_vector, 17, num_results);
+ rtree.IncrementalFindPhantomNodeForCoordinate(q, phantom_node_vector, 17, num_results);
}
TIMER_STOP(query_phantom);
diff --git a/cmake/FingerPrint-Config.cmake b/cmake/FingerPrint-Config.cmake
index 710368d..a3325d3 100644
--- a/cmake/FingerPrint-Config.cmake
+++ b/cmake/FingerPrint-Config.cmake
@@ -1,10 +1,10 @@
-set(OLDFILE ${SOURCE_DIR}/Util/FingerPrint.cpp)
+set(OLDFILE ${SOURCE_DIR}/util/fingerprint_impl.hpp)
if (EXISTS ${OLDFILE})
file(REMOVE_RECURSE ${OLDFILE})
endif()
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/DataStructures/InternalDataFacade.h MD5OBJECTS)
+file(MD5 ${SOURCE_DIR}/util/graph_loader.hpp MD5GRAPH)
+file(MD5 ${SOURCE_DIR}/server/data_structures/internal_datafacade.hpp MD5OBJECTS)
-CONFIGURE_FILE( ${SOURCE_DIR}/Util/finger_print.cpp.in ${SOURCE_DIR}/Util/finger_print.cpp )
+CONFIGURE_FILE(${SOURCE_DIR}/util/fingerprint_impl.hpp.in ${SOURCE_DIR}/util/fingerprint_impl.hpp)
diff --git a/contractor/contractor.hpp b/contractor/contractor.hpp
index c8c107c..ccfabbc 100644
--- a/contractor/contractor.hpp
+++ b/contractor/contractor.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -35,9 +35,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#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 "../util/integer_range.hpp"
+#include "../util/simple_logger.hpp"
+#include "../util/timing_util.hpp"
#include "../typedefs.h"
#include <boost/assert.hpp>
@@ -92,9 +92,11 @@ class Contractor
};
using ContractorGraph = DynamicGraph<ContractorEdgeData>;
- // using ContractorHeap = BinaryHeap<NodeID, NodeID, int, ContractorHeapData, ArrayStorage<NodeID, NodeID>
+ // using ContractorHeap = BinaryHeap<NodeID, NodeID, int, ContractorHeapData,
+ // ArrayStorage<NodeID, NodeID>
// >;
- using ContractorHeap = BinaryHeap<NodeID, NodeID, int, ContractorHeapData, XORFastHashStorage<NodeID, NodeID>>;
+ using ContractorHeap =
+ BinaryHeap<NodeID, NodeID, int, ContractorHeapData, XORFastHashStorage<NodeID, NodeID>>;
using ContractorEdge = ContractorGraph::InputEdge;
struct ContractorThreadData
@@ -131,15 +133,14 @@ class Contractor
bool is_independent : 1;
};
-
struct ThreadDataContainer
{
- explicit ThreadDataContainer(int number_of_nodes) : number_of_nodes(number_of_nodes) {}
+ explicit ThreadDataContainer(int number_of_nodes) : number_of_nodes(number_of_nodes) {}
- inline ContractorThreadData* getThreadData()
+ inline ContractorThreadData *getThreadData()
{
bool exists = false;
- auto& ref = data.local(exists);
+ auto &ref = data.local(exists);
if (!exists)
{
ref = std::make_shared<ContractorThreadData>(number_of_nodes);
@@ -149,7 +150,8 @@ class Contractor
}
int number_of_nodes;
- using EnumerableThreadData = tbb::enumerable_thread_specific<std::shared_ptr<ContractorThreadData>>;
+ using EnumerableThreadData =
+ tbb::enumerable_thread_specific<std::shared_ptr<ContractorThreadData>>;
EnumerableThreadData data;
};
@@ -162,29 +164,25 @@ class Contractor
const auto dend = input_edge_list.dend();
for (auto diter = input_edge_list.dbegin(); diter != dend; ++diter)
{
- BOOST_ASSERT_MSG(static_cast<unsigned int>(std::max(diter->weight, 1)) > 0, "edge distance < 1");
+ BOOST_ASSERT_MSG(static_cast<unsigned int>(std::max(diter->weight, 1)) > 0,
+ "edge distance < 1");
#ifndef NDEBUG
if (static_cast<unsigned int>(std::max(diter->weight, 1)) > 24 * 60 * 60 * 10)
{
- SimpleLogger().Write(logWARNING) << "Edge weight large -> "
- << static_cast<unsigned int>(std::max(diter->weight, 1));
+ SimpleLogger().Write(logWARNING)
+ << "Edge weight large -> "
+ << static_cast<unsigned int>(std::max(diter->weight, 1));
}
#endif
edges.emplace_back(diter->source, diter->target,
- static_cast<unsigned int>(std::max(diter->weight, 1)),
- 1,
- diter->edge_id,
- false,
- diter->forward ? true : false,
- diter->backward ? true : false);
+ static_cast<unsigned int>(std::max(diter->weight, 1)), 1,
+ diter->edge_id, false, diter->forward ? true : false,
+ diter->backward ? true : false);
edges.emplace_back(diter->target, diter->source,
- static_cast<unsigned int>(std::max(diter->weight, 1)),
- 1,
- diter->edge_id,
- false,
- diter->backward ? true : false,
- diter->forward ? true : false);
+ static_cast<unsigned int>(std::max(diter->weight, 1)), 1,
+ diter->edge_id, false, diter->backward ? true : false,
+ diter->forward ? true : false);
}
// clear input vector
input_edge_list.clear();
@@ -282,20 +280,20 @@ class Contractor
std::cout << "contractor finished initalization" << std::endl;
}
- ~Contractor() { }
+ ~Contractor() {}
void Run()
{
// 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;
+ constexpr size_t InitGrainSize = 100000;
+ 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;
+ constexpr size_t ContractGrainSize = 1;
+ constexpr size_t NeighboursGrainSize = 1;
+ constexpr size_t DeleteGrainSize = 1;
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
Percent p(number_of_nodes);
@@ -307,30 +305,28 @@ class Contractor
std::vector<float> node_priorities(number_of_nodes);
std::vector<NodePriorityData> node_data(number_of_nodes);
-
// initialize priorities in parallel
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, InitGrainSize),
- [&remaining_nodes](const tbb::blocked_range<int>& range)
- {
- for (int x = range.begin(); x != range.end(); ++x)
- {
- remaining_nodes[x].id = x;
- }
- }
- );
-
+ [&remaining_nodes](const tbb::blocked_range<int> &range)
+ {
+ for (int x = range.begin(); x != range.end(); ++x)
+ {
+ remaining_nodes[x].id = x;
+ }
+ });
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)
- {
- ContractorThreadData *data = thread_data_list.getThreadData();
- for (int x = range.begin(); x != range.end(); ++x)
- {
- node_priorities[x] = this->EvaluateNodePriority(data, &node_data[x], x);
- }
- }
- );
+ [this, &node_priorities, &node_data, &thread_data_list](
+ const tbb::blocked_range<int> &range)
+ {
+ ContractorThreadData *data = thread_data_list.getThreadData();
+ for (int x = range.begin(); x != range.end(); ++x)
+ {
+ node_priorities[x] =
+ this->EvaluateNodePriority(data, &node_data[x], x);
+ }
+ });
std::cout << "ok" << std::endl << "preprocessing " << number_of_nodes << " nodes ..."
<< std::flush;
@@ -368,7 +364,8 @@ class Contractor
remaining_nodes[new_node_id].id = new_node_id;
}
// walk over all nodes
- for (const auto i : osrm::irange<std::size_t>(0, contractor_graph->GetNumberOfNodes()))
+ for (const auto i :
+ osrm::irange<std::size_t>(0, contractor_graph->GetNumberOfNodes()))
{
const NodeID source = i;
for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(source))
@@ -384,11 +381,9 @@ class Contractor
{
// node is not yet contracted.
// add (renumbered) outgoing edges to new DynamicGraph.
- ContractorEdge new_edge = {
- new_node_id_from_orig_id_map[source],
- new_node_id_from_orig_id_map[target],
- data
- };
+ ContractorEdge new_edge = {new_node_id_from_orig_id_map[source],
+ 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],
@@ -427,28 +422,30 @@ class Contractor
const int last = (int)remaining_nodes.size();
tbb::parallel_for(tbb::blocked_range<int>(0, last, IndependentGrainSize),
- [this, &node_priorities, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
- {
- ContractorThreadData *data = thread_data_list.getThreadData();
- // determine independent node set
- for (int i = range.begin(); i != range.end(); ++i)
- {
- const NodeID node = remaining_nodes[i].id;
- remaining_nodes[i].is_independent =
- this->IsNodeIndependent(node_priorities, data, node);
- }
- }
- );
-
- const auto first = stable_partition(remaining_nodes.begin(),
- remaining_nodes.end(),
+ [this, &node_priorities, &remaining_nodes, &thread_data_list](
+ const tbb::blocked_range<int> &range)
+ {
+ ContractorThreadData *data = thread_data_list.getThreadData();
+ // determine independent node set
+ for (int i = range.begin(); i != range.end(); ++i)
+ {
+ const NodeID node = remaining_nodes[i].id;
+ remaining_nodes[i].is_independent =
+ this->IsNodeIndependent(node_priorities, data, node);
+ }
+ });
+
+ const auto first = stable_partition(remaining_nodes.begin(), remaining_nodes.end(),
[](RemainingNodeData node_data)
- { return !node_data.is_independent; });
+ {
+ return !node_data.is_independent;
+ });
const int first_independent_node = static_cast<int>(first - remaining_nodes.begin());
// contract independent nodes
- tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, ContractGrainSize),
- [this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
+ tbb::parallel_for(
+ tbb::blocked_range<int>(first_independent_node, last, ContractGrainSize),
+ [this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int> &range)
{
ContractorThreadData *data = thread_data_list.getThreadData();
for (int position = range.begin(); position != range.end(); ++position)
@@ -456,19 +453,18 @@ class Contractor
const NodeID x = remaining_nodes[position].id;
this->ContractNode<false>(data, x);
}
- }
- );
+ });
// make sure we really sort each block
- tbb::parallel_for(thread_data_list.data.range(),
- [&](const ThreadDataContainer::EnumerableThreadData::range_type& range)
+ tbb::parallel_for(
+ thread_data_list.data.range(),
+ [&](const ThreadDataContainer::EnumerableThreadData::range_type &range)
{
- for (auto& data : range)
- std::sort(data->inserted_edges.begin(),
- data->inserted_edges.end());
- }
- );
- tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, DeleteGrainSize),
- [this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
+ for (auto &data : range)
+ std::sort(data->inserted_edges.begin(), data->inserted_edges.end());
+ });
+ tbb::parallel_for(
+ tbb::blocked_range<int>(first_independent_node, last, DeleteGrainSize),
+ [this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int> &range)
{
ContractorThreadData *data = thread_data_list.getThreadData();
for (int position = range.begin(); position != range.end(); ++position)
@@ -476,15 +472,15 @@ class Contractor
const NodeID x = remaining_nodes[position].id;
this->DeleteIncomingEdges(data, x);
}
- }
- );
+ });
// insert new edges
- for (auto& data : thread_data_list.data)
+ for (auto &data : thread_data_list.data)
{
for (const ContractorEdge &edge : data->inserted_edges)
{
- const EdgeID current_edge_ID = contractor_graph->FindEdge(edge.source, edge.target);
+ const EdgeID current_edge_ID =
+ contractor_graph->FindEdge(edge.source, edge.target);
if (current_edge_ID < contractor_graph->EndEdges(edge.source))
{
ContractorGraph::EdgeData ¤t_data =
@@ -503,8 +499,10 @@ class Contractor
data->inserted_edges.clear();
}
- tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, NeighboursGrainSize),
- [this, &remaining_nodes, &node_priorities, &node_data, &thread_data_list](const tbb::blocked_range<int>& range)
+ tbb::parallel_for(
+ tbb::blocked_range<int>(first_independent_node, last, NeighboursGrainSize),
+ [this, &remaining_nodes, &node_priorities, &node_data, &thread_data_list](
+ const tbb::blocked_range<int> &range)
{
ContractorThreadData *data = thread_data_list.getThreadData();
for (int position = range.begin(); position != range.end(); ++position)
@@ -512,8 +510,7 @@ class Contractor
NodeID x = remaining_nodes[position].id;
this->UpdateNodeNeighbours(node_priorities, node_data, data, x);
}
- }
- );
+ });
// remove contracted nodes from the pool
number_of_contracted_nodes += last - first_independent_node;
@@ -774,17 +771,11 @@ class Contractor
{
inserted_edges.emplace_back(source, target, path_distance,
out_data.originalEdges + in_data.originalEdges,
- node,
- true,
- true,
- false);
+ node, true, true, false);
inserted_edges.emplace_back(target, source, path_distance,
out_data.originalEdges + in_data.originalEdges,
- node,
- true,
- false,
- true);
+ node, true, false, true);
}
}
}
@@ -883,10 +874,9 @@ class Contractor
return true;
}
- inline bool IsNodeIndependent(
- const std::vector<float> &priorities,
- ContractorThreadData *const data,
- NodeID node) const
+ inline bool IsNodeIndependent(const std::vector<float> &priorities,
+ ContractorThreadData *const data,
+ NodeID node) const
{
const float priority = priorities[node];
diff --git a/contractor/edge_based_graph_factory.cpp b/contractor/edge_based_graph_factory.cpp
index 144b1fa..268bb9f 100644
--- a/contractor/edge_based_graph_factory.cpp
+++ b/contractor/edge_based_graph_factory.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,11 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "edge_based_graph_factory.hpp"
#include "../algorithms/tiny_components.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/compute_angle.hpp"
+#include "../util/integer_range.hpp"
+#include "../util/lua_util.hpp"
+#include "../util/simple_logger.hpp"
+#include "../util/timing_util.hpp"
#include <boost/assert.hpp>
@@ -77,33 +77,25 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes)
nodes.swap(m_edge_based_node_list);
}
-void
-EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
- const NodeID node_v,
- const unsigned component_id)
+void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
+ const NodeID node_v,
+ const unsigned component_id)
{
// 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 e1 = m_node_based_graph->FindEdge(node_u, node_v);
- BOOST_ASSERT(e1 != SPECIAL_EDGEID);
+ 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(e1);
+ const EdgeData &forward_data = m_node_based_graph->GetEdgeData(edge_id_1);
// find reverse edge id and
- const EdgeID e2 = m_node_based_graph->FindEdge(node_v, node_u);
+ const EdgeID edge_id_2 = m_node_based_graph->FindEdge(node_v, node_u);
+ BOOST_ASSERT(edge_id_2 != SPECIAL_EDGEID);
-#ifndef NDEBUG
- if (e2 == m_node_based_graph->EndEdges(node_v))
- {
- SimpleLogger().Write(logWARNING) << "Did not find edge (" << node_v << "," << node_u << ")";
- }
-#endif
- BOOST_ASSERT(e2 != SPECIAL_EDGEID);
- BOOST_ASSERT(e2 < m_node_based_graph->EndEdges(node_v));
- const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(e2);
+ const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(edge_id_2);
if (forward_data.edgeBasedNodeID == SPECIAL_NODEID &&
reverse_data.edgeBasedNodeID == SPECIAL_NODEID)
@@ -111,17 +103,17 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
return;
}
- BOOST_ASSERT(m_geometry_compressor.HasEntryForID(e1) ==
- m_geometry_compressor.HasEntryForID(e2));
- if (m_geometry_compressor.HasEntryForID(e1))
+ BOOST_ASSERT(m_geometry_compressor.HasEntryForID(edge_id_1) ==
+ m_geometry_compressor.HasEntryForID(edge_id_2));
+ if (m_geometry_compressor.HasEntryForID(edge_id_1))
{
- BOOST_ASSERT(m_geometry_compressor.HasEntryForID(e2));
+ BOOST_ASSERT(m_geometry_compressor.HasEntryForID(edge_id_2));
// reconstruct geometry and put in each individual edge with its offset
const std::vector<GeometryCompressor::CompressedNode> &forward_geometry =
- m_geometry_compressor.GetBucketReference(e1);
+ m_geometry_compressor.GetBucketReference(edge_id_1);
const std::vector<GeometryCompressor::CompressedNode> &reverse_geometry =
- m_geometry_compressor.GetBucketReference(e2);
+ m_geometry_compressor.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());
@@ -172,20 +164,13 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
// build edges
- m_edge_based_node_list.emplace_back(forward_data.edgeBasedNodeID,
- reverse_data.edgeBasedNodeID,
- current_edge_source_coordinate_id,
- current_edge_target_coordinate_id,
- forward_data.nameID,
- forward_geometry[i].second,
- reverse_geometry[geometry_size - 1 - i].second,
- forward_dist_prefix_sum[i],
- reverse_dist_prefix_sum[i],
- m_geometry_compressor.GetPositionForID(e1),
- component_id,
- i,
- forward_data.travel_mode,
- reverse_data.travel_mode);
+ m_edge_based_node_list.emplace_back(
+ forward_data.edgeBasedNodeID, reverse_data.edgeBasedNodeID,
+ current_edge_source_coordinate_id, current_edge_target_coordinate_id,
+ forward_data.nameID, forward_geometry[i].second,
+ reverse_geometry[geometry_size - 1 - i].second, forward_dist_prefix_sum[i],
+ reverse_dist_prefix_sum[i], m_geometry_compressor.GetPositionForID(edge_id_1),
+ component_id, i, forward_data.travel_mode, reverse_data.travel_mode);
current_edge_source_coordinate_id = current_edge_target_coordinate_id;
BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
@@ -202,7 +187,7 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
}
else
{
- BOOST_ASSERT(!m_geometry_compressor.HasEntryForID(e2));
+ BOOST_ASSERT(!m_geometry_compressor.HasEntryForID(edge_id_2));
if (forward_data.edgeBasedNodeID != SPECIAL_NODEID)
{
@@ -224,20 +209,10 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
BOOST_ASSERT(forward_data.edgeBasedNodeID != SPECIAL_NODEID ||
reverse_data.edgeBasedNodeID != SPECIAL_NODEID);
- m_edge_based_node_list.emplace_back(forward_data.edgeBasedNodeID,
- reverse_data.edgeBasedNodeID,
- node_u,
- node_v,
- forward_data.nameID,
- forward_data.distance,
- reverse_data.distance,
- 0,
- 0,
- SPECIAL_EDGEID,
- component_id,
- 0,
- forward_data.travel_mode,
- reverse_data.travel_mode);
+ m_edge_based_node_list.emplace_back(
+ forward_data.edgeBasedNodeID, reverse_data.edgeBasedNodeID, node_u, node_v,
+ forward_data.nameID, forward_data.distance, reverse_data.distance, 0, 0, SPECIAL_EDGEID,
+ component_id, 0, forward_data.travel_mode, reverse_data.travel_mode);
BOOST_ASSERT(!m_edge_based_node_list.back().IsCompressed());
}
}
@@ -245,7 +220,8 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
void EdgeBasedGraphFactory::FlushVectorToStream(
std::ofstream &edge_data_file, std::vector<OriginalEdgeData> &original_edge_data_vector) const
{
- if (original_edge_data_vector.empty()) {
+ if (original_edge_data_vector.empty())
+ {
return;
}
edge_data_file.write((char *)&(original_edge_data_vector[0]),
@@ -332,7 +308,6 @@ void EdgeBasedGraphFactory::CompressGeometry()
BOOST_ASSERT(node_u != node_v);
const EdgeID forward_e1 = m_node_based_graph->FindEdge(node_u, node_v);
- BOOST_ASSERT(m_node_based_graph->EndEdges(node_u) != forward_e1);
BOOST_ASSERT(SPECIAL_EDGEID != forward_e1);
BOOST_ASSERT(node_v == m_node_based_graph->GetTarget(forward_e1));
const EdgeID reverse_e1 = m_node_based_graph->FindEdge(node_w, node_v);
@@ -342,15 +317,13 @@ void EdgeBasedGraphFactory::CompressGeometry()
const EdgeData &fwd_edge_data1 = m_node_based_graph->GetEdgeData(forward_e1);
const EdgeData &rev_edge_data1 = m_node_based_graph->GetEdgeData(reverse_e1);
- if ((m_node_based_graph->FindEdge(node_u, node_w) != m_node_based_graph->EndEdges(node_u)) ||
- (m_node_based_graph->FindEdge(node_w, node_u) != m_node_based_graph->EndEdges(node_w)))
+ if (m_node_based_graph->FindEdgeInEitherDirection(node_u, node_w) != SPECIAL_EDGEID)
{
continue;
}
if ( // TODO: rename to IsCompatibleTo
- fwd_edge_data1.IsEqualTo(fwd_edge_data2) &&
- rev_edge_data1.IsEqualTo(rev_edge_data2))
+ fwd_edge_data1.IsEqualTo(fwd_edge_data2) && rev_edge_data1.IsEqualTo(rev_edge_data2))
{
// Get distances before graph is modified
const int forward_weight1 = m_node_based_graph->GetEdgeData(forward_e1).distance;
@@ -365,13 +338,12 @@ void EdgeBasedGraphFactory::CompressGeometry()
BOOST_ASSERT(0 != reverse_weight1);
BOOST_ASSERT(0 != forward_weight2);
- const bool add_traffic_signal_penalty =
- (m_traffic_lights.find(node_v) != m_traffic_lights.end());
+ const bool has_node_penalty = m_traffic_lights.find(node_v) != m_traffic_lights.end();
// add weight of e2's to e1
m_node_based_graph->GetEdgeData(forward_e1).distance += fwd_edge_data2.distance;
m_node_based_graph->GetEdgeData(reverse_e1).distance += rev_edge_data2.distance;
- if (add_traffic_signal_penalty)
+ if (has_node_penalty)
{
m_node_based_graph->GetEdgeData(forward_e1).distance +=
speed_profile.traffic_signal_penalty;
@@ -389,32 +361,21 @@ void EdgeBasedGraphFactory::CompressGeometry()
// update any involved turn restrictions
m_restriction_map->FixupStartingTurnRestriction(node_u, node_v, node_w);
- m_restriction_map->FixupArrivingTurnRestriction(node_u, node_v,
- node_w,
+ m_restriction_map->FixupArrivingTurnRestriction(node_u, node_v, node_w,
m_node_based_graph);
m_restriction_map->FixupStartingTurnRestriction(node_w, node_v, node_u);
- m_restriction_map->FixupArrivingTurnRestriction(node_w,
- node_v,
- node_u, m_node_based_graph);
+ m_restriction_map->FixupArrivingTurnRestriction(node_w, node_v, node_u,
+ m_node_based_graph);
// store compressed geometry in container
m_geometry_compressor.CompressEdge(
- forward_e1,
- forward_e2,
- node_v,
- node_w,
- forward_weight1 +
- (add_traffic_signal_penalty ? speed_profile.traffic_signal_penalty : 0),
+ forward_e1, forward_e2, node_v, node_w,
+ forward_weight1 + (has_node_penalty ? speed_profile.traffic_signal_penalty : 0),
forward_weight2);
m_geometry_compressor.CompressEdge(
- reverse_e1,
- reverse_e2,
- node_v,
- node_u,
- reverse_weight1,
- reverse_weight2 +
- (add_traffic_signal_penalty ? speed_profile.traffic_signal_penalty : 0));
+ reverse_e1, reverse_e2, node_v, node_u, reverse_weight1,
+ reverse_weight2 + (has_node_penalty ? speed_profile.traffic_signal_penalty : 0));
++removed_node_count;
BOOST_ASSERT(m_node_based_graph->GetEdgeData(forward_e1).nameID ==
@@ -427,7 +388,7 @@ void EdgeBasedGraphFactory::CompressGeometry()
unsigned new_node_count = 0;
unsigned new_edge_count = 0;
- for(const auto i : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
+ for (const auto i : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
if (m_node_based_graph->GetOutDegree(i) > 0)
{
@@ -436,10 +397,10 @@ void EdgeBasedGraphFactory::CompressGeometry()
}
}
SimpleLogger().Write() << "new nodes: " << new_node_count << ", edges " << new_edge_count;
- 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;
+ 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;
}
/**
@@ -477,62 +438,69 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
SimpleLogger().Write() << "Identifying components of the (compressed) road network";
// Run a BFS on the undirected graph and identify small components
- TarjanSCC<NodeBasedDynamicGraph> component_explorer(
- m_node_based_graph, *m_restriction_map, m_barrier_nodes);
+ TarjanSCC<NodeBasedDynamicGraph> component_explorer(m_node_based_graph, *m_restriction_map,
+ m_barrier_nodes);
component_explorer.run();
- SimpleLogger().Write() << "identified: " << component_explorer.get_number_of_components() - removed_node_count
+ SimpleLogger().Write() << "identified: "
+ << component_explorer.get_number_of_components() - removed_node_count
<< " (compressed) components";
- SimpleLogger().Write() << "identified " << component_explorer.get_size_one_count() - removed_node_count
+ SimpleLogger().Write() << "identified "
+ << component_explorer.get_size_one_count() - removed_node_count
<< " (compressed) SCCs of size 1";
SimpleLogger().Write() << "generating edge-expanded nodes";
Percent progress(m_node_based_graph->GetNumberOfNodes());
// loop over all edges and generate new set of nodes
- for (const auto u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
+ for (const auto node_u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
- BOOST_ASSERT(u != SPECIAL_NODEID);
- BOOST_ASSERT(u < m_node_based_graph->GetNumberOfNodes());
- progress.printStatus(u);
- for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
+ 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 v = m_node_based_graph->GetTarget(e1);
+ const NodeID node_v = m_node_based_graph->GetTarget(e1);
- BOOST_ASSERT(SPECIAL_NODEID != v);
+ BOOST_ASSERT(SPECIAL_NODEID != node_v);
// pick only every other edge
- if (u > v)
+ if (node_u > node_v)
{
continue;
}
- BOOST_ASSERT(u < v);
+ BOOST_ASSERT(node_u < node_v);
// Note: edges that end on barrier nodes or on a turn restriction
// may actually be in two distinct components. We choose the smallest
- const unsigned size_of_component = std::min(component_explorer.get_component_size(u),
- component_explorer.get_component_size(v));
+ const unsigned size_of_component =
+ std::min(component_explorer.get_component_size(node_u),
+ component_explorer.get_component_size(node_v));
- const unsigned id_of_smaller_component = [u,v,&component_explorer] {
- if (component_explorer.get_component_size(u) < component_explorer.get_component_size(v))
+ const unsigned id_of_smaller_component = [node_u, node_v, &component_explorer]
+ {
+ if (component_explorer.get_component_size(node_u) <
+ component_explorer.get_component_size(node_v))
{
- return component_explorer.get_component_id(u);
+ return component_explorer.get_component_id(node_u);
}
- return component_explorer.get_component_id(v);
+ return component_explorer.get_component_id(node_v);
}();
- const bool component_is_tiny = (size_of_component < 1000);
+ const bool component_is_tiny = size_of_component < 1000;
if (edge_data.edgeBasedNodeID == SPECIAL_NODEID)
{
- InsertEdgeBasedNode(v, u, (component_is_tiny ? id_of_smaller_component + 1 : 0));
+ InsertEdgeBasedNode(node_v, node_u,
+ (component_is_tiny ? id_of_smaller_component + 1 : 0));
}
else
{
- InsertEdgeBasedNode(u, v, (component_is_tiny ? id_of_smaller_component + 1 : 0));
+ InsertEdgeBasedNode(node_u, node_v,
+ (component_is_tiny ? id_of_smaller_component + 1 : 0));
}
}
}
@@ -544,9 +512,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
/**
* Actually it also generates OriginalEdgeData and serializes them...
*/
-void
-EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
- lua_State *lua_state)
+void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
+ const std::string &original_edge_data_filename, lua_State *lua_state)
{
SimpleLogger().Write() << "generating edge-expanded edges";
@@ -571,10 +538,10 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
Percent progress(m_node_based_graph->GetNumberOfNodes());
- for (const auto u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
+ for (const auto node_u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
- progress.printStatus(u);
- for (const EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
+ progress.printStatus(node_u);
+ for (const EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
{
if (!m_node_based_graph->GetEdgeData(e1).forward)
{
@@ -582,21 +549,21 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
}
++node_based_edge_counter;
- const NodeID v = m_node_based_graph->GetTarget(e1);
- const NodeID to_node_of_only_restriction =
- m_restriction_map->CheckForEmanatingIsOnlyTurn(u, v);
- const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end());
+ 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(v))
+ for (const EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(node_v))
{
if (!m_node_based_graph->GetEdgeData(e2).forward)
{
continue;
}
- const NodeID w = m_node_based_graph->GetTarget(e2);
+ const NodeID node_w = m_node_based_graph->GetTarget(e2);
- if ((to_node_of_only_restriction != SPECIAL_NODEID) &&
- (w != to_node_of_only_restriction))
+ 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;
@@ -605,7 +572,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
if (is_barrier_node)
{
- if (u != w)
+ if (node_u != node_w)
{
++skipped_barrier_turns_counter;
continue;
@@ -613,7 +580,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
}
else
{
- if ((u == w) && (m_node_based_graph->GetOutDegree(v) > 1))
+ if ((node_u == node_w) && (m_node_based_graph->GetOutDegree(node_v) > 1))
{
++skipped_uturns_counter;
continue;
@@ -622,9 +589,9 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
// 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) &&
- (to_node_of_only_restriction == SPECIAL_NODEID) &&
- (w != to_node_of_only_restriction))
+ 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;
@@ -641,26 +608,28 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
// the following is the core of the loop.
unsigned distance = edge_data1.distance;
- if (m_traffic_lights.find(v) != m_traffic_lights.end())
+ if (m_traffic_lights.find(node_v) != m_traffic_lights.end())
{
distance += speed_profile.traffic_signal_penalty;
}
// unpack last node of first segment if packed
- const auto first_coordinate = m_node_info_list[(m_geometry_compressor.HasEntryForID(e1) ?
- m_geometry_compressor.GetLastNodeIDOfBucket(e1) :
- u)];
+ const auto first_coordinate =
+ m_node_info_list[(m_geometry_compressor.HasEntryForID(e1)
+ ? m_geometry_compressor.GetLastNodeIDOfBucket(e1)
+ : node_u)];
// unpack first node of second segment if packed
- const auto third_coordinate = m_node_info_list[(m_geometry_compressor.HasEntryForID(e2) ?
- m_geometry_compressor.GetFirstNodeIDOfBucket(e2) :
- w)];
+ const auto third_coordinate =
+ m_node_info_list[(m_geometry_compressor.HasEntryForID(e2)
+ ? m_geometry_compressor.GetFirstNodeIDOfBucket(e2)
+ : node_w)];
const double turn_angle = ComputeAngle::OfThreeFixedPointCoordinates(
- first_coordinate, m_node_info_list[v], third_coordinate);
+ first_coordinate, m_node_info_list[node_v], third_coordinate);
const int turn_penalty = GetTurnPenalty(turn_angle, lua_state);
- TurnInstruction turn_instruction = AnalyzeTurn(u, v, w, turn_angle);
+ TurnInstruction turn_instruction = AnalyzeTurn(node_u, node_v, node_w, turn_angle);
if (turn_instruction == TurnInstruction::UTurn)
{
distance += speed_profile.u_turn_penalty;
@@ -675,10 +644,8 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
}
original_edge_data_vector.emplace_back(
- (edge_is_compressed ? m_geometry_compressor.GetPositionForID(e1) : v),
- edge_data1.nameID,
- turn_instruction,
- edge_is_compressed,
+ (edge_is_compressed ? m_geometry_compressor.GetPositionForID(e1) : node_v),
+ edge_data1.nameID, turn_instruction, edge_is_compressed,
edge_data2.travel_mode);
++original_edges_counter;
@@ -691,12 +658,9 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edgeBasedNodeID);
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edgeBasedNodeID);
- m_edge_based_edge_list.emplace_back(EdgeBasedEdge(edge_data1.edgeBasedNodeID,
- edge_data2.edgeBasedNodeID,
- m_edge_based_edge_list.size(),
- distance,
- true,
- false));
+ m_edge_based_edge_list.emplace_back(
+ EdgeBasedEdge(edge_data1.edgeBasedNodeID, edge_data2.edgeBasedNodeID,
+ m_edge_based_edge_list.size(), distance, true, false));
}
}
}
@@ -727,7 +691,10 @@ int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) co
// call lua profile to compute turn penalty
return luabind::call_function<int>(lua_state, "turn_function", 180. - angle);
}
- catch (const luabind::error &er) { SimpleLogger().Write(logWARNING) << er.what(); }
+ catch (const luabind::error &er)
+ {
+ SimpleLogger().Write(logWARNING) << er.what();
+ }
}
return 0;
}
@@ -735,8 +702,7 @@ int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) co
TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID node_u,
const NodeID node_v,
const NodeID node_w,
- const double angle)
- const
+ const double angle) const
{
if (node_u == node_w)
{
diff --git a/contractor/geometry_compressor.cpp b/contractor/geometry_compressor.cpp
index 9458c44..3997cdc 100644
--- a/contractor/geometry_compressor.cpp
+++ b/contractor/geometry_compressor.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -26,7 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "geometry_compressor.hpp"
-#include "../Util/simple_logger.hpp"
+#include "../util/simple_logger.hpp"
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
@@ -35,9 +35,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <limits>
#include <string>
-int free_list_maximum = 0;
-int UniqueNumber() { return ++free_list_maximum; }
-
GeometryCompressor::GeometryCompressor()
{
m_free_list.reserve(100);
@@ -174,8 +171,8 @@ void GeometryCompressor::CompressEdge(const EdgeID edge_id_1,
m_compressed_geometries[list_to_remove_index];
// found an existing list, append it to the list of edge_id_1
- edge_bucket_list1.insert(
- edge_bucket_list1.end(), edge_bucket_list2.begin(), edge_bucket_list2.end());
+ edge_bucket_list1.insert(edge_bucket_list1.end(), edge_bucket_list2.begin(),
+ edge_bucket_list2.end());
// remove the list of edge_id_2
m_edge_id_to_list_index_map.erase(edge_id_2);
@@ -211,9 +208,8 @@ void GeometryCompressor::PrintStatistics() const
"\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 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);
@@ -226,16 +222,15 @@ GeometryCompressor::GetBucketReference(const EdgeID edge_id) const
return m_compressed_geometries.at(index);
}
- NodeID GeometryCompressor::GetFirstNodeIDOfBucket(const EdgeID edge_id) const
- {
- const auto &bucket = GetBucketReference(edge_id);
- BOOST_ASSERT(bucket.size() >= 2);
- return bucket[1].first;
- }
- NodeID GeometryCompressor::GetLastNodeIDOfBucket(const EdgeID edge_id) const
- {
- const auto &bucket = GetBucketReference(edge_id);
- BOOST_ASSERT(bucket.size() >= 2);
- return bucket[bucket.size()-2].first;
- }
-
+NodeID GeometryCompressor::GetFirstNodeIDOfBucket(const EdgeID edge_id) const
+{
+ const auto &bucket = GetBucketReference(edge_id);
+ BOOST_ASSERT(bucket.size() >= 2);
+ return bucket[1].first;
+}
+NodeID GeometryCompressor::GetLastNodeIDOfBucket(const EdgeID edge_id) const
+{
+ const auto &bucket = GetBucketReference(edge_id);
+ BOOST_ASSERT(bucket.size() >= 2);
+ return bucket[bucket.size() - 2].first;
+}
diff --git a/contractor/geometry_compressor.hpp b/contractor/geometry_compressor.hpp
index dd5748d..ca83fa4 100644
--- a/contractor/geometry_compressor.hpp
+++ b/contractor/geometry_compressor.hpp
@@ -58,6 +58,8 @@ class GeometryCompressor
NodeID GetLastNodeIDOfBucket(const EdgeID edge_id) const;
private:
+ int free_list_maximum = 0;
+
void IncreaseFreeList();
std::vector<std::vector<CompressedNode>> m_compressed_geometries;
std::vector<unsigned> m_free_list;
diff --git a/contractor/processing_chain.cpp b/contractor/processing_chain.cpp
index 23d406b..ccff7fd 100644
--- a/contractor/processing_chain.cpp
+++ b/contractor/processing_chain.cpp
@@ -34,15 +34,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../data_structures/static_rtree.hpp"
#include "../data_structures/restriction_map.hpp"
-#include "../Util/git_sha.hpp"
-#include "../Util/graph_loader.hpp"
-#include "../Util/integer_range.hpp"
-#include "../Util/lua_util.hpp"
-#include "../Util/make_unique.hpp"
-#include "../Util/osrm_exception.hpp"
-#include "../Util/simple_logger.hpp"
-#include "../Util/string_util.hpp"
-#include "../Util/timing_util.hpp"
+#include "../util/git_sha.hpp"
+#include "../util/graph_loader.hpp"
+#include "../util/integer_range.hpp"
+#include "../util/lua_util.hpp"
+#include "../util/make_unique.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 <boost/filesystem/fstream.hpp>
@@ -138,13 +138,9 @@ int Prepare::Process(int argc, char *argv[])
static_assert(sizeof(ImportEdge) == 20,
"changing ImportEdge type has influence on memory consumption!");
#endif
- NodeID number_of_node_based_nodes =
- readBinaryOSRMGraphFromStream(input_stream,
- edge_list,
- barrier_node_list,
- traffic_light_list,
- &internal_to_external_node_map,
- restriction_list);
+ NodeID number_of_node_based_nodes = readBinaryOSRMGraphFromStream(
+ input_stream, edge_list, barrier_node_list, traffic_light_list,
+ &internal_to_external_node_map, restriction_list);
input_stream.close();
if (edge_list.empty())
@@ -162,11 +158,9 @@ int Prepare::Process(int argc, char *argv[])
DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
// init node_based_edge_list, edge_based_edge_list by edgeList
- number_of_edge_based_nodes = BuildEdgeExpandedGraph(lua_state,
- number_of_node_based_nodes,
- node_based_edge_list,
- edge_based_edge_list,
- speed_profile);
+ number_of_edge_based_nodes =
+ BuildEdgeExpandedGraph(lua_state, number_of_node_based_nodes, node_based_edge_list,
+ edge_based_edge_list, speed_profile);
lua_close(lua_state);
TIMER_STOP(expansion);
@@ -343,9 +337,8 @@ bool Prepare::ParseArguments(int argc, char *argv[])
// 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>(&config_file_path)
- ->default_value("contractor.ini"),
+ "config,c", boost::program_options::value<boost::filesystem::path>(&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
@@ -354,21 +347,18 @@ bool Prepare::ParseArguments(int argc, char *argv[])
"restrictions,r",
boost::program_options::value<boost::filesystem::path>(&restrictions_path),
"Restrictions file in .osrm.restrictions format")(
- "profile,p",
- boost::program_options::value<boost::filesystem::path>(&profile_path)
- ->default_value("profile.lua"),
+ "profile,p", boost::program_options::value<boost::filesystem::path>(&profile_path)
+ ->default_value("profile.lua"),
"Path to LUA routing profile")(
- "threads,t",
- boost::program_options::value<unsigned int>(&requested_num_threads)
- ->default_value(tbb::task_scheduler_init::default_num_threads()),
+ "threads,t", boost::program_options::value<unsigned int>(&requested_num_threads)
+ ->default_value(tbb::task_scheduler_init::default_num_threads()),
"Number of threads to use");
// 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>(&input_path),
+ "input,i", boost::program_options::value<boost::filesystem::path>(&input_path),
"Input file in .osm, .osm.bz2 or .osm.pbf format");
// positional option
@@ -394,10 +384,11 @@ bool Prepare::ParseArguments(int argc, char *argv[])
.run(),
option_variables);
- const auto& temp_config_path = option_variables["config"].as<boost::filesystem::path>();
+ 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),
+ boost::program_options::store(boost::program_options::parse_config_file<char>(
+ temp_config_path.string().c_str(), cmdline_options, true),
option_variables);
}
@@ -458,9 +449,8 @@ void Prepare::CheckRestrictionsFile(FingerPrint &fingerprint_orig)
\brief Setups scripting environment (lua-scripting)
Also initializes speed profile.
*/
-bool
-Prepare::SetupScriptingEnvironment(lua_State *lua_state,
- EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile)
+bool Prepare::SetupScriptingEnvironment(
+ lua_State *lua_state, EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile)
{
// open utility libraries string library;
luaL_openlibs(lua_state);
@@ -509,14 +499,12 @@ Prepare::BuildEdgeExpandedGraph(lua_State *lua_state,
SimpleLogger().Write() << "Generating edge-expanded graph representation";
std::shared_ptr<NodeBasedDynamicGraph> node_based_graph =
NodeBasedDynamicGraphFromImportEdges(number_of_node_based_nodes, edge_list);
- std::unique_ptr<RestrictionMap> restriction_map = osrm::make_unique<RestrictionMap>(restriction_list);
+ std::unique_ptr<RestrictionMap> restriction_map =
+ osrm::make_unique<RestrictionMap>(restriction_list);
std::shared_ptr<EdgeBasedGraphFactory> edge_based_graph_factory =
- std::make_shared<EdgeBasedGraphFactory>(node_based_graph,
- std::move(restriction_map),
- barrier_node_list,
- traffic_light_list,
- internal_to_external_node_map,
- speed_profile);
+ std::make_shared<EdgeBasedGraphFactory>(node_based_graph, std::move(restriction_map),
+ barrier_node_list, traffic_light_list,
+ internal_to_external_node_map, speed_profile);
edge_list.clear();
edge_list.shrink_to_fit();
@@ -574,8 +562,6 @@ void Prepare::WriteNodeMapping()
void Prepare::BuildRTree(std::vector<EdgeBasedNode> &node_based_edge_list)
{
SimpleLogger().Write() << "building r-tree ...";
- StaticRTree<EdgeBasedNode>(node_based_edge_list,
- rtree_nodes_path.c_str(),
- rtree_leafs_path.c_str(),
- internal_to_external_node_map);
+ StaticRTree<EdgeBasedNode>(node_based_edge_list, rtree_nodes_path.c_str(),
+ rtree_leafs_path.c_str(), internal_to_external_node_map);
}
diff --git a/data_structures/Coordinate.cpp b/data_structures/Coordinate.cpp
deleted file mode 100644
index 4305256..0000000
--- a/data_structures/Coordinate.cpp
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
-
-Copyright (c) 2013, 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 <osrm/Coordinate.h>
-#include "../Util/MercatorUtil.h"
-#ifndef NDEBUG
-#include "../Util/simple_logger.hpp"
-#endif
-#include "../Util/string_util.hpp"
-
-#include <boost/assert.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
-}
-
-void FixedPointCoordinate::Reset()
-{
- lat = std::numeric_limits<int>::min();
- lon = std::numeric_limits<int>::min();
-}
-bool FixedPointCoordinate::isSet() const
-{
- return (std::numeric_limits<int>::min() != lat) && (std::numeric_limits<int>::min() != lon);
-}
-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;
-}
-
-double FixedPointCoordinate::ApproximateDistance(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());
- double RAD = 0.017453292519943295769236907684886;
- double lt1 = lat1 / COORDINATE_PRECISION;
- double ln1 = lon1 / COORDINATE_PRECISION;
- double lt2 = lat2 / COORDINATE_PRECISION;
- double ln2 = lon2 / COORDINATE_PRECISION;
- double dlat1 = lt1 * (RAD);
-
- double dlong1 = ln1 * (RAD);
- double dlat2 = lt2 * (RAD);
- double dlong2 = ln2 * (RAD);
-
- double dLong = dlong1 - dlong2;
- double dLat = dlat1 - dlat2;
-
- double aHarv = pow(sin(dLat / 2.0), 2.0) + cos(dlat1) * cos(dlat2) * pow(sin(dLong / 2.), 2);
- double cHarv = 2. * atan2(sqrt(aHarv), sqrt(1.0 - aHarv));
- // 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 double earth = 6372797.560856;
- return earth * cHarv;
-}
-
-double FixedPointCoordinate::ApproximateDistance(const FixedPointCoordinate &coordinate_1,
- const FixedPointCoordinate &coordinate_2)
-{
- return ApproximateDistance(
- coordinate_1.lat, coordinate_1.lon, coordinate_2.lat, coordinate_2.lon);
-}
-
-float FixedPointCoordinate::ApproximateEuclideanDistance(const FixedPointCoordinate &coordinate_1,
- const FixedPointCoordinate &coordinate_2)
-{
- return ApproximateEuclideanDistance(
- coordinate_1.lat, coordinate_1.lon, coordinate_2.lat, coordinate_2.lon);
-}
-
-float FixedPointCoordinate::ApproximateEuclideanDistance(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 RAD = 0.017453292519943295769236907684886f;
- 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) * cos((float_lat1 + float_lat2) / 2.f);
- const float y_value = float_lat2 - float_lat1;
- const float earth_radius = 6372797.560856f;
- return sqrt(x_value * x_value + y_value * y_value) * earth_radius;
-}
-
-float
-FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &source_coordinate,
- const FixedPointCoordinate &target_coordinate,
- const FixedPointCoordinate &point)
-{
- // initialize values
- const float x_value = static_cast<float>(lat2y(point.lat / COORDINATE_PRECISION));
- const float y_value = point.lon / COORDINATE_PRECISION;
- float a = static_cast<float>(lat2y(source_coordinate.lat / COORDINATE_PRECISION));
- float b = source_coordinate.lon / COORDINATE_PRECISION;
- float c = static_cast<float>(lat2y(target_coordinate.lat / COORDINATE_PRECISION));
- float d = target_coordinate.lon / COORDINATE_PRECISION;
- float p, q;
- if (std::abs(a - c) > std::numeric_limits<float>::epsilon())
- {
- const float slope = (d - b) / (c - a); // slope
- // Projection of (x,y) on line joining (a,b) and (c,d)
- p = ((x_value + (slope * y_value)) + (slope * slope * a - slope * b)) /
- (1.f + slope * slope);
- q = b + slope * (p - a);
- }
- else
- {
- p = c;
- q = y_value;
- }
-
- float ratio;
- bool inverse_ratio = false;
-
- // straight line segment on equator
- if (std::abs(c) < std::numeric_limits<float>::epsilon() &&
- std::abs(a) < std::numeric_limits<float>::epsilon())
- {
- ratio = (q - b) / (d - b);
- }
- else
- {
- if (std::abs(c) < std::numeric_limits<float>::epsilon())
- {
- // swap start/end
- std::swap(a, c);
- std::swap(b, d);
- inverse_ratio = true;
- }
-
- float 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 = (p - nY * a) / c;
- }
-
- if (std::isnan(ratio))
- {
- ratio = (target_coordinate == point ? 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;
- }
-
- // we need to do this, if we switched start/end coordinates
- if (inverse_ratio)
- {
- ratio = 1.0f - ratio;
- }
-
- // compute the nearest location
- FixedPointCoordinate nearest_location;
- BOOST_ASSERT(!std::isnan(ratio));
- if (ratio <= 0.f)
- { // point is "left" of edge
- nearest_location = source_coordinate;
- }
- else if (ratio >= 1.f)
- { // point is "right" of edge
- nearest_location = target_coordinate;
- }
- else
- { // point lies in between
- nearest_location.lat = static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
- nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
- }
-
- BOOST_ASSERT(nearest_location.is_valid());
- return FixedPointCoordinate::ApproximateEuclideanDistance(point, nearest_location);
-}
-
-float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
- const FixedPointCoordinate &segment_target,
- const FixedPointCoordinate &query_location,
- FixedPointCoordinate &nearest_location,
- float &ratio)
-{
- BOOST_ASSERT(query_location.is_valid());
-
- // initialize values
- const double x = lat2y(query_location.lat / COORDINATE_PRECISION);
- const double y = query_location.lon / COORDINATE_PRECISION;
- const double a = lat2y(segment_source.lat / COORDINATE_PRECISION);
- const double b = segment_source.lon / COORDINATE_PRECISION;
- const double c = 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 = (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<double>::epsilon())
- {
- ratio = 0.f;
- }
- else if (std::abs(ratio - 1.f) <= std::numeric_limits<double>::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>(y2lat(p) * COORDINATE_PRECISION);
- nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
- }
- BOOST_ASSERT(nearest_location.is_valid());
-
- const float approximate_distance =
- FixedPointCoordinate::ApproximateEuclideanDistance(query_location, nearest_location);
- BOOST_ASSERT(0. <= approximate_distance);
- return approximate_distance;
-}
-
-void FixedPointCoordinate::convertInternalLatLonToString(const int value, std::string &output)
-{
- char buffer[12];
- buffer[11] = 0; // zero termination
- output = printInt<11, 6>(buffer, value);
-}
-
-void FixedPointCoordinate::convertInternalCoordinateToString(const FixedPointCoordinate &coord,
- std::string &output)
-{
- std::string tmp;
- tmp.reserve(23);
- convertInternalLatLonToString(coord.lon, tmp);
- output = tmp;
- output += ",";
- convertInternalLatLonToString(coord.lat, tmp);
- output += tmp;
-}
-
-void
-FixedPointCoordinate::convertInternalReversedCoordinateToString(const FixedPointCoordinate &coord,
- std::string &output)
-{
- std::string tmp;
- tmp.reserve(23);
- convertInternalLatLonToString(coord.lat, tmp);
- output = tmp;
- output += ",";
- convertInternalLatLonToString(coord.lon, tmp);
- output += tmp;
-}
-
-void FixedPointCoordinate::Output(std::ostream &out) const
-{
- out << "(" << lat / COORDINATE_PRECISION << "," << lon / COORDINATE_PRECISION << ")";
-}
-
-float FixedPointCoordinate::GetBearing(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 = DegreeToRadian(lon_diff);
- const float lat1 = DegreeToRadian(first_coordinate.lat / COORDINATE_PRECISION);
- const float lat2 = DegreeToRadian(second_coordinate.lat / COORDINATE_PRECISION);
- const float y = sin(lon_delta) * cos(lat2);
- const float x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon_delta);
- float result = RadianToDegree(std::atan2(y, x));
- while (result < 0.f)
- {
- result += 360.f;
- }
-
- while (result >= 360.f)
- {
- result -= 360.f;
- }
- return result;
-}
-
-float FixedPointCoordinate::GetBearing(const FixedPointCoordinate &other) const
-{
- const float lon_delta =
- DegreeToRadian(lon / COORDINATE_PRECISION - other.lon / COORDINATE_PRECISION);
- const float lat1 = DegreeToRadian(other.lat / COORDINATE_PRECISION);
- const float lat2 = DegreeToRadian(lat / COORDINATE_PRECISION);
- const float y_value = std::sin(lon_delta) * std::cos(lat2);
- const float x_value =
- std::cos(lat1) * std::sin(lat2) - std::sin(lat1) * std::cos(lat2) * std::cos(lon_delta);
- float result = RadianToDegree(std::atan2(y_value, x_value));
-
- while (result < 0.f)
- {
- result += 360.f;
- }
-
- while (result >= 360.f)
- {
- result -= 360.f;
- }
- return result;
-}
-
-float FixedPointCoordinate::DegreeToRadian(const float degree)
-{
- return degree * (static_cast<float>(M_PI) / 180.f);
-}
-
-float FixedPointCoordinate::RadianToDegree(const float radian)
-{
- return radian * (180.f * static_cast<float>(M_1_PI));
-}
-
-// This distance computation does integer arithmetic only and is a lot faster than
-// the other distance function which are numerically correct('ish).
-// It preserves some order among the elements that make it useful for certain purposes
-int FixedPointCoordinate::OrderedPerpendicularDistanceApproximation(
- const FixedPointCoordinate &input_point,
- const FixedPointCoordinate &segment_source,
- const FixedPointCoordinate &segment_target)
-{
- // initialize values
- const float x = static_cast<float>(lat2y(input_point.lat / COORDINATE_PRECISION));
- const float y = input_point.lon / COORDINATE_PRECISION;
- const float a = static_cast<float>(lat2y(segment_source.lat / COORDINATE_PRECISION));
- const float b = segment_source.lon / COORDINATE_PRECISION;
- const float c = static_cast<float>(lat2y(segment_target.lat / COORDINATE_PRECISION));
- const float d = segment_target.lon / COORDINATE_PRECISION;
-
- float p, q;
- if (a == c)
- {
- p = c;
- q = y;
- }
- else
- {
- const float 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);
- }
-
- const float nY = (d * p - c * q) / (a * d - b * c);
- float ratio = (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 == input_point) ? 1.f : 0.f;
- }
-
- // compute target quasi-location
- int dx, dy;
- if (ratio < 0.f)
- {
- dx = input_point.lon - segment_source.lon;
- dy = input_point.lat - segment_source.lat;
- }
- else if (ratio > 1.f)
- {
- dx = input_point.lon - segment_target.lon;
- dy = input_point.lat - segment_target.lat;
- }
- else
- {
- // point lies in between
- dx = input_point.lon - static_cast<int>(q * COORDINATE_PRECISION);
- dy = input_point.lat - static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
- }
-
- // return an approximation in the plane
- return static_cast<int>(sqrt(dx * dx + dy * dy));
-}
diff --git a/data_structures/InputReaderFactory.h b/data_structures/InputReaderFactory.h
deleted file mode 100644
index 3f6aa3c..0000000
--- a/data_structures/InputReaderFactory.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
-
-Copyright (c) 2013, 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 INPUT_READER_FACTORY_H
-#define INPUT_READER_FACTORY_H
-
-#include <boost/assert.hpp>
-
-#include <bzlib.h>
-#include <libxml/xmlreader.h>
-
-struct BZ2Context
-{
- FILE *file;
- BZFILE *bz2;
- int error;
- int nUnused;
- char unused[BZ_MAX_UNUSED];
-};
-
-int readFromBz2Stream(void *pointer, char *buffer, int len)
-{
- void *unusedTmpVoid = nullptr;
- char *unusedTmp = nullptr;
- BZ2Context *context = (BZ2Context *)pointer;
- int read = 0;
- while (0 == read &&
- !(BZ_STREAM_END == context->error && 0 == context->nUnused && feof(context->file)))
- {
- read = BZ2_bzRead(&context->error, context->bz2, buffer, len);
- if (BZ_OK == context->error)
- {
- return read;
- }
- else if (BZ_STREAM_END == context->error)
- {
- BZ2_bzReadGetUnused(&context->error, context->bz2, &unusedTmpVoid, &context->nUnused);
- BOOST_ASSERT_MSG(BZ_OK == context->error, "Could not BZ2_bzReadGetUnused");
- unusedTmp = (char *)unusedTmpVoid;
- for (int i = 0; i < context->nUnused; i++)
- {
- context->unused[i] = unusedTmp[i];
- }
- BZ2_bzReadClose(&context->error, context->bz2);
- BOOST_ASSERT_MSG(BZ_OK == context->error, "Could not BZ2_bzReadClose");
- context->error = BZ_STREAM_END; // set to the stream end for next call to this function
- if (0 == context->nUnused && feof(context->file))
- {
- return read;
- }
- else
- {
- context->bz2 = BZ2_bzReadOpen(
- &context->error, context->file, 0, 0, context->unused, context->nUnused);
- BOOST_ASSERT_MSG(nullptr != context->bz2, "Could not open file");
- }
- }
- else
- {
- BOOST_ASSERT_MSG(false, "Could not read bz2 file");
- }
- }
- return read;
-}
-
-int closeBz2Stream(void *pointer)
-{
- BZ2Context *context = (BZ2Context *)pointer;
- fclose(context->file);
- delete context;
- return 0;
-}
-
-xmlTextReaderPtr inputReaderFactory(const char *name)
-{
- std::string inputName(name);
-
- if (inputName.find(".osm.bz2") != std::string::npos)
- {
- BZ2Context *context = new BZ2Context();
- context->error = false;
- context->file = fopen(name, "r");
- int error;
- context->bz2 =
- BZ2_bzReadOpen(&error, context->file, 0, 0, context->unused, context->nUnused);
- if (context->bz2 == nullptr || context->file == nullptr)
- {
- delete context;
- return nullptr;
- }
- return xmlReaderForIO(readFromBz2Stream, closeBz2Stream, (void *)context, nullptr, nullptr, 0);
- }
- else
- {
- return xmlNewTextReaderFilename(name);
- }
-}
-
-#endif // INPUT_READER_FACTORY_H
diff --git a/data_structures/binary_heap.hpp b/data_structures/binary_heap.hpp
index 049f12f..a23a6b0 100644
--- a/data_structures/binary_heap.hpp
+++ b/data_structures/binary_heap.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -36,24 +36,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <type_traits>
#include <unordered_map>
#include <vector>
-#include <cstring>
template <typename NodeID, typename Key> class ArrayStorage
{
public:
- explicit ArrayStorage(size_t size) : positions(new Key[size])
- {
- memset(positions, 0, size * sizeof(Key));
- }
+ explicit ArrayStorage(size_t size) : positions(size, 0) {}
- ~ArrayStorage() { delete[] positions; }
+ ~ArrayStorage() {}
Key &operator[](NodeID node) { return positions[node]; }
+ Key peek_index(const NodeID node) const { return positions[node]; }
+
void Clear() {}
private:
- Key *positions;
+ std::vector<Key> positions;
};
template <typename NodeID, typename Key> class MapStorage
@@ -65,6 +63,16 @@ template <typename NodeID, typename Key> class MapStorage
void Clear() { nodes.clear(); }
+ Key peek_index(const NodeID node) const
+ {
+ const auto iter = nodes.find(node);
+ if (nodes.end() != iter)
+ {
+ return iter->second;
+ }
+ return std::numeric_limits<Key>::max();
+ }
+
private:
std::map<NodeID, Key> nodes;
};
@@ -76,6 +84,16 @@ template <typename NodeID, typename Key> class UnorderedMapStorage
Key &operator[](const NodeID node) { return nodes[node]; }
+ Key peek_index(const NodeID node) const
+ {
+ const auto iter = nodes.find(node);
+ if (std::end(nodes) != iter)
+ {
+ return iter->second;
+ }
+ return std::numeric_limits<Key>::max();
+ }
+
Key const &operator[](const NodeID node) const
{
auto iter = nodes.find(node);
@@ -132,13 +150,13 @@ class BinaryHeap
Data &GetData(NodeID node)
{
- const Key index = node_index[node];
+ const Key index = node_index.peek_index(node);
return inserted_nodes[index].data;
}
Data const &GetData(NodeID node) const
{
- const Key index = node_index[node];
+ const Key index = node_index.peek_index(node);
return inserted_nodes[index].data;
}
@@ -148,17 +166,17 @@ class BinaryHeap
return inserted_nodes[index].weight;
}
- bool WasRemoved(const NodeID node)
+ bool WasRemoved(const NodeID node) const
{
BOOST_ASSERT(WasInserted(node));
- const Key index = node_index[node];
+ const Key index = node_index.peek_index(node);
return inserted_nodes[index].key == 0;
}
- bool WasInserted(const NodeID node)
+ bool WasInserted(const NodeID node) const
{
- const Key index = node_index[node];
- if (index >= static_cast<Key>(inserted_nodes.size()))
+ const auto index = node_index.peek_index(node);
+ if (index >= static_cast<decltype(index)>(inserted_nodes.size()))
{
return false;
}
@@ -200,7 +218,7 @@ class BinaryHeap
void DecreaseKey(NodeID node, Weight weight)
{
BOOST_ASSERT(std::numeric_limits<NodeID>::max() != node);
- const Key &index = node_index[node];
+ const Key &index = node_index.peek_index(node);
Key &key = inserted_nodes[index].key;
BOOST_ASSERT(key >= 0);
@@ -235,12 +253,12 @@ class BinaryHeap
{
const Key droppingIndex = heap[key].index;
const Weight weight = heap[key].weight;
+ const Key heap_size = static_cast<Key>(heap.size());
Key nextKey = key << 1;
- while (nextKey < static_cast<Key>(heap.size()))
+ while (nextKey < heap_size)
{
const Key nextKeyOther = nextKey + 1;
- if ((nextKeyOther < static_cast<Key>(heap.size())) &&
- (heap[nextKey].weight > heap[nextKeyOther].weight))
+ if ((nextKeyOther < heap_size) && (heap[nextKey].weight > heap[nextKeyOther].weight))
{
nextKey = nextKeyOther;
}
@@ -279,7 +297,7 @@ class BinaryHeap
void CheckHeap()
{
#ifndef NDEBUG
- for (Key i = 2; i < (Key)heap.size(); ++i)
+ for (std::size_t i = 2; i < heap.size(); ++i)
{
BOOST_ASSERT(heap[i].weight >= heap[i >> 1].weight);
}
diff --git a/data_structures/concurrent_queue.hpp b/data_structures/concurrent_queue.hpp
index b3d4e1a..7341a8c 100644
--- a/data_structures/concurrent_queue.hpp
+++ b/data_structures/concurrent_queue.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -40,9 +40,10 @@ template <typename Data> class ConcurrentQueue
inline void push(const Data &data)
{
std::unique_lock<std::mutex> lock(m_mutex);
- m_not_full.wait(lock,
- [this]
- { return m_internal_queue.size() < m_internal_queue.capacity(); });
+ m_not_full.wait(lock, [this]
+ {
+ return m_internal_queue.size() < m_internal_queue.capacity();
+ });
m_internal_queue.push_back(data);
m_not_empty.notify_one();
}
@@ -52,9 +53,10 @@ template <typename Data> class ConcurrentQueue
inline void wait_and_pop(Data &popped_value)
{
std::unique_lock<std::mutex> lock(m_mutex);
- m_not_empty.wait(lock,
- [this]
- { return !m_internal_queue.empty(); });
+ m_not_empty.wait(lock, [this]
+ {
+ return !m_internal_queue.empty();
+ });
popped_value = m_internal_queue.front();
m_internal_queue.pop_front();
m_not_full.notify_one();
diff --git a/data_structures/coordinate.cpp b/data_structures/coordinate.cpp
new file mode 100644
index 0000000..df3abe4
--- /dev/null
+++ b/data_structures/coordinate.cpp
@@ -0,0 +1,87 @@
+/*
+
+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"
+
+#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/coordinate_calculation.cpp b/data_structures/coordinate_calculation.cpp
new file mode 100644
index 0000000..0c44989
--- /dev/null
+++ b/data_structures/coordinate_calculation.cpp
@@ -0,0 +1,268 @@
+/*
+
+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;
+}
+
+double coordinate_calculation::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 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 coordinate_calculation::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 coordinate_calculation::euclidean_distance(const FixedPointCoordinate &coordinate_1,
+ const FixedPointCoordinate &coordinate_2)
+{
+ return euclidean_distance(coordinate_1.lat, coordinate_1.lon, coordinate_2.lat,
+ coordinate_2.lon);
+}
+
+float coordinate_calculation::euclidean_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 coordinate_calculation::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 coordinate_calculation::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 coordinate_calculation::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 coordinate_calculation::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 =
+ coordinate_calculation::euclidean_distance(query_location, nearest_location);
+ BOOST_ASSERT(0.f <= approximate_distance);
+ return approximate_distance;
+}
+
+void coordinate_calculation::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 coordinate_calculation::deg_to_rad(const float degree)
+{
+ return degree * (static_cast<float>(M_PI) / 180.f);
+}
+
+float coordinate_calculation::rad_to_deg(const float radian)
+{
+ return radian * (180.f * static_cast<float>(M_1_PI));
+}
+
+float coordinate_calculation::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/data_structures/coordinate_calculation.hpp b/data_structures/coordinate_calculation.hpp
new file mode 100644
index 0000000..73183df
--- /dev/null
+++ b/data_structures/coordinate_calculation.hpp
@@ -0,0 +1,82 @@
+/*
+
+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>
+
+struct coordinate_calculation
+{
+ static double
+ great_circle_distance(const int lat1, const int lon1, const int lat2, const int lon2);
+
+ static double great_circle_distance(const FixedPointCoordinate &first_coordinate,
+ const FixedPointCoordinate &second_coordinate);
+
+ static float euclidean_distance(const FixedPointCoordinate &first_coordinate,
+ const FixedPointCoordinate &second_coordinate);
+
+ static float euclidean_distance(const int lat1, const int lon1, const int lat2, const int lon2);
+
+ static void lat_or_lon_to_string(const int value, std::string &output);
+
+ static float perpendicular_distance(const FixedPointCoordinate &segment_source,
+ const FixedPointCoordinate &segment_target,
+ const FixedPointCoordinate &query_location);
+
+ static float perpendicular_distance(const FixedPointCoordinate &segment_source,
+ const FixedPointCoordinate &segment_target,
+ const FixedPointCoordinate &query_location,
+ FixedPointCoordinate &nearest_location,
+ float &ratio);
+
+ static 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);
+
+ static 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);
+
+ static float deg_to_rad(const float degree);
+ static float rad_to_deg(const float radian);
+
+ static float bearing(const FixedPointCoordinate &first_coordinate,
+ const FixedPointCoordinate &second_coordinate);
+};
+
+#endif // COORDINATE_CALCULATION
diff --git a/data_structures/deallocating_vector.hpp b/data_structures/deallocating_vector.hpp
index 415fa69..de5a24d 100644
--- a/data_structures/deallocating_vector.hpp
+++ b/data_structures/deallocating_vector.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,19 +25,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DEALLOCATINGVECTOR_H_
-#define DEALLOCATINGVECTOR_H_
+#ifndef DEALLOCATING_VECTOR_HPP
+#define DEALLOCATING_VECTOR_HPP
-#include "../Util/integer_range.hpp"
+#include "../util/integer_range.hpp"
#include <boost/iterator/iterator_facade.hpp>
+#include <limits>
#include <utility>
#include <vector>
template <typename ElementT> struct DeallocatingVectorIteratorState
{
- DeallocatingVectorIteratorState() : index(-1), bucket_list(nullptr) {}
+ DeallocatingVectorIteratorState()
+ : index(std::numeric_limits<std::size_t>::max()), bucket_list(nullptr)
+ {
+ }
explicit DeallocatingVectorIteratorState(const DeallocatingVectorIteratorState &r)
: index(r.index), bucket_list(r.bucket_list)
{
@@ -50,7 +54,7 @@ template <typename ElementT> struct DeallocatingVectorIteratorState
std::size_t index;
std::vector<ElementT *> *bucket_list;
- inline DeallocatingVectorIteratorState &operator=(const DeallocatingVectorIteratorState &other)
+ DeallocatingVectorIteratorState &operator=(const DeallocatingVectorIteratorState &other)
{
index = other.index;
bucket_list = other.bucket_list;
@@ -171,17 +175,20 @@ class DeallocatingVector
// this forward-only iterator deallocates all buckets that have been visited
using deallocation_iterator = DeallocatingVectorRemoveIterator<ElementT, ELEMENTS_PER_BLOCK>;
- DeallocatingVector() : current_size(0) { bucket_list.emplace_back(new ElementT[ELEMENTS_PER_BLOCK]); }
+ DeallocatingVector() : current_size(0)
+ {
+ bucket_list.emplace_back(new ElementT[ELEMENTS_PER_BLOCK]);
+ }
~DeallocatingVector() { clear(); }
- inline void swap(DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK> &other)
+ void swap(DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK> &other)
{
std::swap(current_size, other.current_size);
bucket_list.swap(other.bucket_list);
}
- inline void clear()
+ void clear()
{
// Delete[]'ing ptr's to all Buckets
for (auto bucket : bucket_list)
@@ -192,11 +199,12 @@ class DeallocatingVector
bucket = nullptr;
}
}
- bucket_list.clear(); bucket_list.shrink_to_fit();
+ bucket_list.clear();
+ bucket_list.shrink_to_fit();
current_size = 0;
}
- inline void push_back(const ElementT &element)
+ void push_back(const ElementT &element)
{
const std::size_t current_capacity = capacity();
if (current_size == current_capacity)
@@ -209,7 +217,7 @@ class DeallocatingVector
++current_size;
}
- template <typename... Ts> inline void emplace_back(Ts &&... element)
+ template <typename... Ts> void emplace_back(Ts &&... element)
{
const std::size_t current_capacity = capacity();
if (current_size == current_capacity)
@@ -222,9 +230,9 @@ class DeallocatingVector
++current_size;
}
- inline void reserve(const std::size_t) const { /* don't do anything */ }
+ void reserve(const std::size_t) const { /* don't do anything */}
- inline void resize(const std::size_t new_size)
+ void resize(const std::size_t new_size)
{
if (new_size >= current_size)
{
@@ -234,9 +242,10 @@ class DeallocatingVector
}
}
else
- { // down-size
+ { // 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 :
+ osrm::irange(number_of_necessary_buckets, bucket_list.size()))
{
if (nullptr != bucket_list[bucket_index])
{
@@ -248,58 +257,50 @@ class DeallocatingVector
current_size = new_size;
}
- inline std::size_t size() const { return current_size; }
+ std::size_t size() const { return current_size; }
- inline std::size_t capacity() const { return bucket_list.size() * ELEMENTS_PER_BLOCK; }
+ std::size_t capacity() const { return bucket_list.size() * ELEMENTS_PER_BLOCK; }
- inline iterator begin() { return iterator(static_cast<std::size_t>(0), &bucket_list); }
+ iterator begin() { return iterator(static_cast<std::size_t>(0), &bucket_list); }
- inline iterator end() { return iterator(size(), &bucket_list); }
+ iterator end() { return iterator(size(), &bucket_list); }
- inline deallocation_iterator dbegin()
+ deallocation_iterator dbegin()
{
return deallocation_iterator(static_cast<std::size_t>(0), &bucket_list);
}
- inline deallocation_iterator dend() { return deallocation_iterator(size(), &bucket_list); }
+ deallocation_iterator dend() { return deallocation_iterator(size(), &bucket_list); }
- inline const_iterator begin() const
+ const_iterator begin() const
{
return const_iterator(static_cast<std::size_t>(0), &bucket_list);
}
- inline const_iterator end() const { return const_iterator(size(), &bucket_list); }
+ const_iterator end() const { return const_iterator(size(), &bucket_list); }
- inline ElementT &operator[](const std::size_t index)
+ ElementT &operator[](const std::size_t index)
{
const std::size_t _bucket = index / ELEMENTS_PER_BLOCK;
const std::size_t _index = index % ELEMENTS_PER_BLOCK;
return (bucket_list[_bucket][_index]);
}
- const inline ElementT &operator[](const std::size_t index) const
+ ElementT &operator[](const std::size_t index) const
{
const std::size_t _bucket = index / ELEMENTS_PER_BLOCK;
const std::size_t _index = index % ELEMENTS_PER_BLOCK;
return (bucket_list[_bucket][_index]);
}
- inline ElementT &back()
- {
- const std::size_t _bucket = current_size / ELEMENTS_PER_BLOCK;
- const std::size_t _index = current_size % ELEMENTS_PER_BLOCK;
- return (bucket_list[_bucket][_index]);
- }
-
- const inline ElementT &back() const
+ ElementT &back() const
{
const std::size_t _bucket = current_size / ELEMENTS_PER_BLOCK;
const std::size_t _index = current_size % ELEMENTS_PER_BLOCK;
return (bucket_list[_bucket][_index]);
}
- template<class InputIterator>
- const inline void append(InputIterator first, const InputIterator last)
+ template <class InputIterator> void append(InputIterator first, const InputIterator last)
{
InputIterator position = first;
while (position != last)
@@ -310,4 +311,4 @@ class DeallocatingVector
}
};
-#endif /* DEALLOCATINGVECTOR_H_ */
+#endif /* DEALLOCATING_VECTOR_HPP */
diff --git a/data_structures/dynamic_graph.hpp b/data_structures/dynamic_graph.hpp
index 7244d1e..43e6c3a 100644
--- a/data_structures/dynamic_graph.hpp
+++ b/data_structures/dynamic_graph.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -29,16 +29,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define DYNAMICGRAPH_HPP
#include "deallocating_vector.hpp"
-#include "../Util/integer_range.hpp"
+#include "../util/integer_range.hpp"
+#include "../typedefs.h"
#include <boost/assert.hpp>
#include <cstdint>
#include <algorithm>
+#include <atomic>
#include <limits>
+#include <tuple>
#include <vector>
-#include <atomic>
template <typename EdgeDataT> class DynamicGraph
{
@@ -55,26 +57,29 @@ template <typename EdgeDataT> class DynamicGraph
NodeIterator target;
EdgeDataT data;
- InputEdge() : source(std::numeric_limits<NodeIterator>::max()), target(std::numeric_limits<NodeIterator>::max()) { }
+ InputEdge()
+ : source(std::numeric_limits<NodeIterator>::max()),
+ target(std::numeric_limits<NodeIterator>::max())
+ {
+ }
- template<typename... Ts>
- InputEdge(NodeIterator source, NodeIterator target, Ts &&...data) : source(source), target(target), data(std::forward<Ts>(data)...) { }
+ template <typename... Ts>
+ InputEdge(NodeIterator source, NodeIterator target, Ts &&... data)
+ : source(source), target(target), data(std::forward<Ts>(data)...)
+ {
+ }
- bool operator<(const InputEdge &right) const
+ bool operator<(const InputEdge &rhs) const
{
- if (source != right.source)
- {
- return source < right.source;
- }
- return target < right.target;
+ return std::tie(source, target) < std::tie(rhs.source, rhs.target);
}
};
// Constructs an empty graph with a given number of nodes.
explicit DynamicGraph(NodeIterator nodes) : number_of_nodes(nodes), number_of_edges(0)
{
- node_list.reserve(number_of_nodes);
- node_list.resize(number_of_nodes);
+ node_array.reserve(number_of_nodes);
+ node_array.resize(number_of_nodes);
edge_list.reserve(number_of_nodes * 1.1);
edge_list.resize(number_of_nodes);
@@ -83,30 +88,30 @@ template <typename EdgeDataT> class DynamicGraph
template <class ContainerT> DynamicGraph(const NodeIterator nodes, const ContainerT &graph)
{
number_of_nodes = nodes;
- number_of_edges = (EdgeIterator)graph.size();
- node_list.reserve(number_of_nodes + 1);
- node_list.resize(number_of_nodes + 1);
+ number_of_edges = static_cast<EdgeIterator>(graph.size());
+ // node_array.reserve(number_of_nodes + 1);
+ node_array.resize(number_of_nodes + 1);
EdgeIterator edge = 0;
EdgeIterator position = 0;
for (const auto node : osrm::irange(0u, number_of_nodes))
{
- EdgeIterator lastEdge = edge;
+ EdgeIterator last_edge = edge;
while (edge < number_of_edges && graph[edge].source == node)
{
++edge;
}
- node_list[node].firstEdge = position;
- node_list[node].edges = edge - lastEdge;
- position += node_list[node].edges;
+ node_array[node].first_edge = position;
+ node_array[node].edges = edge - last_edge;
+ position += node_array[node].edges;
}
- node_list.back().firstEdge = position;
+ node_array.back().first_edge = position;
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 i : osrm::irange(node_list[node].firstEdge,
- node_list[node].firstEdge + node_list[node].edges))
+ for (const auto i : osrm::irange(node_array[node].first_edge,
+ node_array[node].first_edge + node_array[node].edges))
{
edge_list[i].target = graph[edge].target;
edge_list[i].data = graph[edge].data;
@@ -121,7 +126,7 @@ template <typename EdgeDataT> class DynamicGraph
unsigned GetNumberOfEdges() const { return number_of_edges; }
- unsigned GetOutDegree(const NodeIterator n) const { return node_list[n].edges; }
+ unsigned GetOutDegree(const NodeIterator n) const { return node_array[n].edges; }
unsigned GetDirectedOutDegree(const NodeIterator n) const
{
@@ -146,12 +151,12 @@ template <typename EdgeDataT> class DynamicGraph
EdgeIterator BeginEdges(const NodeIterator n) const
{
- return EdgeIterator(node_list[n].firstEdge);
+ return EdgeIterator(node_array[n].first_edge);
}
EdgeIterator EndEdges(const NodeIterator n) const
{
- return EdgeIterator(node_list[n].firstEdge + node_list[n].edges);
+ return EdgeIterator(node_array[n].first_edge + node_array[n].edges);
}
EdgeRange GetAdjacentEdgeRange(const NodeIterator node) const
@@ -161,7 +166,7 @@ template <typename EdgeDataT> class DynamicGraph
NodeIterator InsertNode()
{
- node_list.emplace_back(node_list.back());
+ node_array.emplace_back(node_array.back());
number_of_nodes += 1;
return number_of_nodes;
@@ -170,14 +175,14 @@ template <typename EdgeDataT> class DynamicGraph
// adds an edge. Invalidates edge iterators for the source node
EdgeIterator InsertEdge(const NodeIterator from, const NodeIterator to, const EdgeDataT &data)
{
- Node &node = node_list[from];
- EdgeIterator newFirstEdge = node.edges + node.firstEdge;
+ Node &node = node_array[from];
+ EdgeIterator newFirstEdge = node.edges + node.first_edge;
if (newFirstEdge >= edge_list.size() || !isDummy(newFirstEdge))
{
- if (node.firstEdge != 0 && isDummy(node.firstEdge - 1))
+ if (node.first_edge != 0 && isDummy(node.first_edge - 1))
{
- node.firstEdge--;
- edge_list[node.firstEdge] = edge_list[node.firstEdge + node.edges];
+ node.first_edge--;
+ edge_list[node.first_edge] = edge_list[node.first_edge + node.edges];
}
else
{
@@ -192,32 +197,32 @@ template <typename EdgeDataT> class DynamicGraph
edge_list.resize(edge_list.size() + newSize);
for (const auto i : osrm::irange(0u, node.edges))
{
- edge_list[newFirstEdge + i] = edge_list[node.firstEdge + i];
- makeDummy(node.firstEdge + i);
+ 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))
{
makeDummy(newFirstEdge + i);
}
- node.firstEdge = newFirstEdge;
+ node.first_edge = newFirstEdge;
}
}
- Edge &edge = edge_list[node.firstEdge + node.edges];
+ Edge &edge = edge_list[node.first_edge + node.edges];
edge.target = to;
edge.data = data;
++number_of_edges;
++node.edges;
- return EdgeIterator(node.firstEdge + node.edges);
+ return EdgeIterator(node.first_edge + node.edges);
}
// removes an edge. Invalidates edge iterators for the source node
void DeleteEdge(const NodeIterator source, const EdgeIterator e)
{
- Node &node = node_list[source];
+ Node &node = node_array[source];
--number_of_edges;
--node.edges;
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != node.edges);
- const unsigned last = node.firstEdge + node.edges;
+ const unsigned last = node.first_edge + node.edges;
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != last);
// swap with last edge
edge_list[e] = edge_list[last];
@@ -242,7 +247,7 @@ template <typename EdgeDataT> class DynamicGraph
}
number_of_edges -= deleted;
- node_list[source].edges -= deleted;
+ node_array[source].edges -= deleted;
return deleted;
}
@@ -257,7 +262,46 @@ template <typename EdgeDataT> class DynamicGraph
return i;
}
}
- return EndEdges(from);
+ return SPECIAL_EDGEID;
+ }
+
+ // searches for a specific edge
+ EdgeIterator FindSmallestEdge(const NodeIterator from, const NodeIterator to) const
+ {
+ EdgeIterator smallest_edge = SPECIAL_EDGEID;
+ EdgeWeight smallest_weight = INVALID_EDGE_WEIGHT;
+ for (auto edge : GetAdjacentEdgeRange(from))
+ {
+ const NodeID target = GetTarget(edge);
+ const EdgeWeight weight = GetEdgeData(edge).distance;
+ if (target == to && weight < smallest_weight)
+ {
+ smallest_edge = edge;
+ smallest_weight = weight;
+ }
+ }
+ return smallest_edge;
+ }
+
+ EdgeIterator FindEdgeInEitherDirection(const NodeIterator from, const NodeIterator to) const
+ {
+ EdgeIterator tmp = FindEdge(from, to);
+ return (SPECIAL_NODEID != tmp ? tmp : FindEdge(to, from));
+ }
+
+ EdgeIterator
+ FindEdgeIndicateIfReverse(const NodeIterator from, const NodeIterator to, bool &result) const
+ {
+ EdgeIterator current_iterator = FindEdge(from, to);
+ if (SPECIAL_NODEID == current_iterator)
+ {
+ current_iterator = FindEdge(to, from);
+ if (SPECIAL_NODEID != current_iterator)
+ {
+ result = true;
+ }
+ }
+ return current_iterator;
}
protected:
@@ -274,7 +318,7 @@ template <typename EdgeDataT> class DynamicGraph
struct Node
{
// index of the first edge
- EdgeIterator firstEdge;
+ EdgeIterator first_edge;
// amount of edges
unsigned edges;
};
@@ -288,7 +332,7 @@ template <typename EdgeDataT> class DynamicGraph
NodeIterator number_of_nodes;
std::atomic_uint number_of_edges;
- std::vector<Node> node_list;
+ std::vector<Node> node_array;
DeallocatingVector<Edge> edge_list;
};
diff --git a/data_structures/edge_based_node.hpp b/data_structures/edge_based_node.hpp
index 98746d9..72a585a 100644
--- a/data_structures/edge_based_node.hpp
+++ b/data_structures/edge_based_node.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -31,94 +31,74 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../data_structures/travel_mode.hpp"
#include "../typedefs.h"
-#include <osrm/Coordinate.h>
-
#include <boost/assert.hpp>
+#include <osrm/coordinate.hpp>
+
#include <limits>
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_id(-1),
- 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,
- 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_id(component_id),
- fwd_segment_position(fwd_segment_position),
- forward_travel_mode(forward_travel_mode),
- backward_travel_mode(backward_travel_mode)
+ 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_id(-1), 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,
+ 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_id(component_id),
+ 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)
+ 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;
+ // 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;
- }
+ bool IsCompressed() const { return packed_geometry_id != SPECIAL_EDGEID; }
- bool is_in_tiny_cc() const
- {
- return 0 != component_id;
- }
+ bool is_in_tiny_cc() const { return 0 != component_id; }
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
+ 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
unsigned component_id;
unsigned short fwd_segment_position; // segment id in a compressed geometry
@@ -126,4 +106,4 @@ struct EdgeBasedNode
TravelMode backward_travel_mode : 4;
};
-#endif //EDGE_BASED_NODE_HPP
+#endif // EDGE_BASED_NODE_HPP
diff --git a/data_structures/external_memory_node.cpp b/data_structures/external_memory_node.cpp
index cd6271b..72b8198 100644
--- a/data_structures/external_memory_node.cpp
+++ b/data_structures/external_memory_node.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -26,6 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "external_memory_node.hpp"
+#include "query_node.hpp"
#include <limits>
@@ -44,11 +45,8 @@ ExternalMemoryNode ExternalMemoryNode::min_value()
ExternalMemoryNode ExternalMemoryNode::max_value()
{
- return ExternalMemoryNode(std::numeric_limits<int>::max(),
- std::numeric_limits<int>::max(),
- std::numeric_limits<unsigned>::max(),
- false,
- false);
+ return ExternalMemoryNode(std::numeric_limits<int>::max(), std::numeric_limits<int>::max(),
+ std::numeric_limits<unsigned>::max(), false, false);
}
bool ExternalMemoryNodeSTXXLCompare::operator()(const ExternalMemoryNode &left,
diff --git a/data_structures/external_memory_node.hpp b/data_structures/external_memory_node.hpp
index f88a23e..83b88e7 100644
--- a/data_structures/external_memory_node.hpp
+++ b/data_structures/external_memory_node.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "query_node.hpp"
-#include <string>
+#include "../typedefs.h"
struct ExternalMemoryNode : QueryNode
{
diff --git a/data_structures/fixed_point_number.hpp b/data_structures/fixed_point_number.hpp
index eab6850..c7ed257 100644
--- a/data_structures/fixed_point_number.hpp
+++ b/data_structures/fixed_point_number.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/data_structures/hidden_markov_model.hpp b/data_structures/hidden_markov_model.hpp
new file mode 100644
index 0000000..cccaf7b
--- /dev/null
+++ b/data_structures/hidden_markov_model.hpp
@@ -0,0 +1,158 @@
+/*
+
+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 <boost/assert.hpp>
+
+#include <cmath>
+
+#include <limits>
+#include <vector>
+
+namespace osrm
+{
+namespace matching
+{
+static const double log_2_pi = std::log(2. * M_PI);
+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
+{
+ double sigma_z;
+ double log_sigma_z;
+
+ EmissionLogProbability(const double sigma_z) : sigma_z(sigma_z), log_sigma_z(std::log(sigma_z))
+ {
+ }
+
+ double operator()(const double distance) const
+ {
+ return -0.5 * (osrm::matching::log_2_pi + (distance / sigma_z) * (distance / sigma_z)) -
+ log_sigma_z;
+ }
+};
+
+struct TransitionLogProbability
+{
+ double beta;
+ double log_beta;
+ TransitionLogProbability(const double beta) : beta(beta), log_beta(std::log(beta)) {}
+
+ double operator()(const double d_t) const { return -log_beta - d_t / beta; }
+};
+
+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<bool>> pruned;
+ std::vector<std::vector<bool>> suspicious;
+ std::vector<bool> breakage;
+
+ const CandidateLists &candidates_list;
+ const EmissionLogProbability &emission_log_probability;
+
+ HiddenMarkovModel(const CandidateLists &candidates_list,
+ const EmissionLogProbability &emission_log_probability)
+ : breakage(candidates_list.size()), candidates_list(candidates_list),
+ emission_log_probability(emission_log_probability)
+ {
+ for (const auto &l : candidates_list)
+ {
+ viterbi.emplace_back(l.size());
+ parents.emplace_back(l.size());
+ path_lengths.emplace_back(l.size());
+ suspicious.emplace_back(l.size());
+ pruned.emplace_back(l.size());
+ }
+
+ clear(0);
+ }
+
+ 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());
+
+ for (const auto t : osrm::irange(initial_timestamp, viterbi.size()))
+ {
+ std::fill(viterbi[t].begin(), viterbi[t].end(), osrm::matching::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(pruned[t].begin(), pruned[t].end(), true);
+ }
+ std::fill(breakage.begin() + initial_timestamp, breakage.end(), true);
+ }
+
+ std::size_t initialize(std::size_t initial_timestamp)
+ {
+ BOOST_ASSERT(initial_timestamp < candidates_list.size());
+
+ do
+ {
+ for (const auto s : osrm::irange<std::size_t>(0u, viterbi[initial_timestamp].size()))
+ {
+ viterbi[initial_timestamp][s] =
+ emission_log_probability(candidates_list[initial_timestamp][s].second);
+ 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;
+
+ breakage[initial_timestamp] =
+ breakage[initial_timestamp] && pruned[initial_timestamp][s];
+ }
+
+ ++initial_timestamp;
+ } while (breakage[initial_timestamp - 1]);
+
+ if (initial_timestamp >= viterbi.size())
+ {
+ return osrm::matching::INVALID_STATE;
+ }
+
+ BOOST_ASSERT(initial_timestamp > 0);
+ --initial_timestamp;
+
+ BOOST_ASSERT(breakage[initial_timestamp] == false);
+
+ return initial_timestamp;
+ }
+};
+
+#endif // HIDDEN_MARKOV_MODEL
diff --git a/data_structures/hilbert_value.cpp b/data_structures/hilbert_value.cpp
index 216b7c5..c097731 100644
--- a/data_structures/hilbert_value.cpp
+++ b/data_structures/hilbert_value.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -27,7 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "hilbert_value.hpp"
-#include <osrm/Coordinate.h>
+#include <osrm/coordinate.hpp>
uint64_t HilbertCode::operator()(const FixedPointCoordinate ¤t_coordinate) const
{
diff --git a/data_structures/hilbert_value.hpp b/data_structures/hilbert_value.hpp
index e194029..7b8bffa 100644
--- a/data_structures/hilbert_value.hpp
+++ b/data_structures/hilbert_value.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/data_structures/import_edge.cpp b/data_structures/import_edge.cpp
index 55f5f16..f41b066 100644
--- a/data_structures/import_edge.cpp
+++ b/data_structures/import_edge.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -27,7 +27,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "import_edge.hpp"
-#include <boost/assert.hpp>
+#include "travel_mode.hpp"
+#include "../typedefs.h"
bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const
{
@@ -57,8 +58,8 @@ NodeBasedEdge::NodeBasedEdge(NodeID source,
bool access_restricted,
TravelMode travel_mode,
bool is_split)
- : source(source), target(target), name_id(name_id), weight(weight),
- forward(forward), backward(backward), roundabout(roundabout), in_tiny_cc(in_tiny_cc),
+ : source(source), target(target), name_id(name_id), weight(weight), forward(forward),
+ backward(backward), roundabout(roundabout), in_tiny_cc(in_tiny_cc),
access_restricted(access_restricted), is_split(is_split), travel_mode(travel_mode)
{
}
diff --git a/data_structures/import_edge.hpp b/data_structures/import_edge.hpp
index f9004d4..f422de1 100644
--- a/data_structures/import_edge.hpp
+++ b/data_structures/import_edge.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/data_structures/raw_route_data.hpp b/data_structures/internal_route_result.hpp
similarity index 80%
rename from data_structures/raw_route_data.hpp
rename to data_structures/internal_route_result.hpp
index f9242cf..068b63a 100644
--- a/data_structures/raw_route_data.hpp
+++ b/data_structures/internal_route_result.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,25 +25,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef RAW_ROUTE_DATA_HPP
-#define RAW_ROUTE_DATA_HPP
+#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.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)
+ : node(SPECIAL_NODEID), name_id(INVALID_EDGE_WEIGHT), segment_duration(INVALID_EDGE_WEIGHT),
+ turn_instruction(TurnInstruction::NoTurn), travel_mode(TRAVEL_MODE_INACCESSIBLE)
{
}
@@ -52,8 +50,8 @@ struct PathData
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)
+ : node(node), name_id(name_id), segment_duration(segment_duration),
+ turn_instruction(turn_instruction), travel_mode(travel_mode)
{
}
NodeID node;
@@ -63,7 +61,7 @@ struct PathData
TravelMode travel_mode : 4;
};
-struct RawRouteData
+struct InternalRouteResult
{
std::vector<std::vector<PathData>> unpacked_path_segments;
std::vector<PathData> unpacked_alternative;
@@ -80,11 +78,10 @@ struct RawRouteData
return (leg != unpacked_path_segments.size() - 1);
}
- RawRouteData() :
- shortest_path_length(INVALID_EDGE_WEIGHT),
- alternative_path_length(INVALID_EDGE_WEIGHT)
+ InternalRouteResult()
+ : shortest_path_length(INVALID_EDGE_WEIGHT), alternative_path_length(INVALID_EDGE_WEIGHT)
{
}
};
-#endif // RAW_ROUTE_DATA_HPP
+#endif // RAW_ROUTE_DATA_H
diff --git a/data_structures/lru_cache.hpp b/data_structures/lru_cache.hpp
index cdbeb38..155ab1e 100644
--- a/data_structures/lru_cache.hpp
+++ b/data_structures/lru_cache.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -86,7 +86,7 @@ template <typename KeyT, typename ValueT> class LRUCache
result = e.value;
// move to front
- itemsInCache.splice(positionMap.find(key)->second, itemsInCache, itemsInCache.begin());
+ itemsInCache.splice(itemsInCache.begin(), itemsInCache, positionMap.find(key)->second);
positionMap.find(key)->second = itemsInCache.begin();
return true;
}
diff --git a/data_structures/node_based_graph.hpp b/data_structures/node_based_graph.hpp
index 8fe7b75..54e07a7 100644
--- a/data_structures/node_based_graph.hpp
+++ b/data_structures/node_based_graph.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "dynamic_graph.hpp"
#include "import_edge.hpp"
-#include "../Util/simple_logger.hpp"
+#include "../util/simple_logger.hpp"
#include <tbb/parallel_sort.h>
@@ -40,9 +40,9 @@ struct NodeBasedEdgeData
{
NodeBasedEdgeData()
: distance(INVALID_EDGE_WEIGHT), edgeBasedNodeID(SPECIAL_NODEID),
- nameID(std::numeric_limits<unsigned>::max()),
- isAccessRestricted(false), shortcut(false), forward(false), backward(false),
- roundabout(false), ignore_in_grid(false), travel_mode(TRAVEL_MODE_INACCESSIBLE)
+ nameID(std::numeric_limits<unsigned>::max()), isAccessRestricted(false), shortcut(false),
+ forward(false), backward(false), roundabout(false), ignore_in_grid(false),
+ travel_mode(TRAVEL_MODE_INACCESSIBLE)
{
}
@@ -85,7 +85,8 @@ using SimpleNodeBasedDynamicGraph = DynamicGraph<SimpleEdgeData>;
inline std::shared_ptr<NodeBasedDynamicGraph>
NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge> &input_edge_list)
{
- static_assert(sizeof(NodeBasedEdgeData) == 16, "changing node based edge data size changes memory consumption");
+ static_assert(sizeof(NodeBasedEdgeData) == 16,
+ "changing node based edge data size changes memory consumption");
DeallocatingVector<NodeBasedDynamicGraph::InputEdge> edges_list;
NodeBasedDynamicGraph::InputEdge edge;
@@ -111,7 +112,7 @@ NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge
continue;
}
- edge.data.distance = (std::max)((int)import_edge.weight, 1);
+ edge.data.distance = (std::max)(static_cast<int>(import_edge.weight), 1);
BOOST_ASSERT(edge.data.distance > 0);
edge.data.shortcut = false;
edge.data.roundabout = import_edge.roundabout;
@@ -134,7 +135,7 @@ NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge
// remove duplicate edges
tbb::parallel_sort(edges_list.begin(), edges_list.end());
NodeID edge_count = 0;
- for (NodeID i = 0; i < edges_list.size(); )
+ for (NodeID i = 0; i < edges_list.size();)
{
const NodeID source = edges_list[i].source;
const NodeID target = edges_list[i].target;
@@ -150,10 +151,10 @@ NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge
forward_edge.data.forward = reverse_edge.data.backward = true;
forward_edge.data.backward = reverse_edge.data.forward = false;
forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
- forward_edge.data.distance = reverse_edge.data.distance =
- std::numeric_limits<int>::max();
+ forward_edge.data.distance = reverse_edge.data.distance = std::numeric_limits<int>::max();
// remove parallel edges
- while (i < edges_list.size() && edges_list[i].source == source && edges_list[i].target == target)
+ while (i < edges_list.size() && edges_list[i].source == source &&
+ edges_list[i].target == target)
{
if (edges_list[i].data.forward)
{
@@ -170,7 +171,7 @@ NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge
// 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 (static_cast<int>(forward_edge.data.distance) != std::numeric_limits<int>::max())
{
forward_edge.data.backward = true;
edges_list[edge_count++] = forward_edge;
@@ -178,28 +179,31 @@ NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge
}
else
{ // insert seperate edges
- if (((int)forward_edge.data.distance) != std::numeric_limits<int>::max())
+ if (static_cast<int>(forward_edge.data.distance) != std::numeric_limits<int>::max())
{
edges_list[edge_count++] = forward_edge;
}
- if ((int)reverse_edge.data.distance != std::numeric_limits<int>::max())
+ if (static_cast<int>(reverse_edge.data.distance) != std::numeric_limits<int>::max())
{
edges_list[edge_count++] = reverse_edge;
}
}
}
edges_list.resize(edge_count);
- SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of " << edges_list.size();
+ SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of "
+ << edges_list.size();
- auto graph = std::make_shared<NodeBasedDynamicGraph>(static_cast<NodeBasedDynamicGraph::NodeIterator>(number_of_nodes), edges_list);
+ auto graph = std::make_shared<NodeBasedDynamicGraph>(
+ static_cast<NodeBasedDynamicGraph::NodeIterator>(number_of_nodes), edges_list);
return graph;
}
-template<class SimpleEdgeT>
+template <class SimpleEdgeT>
inline std::shared_ptr<SimpleNodeBasedDynamicGraph>
SimpleNodeBasedDynamicGraphFromEdges(int number_of_nodes, std::vector<SimpleEdgeT> &input_edge_list)
{
- static_assert(sizeof(NodeBasedEdgeData) == 16, "changing node based edge data size changes memory consumption");
+ static_assert(sizeof(NodeBasedEdgeData) == 16,
+ "changing node based edge data size changes memory consumption");
tbb::parallel_sort(input_edge_list.begin(), input_edge_list.end());
DeallocatingVector<SimpleNodeBasedDynamicGraph::InputEdge> edges_list;
@@ -218,10 +222,10 @@ SimpleNodeBasedDynamicGraphFromEdges(int number_of_nodes, std::vector<SimpleEdge
edges_list.push_back(edge);
}
- // remove duplicate edges
+ // remove duplicate edges
tbb::parallel_sort(edges_list.begin(), edges_list.end());
NodeID edge_count = 0;
- for (NodeID i = 0; i < edges_list.size(); )
+ for (NodeID i = 0; i < edges_list.size();)
{
const NodeID source = edges_list[i].source;
const NodeID target = edges_list[i].target;
@@ -236,33 +240,37 @@ SimpleNodeBasedDynamicGraphFromEdges(int number_of_nodes, std::vector<SimpleEdge
forward_edge = reverse_edge = edges_list[i];
forward_edge.data.capacity = reverse_edge.data.capacity = INVALID_EDGE_WEIGHT;
// remove parallel edges
- while (i < edges_list.size() && edges_list[i].source == source && edges_list[i].target == target)
+ while (i < edges_list.size() && edges_list[i].source == source &&
+ edges_list[i].target == target)
{
- forward_edge.data.capacity = std::min(edges_list[i].data.capacity, forward_edge.data.capacity);
- reverse_edge.data.capacity = std::min(edges_list[i].data.capacity, reverse_edge.data.capacity);
+ forward_edge.data.capacity =
+ std::min(edges_list[i].data.capacity, forward_edge.data.capacity);
+ reverse_edge.data.capacity =
+ std::min(edges_list[i].data.capacity, reverse_edge.data.capacity);
++i;
}
// merge edges (s,t) and (t,s) into bidirectional edge
if (forward_edge.data.capacity == reverse_edge.data.capacity)
{
- if ((int)forward_edge.data.capacity != INVALID_EDGE_WEIGHT)
+ if (static_cast<int>(forward_edge.data.capacity) != INVALID_EDGE_WEIGHT)
{
edges_list[edge_count++] = forward_edge;
}
}
else
{ // insert seperate edges
- if (((int)forward_edge.data.capacity) != INVALID_EDGE_WEIGHT)
+ if (static_cast<int>(forward_edge.data.capacity) != INVALID_EDGE_WEIGHT)
{
edges_list[edge_count++] = forward_edge;
}
- if ((int)reverse_edge.data.capacity != INVALID_EDGE_WEIGHT)
+ if (static_cast<int>(reverse_edge.data.capacity) != INVALID_EDGE_WEIGHT)
{
edges_list[edge_count++] = reverse_edge;
}
}
}
- SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of " << edges_list.size();
+ SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of "
+ << edges_list.size();
auto graph = std::make_shared<SimpleNodeBasedDynamicGraph>(number_of_nodes, edges_list);
return graph;
diff --git a/data_structures/node_id.hpp b/data_structures/node_id.hpp
index 4f07809..4d6fff0 100644
--- a/data_structures/node_id.hpp
+++ b/data_structures/node_id.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/data_structures/original_edge_data.hpp b/data_structures/original_edge_data.hpp
index b4fdfd9..cbbc1b2 100644
--- a/data_structures/original_edge_data.hpp
+++ b/data_structures/original_edge_data.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -48,9 +48,8 @@ struct OriginalEdgeData
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)
+ name_id(std::numeric_limits<unsigned>::max()), turn_instruction(TurnInstruction::NoTurn),
+ compressed_geometry(false), travel_mode(TRAVEL_MODE_INACCESSIBLE)
{
}
diff --git a/data_structures/percent.hpp b/data_structures/percent.hpp
index 0c4e152..392417e 100644
--- a/data_structures/percent.hpp
+++ b/data_structures/percent.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -36,7 +36,7 @@ class Percent
public:
explicit Percent(unsigned max_value, unsigned step = 5) { reinit(max_value, step); }
- // Reinitializes
+ // Reinitializes
void reinit(unsigned max_value, unsigned step = 5)
{
m_max_value = max_value;
diff --git a/data_structures/phantom_node.cpp b/data_structures/phantom_node.cpp
index 413c0d7..eba6492 100644
--- a/data_structures/phantom_node.cpp
+++ b/data_structures/phantom_node.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -27,40 +27,44 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "phantom_node.hpp"
-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, 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_id(component_id),
- 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_id(-1),
- fwd_segment_position(0),
- forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
- backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
-{ }
+#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,
+ 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_id(component_id), 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_id(std::numeric_limits<unsigned>::max()),
+ fwd_segment_position(0), forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
+ backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
+{
+}
int PhantomNode::GetForwardWeightPlusOffset() const
{
@@ -82,43 +86,21 @@ int PhantomNode::GetReverseWeightPlusOffset() const
bool PhantomNode::is_bidirected() const
{
- return (forward_node_id != SPECIAL_NODEID) &&
- (reverse_node_id != SPECIAL_NODEID);
+ 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_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)
- ) &&
- (name_id != INVALID_NAMEID
- );
-}
-
-bool PhantomNode::is_in_tiny_component() const
-{
- return component_id != 0;
-}
-
-bool PhantomNode::is_valid() 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)) &&
(name_id != INVALID_NAMEID);
}
-bool PhantomNode::operator==(const PhantomNode & other) const
-{
- return location == other.location;
-}
+bool PhantomNode::is_in_tiny_component() const { return component_id != 0; }
+
+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
index 9286fb9..b048eb7 100644
--- a/data_structures/phantom_node.hpp
+++ b/data_structures/phantom_node.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,11 +28,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef PHANTOM_NODES_H
#define PHANTOM_NODES_H
-#include <osrm/Coordinate.h>
-#include "../data_structures/travel_mode.hpp"
+#include "travel_mode.hpp"
#include "../typedefs.h"
+#include <osrm/coordinate.hpp>
+
#include <iostream>
+#include <utility>
#include <vector>
struct PhantomNode
@@ -53,6 +55,28 @@ struct PhantomNode
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;
+
+ 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;
@@ -81,14 +105,13 @@ struct PhantomNode
bool is_in_tiny_component() const;
- bool operator==(const PhantomNode & other) const;
+ bool operator==(const PhantomNode &other) const;
};
using PhantomNodeArray = std::vector<std::vector<PhantomNode>>;
class phantom_node_pair : public std::pair<PhantomNode, PhantomNode>
{
-
};
struct PhantomNodeLists
@@ -103,26 +126,26 @@ struct PhantomNodes
PhantomNode target_phantom;
};
-inline std::ostream& operator<<(std::ostream &out, const PhantomNodes & pn)
+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)
+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_id << ", " <<
- "pos: " << pn.fwd_segment_position << ", " <<
- "loc: " << pn.location;
+ 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_id << ", "
+ << "pos: " << pn.fwd_segment_position << ", "
+ << "loc: " << pn.location;
return out;
}
diff --git a/data_structures/query_edge.hpp b/data_structures/query_edge.hpp
index 84a7f15..417bb4a 100644
--- a/data_structures/query_edge.hpp
+++ b/data_structures/query_edge.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,11 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef QUERYEDGE_HPP_
-#define QUERYEDGE_HPP_
+#ifndef QUERYEDGE_HPP
+#define QUERYEDGE_HPP
#include "../typedefs.h"
+#include <tuple>
+
struct QueryEdge
{
NodeID source;
@@ -60,13 +62,9 @@ struct QueryEdge
{
}
- bool operator<(const QueryEdge &right) const
+ bool operator<(const QueryEdge &rhs) const
{
- if (source != right.source)
- {
- return source < right.source;
- }
- return target < right.target;
+ return std::tie(source, target) < std::tie(rhs.source, rhs.target);
}
bool operator==(const QueryEdge &right) const
@@ -78,4 +76,4 @@ struct QueryEdge
}
};
-#endif /* QUERYEDGE_HPP_ */
+#endif // QUERYEDGE_HPP
diff --git a/data_structures/query_node.hpp b/data_structures/query_node.hpp
index 7705df0..f3e9904 100644
--- a/data_structures/query_node.hpp
+++ b/data_structures/query_node.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,16 +30,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../typedefs.h"
-#include <osrm/Coordinate.h>
-
#include <boost/assert.hpp>
+#include <osrm/coordinate.hpp>
+
#include <limits>
struct QueryNode
{
using key_type = NodeID; // type of NodeID
- using value_type = int; // type of lat,lons
+ using value_type = int; // type of lat,lons
explicit QueryNode(int lat, int lon, NodeID node_id) : lat(lat), lon(lon), node_id(node_id) {}
QueryNode()
diff --git a/data_structures/range_table.hpp b/data_structures/range_table.hpp
index eef268b..4662f06 100644
--- a/data_structures/range_table.hpp
+++ b/data_structures/range_table.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,7 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef RANGE_TABLE_HPP
#define RANGE_TABLE_HPP
-#include "../Util/integer_range.hpp"
+#include "../util/integer_range.hpp"
#include "shared_memory_factory.hpp"
#include "shared_memory_vector_wrapper.hpp"
@@ -41,13 +41,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* and otherwise the compiler gets confused.
*/
-template<unsigned BLOCK_SIZE=16, bool USE_SHARED_MEMORY = false> class RangeTable;
+template <unsigned BLOCK_SIZE = 16, bool USE_SHARED_MEMORY = false> class RangeTable;
-template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
-std::ostream& operator<<(std::ostream &out, const RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table);
+template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
+std::ostream &operator<<(std::ostream &out, const RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table);
-template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
-std::istream& operator>>(std::istream &in, RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table);
+template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
+std::istream &operator>>(std::istream &in, RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table);
/**
* Stores adjacent ranges in a compressed format.
@@ -58,33 +58,34 @@ std::istream& operator>>(std::istream &in, RangeTable<BLOCK_SIZE, USE_SHARED_MEM
* But each block consists of an absolute value and BLOCK_SIZE differential values.
* So the effective block size is sizeof(unsigned) + BLOCK_SIZE.
*/
-template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
-class RangeTable
+template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY> class RangeTable
{
-public:
-
+ public:
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>;
- friend std::ostream& operator<< <>(std::ostream &out, const RangeTable &table);
- friend std::istream& operator>> <>(std::istream &in, RangeTable &table);
+ friend std::ostream &operator<<<>(std::ostream &out, const RangeTable &table);
+ friend std::istream &operator>><>(std::istream &in, RangeTable &table);
RangeTable() : sum_lengths(0) {}
// for loading from shared memory
- explicit RangeTable(OffsetContainerT& external_offsets, BlockContainerT& external_blocks, const unsigned sum_lengths)
- : sum_lengths(sum_lengths)
+ explicit RangeTable(OffsetContainerT &external_offsets,
+ BlockContainerT &external_blocks,
+ const unsigned sum_lengths)
+ : sum_lengths(sum_lengths)
{
block_offsets.swap(external_offsets);
diff_blocks.swap(external_blocks);
}
// construct table from length vector
- explicit RangeTable(const std::vector<unsigned>& lengths)
+ explicit RangeTable(const std::vector<unsigned> &lengths)
{
- const unsigned number_of_blocks = [&lengths]() {
+ const unsigned number_of_blocks = [&lengths]()
+ {
unsigned num = (lengths.size() + 1) / (BLOCK_SIZE + 1);
if ((lengths.size() + 1) % (BLOCK_SIZE + 1) != 0)
{
@@ -116,8 +117,8 @@ public:
block_sum += last_length;
}
- BOOST_ASSERT((block_idx == 0 && block_offsets[block_counter] == lengths_prefix_sum)
- || lengths_prefix_sum == (block_offsets[block_counter]+block_sum));
+ BOOST_ASSERT((block_idx == 0 && block_offsets[block_counter] == lengths_prefix_sum) ||
+ lengths_prefix_sum == (block_offsets[block_counter] + block_sum));
// block is full
if (BLOCK_SIZE == block_idx)
@@ -136,7 +137,7 @@ public:
}
// Last block can't be finished because we didn't add the sentinel
- BOOST_ASSERT (block_counter == (number_of_blocks - 1));
+ BOOST_ASSERT(block_counter == (number_of_blocks - 1));
// one block missing: starts with guard value
if (0 == block_idx)
@@ -155,7 +156,8 @@ public:
}
diff_blocks.push_back(block);
- BOOST_ASSERT(diff_blocks.size() == number_of_blocks && block_offsets.size() == number_of_blocks);
+ BOOST_ASSERT(diff_blocks.size() == number_of_blocks &&
+ block_offsets.size() == number_of_blocks);
sum_lengths = lengths_prefix_sum;
}
@@ -172,7 +174,7 @@ public:
unsigned begin_idx = 0;
unsigned end_idx = 0;
begin_idx = block_offsets[block_idx];
- const BlockT& block = diff_blocks[block_idx];
+ const BlockT &block = diff_blocks[block_idx];
if (internal_idx > 0)
{
begin_idx += PrefixSumAtIndex(internal_idx - 1, block);
@@ -195,9 +197,9 @@ public:
return osrm::irange(begin_idx, end_idx);
}
-private:
- inline unsigned PrefixSumAtIndex(int index, const BlockT& block) const;
+ private:
+ inline unsigned PrefixSumAtIndex(int index, const BlockT &block) const;
// contains offset for each differential block
OffsetContainerT block_offsets;
@@ -206,8 +208,9 @@ private:
unsigned sum_lengths;
};
-template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
-unsigned RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY>::PrefixSumAtIndex(int index, const BlockT& block) const
+template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
+unsigned RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY>::PrefixSumAtIndex(int index,
+ const BlockT &block) const
{
// this loop looks inefficent, but a modern compiler
// will emit nice SIMD here, at least for sensible block sizes. (I checked.)
@@ -220,39 +223,39 @@ unsigned RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY>::PrefixSumAtIndex(int index,
return sum;
}
-template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
-std::ostream& operator<<(std::ostream &out, const RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table)
+template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
+std::ostream &operator<<(std::ostream &out, const RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table)
{
// write number of block
const unsigned number_of_blocks = table.diff_blocks.size();
- out.write((char *) &number_of_blocks, sizeof(unsigned));
+ out.write((char *)&number_of_blocks, sizeof(unsigned));
// write total length
- out.write((char *) &table.sum_lengths, sizeof(unsigned));
+ out.write((char *)&table.sum_lengths, sizeof(unsigned));
// write block offsets
- out.write((char *) table.block_offsets.data(), sizeof(unsigned) * table.block_offsets.size());
+ out.write((char *)table.block_offsets.data(), sizeof(unsigned) * table.block_offsets.size());
// write blocks
- out.write((char *) table.diff_blocks.data(), BLOCK_SIZE * table.diff_blocks.size());
+ out.write((char *)table.diff_blocks.data(), BLOCK_SIZE * table.diff_blocks.size());
return out;
}
-template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
-std::istream& operator>>(std::istream &in, RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table)
+template <unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
+std::istream &operator>>(std::istream &in, RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table)
{
// read number of block
unsigned number_of_blocks;
- in.read((char *) &number_of_blocks, sizeof(unsigned));
+ in.read((char *)&number_of_blocks, sizeof(unsigned));
// read total length
- in.read((char *) &table.sum_lengths, sizeof(unsigned));
+ in.read((char *)&table.sum_lengths, sizeof(unsigned));
table.block_offsets.resize(number_of_blocks);
table.diff_blocks.resize(number_of_blocks);
// read block offsets
- in.read((char *) table.block_offsets.data(), sizeof(unsigned) * number_of_blocks);
+ in.read((char *)table.block_offsets.data(), sizeof(unsigned) * number_of_blocks);
// read blocks
- in.read((char *) table.diff_blocks.data(), BLOCK_SIZE * number_of_blocks);
+ in.read((char *)table.diff_blocks.data(), BLOCK_SIZE * number_of_blocks);
return in;
}
-#endif //RANGE_TABLE_HPP
+#endif // RANGE_TABLE_HPP
diff --git a/data_structures/rectangle.hpp b/data_structures/rectangle.hpp
index 2f6815c..55720a3 100644
--- a/data_structures/rectangle.hpp
+++ b/data_structures/rectangle.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,8 +28,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef RECTANGLE_HPP
#define RECTANGLE_HPP
+#include "coordinate_calculation.hpp"
+
#include <boost/assert.hpp>
+#include <osrm/coordinate.hpp>
+
#include <algorithm>
#include <cstdint>
#include <limits>
@@ -37,15 +41,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 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()) {}
+ 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;
- inline void MergeBoundingBoxes(const RectangleInt2D &other)
+ void MergeBoundingBoxes(const RectangleInt2D &other)
{
min_lon = std::min(min_lon, other.min_lon);
max_lon = std::max(max_lon, other.max_lon);
@@ -57,7 +63,7 @@ struct RectangleInt2D
BOOST_ASSERT(max_lon != std::numeric_limits<int32_t>::min());
}
- inline FixedPointCoordinate Centroid() const
+ FixedPointCoordinate Centroid() const
{
FixedPointCoordinate centroid;
// The coordinates of the midpoints are given by:
@@ -67,7 +73,7 @@ struct RectangleInt2D
return centroid;
}
- inline bool Intersects(const RectangleInt2D &other) const
+ bool Intersects(const RectangleInt2D &other) const
{
FixedPointCoordinate upper_left(other.max_lat, other.min_lon);
FixedPointCoordinate upper_right(other.max_lat, other.max_lon);
@@ -78,7 +84,7 @@ struct RectangleInt2D
Contains(lower_left));
}
- inline float GetMinDist(const FixedPointCoordinate &location) const
+ float GetMinDist(const FixedPointCoordinate &location) const
{
const bool is_contained = Contains(location);
if (is_contained)
@@ -88,66 +94,74 @@ struct RectangleInt2D
enum Direction
{
- INVALID = 0,
- NORTH = 1,
- SOUTH = 2,
- EAST = 4,
+ INVALID = 0,
+ NORTH = 1,
+ SOUTH = 2,
+ EAST = 4,
NORTH_EAST = 5,
SOUTH_EAST = 6,
- WEST = 8,
+ WEST = 8,
NORTH_WEST = 9,
SOUTH_WEST = 10
};
Direction d = INVALID;
if (location.lat > max_lat)
- d = (Direction) (d | NORTH);
+ d = (Direction)(d | NORTH);
else if (location.lat < min_lat)
- d = (Direction) (d | SOUTH);
+ d = (Direction)(d | SOUTH);
if (location.lon > max_lon)
- d = (Direction) (d | EAST);
+ d = (Direction)(d | EAST);
else if (location.lon < min_lon)
- d = (Direction) (d | WEST);
+ d = (Direction)(d | WEST);
BOOST_ASSERT(d != INVALID);
float min_dist = std::numeric_limits<float>::max();
switch (d)
{
- case NORTH:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, location.lon));
- break;
- case SOUTH:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, location.lon));
- break;
- case WEST:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, min_lon));
- break;
- case EAST:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, max_lon));
- break;
- case NORTH_EAST:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, max_lon));
- break;
- case NORTH_WEST:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, min_lon));
- break;
- case SOUTH_EAST:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, max_lon));
- break;
- case SOUTH_WEST:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, min_lon));
- break;
- default:
- break;
+ case NORTH:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(max_lat, location.lon));
+ break;
+ case SOUTH:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(min_lat, location.lon));
+ break;
+ case WEST:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(location.lat, min_lon));
+ break;
+ case EAST:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(location.lat, max_lon));
+ break;
+ case NORTH_EAST:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(max_lat, max_lon));
+ break;
+ case NORTH_WEST:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(max_lat, min_lon));
+ break;
+ case SOUTH_EAST:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(min_lat, max_lon));
+ break;
+ case SOUTH_WEST:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(min_lat, min_lon));
+ break;
+ default:
+ break;
}
- BOOST_ASSERT(min_dist != std::numeric_limits<float>::max());
+ BOOST_ASSERT(min_dist < std::numeric_limits<float>::max());
return min_dist;
}
- inline float GetMinMaxDist(const FixedPointCoordinate &location) const
+ float GetMinMaxDist(const FixedPointCoordinate &location) const
{
float min_max_dist = std::numeric_limits<float>::max();
// Get minmax distance to each of the four sides
@@ -156,38 +170,36 @@ struct RectangleInt2D
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(
- FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left),
- FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right)));
-
- min_max_dist = std::min(
- min_max_dist,
- std::max(
- FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right),
- FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right)));
-
- min_max_dist = std::min(
- min_max_dist,
- std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right),
- FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left)));
-
- min_max_dist = std::min(
- min_max_dist,
- std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left),
- FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left)));
+ min_max_dist =
+ std::min(min_max_dist,
+ std::max(coordinate_calculation::euclidean_distance(location, upper_left),
+ coordinate_calculation::euclidean_distance(location, upper_right)));
+
+ min_max_dist =
+ std::min(min_max_dist,
+ std::max(coordinate_calculation::euclidean_distance(location, upper_right),
+ coordinate_calculation::euclidean_distance(location, lower_right)));
+
+ min_max_dist =
+ std::min(min_max_dist,
+ std::max(coordinate_calculation::euclidean_distance(location, lower_right),
+ coordinate_calculation::euclidean_distance(location, lower_left)));
+
+ min_max_dist =
+ std::min(min_max_dist,
+ std::max(coordinate_calculation::euclidean_distance(location, lower_left),
+ coordinate_calculation::euclidean_distance(location, upper_left)));
return min_max_dist;
}
- inline bool Contains(const FixedPointCoordinate &location) const
+ 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;
}
- inline friend std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect)
+ friend std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect)
{
out << rect.min_lat / COORDINATE_PRECISION << "," << rect.min_lon / COORDINATE_PRECISION
<< " " << rect.max_lat / COORDINATE_PRECISION << ","
diff --git a/data_structures/restriction.hpp b/data_structures/restriction.hpp
index 5f6e9b0..b808d30 100644
--- a/data_structures/restriction.hpp
+++ b/data_structures/restriction.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -107,21 +107,19 @@ struct InputRestrictionContainer
struct CmpRestrictionContainerByFrom
{
- typedef InputRestrictionContainer value_type;
- inline bool operator()(const InputRestrictionContainer &a,
- const InputRestrictionContainer &b) const
+ using value_type = InputRestrictionContainer;
+ bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b) const
{
return a.restriction.from.way < b.restriction.from.way;
}
- inline value_type max_value() const { return InputRestrictionContainer::max_value(); }
- inline value_type min_value() const { return InputRestrictionContainer::min_value(); }
+ value_type max_value() const { return InputRestrictionContainer::max_value(); }
+ value_type min_value() const { return InputRestrictionContainer::min_value(); }
};
struct CmpRestrictionContainerByTo
{
- typedef InputRestrictionContainer value_type;
- inline bool operator()(const InputRestrictionContainer &a,
- const InputRestrictionContainer &b) const
+ using value_type = InputRestrictionContainer;
+ bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b) const
{
return a.restriction.to.way < b.restriction.to.way;
}
diff --git a/data_structures/restriction_map.cpp b/data_structures/restriction_map.cpp
index 3c13d73..017ee32 100644
--- a/data_structures/restriction_map.cpp
+++ b/data_structures/restriction_map.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -27,54 +27,51 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "restriction_map.hpp"
-RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_list)
- : m_count(0)
+RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_list) : m_count(0)
+{
+ // decompose restriction consisting of a start, via and end node into a
+ // a pair of starting edge and a list of all end nodes
+ for (auto &restriction : restriction_list)
{
- // decompose restriction consisting of a start, via and end node into a
- // a pair of starting edge and a list of all end nodes
- for (auto &restriction : restriction_list)
- {
- m_restriction_start_nodes.insert(restriction.from.node);
- m_no_turn_via_node_set.insert(restriction.via.node);
+ m_restriction_start_nodes.insert(restriction.from.node);
+ m_no_turn_via_node_set.insert(restriction.via.node);
- RestrictionSource restriction_source = {restriction.from.node, restriction.via.node};
+ RestrictionSource restriction_source = {restriction.from.node, restriction.via.node};
- std::size_t index;
- auto restriction_iter = m_restriction_map.find(restriction_source);
- if (restriction_iter == m_restriction_map.end())
+ std::size_t index;
+ auto restriction_iter = m_restriction_map.find(restriction_source);
+ if (restriction_iter == m_restriction_map.end())
+ {
+ index = m_restriction_bucket_list.size();
+ m_restriction_bucket_list.resize(index + 1);
+ m_restriction_map.emplace(restriction_source, index);
+ }
+ else
+ {
+ index = restriction_iter->second;
+ // Map already contains an is_only_*-restriction
+ if (m_restriction_bucket_list.at(index).begin()->is_only)
{
- index = m_restriction_bucket_list.size();
- m_restriction_bucket_list.resize(index + 1);
- m_restriction_map.emplace(restriction_source, index);
+ continue;
}
- else
+ else if (restriction.flags.is_only)
{
- index = restriction_iter->second;
- // Map already contains an is_only_*-restriction
- if (m_restriction_bucket_list.at(index).begin()->is_only)
- {
- continue;
- }
- else if (restriction.flags.is_only)
- {
- // We are going to insert an is_only_*-restriction. There can be only one.
- m_count -= m_restriction_bucket_list.at(index).size();
- m_restriction_bucket_list.at(index).clear();
- }
+ // We are going to insert an is_only_*-restriction. There can be only one.
+ m_count -= m_restriction_bucket_list.at(index).size();
+ m_restriction_bucket_list.at(index).clear();
}
- ++m_count;
- m_restriction_bucket_list.at(index)
- .emplace_back(restriction.to.node, restriction.flags.is_only);
}
+ ++m_count;
+ m_restriction_bucket_list.at(index)
+ .emplace_back(restriction.to.node, restriction.flags.is_only);
}
-
+}
bool RestrictionMap::IsViaNode(const NodeID node) const
{
return m_no_turn_via_node_set.find(node) != m_no_turn_via_node_set.end();
}
-
// Replaces start edge (v, w) with (u, w). Only start node changes.
void RestrictionMap::FixupStartingTurnRestriction(const NodeID node_u,
const NodeID node_v,
@@ -145,18 +142,25 @@ bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
}
const auto restriction_iter = m_restriction_map.find({node_u, node_v});
- if (restriction_iter != m_restriction_map.end())
+ if (restriction_iter == m_restriction_map.end())
{
- const unsigned index = restriction_iter->second;
- const auto &bucket = m_restriction_bucket_list.at(index);
- for (const RestrictionTarget &restriction_target : bucket)
+ return false;
+ }
+
+ const unsigned index = restriction_iter->second;
+ const auto &bucket = m_restriction_bucket_list.at(index);
+
+ for (const RestrictionTarget &restriction_target : bucket)
+ {
+ if (node_w == restriction_target.target_node && // target found
+ !restriction_target.is_only) // and not an only_-restr.
{
- if ((node_w == restriction_target.target_node) && // target found
- (!restriction_target.is_only) // and not an only_-restr.
- )
- {
- return true;
- }
+ return true;
+ }
+ if (node_w != restriction_target.target_node && // target not found
+ restriction_target.is_only) // and is an only restriction
+ {
+ return true;
}
}
return false;
diff --git a/data_structures/restriction_map.hpp b/data_structures/restriction_map.hpp
index 7633faf..27a6698 100644
--- a/data_structures/restriction_map.hpp
+++ b/data_structures/restriction_map.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,14 +28,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef RESTRICTION_MAP_HPP
#define RESTRICTION_MAP_HPP
-#include <memory>
-
#include "restriction.hpp"
-#include "../Util/std_hash.hpp"
+#include "../util/std_hash.hpp"
#include "../typedefs.h"
#include <boost/assert.hpp>
+#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
@@ -45,9 +44,7 @@ struct RestrictionSource
NodeID start_node;
NodeID via_node;
- RestrictionSource(NodeID start, NodeID via) : start_node(start), via_node(via)
- {
- }
+ RestrictionSource(NodeID start, NodeID via) : start_node(start), via_node(via) {}
friend inline bool operator==(const RestrictionSource &lhs, const RestrictionSource &rhs)
{
@@ -60,9 +57,7 @@ struct RestrictionTarget
NodeID target_node;
bool is_only;
- explicit RestrictionTarget(NodeID target, bool only) : target_node(target), is_only(only)
- {
- }
+ explicit RestrictionTarget(NodeID target, bool only) : target_node(target), is_only(only) {}
friend inline bool operator==(const RestrictionTarget &lhs, const RestrictionTarget &rhs)
{
@@ -99,7 +94,7 @@ class RestrictionMap
RestrictionMap(const std::vector<TurnRestriction> &restriction_list);
// Replace end v with w in each turn restriction containing u as via node
- template<class GraphT>
+ template <class GraphT>
void FixupArrivingTurnRestriction(const NodeID node_u,
const NodeID node_v,
const NodeID node_w,
@@ -136,6 +131,7 @@ class RestrictionMap
const unsigned index = restriction_iterator->second;
auto &bucket = m_restriction_bucket_list.at(index);
+
for (RestrictionTarget &restriction_target : bucket)
{
if (node_v == restriction_target.target_node)
@@ -148,24 +144,18 @@ class RestrictionMap
bool IsViaNode(const NodeID node) const;
-
// Replaces start edge (v, w) with (u, w). Only start node changes.
- void FixupStartingTurnRestriction(const NodeID node_u,
- const NodeID node_v,
- const NodeID node_w);
+ void
+ FixupStartingTurnRestriction(const NodeID node_u, const NodeID node_v, const NodeID node_w);
// Check if edge (u, v) is the start of any turn restriction.
// If so returns id of first target node.
NodeID CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const;
// Checks if turn <u,v,w> is actually a turn restriction.
- bool CheckIfTurnIsRestricted(const NodeID node_u,
- const NodeID node_v,
- const NodeID node_w) const;
+ bool
+ CheckIfTurnIsRestricted(const NodeID node_u, const NodeID node_v, const NodeID node_w) const;
- std::size_t size()
- {
- return m_count;
- }
+ std::size_t size() { return m_count; }
private:
// check of node is the start of any restriction
@@ -182,4 +172,4 @@ class RestrictionMap
std::unordered_set<NodeID> m_no_turn_via_node_set;
};
-#endif //RESTRICTION_MAP_HPP
+#endif // RESTRICTION_MAP_HPP
diff --git a/data_structures/route_parameters.cpp b/data_structures/route_parameters.cpp
index 1019a91..3b615e2 100644
--- a/data_structures/route_parameters.cpp
+++ b/data_structures/route_parameters.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,15 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <osrm/RouteParameters.h>
-
#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/sequence/intrinsic.hpp>
#include <boost/fusion/include/at_c.hpp>
+#include <osrm/route_parameters.hpp>
+
RouteParameters::RouteParameters()
: zoom_level(18), print_instructions(false), alternate_route(true), geometry(true),
- compression(true), deprecatedAPI(false), uturn_default(false), check_sum(-1), num_results(1)
+ compression(true), deprecatedAPI(false), uturn_default(false), classify(false),
+ matching_beta(-1.0), gps_precision(-1.0), check_sum(-1), num_results(1)
{
}
@@ -83,6 +84,12 @@ void RouteParameters::setInstructionFlag(const bool flag) { print_instructions =
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)
@@ -99,6 +106,15 @@ void RouteParameters::addHint(const std::string &hint)
}
}
+void RouteParameters::addTimestamp(const unsigned timestamp)
+{
+ timestamps.resize(coordinates.size());
+ if (!timestamps.empty())
+ {
+ timestamps.back() = timestamp;
+ }
+}
+
void RouteParameters::setLanguage(const std::string &language_string)
{
language = language_string;
@@ -108,10 +124,10 @@ 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> &transmitted_coordinates)
+void RouteParameters::addCoordinate(
+ const boost::fusion::vector<double, double> &received_coordinates)
{
coordinates.emplace_back(
- static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<0>(transmitted_coordinates)),
- static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<1>(transmitted_coordinates)));
+ static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<0>(received_coordinates)),
+ static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<1>(received_coordinates)));
}
diff --git a/data_structures/search_engine.hpp b/data_structures/search_engine.hpp
index 0b2b888..7e47b1f 100644
--- a/data_structures/search_engine.hpp
+++ b/data_structures/search_engine.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#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 <type_traits>
@@ -45,13 +46,18 @@ template <class DataFacadeT> class SearchEngine
ShortestPathRouting<DataFacadeT> 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),
- alternative_path(facade, engine_working_data), distance_table(facade, engine_working_data)
+ : facade(facade),
+ 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");
+ static_assert(std::is_object<DataFacadeT>::value,
+ "don't instantiate with void, function, or reference");
}
~SearchEngine() {}
diff --git a/data_structures/search_engine_data.cpp b/data_structures/search_engine_data.cpp
index 810762a..3282a0c 100644
--- a/data_structures/search_engine_data.cpp
+++ b/data_structures/search_engine_data.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -31,63 +31,63 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes)
{
- if (forwardHeap.get())
+ if (forward_heap_1.get())
{
- forwardHeap->Clear();
+ forward_heap_1->Clear();
}
else
{
- forwardHeap.reset(new QueryHeap(number_of_nodes));
+ forward_heap_1.reset(new QueryHeap(number_of_nodes));
}
- if (backwardHeap.get())
+ if (reverse_heap_1.get())
{
- backwardHeap->Clear();
+ reverse_heap_1->Clear();
}
else
{
- backwardHeap.reset(new QueryHeap(number_of_nodes));
+ reverse_heap_1.reset(new QueryHeap(number_of_nodes));
}
}
void SearchEngineData::InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes)
{
- if (forwardHeap2.get())
+ if (forward_heap_2.get())
{
- forwardHeap2->Clear();
+ forward_heap_2->Clear();
}
else
{
- forwardHeap2.reset(new QueryHeap(number_of_nodes));
+ forward_heap_2.reset(new QueryHeap(number_of_nodes));
}
- if (backwardHeap2.get())
+ if (reverse_heap_2.get())
{
- backwardHeap2->Clear();
+ reverse_heap_2->Clear();
}
else
{
- backwardHeap2.reset(new QueryHeap(number_of_nodes));
+ reverse_heap_2.reset(new QueryHeap(number_of_nodes));
}
}
void SearchEngineData::InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes)
{
- if (forwardHeap3.get())
+ if (forward_heap_3.get())
{
- forwardHeap3->Clear();
+ forward_heap_3->Clear();
}
else
{
- forwardHeap3.reset(new QueryHeap(number_of_nodes));
+ forward_heap_3.reset(new QueryHeap(number_of_nodes));
}
- if (backwardHeap3.get())
+ if (reverse_heap_3.get())
{
- backwardHeap3->Clear();
+ reverse_heap_3->Clear();
}
else
{
- backwardHeap3.reset(new QueryHeap(number_of_nodes));
+ 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
index 6c2efb1..8c1c161 100644
--- a/data_structures/search_engine_data.hpp
+++ b/data_structures/search_engine_data.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -44,12 +44,12 @@ struct SearchEngineData
using QueryHeap = BinaryHeap<NodeID, NodeID, int, HeapData, UnorderedMapStorage<NodeID, int>>;
using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
- static SearchEngineHeapPtr forwardHeap;
- static SearchEngineHeapPtr backwardHeap;
- static SearchEngineHeapPtr forwardHeap2;
- static SearchEngineHeapPtr backwardHeap2;
- static SearchEngineHeapPtr forwardHeap3;
- static SearchEngineHeapPtr backwardHeap3;
+ 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);
diff --git a/data_structures/segment_information.hpp b/data_structures/segment_information.hpp
index dd1fc57..7118a32 100644
--- a/data_structures/segment_information.hpp
+++ b/data_structures/segment_information.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,15 +25,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SEGMENT_INFORMATION_H
-#define SEGMENT_INFORMATION_H
+#ifndef SEGMENT_INFORMATION_HPP
+#define SEGMENT_INFORMATION_HPP
#include "turn_instructions.hpp"
#include "../data_structures/travel_mode.hpp"
#include "../typedefs.h"
-#include <osrm/Coordinate.h>
+#include <osrm/coordinate.hpp>
// Struct fits everything in one cache line
struct SegmentInformation
@@ -75,4 +75,4 @@ struct SegmentInformation
}
};
-#endif /* SEGMENT_INFORMATION_H */
+#endif /* SEGMENT_INFORMATION_HPP */
diff --git a/data_structures/shared_memory_factory.hpp b/data_structures/shared_memory_factory.hpp
index dc714a6..58fed9b 100644
--- a/data_structures/shared_memory_factory.hpp
+++ b/data_structures/shared_memory_factory.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,8 +28,8 @@ 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/osrm_exception.hpp"
+#include "../util/simple_logger.hpp"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@@ -123,8 +123,8 @@ class SharedMemory
{
Remove(key);
}
- shm = boost::interprocess::xsi_shared_memory(
- boost::interprocess::open_or_create, key, size);
+ shm = boost::interprocess::xsi_shared_memory(boost::interprocess::open_or_create, key,
+ size);
#ifdef __linux__
if (-1 == shmctl(shm.get_shmid(), SHM_LOCK, 0))
{
@@ -150,7 +150,10 @@ class SharedMemory
boost::interprocess::xsi_key key(lock_file().string().c_str(), id);
result = RegionExists(key);
}
- catch (...) { result = false; }
+ catch (...)
+ {
+ result = false;
+ }
return result;
}
@@ -165,8 +168,14 @@ class SharedMemory
static bool RegionExists(const boost::interprocess::xsi_key &key)
{
bool result = true;
- try { boost::interprocess::xsi_shared_memory shm(boost::interprocess::open_only, key); }
- catch (...) { result = false; }
+ try
+ {
+ boost::interprocess::xsi_shared_memory shm(boost::interprocess::open_only, key);
+ }
+ catch (...)
+ {
+ result = false;
+ }
return result;
}
@@ -198,12 +207,12 @@ class SharedMemory
// Windows - specific code
class SharedMemory
{
- SharedMemory(const SharedMemory&) = delete;
+ SharedMemory(const SharedMemory &) = delete;
// Remove shared memory on destruction
class shm_remove
{
private:
- shm_remove(const shm_remove&) = delete;
+ shm_remove(const shm_remove &) = delete;
char *m_shmid;
bool m_initialized;
@@ -242,8 +251,7 @@ class SharedMemory
if (0 == size)
{ // read_only
shm = boost::interprocess::shared_memory_object(
- boost::interprocess::open_only,
- key,
+ boost::interprocess::open_only, key,
read_write ? boost::interprocess::read_write : boost::interprocess::read_only);
region = boost::interprocess::mapped_region(
shm, read_write ? boost::interprocess::read_write : boost::interprocess::read_only);
@@ -255,8 +263,8 @@ class SharedMemory
{
Remove(key);
}
- shm = boost::interprocess::shared_memory_object(
- boost::interprocess::open_or_create, key, boost::interprocess::read_write);
+ shm = boost::interprocess::shared_memory_object(boost::interprocess::open_or_create,
+ key, boost::interprocess::read_write);
shm.truncate(size);
region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
@@ -274,7 +282,10 @@ class SharedMemory
build_key(id, k);
result = RegionExists(k);
}
- catch (...) { result = false; }
+ catch (...)
+ {
+ result = false;
+ }
return result;
}
@@ -286,20 +297,20 @@ class SharedMemory
}
private:
- static void build_key(int id, char *key)
- {
- sprintf(key, "%s.%d", "osrm.lock", id);
- }
+ static void build_key(int id, char *key) { sprintf(key, "%s.%d", "osrm.lock", id); }
static bool RegionExists(const char *key)
{
bool result = true;
try
{
- boost::interprocess::shared_memory_object shm(
- boost::interprocess::open_only, key, boost::interprocess::read_write);
+ boost::interprocess::shared_memory_object shm(boost::interprocess::open_only, key,
+ boost::interprocess::read_write);
+ }
+ catch (...)
+ {
+ result = false;
}
- catch (...) { result = false; }
return result;
}
diff --git a/data_structures/shared_memory_vector_wrapper.hpp b/data_structures/shared_memory_vector_wrapper.hpp
index d508e5f..dc51cff 100644
--- a/data_structures/shared_memory_vector_wrapper.hpp
+++ b/data_structures/shared_memory_vector_wrapper.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -147,8 +147,8 @@ template <> class SharedMemoryWrapper<bool>
template <typename DataT, bool UseSharedMemory> struct ShM
{
using vector = typename std::conditional<UseSharedMemory,
- SharedMemoryWrapper<DataT>,
- std::vector<DataT>>::type;
+ SharedMemoryWrapper<DataT>,
+ std::vector<DataT>>::type;
};
#endif // SHARED_MEMORY_VECTOR_WRAPPER_HPP
diff --git a/data_structures/static_graph.hpp b/data_structures/static_graph.hpp
index 05d65ee..7434b56 100644
--- a/data_structures/static_graph.hpp
+++ b/data_structures/static_graph.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,13 +30,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "percent.hpp"
#include "shared_memory_vector_wrapper.hpp"
-#include "../Util/integer_range.hpp"
+#include "../util/integer_range.hpp"
#include "../typedefs.h"
#include <boost/assert.hpp>
-#include <tbb/parallel_sort.h>
-
#include <algorithm>
#include <limits>
#include <utility>
@@ -57,8 +55,11 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
NodeIterator target;
EdgeDataT data;
- template<typename... Ts>
- InputEdge(NodeIterator source, NodeIterator target, Ts &&...data) : source(source), target(target), data(std::forward<Ts>(data)...) { }
+ template <typename... Ts>
+ InputEdge(NodeIterator source, NodeIterator target, Ts &&... data)
+ : source(source), target(target), data(std::forward<Ts>(data)...)
+ {
+ }
bool operator<(const InputEdge &right) const
{
if (source != right.source)
@@ -88,13 +89,12 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
StaticGraph(const int nodes, std::vector<InputEdge> &graph)
{
- tbb::parallel_sort(graph.begin(), 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 : osrm::irange(0u, number_of_nodes + 1))
{
EdgeIterator last_edge = edge;
while (edge < number_of_edges && graph[edge].source == node)
@@ -109,11 +109,10 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
for (const auto node : osrm::irange(0u, number_of_nodes))
{
EdgeIterator e = node_array[node + 1].first_edge;
- for (EdgeIterator i = node_array[node].first_edge; i != e; ++i)
+ for (const auto i : osrm::irange(node_array[node].first_edge, e))
{
edge_array[i].target = graph[edge].target;
edge_array[i].data = graph[edge].data;
- BOOST_ASSERT(edge_array[i].data.distance > 0);
edge++;
}
}
@@ -140,7 +139,7 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
return NodeIterator(edge_array[e].target);
}
- inline EdgeDataT &GetEdgeData(const EdgeIterator e) { return edge_array[e].data; }
+ EdgeDataT &GetEdgeData(const EdgeIterator e) { return edge_array[e].data; }
const EdgeDataT &GetEdgeData(const EdgeIterator e) const { return edge_array[e].data; }
@@ -157,6 +156,19 @@ 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)))
+ {
+ if (to == edge_array[i].target)
+ {
+ return i;
+ }
+ }
+ return SPECIAL_EDGEID;
+ }
+
+ // searches for a specific edge
+ EdgeIterator FindSmallestEdge(const NodeIterator from, const NodeIterator to) const
+ {
EdgeIterator smallest_edge = SPECIAL_EDGEID;
EdgeWeight smallest_weight = INVALID_EDGE_WEIGHT;
for (auto edge : GetAdjacentEdgeRange(from))
diff --git a/data_structures/static_kdtree.hpp b/data_structures/static_kdtree.hpp
index b173d3a..1e65dc8 100644
--- a/data_structures/static_kdtree.hpp
+++ b/data_structures/static_kdtree.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -138,8 +138,8 @@ class StaticKDTree
continue;
Iterator middle = tree.left + (tree.right - tree.left) / 2;
- std::nth_element(
- kdtree + tree.left, kdtree + middle, kdtree + tree.right, Less(tree.dimension));
+ 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));
}
diff --git a/data_structures/static_rtree.hpp b/data_structures/static_rtree.hpp
index f670ca3..f219a64 100644
--- a/data_structures/static_rtree.hpp
+++ b/data_structures/static_rtree.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -35,16 +35,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rectangle.hpp"
#include "shared_memory_factory.hpp"
#include "shared_memory_vector_wrapper.hpp"
-
-#include "../Util/floating_point.hpp"
-#include "../Util/integer_range.hpp"
-#include "../Util/MercatorUtil.h"
-#include "../Util/osrm_exception.hpp"
-#include "../Util/simple_logger.hpp"
-#include "../Util/timing_util.hpp"
+#include "upper_bound.hpp"
+
+#include "../util/floating_point.hpp"
+#include "../util/integer_range.hpp"
+#include "../util/mercator.hpp"
+#include "../util/osrm_exception.hpp"
+#include "../util/simple_logger.hpp"
+#include "../util/timing_util.hpp"
#include "../typedefs.h"
-#include <osrm/Coordinate.h>
+#include <osrm/coordinate.hpp>
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
@@ -68,8 +69,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
template <class EdgeDataT,
class CoordinateListT = std::vector<FixedPointCoordinate>,
bool UseSharedMemory = false,
- uint32_t BRANCHING_FACTOR=64,
- uint32_t LEAF_NODE_SIZE=1024>
+ uint32_t BRANCHING_FACTOR = 64,
+ uint32_t LEAF_NODE_SIZE = 1024>
class StaticRTree
{
public:
@@ -86,19 +87,15 @@ class StaticRTree
{
for (uint32_t i = 0; i < element_count; ++i)
{
- min_lon = std::min(min_lon,
- std::min(coordinate_list.at(objects[i].u).lon,
- coordinate_list.at(objects[i].v).lon));
- max_lon = std::max(max_lon,
- std::max(coordinate_list.at(objects[i].u).lon,
- coordinate_list.at(objects[i].v).lon));
-
- min_lat = std::min(min_lat,
- std::min(coordinate_list.at(objects[i].u).lat,
- coordinate_list.at(objects[i].v).lat));
- max_lat = std::max(max_lat,
- std::max(coordinate_list.at(objects[i].u).lat,
- coordinate_list.at(objects[i].v).lat));
+ min_lon = std::min(min_lon, std::min(coordinate_list.at(objects[i].u).lon,
+ coordinate_list.at(objects[i].v).lon));
+ max_lon = std::max(max_lon, std::max(coordinate_list.at(objects[i].u).lon,
+ coordinate_list.at(objects[i].v).lon));
+
+ min_lat = std::min(min_lat, std::min(coordinate_list.at(objects[i].u).lat,
+ coordinate_list.at(objects[i].v).lat));
+ max_lat = std::max(max_lat, std::max(coordinate_list.at(objects[i].u).lat,
+ coordinate_list.at(objects[i].v).lat));
}
BOOST_ASSERT(min_lat != std::numeric_limits<int>::min());
BOOST_ASSERT(min_lon != std::numeric_limits<int>::min());
@@ -149,58 +146,66 @@ class StaticRTree
enum Direction
{
- INVALID = 0,
- NORTH = 1,
- SOUTH = 2,
- EAST = 4,
+ INVALID = 0,
+ NORTH = 1,
+ SOUTH = 2,
+ EAST = 4,
NORTH_EAST = 5,
SOUTH_EAST = 6,
- WEST = 8,
+ WEST = 8,
NORTH_WEST = 9,
SOUTH_WEST = 10
};
Direction d = INVALID;
if (location.lat > max_lat)
- d = (Direction) (d | NORTH);
+ d = (Direction)(d | NORTH);
else if (location.lat < min_lat)
- d = (Direction) (d | SOUTH);
+ d = (Direction)(d | SOUTH);
if (location.lon > max_lon)
- d = (Direction) (d | EAST);
+ d = (Direction)(d | EAST);
else if (location.lon < min_lon)
- d = (Direction) (d | WEST);
+ d = (Direction)(d | WEST);
BOOST_ASSERT(d != INVALID);
float min_dist = std::numeric_limits<float>::max();
switch (d)
{
- case NORTH:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, location.lon));
- break;
- case SOUTH:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, location.lon));
- break;
- case WEST:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, min_lon));
- break;
- case EAST:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, max_lon));
- break;
- case NORTH_EAST:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, max_lon));
- break;
- case NORTH_WEST:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, min_lon));
- break;
- case SOUTH_EAST:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, max_lon));
- break;
- case SOUTH_WEST:
- min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, min_lon));
- break;
- default:
- break;
+ case NORTH:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(max_lat, location.lon));
+ break;
+ case SOUTH:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(min_lat, location.lon));
+ break;
+ case WEST:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(location.lat, min_lon));
+ break;
+ case EAST:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(location.lat, max_lon));
+ break;
+ case NORTH_EAST:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(max_lat, max_lon));
+ break;
+ case NORTH_WEST:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(max_lat, min_lon));
+ break;
+ case SOUTH_EAST:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(min_lat, max_lon));
+ break;
+ case SOUTH_WEST:
+ min_dist = coordinate_calculation::euclidean_distance(
+ location, FixedPointCoordinate(min_lat, min_lon));
+ break;
+ default:
+ break;
}
BOOST_ASSERT(min_dist != std::numeric_limits<float>::max());
@@ -219,25 +224,23 @@ class StaticRTree
min_max_dist = std::min(
min_max_dist,
- std::max(
- FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left),
- FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right)));
+ std::max(coordinate_calculation::euclidean_distance(location, upper_left),
+ coordinate_calculation::euclidean_distance(location, upper_right)));
min_max_dist = std::min(
min_max_dist,
- std::max(
- FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right),
- FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right)));
+ std::max(coordinate_calculation::euclidean_distance(location, upper_right),
+ coordinate_calculation::euclidean_distance(location, lower_right)));
min_max_dist = std::min(
min_max_dist,
- std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right),
- FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left)));
+ std::max(coordinate_calculation::euclidean_distance(location, lower_right),
+ coordinate_calculation::euclidean_distance(location, lower_left)));
min_max_dist = std::min(
min_max_dist,
- std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left),
- FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left)));
+ std::max(coordinate_calculation::euclidean_distance(location, lower_left),
+ coordinate_calculation::euclidean_distance(location, upper_left)));
return min_max_dist;
}
@@ -377,7 +380,8 @@ class StaticRTree
FixedPointCoordinate(coordinate_list.at(current_element.v).lat,
coordinate_list.at(current_element.v).lon));
current_centroid.lat =
- COORDINATE_PRECISION * lat2y(current_centroid.lat / COORDINATE_PRECISION);
+ COORDINATE_PRECISION *
+ mercator::lat2y(current_centroid.lat / COORDINATE_PRECISION);
current_wrapper.m_hilbert_value = get_hilbert_number(current_centroid);
}
@@ -415,8 +419,8 @@ class StaticRTree
}
// generate tree node that resemble the objects in leaf and store it for next level
- InitializeMBRectangle(current_node.minimum_bounding_rectangle,
- current_leaf.objects, current_leaf.object_count, coordinate_list);
+ InitializeMBRectangle(current_node.minimum_bounding_rectangle, current_leaf.objects,
+ current_leaf.object_count, coordinate_list);
current_node.child_is_on_disk = true;
current_node.children[0] = tree_nodes_in_level.size();
tree_nodes_in_level.emplace_back(current_node);
@@ -439,8 +443,7 @@ class StaticRTree
TreeNode parent_node;
// pack BRANCHING_FACTOR elements into tree_nodes each
for (uint32_t current_child_node_index = 0;
- BRANCHING_FACTOR > current_child_node_index;
- ++current_child_node_index)
+ BRANCHING_FACTOR > current_child_node_index; ++current_child_node_index)
{
if (processed_tree_nodes_in_level < tree_nodes_in_level.size())
{
@@ -473,17 +476,17 @@ class StaticRTree
tbb::parallel_for(tbb::blocked_range<uint32_t>(0, search_tree_size),
[this, &search_tree_size](const tbb::blocked_range<uint32_t> &range)
{
- for (uint32_t i = range.begin(); i != range.end(); ++i)
- {
- TreeNode ¤t_tree_node = this->m_search_tree[i];
- for (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;
- current_tree_node.children[j] = new_id;
- }
- }
- });
+ for (uint32_t i = range.begin(); i != range.end(); ++i)
+ {
+ TreeNode ¤t_tree_node = this->m_search_tree[i];
+ for (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;
+ current_tree_node.children[j] = new_id;
+ }
+ }
+ });
// open tree file
boost::filesystem::ofstream tree_node_file(tree_node_filename, std::ios::binary);
@@ -605,12 +608,10 @@ class StaticRTree
continue;
}
- float current_minimum_distance =
- FixedPointCoordinate::ApproximateEuclideanDistance(
- input_coordinate.lat,
- input_coordinate.lon,
- m_coordinate_list->at(current_edge.u).lat,
- m_coordinate_list->at(current_edge.u).lon);
+ float current_minimum_distance = coordinate_calculation::euclidean_distance(
+ input_coordinate.lat, input_coordinate.lon,
+ m_coordinate_list->at(current_edge.u).lat,
+ m_coordinate_list->at(current_edge.u).lon);
if (current_minimum_distance < min_dist)
{
// found a new minimum
@@ -618,12 +619,10 @@ class StaticRTree
result_coordinate = m_coordinate_list->at(current_edge.u);
}
- current_minimum_distance =
- FixedPointCoordinate::ApproximateEuclideanDistance(
- input_coordinate.lat,
- input_coordinate.lon,
- m_coordinate_list->at(current_edge.v).lat,
- m_coordinate_list->at(current_edge.v).lon);
+ current_minimum_distance = coordinate_calculation::euclidean_distance(
+ input_coordinate.lat, input_coordinate.lon,
+ m_coordinate_list->at(current_edge.v).lat,
+ m_coordinate_list->at(current_edge.v).lon);
if (current_minimum_distance < min_dist)
{
@@ -635,32 +634,34 @@ class StaticRTree
}
else
{
- min_max_dist = ExploreTreeNode(current_tree_node,
- input_coordinate,
- min_dist,
- min_max_dist,
- traversal_queue);
+ min_max_dist = ExploreTreeNode(current_tree_node, input_coordinate, min_dist,
+ min_max_dist, traversal_queue);
}
}
}
return result_coordinate.is_valid();
}
-
- // implementation of the Hjaltason/Samet query [3], a BFS traversal of the tree
- // - searches for k elements nearest elements
- // - continues to find the k+1st element from a big component if k elements
- // come from tiny components
- bool
- IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
- std::vector<PhantomNode> &result_phantom_node_vector,
- const unsigned max_number_of_phantom_nodes,
- const unsigned max_checked_elements = 4*LEAF_NODE_SIZE)
+ bool IncrementalFindPhantomNodeForCoordinate(
+ const FixedPointCoordinate &input_coordinate,
+ std::vector<PhantomNode> &result_phantom_node_vector,
+ const unsigned max_number_of_phantom_nodes,
+ const unsigned max_checked_elements = 4 * LEAF_NODE_SIZE)
{
unsigned inspected_elements = 0;
unsigned number_of_elements_from_big_cc = 0;
unsigned number_of_elements_from_tiny_cc = 0;
+#ifdef NDEBUG
+ unsigned pruned_elements = 0;
+#endif
+ std::pair<double, double> projected_coordinate = {
+ mercator::lat2y(input_coordinate.lat / COORDINATE_PRECISION),
+ input_coordinate.lon / COORDINATE_PRECISION};
+
+ // upper bound pruning technique
+ upper_bound<float> pruning_bound(max_number_of_phantom_nodes);
+
// initialize queue with root element
std::priority_queue<IncrementalQueryCandidate> traversal_queue;
traversal_queue.emplace(0.f, m_search_tree[0]);
@@ -672,7 +673,8 @@ class StaticRTree
if (current_query_node.node.template is<TreeNode>())
{ // current object is a tree node
- const TreeNode & current_tree_node = current_query_node.node.template get<TreeNode>();
+ const TreeNode ¤t_tree_node =
+ current_query_node.node.template get<TreeNode>();
if (current_tree_node.child_is_on_disk)
{
LeafNode current_leaf_node;
@@ -682,16 +684,26 @@ class StaticRTree
for (const auto i : osrm::irange(0u, current_leaf_node.object_count))
{
const auto ¤t_edge = current_leaf_node.objects[i];
- const float current_perpendicular_distance =
- FixedPointCoordinate::ComputePerpendicularDistance(
+ 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);
+ m_coordinate_list->at(current_edge.v), input_coordinate,
+ projected_coordinate);
// distance must be non-negative
BOOST_ASSERT(0.f <= current_perpendicular_distance);
- // put element in queue
- traversal_queue.emplace(current_perpendicular_distance, current_edge);
+ if (pruning_bound.get() >= current_perpendicular_distance ||
+ current_edge.is_in_tiny_cc())
+ {
+ pruning_bound.insert(current_perpendicular_distance);
+ traversal_queue.emplace(current_perpendicular_distance, current_edge);
+ }
+#ifdef NDEBUG
+ else
+ {
+ ++pruned_elements;
+ }
+#endif
}
}
else
@@ -701,8 +713,10 @@ class StaticRTree
{
const int32_t child_id = current_tree_node.children[i];
const TreeNode &child_tree_node = m_search_tree[child_id];
- const RectangleT &child_rectangle = child_tree_node.minimum_bounding_rectangle;
- const float lower_bound_to_element = child_rectangle.GetMinDist(input_coordinate);
+ const RectangleT &child_rectangle =
+ child_tree_node.minimum_bounding_rectangle;
+ const float lower_bound_to_element =
+ child_rectangle.GetMinDist(input_coordinate);
BOOST_ASSERT(0.f <= lower_bound_to_element);
traversal_queue.emplace(lower_bound_to_element, child_tree_node);
@@ -713,7 +727,8 @@ class StaticRTree
{ // current object is a leaf node
++inspected_elements;
// inspecting an actual road segment
- const EdgeDataT & current_segment = current_query_node.node.template get<EdgeDataT>();
+ const EdgeDataT ¤t_segment =
+ current_query_node.node.template get<EdgeDataT>();
// continue searching for the first segment from a big component
if (number_of_elements_from_big_cc == 0 &&
@@ -726,29 +741,16 @@ class StaticRTree
// check if it is smaller than what we had before
float current_ratio = 0.f;
FixedPointCoordinate foot_point_coordinate_on_segment;
+
// const float current_perpendicular_distance =
- FixedPointCoordinate::ComputePerpendicularDistance(
- m_coordinate_list->at(current_segment.u),
- m_coordinate_list->at(current_segment.v),
- input_coordinate,
- foot_point_coordinate_on_segment,
- current_ratio);
+ coordinate_calculation::perpendicular_distance_from_projected_coordinate(
+ m_coordinate_list->at(current_segment.u),
+ m_coordinate_list->at(current_segment.v), input_coordinate,
+ projected_coordinate, foot_point_coordinate_on_segment, current_ratio);
// store phantom node in result vector
- result_phantom_node_vector.emplace_back(
- current_segment.forward_edge_based_node_id,
- current_segment.reverse_edge_based_node_id,
- current_segment.name_id,
- current_segment.forward_weight,
- current_segment.reverse_weight,
- current_segment.forward_offset,
- current_segment.reverse_offset,
- current_segment.packed_geometry_id,
- current_segment.component_id,
- foot_point_coordinate_on_segment,
- current_segment.fwd_segment_position,
- current_segment.forward_travel_mode,
- current_segment.backward_travel_mode);
+ result_phantom_node_vector.emplace_back(current_segment,
+ foot_point_coordinate_on_segment);
// Hack to fix rounding errors and wandering via nodes.
FixUpRoundingIssue(input_coordinate, result_phantom_node_vector.back());
@@ -766,39 +768,55 @@ class StaticRTree
{ // found an element in a big component
++number_of_elements_from_big_cc;
}
-
- // SimpleLogger().Write() << "result_phantom_node_vector.size(): " << result_phantom_node_vector.size();
- // SimpleLogger().Write() << "max_number_of_phantom_nodes: " << max_number_of_phantom_nodes;
- // SimpleLogger().Write() << "number_of_elements_from_big_cc: " << number_of_elements_from_big_cc;
- // SimpleLogger().Write() << "number_of_elements_from_tiny_cc: " << number_of_elements_from_tiny_cc;
- // SimpleLogger().Write() << "inspected_elements: " << inspected_elements;
- // SimpleLogger().Write() << "max_checked_elements: " << max_checked_elements;
}
// stop the search by flushing the queue
- if ((result_phantom_node_vector.size() >= max_number_of_phantom_nodes && number_of_elements_from_big_cc > 0) ||
+ if ((result_phantom_node_vector.size() >= max_number_of_phantom_nodes &&
+ number_of_elements_from_big_cc > 0) ||
inspected_elements >= max_checked_elements)
{
traversal_queue = std::priority_queue<IncrementalQueryCandidate>{};
}
}
- // SimpleLogger().Write() << "inspected_elements: " << inspected_elements;
+#ifdef NDEBUG
+// SimpleLogger().Write() << "result_phantom_node_vector.size(): " <<
+// result_phantom_node_vector.size();
+// SimpleLogger().Write() << "max_number_of_phantom_nodes: " << max_number_of_phantom_nodes;
+// SimpleLogger().Write() << "number_of_elements_from_big_cc: " <<
+// number_of_elements_from_big_cc;
+// SimpleLogger().Write() << "number_of_elements_from_tiny_cc: " <<
+// number_of_elements_from_tiny_cc;
+// SimpleLogger().Write() << "inspected_elements: " << inspected_elements;
+// SimpleLogger().Write() << "max_checked_elements: " << max_checked_elements;
+// SimpleLogger().Write() << "pruned_elements: " << pruned_elements;
+#endif
return !result_phantom_node_vector.empty();
}
- // implementation of the Hjaltason/Samet query [3], a BFS traversal of the tree
- bool
- IncrementalFindPhantomNodeForCoordinateWithDistance(const FixedPointCoordinate &input_coordinate,
- std::vector<std::pair<PhantomNode, double>> &result_phantom_node_vector,
- const unsigned number_of_results,
- const unsigned max_checked_segments = 4*LEAF_NODE_SIZE)
+ // Returns elements within max_distance.
+ // If the minium of elements could not be found in the search radius, widen
+ // it until the minimum can be satisfied.
+ // At the number of returned nodes is capped at the given maximum.
+ bool IncrementalFindPhantomNodeForCoordinateWithDistance(
+ const FixedPointCoordinate &input_coordinate,
+ std::vector<std::pair<PhantomNode, double>> &result_phantom_node_vector,
+ const double max_distance,
+ const unsigned min_number_of_phantom_nodes,
+ const unsigned max_number_of_phantom_nodes,
+ const unsigned max_checked_elements = 4 * LEAF_NODE_SIZE)
{
- std::vector<float> min_found_distances(number_of_results, std::numeric_limits<float>::max());
+ unsigned inspected_elements = 0;
+ unsigned number_of_elements_from_big_cc = 0;
+ unsigned number_of_elements_from_tiny_cc = 0;
- unsigned number_of_results_found_in_big_cc = 0;
- unsigned number_of_results_found_in_tiny_cc = 0;
+ unsigned pruned_elements = 0;
- unsigned inspected_segments = 0;
+ std::pair<double, double> projected_coordinate = {
+ mercator::lat2y(input_coordinate.lat / COORDINATE_PRECISION),
+ input_coordinate.lon / COORDINATE_PRECISION};
+
+ // upper bound pruning technique
+ upper_bound<float> pruning_bound(max_number_of_phantom_nodes);
// initialize queue with root element
std::priority_queue<IncrementalQueryCandidate> traversal_queue;
@@ -809,144 +827,141 @@ class StaticRTree
const IncrementalQueryCandidate current_query_node = traversal_queue.top();
traversal_queue.pop();
- const float current_min_dist = min_found_distances[number_of_results-1];
-
- if (current_query_node.min_dist > current_min_dist)
- {
- continue;
- }
-
- if (current_query_node.RepresentsTreeNode())
- {
- const TreeNode & current_tree_node = current_query_node.node.template get<TreeNode>();
+ if (current_query_node.node.template is<TreeNode>())
+ { // current object is a tree node
+ const TreeNode ¤t_tree_node =
+ current_query_node.node.template get<TreeNode>();
if (current_tree_node.child_is_on_disk)
{
LeafNode current_leaf_node;
LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
- // Add all objects from leaf into queue
- for (uint32_t i = 0; i < current_leaf_node.object_count; ++i)
+
+ // current object represents a block on disk
+ for (const auto i : osrm::irange(0u, current_leaf_node.object_count))
{
const auto ¤t_edge = current_leaf_node.objects[i];
- const float current_perpendicular_distance =
- FixedPointCoordinate::ComputePerpendicularDistance(
+ 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);
+ m_coordinate_list->at(current_edge.v), input_coordinate,
+ projected_coordinate);
// distance must be non-negative
- BOOST_ASSERT(0. <= current_perpendicular_distance);
+ BOOST_ASSERT(0.f <= current_perpendicular_distance);
- if (current_perpendicular_distance < current_min_dist)
+ if (pruning_bound.get() >= current_perpendicular_distance ||
+ current_edge.is_in_tiny_cc())
{
+ pruning_bound.insert(current_perpendicular_distance);
traversal_queue.emplace(current_perpendicular_distance, current_edge);
}
+ else
+ {
+ ++pruned_elements;
+ }
}
}
else
{
- // for each child mbr
- for (uint32_t i = 0; i < current_tree_node.child_count; ++i)
+ // for each child mbr get a lower bound and enqueue it
+ for (const auto i : osrm::irange(0u, current_tree_node.child_count))
{
const int32_t child_id = current_tree_node.children[i];
const TreeNode &child_tree_node = m_search_tree[child_id];
- const RectangleT &child_rectangle = child_tree_node.minimum_bounding_rectangle;
- const float lower_bound_to_element = child_rectangle.GetMinDist(input_coordinate);
-
- // TODO - enough elements found, i.e. nearest distance > maximum distance?
- // ie. some measure of 'confidence of accuracy'
+ const RectangleT &child_rectangle =
+ child_tree_node.minimum_bounding_rectangle;
+ const float lower_bound_to_element =
+ child_rectangle.GetMinDist(input_coordinate);
+ BOOST_ASSERT(0.f <= lower_bound_to_element);
- // check if it needs to be explored by mindist
- if (lower_bound_to_element < current_min_dist)
- {
- traversal_queue.emplace(lower_bound_to_element, child_tree_node);
- }
+ traversal_queue.emplace(lower_bound_to_element, child_tree_node);
}
- // SimpleLogger().Write(logDEBUG) << "added " << current_tree_node.child_count << " mbrs into queue of " << traversal_queue.size();
}
}
else
- {
- ++inspected_segments;
+ { // current object is a leaf node
+ ++inspected_elements;
// inspecting an actual road segment
- const EdgeDataT & current_segment = current_query_node.node.template get<EdgeDataT>();
-
- // don't collect too many results from small components
- if (number_of_results_found_in_big_cc == number_of_results && !current_segment.is_in_tiny_cc)
- {
- continue;
- }
+ const EdgeDataT ¤t_segment =
+ current_query_node.node.template get<EdgeDataT>();
- // don't collect too many results from big components
- if (number_of_results_found_in_tiny_cc == number_of_results && current_segment.is_in_tiny_cc)
+ // continue searching for the first segment from a big component
+ if (number_of_elements_from_big_cc == 0 &&
+ number_of_elements_from_tiny_cc >= max_number_of_phantom_nodes - 1 &&
+ current_segment.is_in_tiny_cc())
{
continue;
}
// check if it is smaller than what we had before
- float current_ratio = 0.;
+ float current_ratio = 0.f;
FixedPointCoordinate foot_point_coordinate_on_segment;
+
const float current_perpendicular_distance =
- FixedPointCoordinate::ComputePerpendicularDistance(
+ coordinate_calculation::perpendicular_distance_from_projected_coordinate(
m_coordinate_list->at(current_segment.u),
- m_coordinate_list->at(current_segment.v),
- input_coordinate,
- foot_point_coordinate_on_segment,
- current_ratio);
-
- BOOST_ASSERT(0. <= current_perpendicular_distance);
+ m_coordinate_list->at(current_segment.v), input_coordinate,
+ projected_coordinate, foot_point_coordinate_on_segment, current_ratio);
- if ((current_perpendicular_distance < current_min_dist) &&
- !osrm::epsilon_compare(current_perpendicular_distance, current_min_dist))
+ if (number_of_elements_from_big_cc > 0 &&
+ result_phantom_node_vector.size() >= min_number_of_phantom_nodes &&
+ current_perpendicular_distance >= max_distance)
{
- // store phantom node in result vector
- result_phantom_node_vector.emplace_back(
+ traversal_queue = std::priority_queue<IncrementalQueryCandidate>{};
+ continue;
+ }
+
+ // store phantom node in result vector
+ result_phantom_node_vector.emplace_back(
+ PhantomNode(
current_segment.forward_edge_based_node_id,
- current_segment.reverse_edge_based_node_id,
- current_segment.name_id,
- current_segment.forward_weight,
- current_segment.reverse_weight,
- current_segment.forward_offset,
- current_segment.reverse_offset,
- current_segment.packed_geometry_id,
- foot_point_coordinate_on_segment,
- current_segment.fwd_segment_position,
- current_perpendicular_distance);
-
- // Hack to fix rounding errors and wandering via nodes.
- FixUpRoundingIssue(input_coordinate, result_phantom_node_vector.back());
-
- // set forward and reverse weights on the phantom node
- SetForwardAndReverseWeightsOnPhantomNode(current_segment,
- result_phantom_node_vector.back());
-
- // do we have results only in a small scc
- if (current_segment.is_in_tiny_cc)
- {
- ++number_of_results_found_in_tiny_cc;
- }
- else
- {
- // found an element in a large component
- min_found_distances[number_of_results_found_in_big_cc] = current_perpendicular_distance;
- ++number_of_results_found_in_big_cc;
- // SimpleLogger().Write(logDEBUG) << std::setprecision(8) << foot_point_coordinate_on_segment << " at " << current_perpendicular_distance;
- }
+ current_segment.reverse_edge_based_node_id, current_segment.name_id,
+ current_segment.forward_weight, current_segment.reverse_weight,
+ current_segment.forward_offset, current_segment.reverse_offset,
+ current_segment.packed_geometry_id, current_segment.component_id,
+ foot_point_coordinate_on_segment, current_segment.fwd_segment_position,
+ current_segment.forward_travel_mode, current_segment.backward_travel_mode),
+ current_perpendicular_distance);
+
+ // Hack to fix rounding errors and wandering via nodes.
+ FixUpRoundingIssue(input_coordinate, result_phantom_node_vector.back().first);
+
+ // set forward and reverse weights on the phantom node
+ SetForwardAndReverseWeightsOnPhantomNode(current_segment,
+ result_phantom_node_vector.back().first);
+
+ // update counts on what we found from which result class
+ if (current_segment.is_in_tiny_cc())
+ { // found an element in tiny component
+ ++number_of_elements_from_tiny_cc;
+ }
+ else
+ { // found an element in a big component
+ ++number_of_elements_from_big_cc;
}
}
- // TODO add indicator to prune if maxdist > threshold
- if (number_of_results == number_of_results_found_in_big_cc || inspected_segments >= max_checked_segments)
+ // stop the search by flushing the queue
+ if ((result_phantom_node_vector.size() >= max_number_of_phantom_nodes &&
+ number_of_elements_from_big_cc > 0) ||
+ inspected_elements >= max_checked_elements)
{
- // SimpleLogger().Write(logDEBUG) << "flushing queue of " << traversal_queue.size() << " elements";
- // work-around for traversal_queue.clear();
traversal_queue = std::priority_queue<IncrementalQueryCandidate>{};
}
}
+ // SimpleLogger().Write() << "result_phantom_node_vector.size(): " <<
+ // result_phantom_node_vector.size();
+ // SimpleLogger().Write() << "max_number_of_phantom_nodes: " << max_number_of_phantom_nodes;
+ // SimpleLogger().Write() << "number_of_elements_from_big_cc: " <<
+ // number_of_elements_from_big_cc;
+ // SimpleLogger().Write() << "number_of_elements_from_tiny_cc: " <<
+ // number_of_elements_from_tiny_cc;
+ // SimpleLogger().Write() << "inspected_elements: " << inspected_elements;
+ // SimpleLogger().Write() << "max_checked_elements: " << max_checked_elements;
+ // SimpleLogger().Write() << "pruned_elements: " << pruned_elements;
return !result_phantom_node_vector.empty();
}
-
-
bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
PhantomNode &result_phantom_node,
const unsigned zoom_level)
@@ -985,11 +1000,9 @@ class StaticRTree
float current_ratio = 0.;
FixedPointCoordinate nearest;
const float current_perpendicular_distance =
- FixedPointCoordinate::ComputePerpendicularDistance(
+ coordinate_calculation::perpendicular_distance(
m_coordinate_list->at(current_edge.u),
- m_coordinate_list->at(current_edge.v),
- input_coordinate,
- nearest,
+ m_coordinate_list->at(current_edge.v), input_coordinate, nearest,
current_ratio);
BOOST_ASSERT(0. <= current_perpendicular_distance);
@@ -1017,11 +1030,8 @@ class StaticRTree
}
else
{
- min_max_dist = ExploreTreeNode(current_tree_node,
- input_coordinate,
- min_dist,
- min_max_dist,
- traversal_queue);
+ min_max_dist = ExploreTreeNode(current_tree_node, input_coordinate, min_dist,
+ min_max_dist, traversal_queue);
}
}
}
@@ -1038,45 +1048,46 @@ class StaticRTree
}
private:
-
- inline void SetForwardAndReverseWeightsOnPhantomNode(const EdgeDataT & nearest_edge,
+ inline void SetForwardAndReverseWeightsOnPhantomNode(const EdgeDataT &nearest_edge,
PhantomNode &result_phantom_node) const
{
- const float distance_1 = FixedPointCoordinate::ApproximateEuclideanDistance(
+ const float distance_1 = coordinate_calculation::euclidean_distance(
m_coordinate_list->at(nearest_edge.u), result_phantom_node.location);
- const float distance_2 = FixedPointCoordinate::ApproximateEuclideanDistance(
+ const float distance_2 = coordinate_calculation::euclidean_distance(
m_coordinate_list->at(nearest_edge.u), m_coordinate_list->at(nearest_edge.v));
const float ratio = std::min(1.f, distance_1 / distance_2);
using TreeWeightType = decltype(result_phantom_node.forward_weight);
static_assert(std::is_same<decltype(result_phantom_node.forward_weight),
decltype(result_phantom_node.reverse_weight)>::value,
- "forward and reverse weight type in tree must be the same");
+ "forward and reverse weight type in tree must be the same");
if (SPECIAL_NODEID != result_phantom_node.forward_node_id)
{
- const auto new_weight = static_cast<TreeWeightType>(result_phantom_node.forward_weight * ratio);
+ const auto new_weight =
+ static_cast<TreeWeightType>(result_phantom_node.forward_weight * ratio);
result_phantom_node.forward_weight = new_weight;
}
if (SPECIAL_NODEID != result_phantom_node.reverse_node_id)
{
- const auto new_weight = static_cast<TreeWeightType>(result_phantom_node.reverse_weight * (1.f-ratio));
+ const auto new_weight =
+ static_cast<TreeWeightType>(result_phantom_node.reverse_weight * (1.f - ratio));
result_phantom_node.reverse_weight = new_weight;
}
}
// fixup locations if too close to inputs
inline void FixUpRoundingIssue(const FixedPointCoordinate &input_coordinate,
- PhantomNode &result_phantom_node) const
+ PhantomNode &result_phantom_node) const
{
- if (1 == std::abs(input_coordinate.lon - result_phantom_node.location.lon))
- {
- result_phantom_node.location.lon = input_coordinate.lon;
- }
- if (1 == std::abs(input_coordinate.lat - result_phantom_node.location.lat))
- {
- result_phantom_node.location.lat = input_coordinate.lat;
- }
+ if (1 == std::abs(input_coordinate.lon - result_phantom_node.location.lon))
+ {
+ result_phantom_node.location.lon = input_coordinate.lon;
+ }
+ if (1 == std::abs(input_coordinate.lat - result_phantom_node.location.lat))
+ {
+ result_phantom_node.location.lat = input_coordinate.lat;
+ }
}
template <class QueueT>
@@ -1122,8 +1133,7 @@ class StaticRTree
}
const uint64_t seek_pos = sizeof(uint64_t) + leaf_id * sizeof(LeafNode);
leaves_stream.seekg(seek_pos);
- BOOST_ASSERT_MSG(leaves_stream.good(),
- "Seeking to position in leaf file failed.");
+ BOOST_ASSERT_MSG(leaves_stream.good(), "Seeking to position in leaf file failed.");
leaves_stream.read((char *)&result_node, sizeof(LeafNode));
BOOST_ASSERT_MSG(leaves_stream.good(), "Reading from leaf file failed.");
}
@@ -1136,26 +1146,26 @@ class StaticRTree
return (a == b && c == d) || (a == c && b == d) || (a == d && b == c);
}
- inline void InitializeMBRectangle(RectangleT& rectangle,
+ inline void InitializeMBRectangle(RectangleT &rectangle,
const std::array<EdgeDataT, LEAF_NODE_SIZE> &objects,
const uint32_t element_count,
const std::vector<QueryNode> &coordinate_list)
{
for (uint32_t i = 0; i < element_count; ++i)
{
- rectangle.min_lon = std::min(rectangle.min_lon,
- std::min(coordinate_list.at(objects[i].u).lon,
- coordinate_list.at(objects[i].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));
-
- rectangle.min_lat = std::min(rectangle.min_lat,
- std::min(coordinate_list.at(objects[i].u).lat,
- coordinate_list.at(objects[i].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));
+ rectangle.min_lon =
+ std::min(rectangle.min_lon, std::min(coordinate_list.at(objects[i].u).lon,
+ coordinate_list.at(objects[i].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));
+
+ rectangle.min_lat =
+ std::min(rectangle.min_lat, std::min(coordinate_list.at(objects[i].u).lat,
+ coordinate_list.at(objects[i].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));
}
BOOST_ASSERT(rectangle.min_lat != std::numeric_limits<int>::min());
BOOST_ASSERT(rectangle.min_lon != std::numeric_limits<int>::min());
diff --git a/data_structures/travel_mode.hpp b/data_structures/travel_mode.hpp
index 345ec90..2bbe463 100644
--- a/data_structures/travel_mode.hpp
+++ b/data_structures/travel_mode.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,7 +28,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef TRAVEL_MODE_HPP
#define TRAVEL_MODE_HPP
-namespace {
+namespace
+{
using TravelMode = unsigned char;
static const TravelMode TRAVEL_MODE_INACCESSIBLE = 0;
static const TravelMode TRAVEL_MODE_DEFAULT = 1;
diff --git a/Util/git_sha.cpp.in b/data_structures/tribool.hpp
similarity index 86%
copy from Util/git_sha.cpp.in
copy to data_structures/tribool.hpp
index 5b19337..2d4b610 100644
--- a/Util/git_sha.cpp.in
+++ b/data_structures/tribool.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,7 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "git_sha.hpp"
+#ifndef TRIBOOL_HPP
+#define TRIBOOL_HPP
-#define GIT_DESCRIPTION "${GIT_DESCRIPTION}"
-char g_GIT_DESCRIPTION[] = GIT_DESCRIPTION;
+namespace osrm
+{
+enum class tribool : char
+{
+ yes,
+ no,
+ indeterminate
+};
+}
+#endif // TRIBOOL_HPP
diff --git a/data_structures/turn_instructions.hpp b/data_structures/turn_instructions.hpp
index 4b36658..1ca065f 100644
--- a/data_structures/turn_instructions.hpp
+++ b/data_structures/turn_instructions.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,10 +30,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
enum class TurnInstruction : unsigned char
{
- NoTurn = 0, GoStraight, TurnSlightRight, TurnRight, TurnSharpRight, UTurn,
- TurnSharpLeft, TurnLeft, TurnSlightLeft, ReachViaLocation, HeadOn, EnterRoundAbout,
- LeaveRoundAbout, StayOnRoundAbout, StartAtEndOfStreet, ReachedYourDestination,
- EnterAgainstAllowedDirection, LeaveAgainstAllowedDirection,
+ 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
@@ -42,7 +56,7 @@ enum class TurnInstruction : unsigned char
struct TurnInstructionsClass
{
TurnInstructionsClass() = delete;
- TurnInstructionsClass(const TurnInstructionsClass&) = delete;
+ TurnInstructionsClass(const TurnInstructionsClass &) = delete;
static inline TurnInstruction GetTurnDirectionOfInstruction(const double angle)
{
@@ -79,7 +93,8 @@ struct TurnInstructionsClass
static inline bool TurnIsNecessary(const TurnInstruction turn_instruction)
{
- if (TurnInstruction::NoTurn == turn_instruction || TurnInstruction::StayOnRoundAbout == turn_instruction)
+ if (TurnInstruction::NoTurn == turn_instruction ||
+ TurnInstruction::StayOnRoundAbout == turn_instruction)
{
return false;
}
diff --git a/Util/integer_range.hpp b/data_structures/upper_bound.hpp
similarity index 54%
copy from Util/integer_range.hpp
copy to data_structures/upper_bound.hpp
index 030b2fa..80695f2 100644
--- a/Util/integer_range.hpp
+++ b/data_structures/upper_bound.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013,2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,46 +25,53 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef INTEGER_RANGE_HPP
-#define INTEGER_RANGE_HPP
+#ifndef LOWER_BOUND_HPP
+#define LOWER_BOUND_HPP
+#include <functional>
+#include <limits>
+#include <queue>
#include <type_traits>
-namespace osrm
-{
+// 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 Integer> class range
+template <typename key_type> class upper_bound
{
private:
- Integer last;
- Integer iter;
+ using parameter_type =
+ typename std::conditional<std::is_fundamental<key_type>::value, key_type, key_type &>::type;
public:
- range(Integer start, Integer end) : last(end), iter(start)
+ upper_bound() = delete;
+ upper_bound(std::size_t size) : size(size) {}
+
+ key_type get() const
{
- static_assert(std::is_integral<Integer>::value, "range type must be integral");
+ if (queue.size() < size)
+ {
+ return std::numeric_limits<key_type>::max();
+ }
+ return queue.top();
}
- // Iterable functions
- const range &begin() const { return *this; }
- const range &end() const { return *this; }
- Integer front() const { return iter; }
- Integer back() const { return last - 1; }
+ void insert(const parameter_type key)
+ {
+ if (key < get())
+ {
+ queue.emplace(key);
+ while (queue.size() > size)
+ {
+ queue.pop();
+ }
+ }
+ }
- // Iterator functions
- bool operator!=(const range &) const { return iter < last; }
- void operator++() { ++iter; }
- Integer operator*() const { return iter; }
+ private:
+ std::priority_queue<key_type, std::vector<key_type>, std::less<key_type>> queue;
+ const std::size_t size;
};
-// 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)
-{
- return range<Integer>(first, last);
-}
-}
-
-#endif // INTEGER_RANGE_HPP
+#endif // LOWER_BOUND_HPP
diff --git a/data_structures/xor_fast_hash.hpp b/data_structures/xor_fast_hash.hpp
index 1f6dc29..3af5ab1 100644
--- a/data_structures/xor_fast_hash.hpp
+++ b/data_structures/xor_fast_hash.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -61,8 +61,8 @@ class XORFastHash
table2.resize(2 << 16);
for (unsigned i = 0; i < (2 << 16); ++i)
{
- table1[i] = i;
- table2[i] = 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());
@@ -92,10 +92,10 @@ class XORMiniHash
table4.resize(1 << 8);
for (unsigned i = 0; i < (1 << 8); ++i)
{
- table1[i] = i;
- table2[i] = i;
- table3[i] = i;
- table4[i] = 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());
diff --git a/data_structures/xor_fast_hash_storage.hpp b/data_structures/xor_fast_hash_storage.hpp
index 1d84260..ff65717 100644
--- a/data_structures/xor_fast_hash_storage.hpp
+++ b/data_structures/xor_fast_hash_storage.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -38,22 +38,24 @@ template <typename NodeID, typename Key> class XORFastHashStorage
public:
struct HashCell
{
- Key key;
- NodeID id;
unsigned time;
+ NodeID id;
+ Key key;
HashCell()
- : key(std::numeric_limits<unsigned>::max()), id(std::numeric_limits<unsigned>::max()),
- time(std::numeric_limits<unsigned>::max())
+ : time(std::numeric_limits<unsigned>::max()), id(std::numeric_limits<unsigned>::max()),
+ key(std::numeric_limits<unsigned>::max())
{
}
- HashCell(const HashCell &other) : key(other.key), id(other.id), time(other.time) {}
+ 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; }
+ 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)
@@ -64,23 +66,33 @@ template <typename NodeID, typename Key> class XORFastHashStorage
++position %= (2 << 16);
}
- positions[position].id = node;
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));
+ positions.resize(2 << 16);
}
}
private:
- XORFastHashStorage() : positions(2 << 16), current_timestamp(0) {}
std::vector<HashCell> positions;
XORFastHash fast_hasher;
unsigned current_timestamp;
diff --git a/datastore.cpp b/datastore.cpp
index d292004..3c032a2 100644
--- a/datastore.cpp
+++ b/datastore.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,22 +28,25 @@ 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/DataStructures/BaseDataFacade.h"
-#include "Server/DataStructures/SharedDataType.h"
-#include "Server/DataStructures/SharedBarriers.h"
-#include "Util/BoostFileSystemFix.h"
-#include "Util/DataStoreOptions.h"
-#include "Util/simple_logger.hpp"
-#include "Util/osrm_exception.hpp"
-#include "Util/FingerPrint.h"
+#include "server/data_structures/datafacade_base.hpp"
+#include "server/data_structures/shared_datatype.hpp"
+#include "server/data_structures/shared_barriers.hpp"
+#include "util/boost_filesystem_2_fix.hpp"
+#include "util/datastore_options.hpp"
+#include "util/simple_logger.hpp"
+#include "util/osrm_exception.hpp"
+#include "util/fingerprint.hpp"
#include "typedefs.h"
-#include <osrm/Coordinate.h>
+#include <osrm/coordinate.hpp>
+#include <osrm/server_paths.hpp>
using RTreeLeaf = BaseDataFacade<QueryEdge::EdgeData>::RTreeLeaf;
using RTreeNode = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode;
@@ -103,7 +106,8 @@ int main(const int argc, const char *argv[])
const bool lock_flags = MCL_CURRENT | MCL_FUTURE;
if (-1 == mlockall(lock_flags))
{
- SimpleLogger().Write(logWARNING) << "Process " << argv[0] << " could not request RAM lock";
+ SimpleLogger().Write(logWARNING) << "Process " << argv[0]
+ << " could not request RAM lock";
}
#endif
try
@@ -340,8 +344,8 @@ int main(const int argc, const char *argv[])
geometry_input_stream.read((char *)&number_of_geometries_indices, sizeof(unsigned));
shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::GEOMETRIES_INDEX,
number_of_geometries_indices);
- boost::iostreams::seek(
- geometry_input_stream, number_of_geometries_indices * sizeof(unsigned), BOOST_IOS::cur);
+ 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);
@@ -410,9 +414,8 @@ int main(const int argc, const char *argv[])
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);
+ 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>(
diff --git a/descriptors/description_factory.cpp b/descriptors/description_factory.cpp
index 075eff0..e466562 100644
--- a/descriptors/description_factory.cpp
+++ b/descriptors/description_factory.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -27,12 +27,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "description_factory.hpp"
-#include <osrm/Coordinate.h>
-
-#include "../typedefs.h"
#include "../algorithms/polyline_formatter.hpp"
-#include "../data_structures/raw_route_data.hpp"
+#include "../data_structures/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); }
@@ -45,9 +46,8 @@ void DescriptionFactory::SetStartSegment(const PhantomNode &source, const bool t
(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));
+ AppendSegment(source.location, PathData(0, source.name_id, TurnInstruction::HeadOn,
+ segment_duration, travel_mode));
BOOST_ASSERT(path_description.back().duration == segment_duration);
}
@@ -60,15 +60,10 @@ void DescriptionFactory::SetEndSegment(const PhantomNode &target,
(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,
+ path_description.emplace_back(target.location, target.name_id, segment_duration, 0.f,
is_via_location ? TurnInstruction::ReachViaLocation
: TurnInstruction::NoTurn,
- true,
- true,
- travel_mode);
+ true, true, travel_mode);
BOOST_ASSERT(path_description.back().duration == segment_duration);
}
@@ -99,15 +94,11 @@ void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
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);
+ path_description.emplace_back(coordinate, path_point.name_id, path_point.segment_duration, 0.f,
+ turn, path_point.travel_mode);
}
-JSON::Value DescriptionFactory::AppendGeometryString(const bool return_encoded)
+osrm::json::Value DescriptionFactory::AppendGeometryString(const bool return_encoded)
{
if (return_encoded)
{
@@ -122,3 +113,132 @@ void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned
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::euclidean_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.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.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;
+ }
+
+ ++necessary_segments;
+
+ if (first.is_via_location)
+ { // mark the end of a leg (of several segments)
+ via_indices.push_back(necessary_segments);
+ }
+
+ const double angle = coordinate_calculation::bearing(first.location, second.location);
+ first.bearing = static_cast<short>(angle * 10);
+ });
+
+ via_indices.push_back(necessary_segments + 1);
+ BOOST_ASSERT(via_indices.size() >= 2);
+ return;
+}
diff --git a/descriptors/description_factory.hpp b/descriptors/description_factory.hpp
index 9b96dd2..985f9c1 100644
--- a/descriptors/description_factory.hpp
+++ b/descriptors/description_factory.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,14 +30,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../algorithms/douglas_peucker.hpp"
#include "../data_structures/phantom_node.hpp"
-#include "../data_structures/json_container.hpp"
#include "../data_structures/segment_information.hpp"
#include "../data_structures/turn_instructions.hpp"
-#include "../typedefs.h"
#include <boost/assert.hpp>
-#include <osrm/Coordinate.h>
+#include <osrm/coordinate.hpp>
+#include <osrm/json_container.hpp>
#include <cmath>
@@ -73,7 +72,7 @@ class DescriptionFactory
{
// compute distance/duration for route summary
distance = static_cast<unsigned>(std::round(raw_distance));
- duration = static_cast<unsigned>(std::round(raw_duration / 10.));
+ duration = static_cast<EdgeWeight>(std::round(raw_duration / 10.));
}
} summary;
@@ -86,141 +85,12 @@ class DescriptionFactory
void SetEndSegment(const PhantomNode &start_phantom,
const bool traversed_in_reverse,
const bool is_via_location = false);
- JSON::Value AppendGeometryString(const bool return_encoded);
+ osrm::json::Value AppendGeometryString(const bool return_encoded);
std::vector<unsigned> const &GetViaIndices() const;
- double get_entire_length() const
- {
- return entire_length;
- }
-
- template <class DataFacadeT> void Run(const DataFacadeT *facade, const unsigned zoomLevel)
- {
- if (path_description.empty())
- {
- return;
- }
+ double get_entire_length() const { return entire_length; }
- /** starts at index 1 */
- path_description[0].length = 0;
- for (unsigned i = 1; i < path_description.size(); ++i)
- {
- // move down names by one, q&d hack
- path_description[i - 1].name_id = path_description[i].name_id;
- path_description[i].length = FixedPointCoordinate::ApproximateEuclideanDistance(
- 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.;
- unsigned segment_duration = 0;
- unsigned segment_start_index = 0;
-
- for (unsigned i = 1; i < path_description.size(); ++i)
- {
- 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 (std::numeric_limits<double>::epsilon() > path_description.back().length)
- {
- if (path_description.size() > 2)
- {
- 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 (std::numeric_limits<double>::epsilon() > path_description.front().length)
- {
- if (path_description.size() > 2)
- {
- 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(), zoomLevel);
-
- // fix what needs to be fixed else
- unsigned necessary_pieces = 0; // a running index that counts the necessary pieces
- for (unsigned i = 0; i < path_description.size() - 1 && path_description.size() >= 2; ++i)
- {
- if (path_description[i].necessary)
- {
- ++necessary_pieces;
- if (path_description[i].is_via_location)
- { // mark the end of a leg
- via_indices.push_back(necessary_pieces);
- }
- const double angle =
- path_description[i + 1].location.GetBearing(path_description[i].location);
- path_description[i].bearing = static_cast<unsigned>(angle * 10);
- }
- }
- via_indices.push_back(necessary_pieces + 1);
- BOOST_ASSERT(via_indices.size() >= 2);
- // BOOST_ASSERT(0 != necessary_pieces || path_description.empty());
- return;
- }
+ void Run(const unsigned zoom_level);
};
#endif /* DESCRIPTION_FACTORY_HPP */
diff --git a/descriptors/descriptor_base.hpp b/descriptors/descriptor_base.hpp
index 31c08ea..497c216 100644
--- a/descriptors/descriptor_base.hpp
+++ b/descriptors/descriptor_base.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,17 +28,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef DESCRIPTOR_BASE_HPP
#define DESCRIPTOR_BASE_HPP
+#include "../data_structures/coordinate_calculation.hpp"
+#include "../data_structures/internal_route_result.hpp"
#include "../data_structures/phantom_node.hpp"
-#include "../data_structures/raw_route_data.hpp"
#include "../typedefs.h"
-#include <osrm/Reply.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)
@@ -52,18 +54,16 @@ struct DescriptorTable : public std::unordered_map<std::string, unsigned>
}
};
-
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)
+ 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);
}
@@ -80,8 +80,8 @@ template <class DataFacadeT> class BaseDescriptor
BaseDescriptor() {}
// Maybe someone can explain the pure virtual destructor thing to me (dennis)
virtual ~BaseDescriptor() {}
- virtual void Run(const RawRouteData &raw_route, http::Reply &reply) = 0;
- virtual void SetConfig(const DescriptorConfig &config) = 0;
+ 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
index 2dd0034..fb4c5b9 100644
--- a/descriptors/gpx_descriptor.hpp
+++ b/descriptors/gpx_descriptor.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -29,8 +29,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define GPX_DESCRIPTOR_HPP
#include "descriptor_base.hpp"
-#include "../data_structures/json_container.hpp"
-#include "../Util/xml_renderer.hpp"
+#include "../util/xml_renderer.hpp"
+
+#include <osrm/json_container.hpp>
#include <iostream>
@@ -40,39 +41,39 @@ template <class DataFacadeT> class GPXDescriptor final : public BaseDescriptor<D
DescriptorConfig config;
DataFacadeT *facade;
- void AddRoutePoint(const FixedPointCoordinate &coordinate, JSON::Array &json_result)
+ void AddRoutePoint(const FixedPointCoordinate &coordinate, osrm::json::Array &json_route)
{
- JSON::Object json_lat;
- JSON::Object json_lon;
- JSON::Array json_row;
+ osrm::json::Object json_lat;
+ osrm::json::Object json_lon;
+ osrm::json::Array json_row;
std::string tmp;
- FixedPointCoordinate::convertInternalLatLonToString(coordinate.lat, tmp);
+ coordinate_calculation::lat_or_lon_to_string(coordinate.lat, tmp);
json_lat.values["_lat"] = tmp;
- FixedPointCoordinate::convertInternalLatLonToString(coordinate.lon, 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);
- JSON::Object entry;
+ osrm::json::Object entry;
entry.values["rtept"] = json_row;
- json_result.values.push_back(entry);
+ json_route.values.push_back(entry);
}
public:
explicit GPXDescriptor(DataFacadeT *facade) : facade(facade) {}
- void SetConfig(const DescriptorConfig &c) final { config = c; }
+ virtual void SetConfig(const DescriptorConfig &c) final { config = c; }
- void Run(const RawRouteData &raw_route, http::Reply &reply) final
+ virtual void Run(const InternalRouteResult &raw_route, osrm::json::Object &json_result) final
{
- JSON::Array json_result;
+ 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_result);
+ json_route);
for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
{
@@ -80,13 +81,14 @@ template <class DataFacadeT> class GPXDescriptor final : public BaseDescriptor<D
{
const FixedPointCoordinate current_coordinate =
facade->GetCoordinateOfNode(path_data.node);
- AddRoutePoint(current_coordinate, json_result);
+ AddRoutePoint(current_coordinate, json_route);
}
}
AddRoutePoint(raw_route.segment_end_coordinates.back().target_phantom.location,
- json_result);
+ json_route);
}
- JSON::gpx_render(reply.content, json_result);
+ // 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
index 2aae939..13b68c6 100644
--- a/descriptors/json_descriptor.hpp
+++ b/descriptors/json_descriptor.hpp
@@ -1,393 +1,392 @@
-/*
-
-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 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/json_container.hpp"
-#include "../data_structures/segment_information.hpp"
-#include "../data_structures/turn_instructions.hpp"
-#include "../Util/bearing.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 <algorithm>
-
-template <class DataFacadeT> class JSONDescriptor final : public BaseDescriptor<DataFacadeT>
-{
- private:
- DataFacadeT *facade;
- DescriptorConfig config;
- DescriptionFactory description_factory, alternate_description_factory;
- FixedPointCoordinate current;
- unsigned entered_restricted_area_count;
- struct RoundAbout
- {
- RoundAbout() : start_index(INT_MAX), name_id(INVALID_NAMEID), leave_at_exit(INT_MAX) {}
- int start_index;
- unsigned name_id;
- int leave_at_exit;
- } round_about;
-
- 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;
- };
- std::vector<Segment> shortest_path_segments, alternative_path_segments;
- ExtractRouteNames<DataFacadeT, Segment> GenerateRouteNames;
-
- public:
- explicit JSONDescriptor(DataFacadeT *facade) : facade(facade), entered_restricted_area_count(0) {}
-
- void SetConfig(const DescriptorConfig &c) 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;
- }
-
- void Run(const RawRouteData &raw_route, http::Reply &reply) final
- {
- JSON::Object json_result;
- if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
- {
- // We do not need to do much, if there is no route ;-)
- json_result.values["status"] = 207;
- json_result.values["status_message"] = "Cannot find route between points";
- JSON::render(reply.content, json_result);
- return;
- }
-
- // check if first segment is non-zero
- std::string road_name = facade->GetEscapedNameForNameID(
- raw_route.segment_end_coordinates.front().source_phantom.name_id);
-
- 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());
- json_result.values["status"] = 0;
- json_result.values["status_message"] = "Found route between points";
-
- // 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(facade, config.zoom_level);
-
- if (config.geometry)
- {
- JSON::Value route_geometry =
- description_factory.AppendGeometryString(config.encode_geometry);
- json_result.values["route_geometry"] = route_geometry;
- }
- if (config.instructions)
- {
- JSON::Array json_route_instructions;
- BuildTextualDescription(description_factory,
- json_route_instructions,
- raw_route.shortest_path_length,
- shortest_path_segments);
- json_result.values["route_instructions"] = json_route_instructions;
- }
- description_factory.BuildRouteSummary(description_factory.get_entire_length(),
- raw_route.shortest_path_length);
- 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->GetEscapedNameForNameID(description_factory.summary.source_name_id);
- json_route_summary.values["end_point"] =
- facade->GetEscapedNameForNameID(description_factory.summary.target_name_id);
- json_result.values["route_summary"] = json_route_summary;
-
- BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
-
- JSON::Array json_via_points_array;
- 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;
- 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;
-
- 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"] = 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(facade, config.zoom_level);
-
- if (config.geometry)
- {
- JSON::Value alternate_geometry_string =
- alternate_description_factory.AppendGeometryString(config.encode_geometry);
- 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)
- JSON::Array json_alt_instructions;
- JSON::Array json_current_alt_instructions;
- if (config.instructions)
- {
- BuildTextualDescription(alternate_description_factory,
- json_current_alt_instructions,
- raw_route.alternative_path_length,
- 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);
-
- JSON::Object json_alternate_route_summary;
- 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->GetEscapedNameForNameID(
- alternate_description_factory.summary.source_name_id);
- json_alternate_route_summary.values["end_point"] = facade->GetEscapedNameForNameID(
- 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();
- 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"] = JSON::False();
- }
-
- // Get Names for both routes
- RouteNames route_names =
- GenerateRouteNames(shortest_path_segments, alternative_path_segments, facade);
- 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)
- {
- JSON::Array json_alternate_names_array;
- 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::Object json_hint_object;
- json_hint_object.values["checksum"] = facade->GetCheckSum();
- 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;
- json_result.values["hint_data"] = json_hint_object;
-
- // render the content to the output array
- TIMER_START(route_render);
- JSON::render(reply.content, json_result);
- TIMER_STOP(route_render);
- SimpleLogger().Write(logDEBUG) << "rendering took: " << TIMER_MSEC(route_render);
- }
-
- // TODO: reorder parameters
- inline void BuildTextualDescription(DescriptionFactory &description_factory,
- JSON::Array &json_instruction_array,
- const int route_length,
- std::vector<Segment> &route_segments_list)
- {
- // Segment information has following format:
- //["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
- unsigned necessary_segments_running_index = 0;
- round_about.leave_at_exit = 0;
- round_about.name_id = 0;
- std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
-
- // Fetch data from Factory and generate a string from it.
- for (const SegmentInformation &segment : description_factory.path_description)
- {
- JSON::Array json_instruction_row;
- TurnInstruction current_instruction = segment.turn_instruction;
- entered_restricted_area_count += (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 =
- cast::integral_to_string(cast::enum_to_underlying(TurnInstruction::EnterRoundAbout));
- current_turn_instruction += temp_instruction;
- current_turn_instruction += "-";
- temp_instruction = cast::integral_to_string(round_about.leave_at_exit + 1);
- current_turn_instruction += temp_instruction;
- round_about.leave_at_exit = 0;
- }
- else
- {
- temp_instruction = cast::integral_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->GetEscapedNameForNameID(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(round(segment.duration / 10));
- json_instruction_row.values.push_back(
- cast::integral_to_string(static_cast<unsigned>(segment.length)) + "m");
- const double bearing_value = (segment.bearing / 10.);
- json_instruction_row.values.push_back(Bearing::Get(bearing_value));
- json_instruction_row.values.push_back(
- static_cast<unsigned>(round(bearing_value)));
- json_instruction_row.values.push_back(segment.travel_mode);
-
- route_segments_list.emplace_back(
- segment.name_id,
- static_cast<int>(segment.length),
- static_cast<unsigned>(route_segments_list.size()));
- json_instruction_array.values.push_back(json_instruction_row);
- }
- }
- else if (TurnInstruction::StayOnRoundAbout == current_instruction)
- {
- ++round_about.leave_at_exit;
- }
- if (segment.necessary)
- {
- ++necessary_segments_running_index;
- }
- }
-
- JSON::Array json_last_instruction_row;
- temp_instruction = cast::integral_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_instruction_array.values.push_back(json_last_instruction_row);
- }
-};
-
-#endif /* JSON_DESCRIPTOR_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 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/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 <algorithm>
+
+template <class DataFacadeT> class JSONDescriptor final : public BaseDescriptor<DataFacadeT>
+{
+ private:
+ DataFacadeT *facade;
+ DescriptorConfig config;
+ DescriptionFactory description_factory, alternate_description_factory;
+ FixedPointCoordinate current;
+ unsigned entered_restricted_area_count;
+ struct RoundAbout
+ {
+ RoundAbout() : start_index(INT_MAX), name_id(INVALID_NAMEID), leave_at_exit(INT_MAX) {}
+ int start_index;
+ unsigned name_id;
+ int leave_at_exit;
+ } round_about;
+
+ 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;
+ };
+ std::vector<Segment> shortest_path_segments, alternative_path_segments;
+ ExtractRouteNames<DataFacadeT, Segment> GenerateRouteNames;
+
+ public:
+ explicit JSONDescriptor(DataFacadeT *facade) : facade(facade), entered_restricted_area_count(0)
+ {
+ }
+
+ 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 ;-)
+ json_result.values["status"] = 207;
+ json_result.values["status_message"] = "Cannot find route between points";
+ // osrm::json::render(reply.content, json_result);
+ 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());
+ json_result.values["status"] = 0;
+ json_result.values["status_message"] = "Found route between points";
+
+ // 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, json_route_instructions,
+ raw_route.shortest_path_length, 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)
+ {
+ BuildTextualDescription(
+ alternate_description_factory, json_current_alt_instructions,
+ raw_route.alternative_path_length, 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;
+ }
+
+ 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;
+ json_result.values["hint_data"] = json_hint_object;
+
+ // render the content to the output array
+ // TIMER_START(route_render);
+ // osrm::json::render(reply.content, json_result);
+ // TIMER_STOP(route_render);
+ // SimpleLogger().Write(logDEBUG) << "rendering took: " << TIMER_MSEC(route_render);
+ }
+
+ // TODO: reorder parameters
+ inline void BuildTextualDescription(DescriptionFactory &description_factory,
+ osrm::json::Array &json_instruction_array,
+ const int route_length,
+ std::vector<Segment> &route_segments_list)
+ {
+ // Segment information has following format:
+ //["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
+ unsigned necessary_segments_running_index = 0;
+ round_about.leave_at_exit = 0;
+ round_about.name_id = 0;
+ std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
+
+ // 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;
+ entered_restricted_area_count += (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 = cast::integral_to_string(
+ cast::enum_to_underlying(TurnInstruction::EnterRoundAbout));
+ current_turn_instruction += temp_instruction;
+ current_turn_instruction += "-";
+ temp_instruction = cast::integral_to_string(round_about.leave_at_exit + 1);
+ current_turn_instruction += temp_instruction;
+ round_about.leave_at_exit = 0;
+ }
+ else
+ {
+ temp_instruction =
+ cast::integral_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(
+ cast::integral_to_string(static_cast<unsigned>(segment.length)) + "m");
+ const double bearing_value = (segment.bearing / 10.);
+ json_instruction_row.values.push_back(bearing::get(bearing_value));
+ json_instruction_row.values.push_back(
+ static_cast<unsigned>(round(bearing_value)));
+ json_instruction_row.values.push_back(segment.travel_mode);
+
+ route_segments_list.emplace_back(
+ segment.name_id, static_cast<int>(segment.length),
+ static_cast<unsigned>(route_segments_list.size()));
+ json_instruction_array.values.push_back(json_instruction_row);
+ }
+ }
+ 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 = cast::integral_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_instruction_array.values.push_back(json_last_instruction_row);
+ }
+};
+
+#endif /* JSON_DESCRIPTOR_H_ */
diff --git a/extract.cpp b/extract.cpp
index 2ad1f7a..a147629 100644
--- a/extract.cpp
+++ b/extract.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -26,17 +26,58 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "extractor/extractor.hpp"
-#include "Util/simple_logger.hpp"
+#include "extractor/extractor_options.hpp"
+#include "util/simple_logger.hpp"
-int main (int argc, char *argv[])
+#include <boost/filesystem.hpp>
+
+#include <exception>
+
+int main(int argc, char *argv[])
{
try
{
- return Extractor().Run(argc, argv);
+ LogPolicy::GetInstance().Unmute();
+ ExtractorConfig extractor_config;
+
+ const return_code result = ExtractorOptions::ParseArguments(argc, argv, extractor_config);
+
+ if (return_code::fail == result)
+ {
+ return 1;
+ }
+
+ if (return_code::exit == result)
+ {
+ return 0;
+ }
+
+ ExtractorOptions::GenerateOutputFilesNames(extractor_config);
+
+ if (1 > extractor_config.requested_num_threads)
+ {
+ SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
+ return 1;
+ }
+
+ if (!boost::filesystem::is_regular_file(extractor_config.input_path))
+ {
+ SimpleLogger().Write(logWARNING)
+ << "Input file " << extractor_config.input_path.string() << " not found!";
+ return 1;
+ }
+
+ if (!boost::filesystem::is_regular_file(extractor_config.profile_path))
+ {
+ SimpleLogger().Write(logWARNING) << "Profile " << extractor_config.profile_path.string()
+ << " not found!";
+ return 1;
+ }
+ return extractor().run(extractor_config);
}
catch (const std::exception &e)
{
SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+ return 1;
}
-
}
diff --git a/extractor/extraction_containers.cpp b/extractor/extraction_containers.cpp
index 604f863..8c484eb 100644
--- a/extractor/extraction_containers.cpp
+++ b/extractor/extraction_containers.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,12 +28,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "extraction_containers.hpp"
#include "extraction_way.hpp"
+#include "../data_structures/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/osrm_exception.hpp"
+#include "../util/simple_logger.hpp"
+#include "../util/timing_util.hpp"
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
@@ -82,41 +83,34 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
TIMER_STOP(erasing_dups);
std::cout << "ok, after " << TIMER_SEC(erasing_dups) << "s" << std::endl;
-
std::cout << "[extractor] Sorting all nodes ... " << std::flush;
TIMER_START(sorting_nodes);
- stxxl::sort(all_nodes_list.begin(),
- all_nodes_list.end(),
- ExternalMemoryNodeSTXXLCompare(),
+ stxxl::sort(all_nodes_list.begin(), all_nodes_list.end(), ExternalMemoryNodeSTXXLCompare(),
stxxl_memory);
TIMER_STOP(sorting_nodes);
std::cout << "ok, after " << TIMER_SEC(sorting_nodes) << "s" << std::endl;
-
std::cout << "[extractor] Sorting used ways ... " << std::flush;
TIMER_START(sort_ways);
- stxxl::sort(way_start_end_id_list.begin(),
- way_start_end_id_list.end(),
- FirstAndLastSegmentOfWayStxxlCompare(),
- stxxl_memory);
+ stxxl::sort(way_start_end_id_list.begin(), way_start_end_id_list.end(),
+ FirstAndLastSegmentOfWayStxxlCompare(), stxxl_memory);
TIMER_STOP(sort_ways);
std::cout << "ok, after " << TIMER_SEC(sort_ways) << "s" << std::endl;
- std::cout << "[extractor] Sorting " << restrictions_list.size() << " restrictions. by from... " << std::flush;
+ std::cout << "[extractor] Sorting " << restrictions_list.size()
+ << " restrictions. 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;
std::cout << "[extractor] Fixing restriction starts ... " << std::flush;
TIMER_START(fix_restriction_starts);
auto restrictions_iterator = restrictions_list.begin();
- auto way_start_and_end_iterator = way_start_end_id_list.begin();
+ auto way_start_and_end_iterator = way_start_end_id_list.cbegin();
- while (way_start_and_end_iterator != way_start_end_id_list.end() &&
+ while (way_start_and_end_iterator != way_start_end_id_list.cend() &&
restrictions_iterator != restrictions_list.end())
{
if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.from.way)
@@ -131,27 +125,19 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
continue;
}
- BOOST_ASSERT(way_start_and_end_iterator->way_id == restrictions_iterator->restriction.from.way);
+ BOOST_ASSERT(way_start_and_end_iterator->way_id ==
+ restrictions_iterator->restriction.from.way);
const NodeID via_node_id = restrictions_iterator->restriction.via.node;
if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
{
restrictions_iterator->restriction.from.node =
- way_start_and_end_iterator->first_segment_source_id;
- }
- else if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
- {
- restrictions_iterator->restriction.from.node =
- way_start_and_end_iterator->first_segment_source_id;
- }
- else if (way_start_and_end_iterator->last_segment_source_id == via_node_id)
- {
- restrictions_iterator->restriction.from.node =
- way_start_and_end_iterator->last_segment_target_id;
+ way_start_and_end_iterator->first_segment_target_id;
}
else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
{
- restrictions_iterator->restriction.from.node = way_start_and_end_iterator->last_segment_source_id;
+ restrictions_iterator->restriction.from.node =
+ way_start_and_end_iterator->last_segment_source_id;
}
++restrictions_iterator;
}
@@ -161,19 +147,16 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
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;
- unsigned number_of_useable_restrictions = 0;
std::cout << "[extractor] Fixing restriction ends ... " << std::flush;
TIMER_START(fix_restriction_ends);
restrictions_iterator = restrictions_list.begin();
- way_start_and_end_iterator = way_start_end_id_list.begin();
- while (way_start_and_end_iterator != way_start_end_id_list.end() &&
+ way_start_and_end_iterator = way_start_end_id_list.cbegin();
+ while (way_start_and_end_iterator != way_start_end_id_list.cend() &&
restrictions_iterator != restrictions_list.end())
{
if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.to.way)
@@ -186,51 +169,48 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
++restrictions_iterator;
continue;
}
- NodeID via_node_id = restrictions_iterator->restriction.via.node;
- if (way_start_and_end_iterator->last_segment_source_id == via_node_id)
+ BOOST_ASSERT(way_start_and_end_iterator->way_id ==
+ restrictions_iterator->restriction.to.way);
+ const NodeID via_node_id = restrictions_iterator->restriction.via.node;
+
+ if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
{
- restrictions_iterator->restriction.to.node = way_start_and_end_iterator->last_segment_target_id;
+ restrictions_iterator->restriction.to.node =
+ way_start_and_end_iterator->first_segment_target_id;
}
else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
{
- restrictions_iterator->restriction.to.node = way_start_and_end_iterator->last_segment_source_id;
- }
- else if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
- {
- restrictions_iterator->restriction.to.node = way_start_and_end_iterator->first_segment_target_id;
- }
- else if (way_start_and_end_iterator->first_segment_target_id == via_node_id)
- {
- restrictions_iterator->restriction.to.node = way_start_and_end_iterator->first_segment_source_id;
- }
-
- if (std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.from.node &&
- std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.to.node)
- {
- ++number_of_useable_restrictions;
+ restrictions_iterator->restriction.to.node =
+ way_start_and_end_iterator->last_segment_source_id;
}
++restrictions_iterator;
}
TIMER_STOP(fix_restriction_ends);
std::cout << "ok, after " << TIMER_SEC(fix_restriction_ends) << "s" << std::endl;
- SimpleLogger().Write() << "usable restrictions: " << number_of_useable_restrictions;
// serialize restrictions
std::ofstream restrictions_out_stream;
+ unsigned written_restriction_count = 0;
restrictions_out_stream.open(restrictions_file_name.c_str(), std::ios::binary);
restrictions_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
- restrictions_out_stream.write((char *)&number_of_useable_restrictions, sizeof(unsigned));
+ const auto count_position = restrictions_out_stream.tellp();
+ restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
- for(const auto & restriction_container : restrictions_list)
+ for (const auto &restriction_container : restrictions_list)
{
- if (std::numeric_limits<unsigned>::max() != restriction_container.restriction.from.node &&
- std::numeric_limits<unsigned>::max() != restriction_container.restriction.to.node)
+ if (SPECIAL_NODEID != restriction_container.restriction.from.node &&
+ SPECIAL_NODEID != restriction_container.restriction.to.node)
{
restrictions_out_stream.write((char *)&(restriction_container.restriction),
sizeof(TurnRestriction));
+ ++written_restriction_count;
}
}
+ 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;
std::ofstream file_out_stream;
file_out_stream.open(output_file_name.c_str(), std::ios::binary);
@@ -280,7 +260,6 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
TIMER_STOP(sort_edges_by_start);
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_start) << "s" << std::endl;
-
std::cout << "[extractor] Setting start coords ... " << std::flush;
TIMER_START(set_start_coords);
file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
@@ -311,7 +290,8 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
// 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(), CmpEdgeByTargetID(), stxxl_memory);
+ stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByTargetID(),
+ stxxl_memory);
TIMER_STOP(sort_edges_by_target);
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_target) << "s" << std::endl;
@@ -341,20 +321,19 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
edge_iterator->target_coordinate.lat = node_iterator->lat;
edge_iterator->target_coordinate.lon = node_iterator->lon;
- const double distance = FixedPointCoordinate::ApproximateEuclideanDistance(
- edge_iterator->source_coordinate.lat,
- edge_iterator->source_coordinate.lon,
- node_iterator->lat,
- node_iterator->lon);
+ const double distance = coordinate_calculation::euclidean_distance(
+ edge_iterator->source_coordinate.lat, edge_iterator->source_coordinate.lon,
+ node_iterator->lat, node_iterator->lon);
const double weight = (distance * 10.) / (edge_iterator->speed / 3.6);
int integer_weight = std::max(
- 1,
- (int)std::floor(
- (edge_iterator->is_duration_set ? edge_iterator->speed : weight) + .5));
- int integer_distance = std::max(1, (int)distance);
- short zero = 0;
- short one = 1;
+ 1, (int)std::floor(
+ (edge_iterator->is_duration_set ? edge_iterator->speed : weight) + .5));
+ const int integer_distance = std::max(1, (int)distance);
+ const short zero = 0;
+ const short one = 1;
+ const bool yes = true;
+ const bool no = false;
file_out_stream.write((char *)&edge_iterator->start, sizeof(unsigned));
file_out_stream.write((char *)&edge_iterator->target, sizeof(unsigned));
@@ -379,15 +358,43 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
file_out_stream.write((char *)&integer_weight, sizeof(int));
file_out_stream.write((char *)&edge_iterator->name_id, sizeof(unsigned));
- file_out_stream.write((char *)&edge_iterator->is_roundabout, sizeof(bool));
- file_out_stream.write((char *)&edge_iterator->is_in_tiny_cc, sizeof(bool));
- file_out_stream.write((char *)&edge_iterator->is_access_restricted, sizeof(bool));
+ if (edge_iterator->is_roundabout)
+ {
+ file_out_stream.write((char *)&yes, sizeof(bool));
+ }
+ else
+ {
+ file_out_stream.write((char *)&no, sizeof(bool));
+ }
+ if (edge_iterator->is_in_tiny_cc)
+ {
+ file_out_stream.write((char *)&yes, sizeof(bool));
+ }
+ else
+ {
+ file_out_stream.write((char *)&no, sizeof(bool));
+ }
+ if (edge_iterator->is_access_restricted)
+ {
+ file_out_stream.write((char *)&yes, sizeof(bool));
+ }
+ else
+ {
+ file_out_stream.write((char *)&no, sizeof(bool));
+ }
// cannot take adress of bit field, so use local
- const TravelMode travel_mode = edge_iterator->travel_mode;
+ const TravelMode travel_mode = edge_iterator->travel_mode;
file_out_stream.write((char *)&travel_mode, sizeof(TravelMode));
- file_out_stream.write((char *)&edge_iterator->is_split, sizeof(bool));
+ if (edge_iterator->is_split)
+ {
+ file_out_stream.write((char *)&yes, sizeof(bool));
+ }
+ else
+ {
+ file_out_stream.write((char *)&no, sizeof(bool));
+ }
++number_of_used_edges;
}
++edge_iterator;
@@ -411,7 +418,8 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
std::vector<unsigned> name_lengths;
for (const std::string &temp_string : name_list)
{
- const unsigned string_length = std::min(static_cast<unsigned>(temp_string.length()), 255u);
+ const unsigned string_length =
+ std::min(static_cast<unsigned>(temp_string.length()), 255u);
name_lengths.push_back(string_length);
total_length += string_length;
}
@@ -419,11 +427,12 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
RangeTable<> table(name_lengths);
name_file_stream << table;
- name_file_stream.write((char*) &total_length, sizeof(unsigned));
+ name_file_stream.write((char *)&total_length, sizeof(unsigned));
// write all chars consecutively
for (const std::string &temp_string : name_list)
{
- const unsigned string_length = std::min(static_cast<unsigned>(temp_string.length()), 255u);
+ const unsigned string_length =
+ std::min(static_cast<unsigned>(temp_string.length()), 255u);
name_file_stream.write(temp_string.c_str(), string_length);
}
@@ -434,5 +443,8 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
SimpleLogger().Write() << "Processed " << number_of_used_nodes << " nodes and "
<< number_of_used_edges << " edges";
}
- catch (const std::exception &e) { std::cerr << "Caught Execption:" << e.what() << std::endl; }
+ catch (const std::exception &e)
+ {
+ std::cerr << "Caught Execption:" << e.what() << std::endl;
+ }
}
diff --git a/extractor/extraction_containers.hpp b/extractor/extraction_containers.hpp
index 8a1df8c..12d88a2 100644
--- a/extractor/extraction_containers.hpp
+++ b/extractor/extraction_containers.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -32,24 +32,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "first_and_last_segment_of_way.hpp"
#include "../data_structures/external_memory_node.hpp"
#include "../data_structures/restriction.hpp"
-#include "../Util/FingerPrint.h"
+#include "../util/fingerprint.hpp"
#include <stxxl/vector>
class ExtractionContainers
{
#ifndef _MSC_VER
- constexpr static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? std::numeric_limits<int>::max() : std::numeric_limits<unsigned>::max());
+ constexpr static unsigned stxxl_memory =
+ ((sizeof(std::size_t) == 4) ? std::numeric_limits<int>::max()
+ : std::numeric_limits<unsigned>::max());
#else
const static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? INT_MAX : UINT_MAX);
#endif
public:
- using STXXLNodeIDVector = stxxl::vector<NodeID>;
- using STXXLNodeVector = stxxl::vector<ExternalMemoryNode>;
- using STXXLEdgeVector = stxxl::vector<InternalExtractorEdge>;
- using STXXLStringVector = stxxl::vector<std::string>;
- using STXXLRestrictionsVector = stxxl::vector<InputRestrictionContainer>;
- using STXXLWayIDStartEndVector = stxxl::vector<FirstAndLastSegmentOfWay>;
+ using STXXLNodeIDVector = stxxl::vector<NodeID>;
+ using STXXLNodeVector = stxxl::vector<ExternalMemoryNode>;
+ using STXXLEdgeVector = stxxl::vector<InternalExtractorEdge>;
+ using STXXLStringVector = stxxl::vector<std::string>;
+ using STXXLRestrictionsVector = stxxl::vector<InputRestrictionContainer>;
+ using STXXLWayIDStartEndVector = stxxl::vector<FirstAndLastSegmentOfWay>;
STXXLNodeIDVector used_node_id_list;
STXXLNodeVector all_nodes_list;
diff --git a/extractor/extraction_helper_functions.hpp b/extractor/extraction_helper_functions.hpp
index d2a73c9..d10200a 100644
--- a/extractor/extraction_helper_functions.hpp
+++ b/extractor/extraction_helper_functions.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,7 +28,8 @@ 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/cast.hpp"
+#include "../util/iso_8601_duration_parser.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string_regex.hpp>
@@ -37,53 +38,81 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <limits>
-namespace qi = boost::spirit::qi;
-
-// TODO: Move into LUA
-
-bool durationIsValid(const std::string &s)
+bool simple_duration_is_valid(const std::string &s)
{
- boost::regex e(
+ boost::regex simple_format(
"((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",
boost::regex_constants::icase | boost::regex_constants::perl);
- std::vector<std::string> result;
- boost::algorithm::split_regex(result, s, boost::regex(":"));
- const bool matched = regex_match(s, e);
- return matched;
+ const bool simple_matched = regex_match(s, simple_format);
+
+ if (simple_matched)
+ {
+ return true;
+ }
+ return false;
}
-unsigned parseDuration(const std::string &s)
+bool iso_8601_duration_is_valid(const std::string &s)
{
- unsigned hours = 0;
- unsigned minutes = 0;
- unsigned seconds = 0;
- boost::regex e(
- "((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",
- boost::regex_constants::icase | boost::regex_constants::perl);
+ iso_8601_grammar<std::string::const_iterator> iso_parser;
+ const bool result = qi::parse(s.begin(), s.end(), iso_parser);
- std::vector<std::string> result;
- boost::algorithm::split_regex(result, s, boost::regex(":"));
- const bool matched = regex_match(s, e);
- if (matched)
+ // check if the was an error with the request
+ if (result && (0 != iso_parser.get_duration()))
{
- if (1 == result.size())
- {
- minutes = cast::string_to_int(result[0]);
- }
- if (2 == result.size())
- {
- minutes = cast::string_to_int(result[1]);
- hours = cast::string_to_int(result[0]);
- }
- if (3 == result.size())
+ return true;
+ }
+ return false;
+}
+
+bool durationIsValid(const std::string &s)
+{
+ return simple_duration_is_valid(s) || iso_8601_duration_is_valid(s);
+}
+
+unsigned parseDuration(const std::string &s)
+{
+ if (simple_duration_is_valid(s))
+ {
+ unsigned hours = 0;
+ unsigned minutes = 0;
+ unsigned seconds = 0;
+ boost::regex e(
+ "((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",
+ boost::regex_constants::icase | boost::regex_constants::perl);
+
+ std::vector<std::string> result;
+ boost::algorithm::split_regex(result, s, boost::regex(":"));
+ const bool matched = regex_match(s, e);
+ if (matched)
{
- seconds = cast::string_to_int(result[2]);
- minutes = cast::string_to_int(result[1]);
- hours = cast::string_to_int(result[0]);
+ if (1 == result.size())
+ {
+ minutes = cast::string_to_int(result[0]);
+ }
+ if (2 == result.size())
+ {
+ minutes = cast::string_to_int(result[1]);
+ hours = cast::string_to_int(result[0]);
+ }
+ if (3 == result.size())
+ {
+ seconds = cast::string_to_int(result[2]);
+ minutes = cast::string_to_int(result[1]);
+ hours = cast::string_to_int(result[0]);
+ }
+ return 10 * (3600 * hours + 60 * minutes + seconds);
}
- return 10 * (3600 * hours + 60 * minutes + seconds);
}
+ 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);
+
+ return iso_parser.get_duration();
+ }
+
return std::numeric_limits<unsigned>::max();
}
diff --git a/extractor/extraction_node.hpp b/extractor/extraction_node.hpp
index defd333..e821d6f 100644
--- a/extractor/extraction_node.hpp
+++ b/extractor/extraction_node.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,11 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct ExtractionNode
{
- ExtractionNode() : traffic_lights(false), barrier(false) { }
- void clear()
- {
- traffic_lights = barrier = false;
- }
+ ExtractionNode() : traffic_lights(false), barrier(false) {}
+ void clear() { traffic_lights = barrier = false; }
bool traffic_lights;
bool barrier;
};
diff --git a/extractor/extraction_way.hpp b/extractor/extraction_way.hpp
index b414487..d47de20 100644
--- a/extractor/extraction_way.hpp
+++ b/extractor/extraction_way.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -52,10 +52,12 @@ struct ExtractionWay
}
enum Directions
- { notSure = 0,
- oneway,
- bidirectional,
- opposite };
+ {
+ 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
@@ -69,19 +71,20 @@ struct ExtractionWay
}
else if (Directions::opposite == m)
{
- forward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
- backward_travel_mode = TRAVEL_MODE_DEFAULT;
+ 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;
+ 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)
+ if (TRAVEL_MODE_INACCESSIBLE != forward_travel_mode &&
+ TRAVEL_MODE_INACCESSIBLE != backward_travel_mode)
{
return Directions::bidirectional;
}
diff --git a/extractor/extractor.cpp b/extractor/extractor.cpp
index 880e9e4..0581e4e 100644
--- a/extractor/extractor.cpp
+++ b/extractor/extractor.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -31,18 +31,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "extraction_node.hpp"
#include "extraction_way.hpp"
#include "extractor_callbacks.hpp"
-#include "extractor_options.hpp"
#include "restriction_parser.hpp"
#include "scripting_environment.hpp"
-#include "../Util/git_sha.hpp"
-#include "../Util/IniFileUtil.h"
-#include "../Util/simple_logger.hpp"
-#include "../Util/timing_util.hpp"
-#include "../Util/make_unique.hpp"
+#include "../util/git_sha.hpp"
+#include "../util/make_unique.hpp"
+#include "../util/simple_logger.hpp"
+#include "../util/timing_util.hpp"
#include "../typedefs.h"
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
#include <luabind/luabind.hpp>
#include <osmium/io/any_input.hpp>
@@ -63,43 +64,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unordered_map>
#include <vector>
-int Extractor::Run(int argc, char *argv[])
+int extractor::run(const ExtractorConfig &extractor_config)
{
- ExtractorConfig extractor_config;
-
try
{
LogPolicy::GetInstance().Unmute();
TIMER_START(extracting);
- if (!ExtractorOptions::ParseArguments(argc, argv, extractor_config))
- {
- return 0;
- }
- ExtractorOptions::GenerateOutputFilesNames(extractor_config);
-
- if (1 > extractor_config.requested_num_threads)
- {
- SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
- return 1;
- }
-
- if (!boost::filesystem::is_regular_file(extractor_config.input_path))
- {
- SimpleLogger().Write(logWARNING)
- << "Input file " << extractor_config.input_path.string() << " not found!";
- return 1;
- }
-
- if (!boost::filesystem::is_regular_file(extractor_config.profile_path))
- {
- SimpleLogger().Write(logWARNING) << "Profile " << extractor_config.profile_path.string()
- << " not found!";
- return 1;
- }
-
const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
- const auto number_of_threads = std::min(recommended_num_threads, extractor_config.requested_num_threads);
+ const auto number_of_threads =
+ std::min(recommended_num_threads, extractor_config.requested_num_threads);
tbb::task_scheduler_init init(number_of_threads);
SimpleLogger().Write() << "Input file: " << extractor_config.input_path.filename().string();
@@ -120,10 +94,10 @@ int Extractor::Run(int argc, char *argv[])
osmium::io::Reader reader(input_file);
const osmium::io::Header header = reader.header();
- std::atomic<unsigned> number_of_nodes {0};
- std::atomic<unsigned> number_of_ways {0};
- std::atomic<unsigned> number_of_relations {0};
- std::atomic<unsigned> number_of_others {0};
+ std::atomic<unsigned> number_of_nodes{0};
+ std::atomic<unsigned> number_of_ways{0};
+ std::atomic<unsigned> number_of_relations{0};
+ std::atomic<unsigned> number_of_others{0};
SimpleLogger().Write() << "Parsing in progress..";
TIMER_START(parsing);
@@ -160,7 +134,8 @@ int Extractor::Run(int argc, char *argv[])
{
// create a vector of iterators into the buffer
std::vector<osmium::memory::Buffer::const_iterator> osm_elements;
- for (auto iter = std::begin(buffer); iter != std::end(buffer); ++iter) {
+ for (auto iter = std::begin(buffer); iter != std::end(buffer); ++iter)
+ {
osm_elements.push_back(iter);
}
@@ -170,55 +145,56 @@ int Extractor::Run(int argc, char *argv[])
resulting_restrictions.clear();
// parse OSM entities in parallel, store in resulting vectors
- tbb::parallel_for(tbb::blocked_range<std::size_t>(0, osm_elements.size()),
- [&](const tbb::blocked_range<std::size_t> &range)
- {
- for (auto x = range.begin(); x != range.end(); ++x)
+ tbb::parallel_for(
+ tbb::blocked_range<std::size_t>(0, osm_elements.size()),
+ [&](const tbb::blocked_range<std::size_t> &range)
{
- const auto entity = osm_elements[x];
-
ExtractionNode result_node;
ExtractionWay result_way;
+ lua_State *local_state = scripting_environment.get_lua_state();
- lua_State * local_state = scripting_environment.get_lua_state();
-
- switch (entity->type())
+ for (auto x = range.begin(); x != range.end(); ++x)
{
- case osmium::item_type::node:
- ++number_of_nodes;
- luabind::call_function<void>(
- local_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));
- break;
- case osmium::item_type::way:
- ++number_of_ways;
- luabind::call_function<void>(
- local_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));
- break;
- case osmium::item_type::relation:
- ++number_of_relations;
- resulting_restrictions.push_back(
- restriction_parser.TryParse(static_cast<const osmium::Relation &>(*entity)));
- break;
- default:
- ++number_of_others;
- break;
+ const auto entity = osm_elements[x];
+
+ switch (entity->type())
+ {
+ case osmium::item_type::node:
+ result_node.clear();
+ ++number_of_nodes;
+ luabind::call_function<void>(
+ local_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));
+ break;
+ case osmium::item_type::way:
+ result_way.clear();
+ ++number_of_ways;
+ luabind::call_function<void>(
+ local_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));
+ break;
+ case osmium::item_type::relation:
+ ++number_of_relations;
+ resulting_restrictions.push_back(restriction_parser.TryParse(
+ static_cast<const osmium::Relation &>(*entity)));
+ break;
+ default:
+ ++number_of_others;
+ break;
+ }
}
- }
- });
+ });
// put parsed objects thru extractor callbacks
for (const auto &result : resulting_nodes)
{
extractor_callbacks->ProcessNode(
- static_cast<const osmium::Node &>(*(osm_elements[result.first])), result.second);
+ static_cast<const osmium::Node &>(*(osm_elements[result.first])),
+ result.second);
}
for (const auto &result : resulting_ways)
{
@@ -233,15 +209,10 @@ int Extractor::Run(int argc, char *argv[])
TIMER_STOP(parsing);
SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing) << " seconds";
- unsigned nn = number_of_nodes;
- unsigned nw = number_of_ways;
- unsigned nr = number_of_relations;
- unsigned no = number_of_others;
- SimpleLogger().Write() << "Raw input contains "
- << nn << " nodes, "
- << nw << " ways, and "
- << nr << " relations, and "
- << no << " unknown entities";
+ 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();
diff --git a/extractor/extractor.hpp b/extractor/extractor.hpp
index e9edbea..8ea56c3 100644
--- a/extractor/extractor.hpp
+++ b/extractor/extractor.hpp
@@ -1,13 +1,37 @@
+/*
+
+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 EXTRACTOR_HPP
#define EXTRACTOR_HPP
-#include <string>
-
-#include <boost/filesystem.hpp>
+#include "extractor_options.hpp"
-/** \brief Class of 'extract' utility. */
-struct Extractor
+struct extractor
{
- int Run(int argc, char *argv[]);
+ int run(const ExtractorConfig &extractor_config);
};
#endif /* EXTRACTOR_HPP */
diff --git a/extractor/extractor_callbacks.cpp b/extractor/extractor_callbacks.cpp
index 87e4f4f..224468b 100644
--- a/extractor/extractor_callbacks.cpp
+++ b/extractor/extractor_callbacks.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -32,10 +32,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../data_structures/external_memory_node.hpp"
#include "../data_structures/restriction.hpp"
-#include "../Util/container.hpp"
-#include "../Util/simple_logger.hpp"
+#include "../util/container.hpp"
+#include "../util/simple_logger.hpp"
-#include <osrm/Coordinate.h>
+#include <osrm/coordinate.hpp>
#include <limits>
#include <string>
@@ -51,13 +51,12 @@ ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containe
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),
- static_cast<NodeID>(input_node.id()),
- result_node.barrier,
- result_node.traffic_lights
- });
+ 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),
+ static_cast<NodeID>(input_node.id()),
+ result_node.barrier,
+ result_node.traffic_lights});
}
void ExtractorCallbacks::ProcessRestriction(
@@ -69,7 +68,8 @@ void ExtractorCallbacks::ProcessRestriction(
// 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 ? "y" : "n");
+ // ", only: " << (restriction.get().restriction.flags.is_only ?
+ // "y" : "n");
}
}
/** warning: caller needs to take care of synchronization! */
@@ -99,8 +99,10 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
{
// TODO: iterate all way segments and set duration corresponding to the length of each
// segment
- const_cast<ExtractionWay&>(parsed_way).forward_speed = parsed_way.duration / (input_way.nodes().size() - 1);
- const_cast<ExtractionWay&>(parsed_way).backward_speed = parsed_way.duration / (input_way.nodes().size() - 1);
+ const_cast<ExtractionWay &>(parsed_way).forward_speed =
+ parsed_way.duration / (input_way.nodes().size() - 1);
+ const_cast<ExtractionWay &>(parsed_way).backward_speed =
+ parsed_way.duration / (input_way.nodes().size() - 1);
}
if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.forward_speed))
@@ -129,41 +131,36 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
((parsed_way.forward_speed != parsed_way.backward_speed) ||
(parsed_way.forward_travel_mode != parsed_way.backward_travel_mode));
- auto pair_wise_segment_split = [&](const osmium::NodeRef &first_node,
- const osmium::NodeRef &last_node)
+ auto pair_wise_segment_split =
+ [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
{
// SimpleLogger().Write() << "adding edge (" << first_node.ref() << "," <<
// last_node.ref() << "), fwd speed: " << parsed_way.forward_speed;
external_memory.all_edges_list.push_back(InternalExtractorEdge(
- first_node.ref(),
- last_node.ref(),
+ first_node.ref(), last_node.ref(),
((split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode)
? ExtractionWay::oneway
: ExtractionWay::bidirectional),
- parsed_way.forward_speed,
- name_id,
- parsed_way.roundabout,
- parsed_way.ignore_in_grid,
- (0 < parsed_way.duration),
- parsed_way.is_access_restricted,
- parsed_way.forward_travel_mode,
- split_edge));
+ parsed_way.forward_speed, name_id, parsed_way.roundabout, parsed_way.ignore_in_grid,
+ (0 < parsed_way.duration), parsed_way.is_access_restricted,
+ parsed_way.forward_travel_mode, split_edge));
external_memory.used_node_id_list.push_back(first_node.ref());
};
const bool is_opposite_way = TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode;
if (is_opposite_way)
{
- const_cast<ExtractionWay&>(parsed_way).forward_travel_mode = parsed_way.backward_travel_mode;
- const_cast<ExtractionWay&>(parsed_way).backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
- osrm::for_each_pair(
- input_way.nodes().crbegin(), input_way.nodes().crend(), pair_wise_segment_split);
+ const_cast<ExtractionWay &>(parsed_way).forward_travel_mode =
+ parsed_way.backward_travel_mode;
+ const_cast<ExtractionWay &>(parsed_way).backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
+ osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
+ pair_wise_segment_split);
external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
}
else
{
- osrm::for_each_pair(
- input_way.nodes().cbegin(), input_way.nodes().cend(), pair_wise_segment_split);
+ osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
+ pair_wise_segment_split);
external_memory.used_node_id_list.push_back(input_way.nodes().back().ref());
}
@@ -177,39 +174,30 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
if (split_edge)
{ // Only true if the way should be split
- BOOST_ASSERT(parsed_way.backward_travel_mode>0);
- auto pair_wise_segment_split_2 = [&](const osmium::NodeRef &first_node,
- const osmium::NodeRef &last_node)
+ BOOST_ASSERT(parsed_way.backward_travel_mode > 0);
+ auto pair_wise_segment_split_2 =
+ [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
{
// SimpleLogger().Write() << "adding edge (" << last_node.ref() << "," <<
// first_node.ref() << "), bwd speed: " << parsed_way.backward_speed;
- external_memory.all_edges_list.push_back(
- InternalExtractorEdge(last_node.ref(),
- first_node.ref(),
- ExtractionWay::oneway,
- parsed_way.backward_speed,
- name_id,
- parsed_way.roundabout,
- parsed_way.ignore_in_grid,
- (0 < parsed_way.duration),
- parsed_way.is_access_restricted,
- parsed_way.backward_travel_mode,
- split_edge));
+ external_memory.all_edges_list.push_back(InternalExtractorEdge(
+ last_node.ref(), first_node.ref(), ExtractionWay::oneway, parsed_way.backward_speed,
+ name_id, parsed_way.roundabout, parsed_way.ignore_in_grid,
+ (0 < parsed_way.duration), parsed_way.is_access_restricted,
+ parsed_way.backward_travel_mode, split_edge));
};
if (is_opposite_way)
{
// SimpleLogger().Write() << "opposite2";
- osrm::for_each_pair(input_way.nodes().crbegin(),
- input_way.nodes().crend(),
- pair_wise_segment_split_2);
+ osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
+ pair_wise_segment_split_2);
external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
}
else
{
- osrm::for_each_pair(input_way.nodes().cbegin(),
- input_way.nodes().cend(),
- pair_wise_segment_split_2);
+ osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
+ pair_wise_segment_split_2);
external_memory.used_node_id_list.push_back(input_way.nodes().back().ref());
}
diff --git a/extractor/extractor_callbacks.hpp b/extractor/extractor_callbacks.hpp
index 0bb3010..8eab018 100644
--- a/extractor/extractor_callbacks.hpp
+++ b/extractor/extractor_callbacks.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/extractor/extractor_options.cpp b/extractor/extractor_options.cpp
index d14d8d9..9ae5cd4 100644
--- a/extractor/extractor_options.cpp
+++ b/extractor/extractor_options.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -27,23 +27,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "extractor_options.hpp"
-#include "../Util/git_sha.hpp"
-#include "../Util/IniFileUtil.h"
-#include "../Util/simple_logger.hpp"
+#include "../util/git_sha.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>
-bool ExtractorOptions::ParseArguments(int argc, char *argv[], ExtractorConfig &extractor_config)
+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")(
- "config,c",
- boost::program_options::value<boost::filesystem::path>(&extractor_config.config_file_path)
- ->default_value("extractor.ini"),
+ "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
@@ -60,10 +60,9 @@ bool ExtractorOptions::ParseArguments(int argc, char *argv[], ExtractorConfig &e
// 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");
+ 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;
@@ -81,46 +80,54 @@ bool ExtractorOptions::ParseArguments(int argc, char *argv[], ExtractorConfig &e
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"))
+ try
{
- SimpleLogger().Write() << g_GIT_DESCRIPTION;
- return false;
- }
-
- if (option_variables.count("help"))
- {
- SimpleLogger().Write() << visible_options;
- return false;
- }
+ 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() << g_GIT_DESCRIPTION;
+ return return_code::exit;
+ }
- boost::program_options::notify(option_variables);
+ if (option_variables.count("help"))
+ {
+ SimpleLogger().Write() << visible_options;
+ return return_code::exit;
+ }
- // 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 =
- ReadIniFileAndLowerContents(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"))
+ // 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() << visible_options;
- return false;
+ SimpleLogger().Write(logWARNING) << e.what();
+ return return_code::fail;
}
- return true;
+
+ return return_code::ok;
}
void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_config)
diff --git a/extractor/extractor_options.hpp b/extractor/extractor_options.hpp
index 118da78..5712ea0 100644
--- a/extractor/extractor_options.hpp
+++ b/extractor/extractor_options.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,12 +28,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef EXTRACTOR_OPTIONS_HPP
#define EXTRACTOR_OPTIONS_HPP
-#include "extractor.hpp"
+#include <boost/filesystem/path.hpp>
+
+#include <string>
+
+enum class return_code : unsigned
+{
+ ok,
+ fail,
+ exit
+};
struct ExtractorConfig
{
ExtractorConfig() noexcept : requested_num_threads(0) {}
- unsigned requested_num_threads;
boost::filesystem::path config_file_path;
boost::filesystem::path input_path;
boost::filesystem::path profile_path;
@@ -41,11 +49,13 @@ struct ExtractorConfig
std::string output_file_name;
std::string restriction_file_name;
std::string timestamp_file_name;
+
+ unsigned requested_num_threads;
};
struct ExtractorOptions
{
- static bool ParseArguments(int argc, char *argv[], ExtractorConfig &extractor_config);
+ static return_code ParseArguments(int argc, char *argv[], ExtractorConfig &extractor_config);
static void GenerateOutputFilesNames(ExtractorConfig &extractor_config);
};
diff --git a/extractor/first_and_last_segment_of_way.hpp b/extractor/first_and_last_segment_of_way.hpp
index 8e8ad72..3a26be7 100644
--- a/extractor/first_and_last_segment_of_way.hpp
+++ b/extractor/first_and_last_segment_of_way.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/extractor/internal_extractor_edge.hpp b/extractor/internal_extractor_edge.hpp
index ffd2d4a..27e1af1 100644
--- a/extractor/internal_extractor_edge.hpp
+++ b/extractor/internal_extractor_edge.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,16 +30,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../typedefs.h"
#include "../data_structures/travel_mode.hpp"
-#include <osrm/Coordinate.h>
#include <boost/assert.hpp>
+#include <osrm/coordinate.hpp>
+
struct InternalExtractorEdge
{
InternalExtractorEdge()
- : start(0), target(0), direction(0), speed(0), name_id(0), is_roundabout(false),
+ : start(0), target(0), speed(0), name_id(0), direction(0), is_roundabout(false),
is_in_tiny_cc(false), is_duration_set(false), is_access_restricted(false),
- travel_mode(TRAVEL_MODE_INACCESSIBLE), is_split(false)
+ is_split(false), travel_mode(TRAVEL_MODE_INACCESSIBLE)
{
}
@@ -54,35 +55,36 @@ struct InternalExtractorEdge
bool is_access_restricted,
TravelMode travel_mode,
bool is_split)
- : start(start), target(target), direction(direction), speed(speed),
- name_id(name_id), is_roundabout(is_roundabout), is_in_tiny_cc(is_in_tiny_cc),
+ : start(start), target(target), speed(speed), name_id(name_id), direction(direction),
+ is_roundabout(is_roundabout), is_in_tiny_cc(is_in_tiny_cc),
is_duration_set(is_duration_set), is_access_restricted(is_access_restricted),
- travel_mode(travel_mode), is_split(is_split)
+ is_split(is_split), travel_mode(travel_mode)
{
}
// necessary static util functions for stxxl's sorting
static InternalExtractorEdge min_value()
{
- return InternalExtractorEdge(0, 0, 0, 0, 0, false, false, false, false, TRAVEL_MODE_INACCESSIBLE, false);
+ return InternalExtractorEdge(0, 0, 0, 0, 0, false, false, false, false,
+ TRAVEL_MODE_INACCESSIBLE, false);
}
static InternalExtractorEdge max_value()
{
- return InternalExtractorEdge(
- SPECIAL_NODEID, SPECIAL_NODEID, 0, 0, 0, false, false, false, false, TRAVEL_MODE_INACCESSIBLE, false);
+ return InternalExtractorEdge(SPECIAL_NODEID, SPECIAL_NODEID, 0, 0, 0, false, false, false,
+ false, TRAVEL_MODE_INACCESSIBLE, false);
}
NodeID start;
NodeID target;
- short direction;
double speed;
unsigned name_id;
- bool is_roundabout;
- bool is_in_tiny_cc;
- bool is_duration_set;
- bool is_access_restricted;
+ short direction;
+ bool is_roundabout : 1;
+ bool is_in_tiny_cc : 1;
+ bool is_duration_set : 1;
+ bool is_access_restricted : 1;
+ bool is_split : 1;
TravelMode travel_mode : 4;
- bool is_split;
FixedPointCoordinate source_coordinate;
FixedPointCoordinate target_coordinate;
diff --git a/extractor/restriction_parser.cpp b/extractor/restriction_parser.cpp
index 2f53d33..ea9cad2 100644
--- a/extractor/restriction_parser.cpp
+++ b/extractor/restriction_parser.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,15 +30,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "scripting_environment.hpp"
#include "../data_structures/external_memory_node.hpp"
-#include "../Util/lua_util.hpp"
-#include "../Util/osrm_exception.hpp"
-#include "../Util/simple_logger.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/ref.hpp>
#include <boost/regex.hpp>
+#include <algorithm>
+
namespace
{
int lua_error_callback(lua_State *lua_state)
@@ -85,8 +87,8 @@ void RestrictionParser::ReadRestrictionExceptions(lua_State *lua_state)
{
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));
+ 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:";
@@ -166,9 +168,8 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
continue;
}
BOOST_ASSERT(0 == strcmp("via", role));
- // set the via node id
- // SimpleLogger().Write() << "via: " << member.ref();
+ // set via node id
restriction_container.restriction.via.node = member.ref();
break;
@@ -177,37 +178,26 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
0 == strcmp("via", role));
if (0 == strcmp("from", role))
{
- // SimpleLogger().Write() << "from: " << member.ref();
restriction_container.restriction.from.way = member.ref();
}
else if (0 == strcmp("to", role))
{
- // SimpleLogger().Write() << "to: " << member.ref();
restriction_container.restriction.to.way = member.ref();
}
- else if (0 == strcmp("via", role))
- {
- // not yet suppported
- // restriction_container.restriction.via.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...
- continue;
break;
default:
- BOOST_ASSERT(false);
+ // shouldn't ever happen
break;
}
}
-
- // SimpleLogger().Write() << (restriction_container.restriction.flags.is_only ? "only" : "no")
- // << "-restriction "
- // << "<" << restriction_container.restriction.from.node << "->"
- // << restriction_container.restriction.via.node << "->" <<
- // restriction_container.restriction.to.node
- // << ">";
-
return mapbox::util::optional<InputRestrictionContainer>(restriction_container);
}
@@ -228,14 +218,16 @@ bool RestrictionParser::ShouldIgnoreRestriction(const std::string &except_tag_st
// only a few exceptions are actually defined.
std::vector<std::string> exceptions;
boost::algorithm::split_regex(exceptions, except_tag_string, boost::regex("[;][ ]*"));
- for (std::string ¤t_string : exceptions)
- {
- const auto string_iterator =
- std::find(restriction_exceptions.begin(), restriction_exceptions.end(), current_string);
- if (restriction_exceptions.end() != string_iterator)
- {
- return true;
- }
- }
- return false;
+
+ 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;
+ });
}
diff --git a/extractor/restriction_parser.hpp b/extractor/restriction_parser.hpp
index d5adb43..0a632d8 100644
--- a/extractor/restriction_parser.hpp
+++ b/extractor/restriction_parser.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -46,7 +46,8 @@ class RestrictionParser
public:
// RestrictionParser(ScriptingEnvironment &scripting_environment);
RestrictionParser(lua_State *lua_state);
- mapbox::util::optional<InputRestrictionContainer> TryParse(const osmium::Relation &relation) const;
+ mapbox::util::optional<InputRestrictionContainer>
+ TryParse(const osmium::Relation &relation) const;
private:
void ReadUseRestrictionsSetting(lua_State *lua_state);
diff --git a/extractor/scripting_environment.cpp b/extractor/scripting_environment.cpp
index c51651e..9727722 100644
--- a/extractor/scripting_environment.cpp
+++ b/extractor/scripting_environment.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -31,9 +31,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "extraction_node.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 "../util/lua_util.hpp"
+#include "../util/osrm_exception.hpp"
+#include "../util/simple_logger.hpp"
#include "../typedefs.h"
#include <luabind/tag_function.hpp>
@@ -41,10 +41,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <osmium/osm.hpp>
#include <sstream>
-namespace {
+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))
+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, "");
}
@@ -59,16 +60,14 @@ int lua_error_callback(lua_State *L) // This is so I can use my own function as
}
}
-
-ScriptingEnvironment::ScriptingEnvironment(const std::string &file_name)
-: file_name(file_name)
+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)
+void ScriptingEnvironment::init_lua_state(lua_State *lua_state)
{
- typedef double (osmium::Location::* location_member_ptr_type)() const;
+ typedef double (osmium::Location::*location_member_ptr_type)() const;
luabind::open(lua_state);
// open utility libraries string library;
@@ -83,41 +82,47 @@ void ScriptingEnvironment::init_lua_state(lua_State* lua_state)
luabind::def("parseDuration", parseDuration),
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)),
+ .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),
+ .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("get_value_by_key", &osmium::Node::get_value_by_key)
- .def("get_value_by_key", &get_value_by_key<osmium::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),
+ .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("ignore_in_index", &ExtractionWay::ignore_in_grid)
- .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)
- ],
+ // .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("ignore_in_index", &ExtractionWay::ignore_in_grid)
+ .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("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)
];
if (0 != luaL_dofile(lua_state, file_name.c_str()))
@@ -133,7 +138,7 @@ lua_State *ScriptingEnvironment::get_lua_state()
{
std::lock_guard<std::mutex> lock(init_mutex);
bool initialized = false;
- auto& ref = script_contexts.local(initialized);
+ auto &ref = script_contexts.local(initialized);
if (!initialized)
{
std::shared_ptr<lua_State> state(luaL_newstate(), lua_close);
diff --git a/extractor/scripting_environment.hpp b/extractor/scripting_environment.hpp
index 6e0b079..be05103 100644
--- a/extractor/scripting_environment.hpp
+++ b/extractor/scripting_environment.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -44,8 +44,8 @@ class ScriptingEnvironment
lua_State *get_lua_state();
private:
- void init_lua_state(lua_State* lua_state);
- std::mutex init_mutex;
+ 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;
};
diff --git a/features/bicycle/bridge.feature b/features/bicycle/bridge.feature
new file mode 100644
index 0000000..2325816
--- /dev/null
+++ b/features/bicycle/bridge.feature
@@ -0,0 +1,47 @@
+ at routing @bicycle @bridge
+Feature: Bicycle - Handle movable bridge
+
+ Background:
+ Given the profile "bicycle"
+
+ Scenario: Car - Use a ferry route
+ Given the node map
+ | a | b | c | | |
+ | | | d | | |
+ | | | e | f | g |
+
+ And the ways
+ | nodes | highway | bridge | bicycle |
+ | abc | primary | | |
+ | cde | | movable | yes |
+ | 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 |
+
+ Scenario: Car - Properly handle durations
+ Given the node map
+ | a | b | c | | |
+ | | | d | | |
+ | | | e | f | g |
+
+ And the ways
+ | nodes | highway | bridge | duration |
+ | abc | primary | | |
+ | cde | | movable | 00:05:00 |
+ | 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 | 3 km/h |
+ | c | e | cde | 5 | 2 km/h |
+ | e | c | cde | 5 | 2 km/h |
diff --git a/features/car/access.feature b/features/car/access.feature
index 37dfed4..5fd56f3 100644
--- a/features/car/access.feature
+++ b/features/car/access.feature
@@ -93,6 +93,7 @@ Feature: Car - Restricted access
| private | |
| agricultural | |
| forestry | |
+ | psv | |
| some_tag | x |
@@ -106,6 +107,7 @@ Feature: Car - Restricted access
| private | |
| agricultural | |
| forestry | |
+ | psv | |
| some_tag | x |
Scenario: Car - Access tags on both node and way
diff --git a/features/car/barrier.feature b/features/car/barrier.feature
index e637049..7c89688 100644
--- a/features/car/barrier.feature
+++ b/features/car/barrier.feature
@@ -10,6 +10,7 @@ Feature: Car - Barriers
| | x |
| bollard | |
| gate | x |
+ | lift_gate | x |
| cattle_grid | x |
| border_control | x |
| toll_booth | x |
diff --git a/features/car/bridge.feature b/features/car/bridge.feature
new file mode 100644
index 0000000..41dc10b
--- /dev/null
+++ b/features/car/bridge.feature
@@ -0,0 +1,47 @@
+ at routing @car @bridge
+Feature: Car - Handle movable bridge
+
+ Background:
+ Given the profile "car"
+
+ Scenario: Car - Use a ferry route
+ Given the node map
+ | a | b | c | | |
+ | | | d | | |
+ | | | e | f | g |
+
+ And the ways
+ | nodes | highway | bridge | bicycle |
+ | abc | primary | | |
+ | cde | | movable | yes |
+ | 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 |
+
+ Scenario: Car - Properly handle durations
+ Given the node map
+ | a | b | c | | |
+ | | | d | | |
+ | | | e | f | g |
+
+ And the ways
+ | nodes | highway | bridge | duration |
+ | abc | primary | | |
+ | cde | | movable | 00:05:00 |
+ | efg | primary | | |
+
+ When I route I should get
+ | from | to | route | modes | speed |
+ | a | g | abc,cde,efg | 1,3,1 | 6 km/h |
+ | b | f | abc,cde,efg | 1,3,1 | 4 km/h |
+ | c | e | cde | 3 | 2 km/h |
+ | e | c | cde | 3 | 2 km/h |
diff --git a/features/car/ferry.feature b/features/car/ferry.feature
index abbe5ed..eb24559 100644
--- a/features/car/ferry.feature
+++ b/features/car/ferry.feature
@@ -27,7 +27,7 @@ Feature: Car - Handle ferry routes
| c | f | cde,efg | 2,1 |
| c | g | cde,efg | 2,1 |
- Scenario: Car - Properly handle durations
+ Scenario: Car - Properly handle simple durations
Given the node map
| a | b | c | | |
| | | d | | |
@@ -45,3 +45,22 @@ Feature: Car - Handle ferry routes
| 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 |
+
+ Scenario: Car - Properly handle ISO 8601 durations
+ Given the node map
+ | a | b | c | | |
+ | | | d | | |
+ | | | e | f | g |
+
+ And the ways
+ | nodes | highway | route | duration |
+ | abc | primary | | |
+ | cde | | ferry | PT1M |
+ | efg | primary | | |
+
+ When I route I should get
+ | from | to | route | modes | speed |
+ | a | g | abc,cde,efg | 1,2,1 | 26 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 |
diff --git a/features/car/maxspeed.feature b/features/car/maxspeed.feature
index 8f85d3a..781f4c6 100644
--- a/features/car/maxspeed.feature
+++ b/features/car/maxspeed.feature
@@ -73,3 +73,23 @@ OSRM will use 4/5 of the projected free-flow speed.
| runway | | | 100 | | | |
| runway | | | | 100 | | |
| runway | | | | | 100 | |
+
+ Scenario: Car - Too narrow streets should be ignored or incur a penalty
+ Then routability should be
+
+ | highway | maxspeed | width | maxspeed:forward | maxspeed:backward | forw | backw |
+ | primary | | | | | 63 km/h | 63 km/h |
+ | primary | | 3 | | | 32 km/h | 32 km/h |
+ | primary | 60 | | | | 59 km/h | 59 km/h |
+ | primary | 60 | 3 | | | 30 km/h | 30 km/h |
+ | primary | | | 60 | | 59 km/h | 63 km/h |
+ | primary | | 3 | 60 | | 30 km/h | 32 km/h |
+ | primary | | | | 60 | 63 km/h | 59 km/h |
+ | primary | | 3 | | 60 | 32 km/h | 30 km/h |
+ | primary | 15 | | 60 | | 59 km/h | 23 km/h |
+ | primary | 15 | 3 | 60 | | 30 km/h | 7 km/h |
+ | primary | 15 | | | 60 | 23 km/h | 59 km/h |
+ | primary | 15 | 3 | | 60 | 7 km/h | 30 km/h |
+ | primary | 15 | | 30 | 60 | 34 km/h | 59 km/h |
+ | primary | 15 | 3 | 30 | 60 | 15 km/h | 30 km/h |
+
diff --git a/features/options/routed/help.feature b/features/options/routed/help.feature
index 9603c40..c0fca47 100644
--- a/features/options/routed/help.feature
+++ b/features/options/routed/help.feature
@@ -24,8 +24,10 @@ Feature: osrm-routed command line options: help
And stdout should contain "--ip"
And stdout should contain "--port"
And stdout should contain "--threads"
- And stdout should contain "--sharedmemory"
- And stdout should contain 22 lines
+ And stdout should contain "--shared-memory"
+ And stdout should contain "--max-table-size"
+ And stdout should contain "--max-matching-size"
+ And stdout should contain 26 lines
And it should exit with code 0
Scenario: osrm-routed - Help, short
@@ -48,8 +50,10 @@ Feature: osrm-routed command line options: help
And stdout should contain "--ip"
And stdout should contain "--port"
And stdout should contain "--threads"
- And stdout should contain "--sharedmemory"
- And stdout should contain 22 lines
+ And stdout should contain "--shared-memory"
+ And stdout should contain "--max-table-size"
+ And stdout should contain "--max-matching-size"
+ And stdout should contain 26 lines
And it should exit with code 0
Scenario: osrm-routed - Help, long
@@ -72,6 +76,8 @@ Feature: osrm-routed command line options: help
And stdout should contain "--ip"
And stdout should contain "--port"
And stdout should contain "--threads"
- And stdout should contain "--sharedmemory"
- And stdout should contain 22 lines
+ And stdout should contain "--shared-memory"
+ And stdout should contain "--max-table-size"
+ And stdout should contain "--max-matching-size"
+ And stdout should contain 26 lines
And it should exit with code 0
diff --git a/features/step_definitions/matching.rb b/features/step_definitions/matching.rb
new file mode 100644
index 0000000..3f3181f
--- /dev/null
+++ b/features/step_definitions/matching.rb
@@ -0,0 +1,96 @@
+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
+ 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 = {'trace' => row['trace'] }
+ response = request_matching trace, timestamps, params
+ else
+ raise "*** no trace"
+ 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
+
+ sub_matchings = []
+ if response.code == "200"
+ if table.headers.include? 'matchings'
+ sub_matchings = json['matchings'].compact.map { |sub| sub['matched_points']}
+ end
+ 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
+ got['matchings'] = row['matchings']
+ got['timestamps'] = row['timestamps']
+ else
+ got['matchings'] = encoded_result
+ row['matchings'] = extended_target
+ log_fail row,got, { 'matching' => {:query => @query, :response => response} }
+ end
+
+ actual << got
+ end
+ end
+ table.routing_diff! actual
+end
+
diff --git a/features/support/env.rb b/features/support/env.rb
index a01341d..f9a4fe4 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -64,6 +64,19 @@ 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}"
+ raise "*** #{BIN_PATH}/#{bin} is missing. Build failed?"
+ end
+ end
+end
if ENV['OS']=~/Windows.*/ then
EXE='.exe'
@@ -74,10 +87,9 @@ else
end
AfterConfiguration do |config|
- if OSRMLoader::OSRMBaseLoader.new.osrm_up?
- raise "*** osrm-routed is already running."
- end
clear_log_files
+ verify_osrm_is_not_running
+ verify_existance_of_binaries
end
at_exit do
diff --git a/features/support/launch.rb b/features/support/launch.rb
index 0f983c1..d8d23ae 100644
--- a/features/support/launch.rb
+++ b/features/support/launch.rb
@@ -4,7 +4,7 @@ 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
+# however, osrm-routed it shut down and relaunched for each scenario thats
# loads data directly.
class OSRMLoader
@@ -118,7 +118,7 @@ class OSRMLoader
def osrm_up
return if osrm_up?
- @@pid = Process.spawn("#{BIN_PATH}/osrm-routed --sharedmemory=1 --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
+ @@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
diff --git a/features/support/match.rb b/features/support/match.rb
new file mode 100644
index 0000000..bf51189
--- /dev/null
+++ b/features/support/match.rb
@@ -0,0 +1,26 @@
+require 'net/http'
+
+HOST = "http://127.0.0.1:#{OSRM_PORT}"
+
+def request_matching trace=[], timestamps=[], options={}
+ defaults = { 'output' => 'json' }
+ locs = trace.compact.map { |w| "loc=#{w.lat},#{w.lon}" }
+ ts = timestamps.compact.map { |t| "t=#{t}" }
+ if ts.length > 0
+ trace_params = locs.zip(ts).map { |a| a.join('&')}
+ else
+ trace_params = locs
+ end
+ params = (trace_params + defaults.merge(options).to_param).join('&')
+ params = nil if params==""
+ uri = URI.parse ["#{HOST}/match", params].compact.join('?')
+ @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
+
diff --git a/features/testbot/loop.feature b/features/testbot/loop.feature
index fe898ec..72cad33 100644
--- a/features/testbot/loop.feature
+++ b/features/testbot/loop.feature
@@ -64,13 +64,13 @@ Feature: Avoid weird loops caused by rounding errors
| | d | |
And the ways
- | nodes | highway |
- | ab | primary |
- | bc | primary |
- | cd | primary |
- | be | secondary |
- | ef | secondary |
- | cf | secondary |
+ | nodes | highway |
+ | ab | residential |
+ | bc | residential |
+ | cd | residential |
+ | be | primary |
+ | ef | primary |
+ | cf | primary |
When I route I should get
| waypoints | route | turns |
diff --git a/features/testbot/matching.feature b/features/testbot/matching.feature
new file mode 100644
index 0000000..774e8a9
--- /dev/null
+++ b/features/testbot/matching.feature
@@ -0,0 +1,55 @@
+ at match @testbot
+Feature: Basic Map Matching
+
+ Background:
+ Given the profile "testbot"
+ Given a grid size of 10 meters
+
+ Scenario: Testbot - Map matching with trace splitting
+ 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 62 63 | ab,cd |
+
+ Scenario: Testbot - Map matching with small distortion
+ Given the node map
+ | a | b | c | d | e |
+ | | f | | | |
+ | | | | | |
+ | | | | | |
+ | | | | | |
+ | | h | | | k |
+
+ # The second way does not need to be a oneway
+ # but the grid spacing triggers the uturn
+ # detection on f
+ And the ways
+ | nodes | oneway |
+ | abcde | no |
+ | bfhke | yes |
+
+ When I match I should get
+ | trace | matchings |
+ | afcde | abcde |
+
+ Scenario: Testbot - Map matching with oneways
+ 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 |
+
diff --git a/Util/integer_range.hpp b/include/osrm/coordinate.hpp
similarity index 53%
copy from Util/integer_range.hpp
copy to include/osrm/coordinate.hpp
index 030b2fa..6318465 100644
--- a/Util/integer_range.hpp
+++ b/include/osrm/coordinate.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013,2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,46 +25,47 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef INTEGER_RANGE_HPP
-#define INTEGER_RANGE_HPP
+#ifndef COORDINATE_HPP_
+#define COORDINATE_HPP_
+#include <iosfwd> //for std::ostream
+#include <string>
#include <type_traits>
-namespace osrm
+namespace
{
+constexpr static const float COORDINATE_PRECISION = 1000000.f;
+}
-template <typename Integer> class range
+struct FixedPointCoordinate
{
- private:
- Integer last;
- Integer iter;
+ int lat;
+ int lon;
+
+ FixedPointCoordinate();
+ FixedPointCoordinate(int lat, int lon);
- public:
- range(Integer start, Integer end) : last(end), iter(start)
+ template <class T>
+ FixedPointCoordinate(const T &coordinate)
+ : lat(coordinate.lat), lon(coordinate.lon)
{
- static_assert(std::is_integral<Integer>::value, "range type must be integral");
+ 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");
}
- // Iterable functions
- const range &begin() const { return *this; }
- const range &end() const { return *this; }
- Integer front() const { return iter; }
- Integer back() const { return last - 1; }
+ bool is_valid() const;
+ bool operator==(const FixedPointCoordinate &other) const;
- // Iterator functions
- bool operator!=(const range &) const { return iter < last; }
- void operator++() { ++iter; }
- Integer operator*() const { return iter; }
+ float bearing(const FixedPointCoordinate &other) const;
+ void output(std::ostream &out) const;
};
-// 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)
+inline std::ostream &operator<<(std::ostream &out_stream, FixedPointCoordinate const &coordinate)
{
- return range<Integer>(first, last);
-}
+ coordinate.output(out_stream);
+ return out_stream;
}
-#endif // INTEGER_RANGE_HPP
+#endif /* COORDINATE_HPP_ */
diff --git a/data_structures/json_container.hpp b/include/osrm/json_container.hpp
similarity index 92%
rename from data_structures/json_container.hpp
rename to include/osrm/json_container.hpp
index 9bbbec4..40f39b8 100644
--- a/data_structures/json_container.hpp
+++ b/include/osrm/json_container.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,8 +28,8 @@ 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_H
-#define JSON_CONTAINER_H
+#ifndef JSON_CONTAINER_HPP
+#define JSON_CONTAINER_HPP
#include <variant/variant.hpp>
@@ -38,7 +38,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
#include <unordered_map>
-namespace JSON
+namespace osrm
+{
+namespace json
{
struct Object;
@@ -90,5 +92,5 @@ struct Array
};
} // namespace JSON
-
-#endif // JSON_CONTAINER_H
+} // namespace osrm
+#endif // JSON_CONTAINER_HPP
diff --git a/prepare.cpp b/include/osrm/libosrm_config.hpp
similarity index 62%
copy from prepare.cpp
copy to include/osrm/libosrm_config.hpp
index e50f134..500abf5 100644
--- a/prepare.cpp
+++ b/include/osrm/libosrm_config.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,29 +25,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "contractor/processing_chain.hpp"
+#ifndef SERVER_CONFIG_HPP
+#define SERVER_CONFIG_HPP
-#include <boost/program_options.hpp>
+#include <osrm/server_paths.hpp>
-int main(int argc, char *argv[])
+struct libosrm_config
{
- try
+ libosrm_config(const libosrm_config &) = delete;
+ libosrm_config()
+ : max_locations_distance_table(100), max_locations_map_matching(-1),
+ use_shared_memory(false)
{
- return Prepare().Process(argc, argv);
}
- catch (boost::program_options::too_many_positional_options_error &)
- {
- SimpleLogger().Write(logWARNING) << "Only one file can be specified";
- return 1;
- }
- catch (boost::program_options::error &e)
- {
- SimpleLogger().Write(logWARNING) << e.what();
- return 1;
- }
- catch (const std::exception &e)
+
+ libosrm_config(const ServerPaths &paths, const bool flag, const int max_table, const int max_matching)
+ : server_paths(paths), max_locations_distance_table(max_table),
+ max_locations_map_matching(max_matching), use_shared_memory(flag)
{
- SimpleLogger().Write(logWARNING) << "Exception occured: " << e.what() << std::endl;
- return 1;
}
-}
+
+ ServerPaths server_paths;
+ int max_locations_distance_table;
+ int max_locations_map_matching;
+ bool use_shared_memory;
+};
+
+#endif // SERVER_CONFIG_HPP
diff --git a/Include/osrm/RouteParameters.h b/include/osrm/route_parameters.hpp
similarity index 84%
rename from Include/osrm/RouteParameters.h
rename to include/osrm/route_parameters.hpp
index fd570a1..9babbd7 100644
--- a/Include/osrm/RouteParameters.h
+++ b/include/osrm/route_parameters.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,10 +25,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ROUTE_PARAMETERS_H
-#define ROUTE_PARAMETERS_H
+#ifndef ROUTE_PARAMETERS_HPP
+#define ROUTE_PARAMETERS_HPP
-#include <osrm/Coordinate.h>
+#include <osrm/coordinate.hpp>
#include <boost/fusion/container/vector/vector_fwd.hpp>
@@ -40,7 +40,7 @@ struct RouteParameters
RouteParameters();
void setZoomLevel(const short level);
-
+
void setNumberOfResults(const short number);
void setAlternateRouteFlag(const bool flag);
@@ -49,6 +49,12 @@ struct RouteParameters
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);
@@ -63,13 +69,15 @@ struct RouteParameters
void addHint(const std::string &hint);
+ void addTimestamp(const unsigned timestamp);
+
void setLanguage(const std::string &language);
void setGeometryFlag(const bool flag);
void setCompressionFlag(const bool flag);
- void addCoordinate(const boost::fusion::vector<double, double> &coordinates);
+ void addCoordinate(const boost::fusion::vector<double, double> &received_coordinates);
short zoom_level;
bool print_instructions;
@@ -78,6 +86,9 @@ struct RouteParameters
bool compression;
bool deprecatedAPI;
bool uturn_default;
+ bool classify;
+ double matching_beta;
+ double gps_precision;
unsigned check_sum;
short num_results;
std::string service;
@@ -85,8 +96,9 @@ struct RouteParameters
std::string jsonp_parameter;
std::string language;
std::vector<std::string> hints;
+ std::vector<unsigned> timestamps;
std::vector<bool> uturns;
std::vector<FixedPointCoordinate> coordinates;
};
-#endif // ROUTE_PARAMETERS_H
+#endif // ROUTE_PARAMETERS_HPP
diff --git a/Include/osrm/ServerPaths.h b/include/osrm/server_paths.hpp
similarity index 91%
rename from Include/osrm/ServerPaths.h
rename to include/osrm/server_paths.hpp
index 52b60c7..669ee7d 100644
--- a/Include/osrm/ServerPaths.h
+++ b/include/osrm/server_paths.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -33,6 +33,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unordered_map>
#include <string>
-typedef std::unordered_map<std::string, boost::filesystem::path> ServerPaths;
+using ServerPaths = std::unordered_map<std::string, boost::filesystem::path>;
#endif // SERVER_PATH_H
diff --git a/Library/OSRM.h b/library/osrm.hpp
similarity index 81%
rename from Library/OSRM.h
rename to library/osrm.hpp
index 372e82c..27acb40 100644
--- a/Library/OSRM.h
+++ b/library/osrm.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,19 +25,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef OSRM_H
-#define OSRM_H
+#ifndef OSRM_HPP
+#define OSRM_HPP
-#include <osrm/ServerPaths.h>
+#include <osrm/libosrm_config.hpp>
#include <memory>
class OSRM_impl;
struct RouteParameters;
-namespace http
+namespace osrm
{
-class Reply;
+namespace json
+{
+struct Object;
+}
}
class OSRM
@@ -46,9 +49,9 @@ class OSRM
std::unique_ptr<OSRM_impl> OSRM_pimpl_;
public:
- explicit OSRM(ServerPaths paths, const bool use_shared_memory = false);
+ explicit OSRM(libosrm_config &lib_config);
~OSRM();
- void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
+ int RunQuery(RouteParameters &route_parameters, osrm::json::Object &json_result);
};
-#endif // OSRM_H
+#endif // OSRM_HPP
diff --git a/Library/OSRM_impl.cpp b/library/osrm_impl.cpp
similarity index 52%
rename from Library/OSRM_impl.cpp
rename to library/osrm_impl.cpp
index 40fef68..5bb58d1 100644
--- a/Library/OSRM_impl.cpp
+++ b/library/osrm_impl.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,14 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-namespace boost { namespace interprocess { class named_mutex; } }
-
-#include "OSRM_impl.h"
-#include "OSRM.h"
+namespace boost
+{
+namespace interprocess
+{
+class named_mutex;
+}
+}
-#include <osrm/Reply.h>
-#include <osrm/RouteParameters.h>
-#include <osrm/ServerPaths.h>
+#include "osrm_impl.hpp"
+#include "osrm.hpp"
#include "../plugins/distance_table.hpp"
#include "../plugins/hello_world.hpp"
@@ -40,26 +42,29 @@ namespace boost { namespace interprocess { class named_mutex; } }
#include "../plugins/nearest.hpp"
#include "../plugins/timestamp.hpp"
#include "../plugins/viaroute.hpp"
-#include "../Server/DataStructures/BaseDataFacade.h"
-#include "../Server/DataStructures/InternalDataFacade.h"
-#include "../Server/DataStructures/SharedBarriers.h"
-#include "../Server/DataStructures/SharedDataFacade.h"
-#include "../Util/make_unique.hpp"
-#include "../Util/ProgramOptions.h"
-#include "../Util/simple_logger.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 <algorithm>
#include <fstream>
#include <utility>
#include <vector>
-OSRM_impl::OSRM_impl(ServerPaths server_paths, const bool use_shared_memory)
+OSRM_impl::OSRM_impl(libosrm_config &lib_config)
{
- if (use_shared_memory)
+ if (lib_config.use_shared_memory)
{
barrier = osrm::make_unique<SharedBarriers>();
query_data_facade = new SharedDataFacade<QueryEdge::EdgeData>();
@@ -67,15 +72,18 @@ OSRM_impl::OSRM_impl(ServerPaths server_paths, const bool use_shared_memory)
else
{
// populate base path
- populate_base_path(server_paths);
- query_data_facade = new InternalDataFacade<QueryEdge::EdgeData>(server_paths);
+ 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));
+ RegisterPlugin(new DistanceTablePlugin<BaseDataFacade<QueryEdge::EdgeData>>(
+ query_data_facade, lib_config.max_locations_distance_table));
RegisterPlugin(new HelloWorldPlugin());
RegisterPlugin(new LocatePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
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));
}
@@ -99,67 +107,75 @@ void OSRM_impl::RegisterPlugin(BasePlugin *plugin)
plugin_map.emplace(plugin->GetDescriptor(), plugin);
}
-void OSRM_impl::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
+int OSRM_impl::RunQuery(RouteParameters &route_parameters, osrm::json::Object &json_result)
{
- const PluginMap::const_iterator &iter = plugin_map.find(route_parameters.service);
+ const auto &plugin_iterator = plugin_map.find(route_parameters.service);
- if (plugin_map.end() != iter)
+ if (plugin_map.end() == plugin_iterator)
{
- reply.status = http::Reply::ok;
- if (barrier)
- {
- // 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();
- }
-
- iter->second->HandleRequest(route_parameters, reply);
- if (barrier)
- {
- // 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();
- }
- }
+ return 400;
}
- else
+
+ increase_concurrent_query_count();
+ plugin_iterator->second->HandleRequest(route_parameters, json_result);
+ decrease_concurrent_query_count();
+ return 200;
+}
+
+// decrease number of concurrent queries
+void OSRM_impl::decrease_concurrent_query_count()
+{
+ if (!barrier)
{
- reply = http::Reply::StockReply(http::Reply::badRequest);
+ return;
}
-}
+ // lock query
+ boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
+ barrier->query_mutex);
-// proxy code for compilation firewall
+ // decrement query count
+ --(barrier->number_of_queries);
+ BOOST_ASSERT_MSG(0 <= barrier->number_of_queries, "invalid number of queries");
-OSRM::OSRM(ServerPaths paths, const bool use_shared_memory)
- : OSRM_pimpl_(osrm::make_unique<OSRM_impl>(paths, use_shared_memory))
+ // 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_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(libosrm_config &lib_config) : OSRM_pimpl_(osrm::make_unique<OSRM_impl>(lib_config)) {}
+
OSRM::~OSRM() { OSRM_pimpl_.reset(); }
-void OSRM::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
+int OSRM::RunQuery(RouteParameters &route_parameters, osrm::json::Object &json_result)
{
- OSRM_pimpl_->RunQuery(route_parameters, reply);
+ return OSRM_pimpl_->RunQuery(route_parameters, json_result);
}
diff --git a/Library/OSRM_impl.h b/library/osrm_impl.hpp
similarity index 79%
rename from Library/OSRM_impl.h
rename to library/osrm_impl.hpp
index e8b47df..a736c04 100644
--- a/Library/OSRM_impl.h
+++ b/library/osrm_impl.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,17 +25,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef OSRM_IMPL_H
-#define OSRM_IMPL_H
+#ifndef OSRM_IMPL_HPP
+#define OSRM_IMPL_HPP
class BasePlugin;
-namespace http { class Reply; }
struct RouteParameters;
-#include <osrm/ServerPaths.h>
-
#include "../data_structures/query_edge.hpp"
+#include <osrm/json_container.hpp>
+#include <osrm/libosrm_config.hpp>
+
#include <memory>
#include <unordered_map>
#include <string>
@@ -49,10 +49,10 @@ class OSRM_impl
using PluginMap = std::unordered_map<std::string, BasePlugin *>;
public:
- OSRM_impl(ServerPaths paths, const bool use_shared_memory);
+ OSRM_impl(libosrm_config &lib_config);
OSRM_impl(const OSRM_impl &) = delete;
virtual ~OSRM_impl();
- void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
+ int RunQuery(RouteParameters &route_parameters, osrm::json::Object &json_result);
private:
void RegisterPlugin(BasePlugin *plugin);
@@ -61,6 +61,11 @@ class OSRM_impl
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_H
+#endif // OSRM_IMPL_HPP
diff --git a/plugins/distance_table.hpp b/plugins/distance_table.hpp
index 6ef90a5..d7a9804 100644
--- a/plugins/distance_table.hpp
+++ b/plugins/distance_table.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,20 +25,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DISTANCE_TABLE_PLUGIN_H
-#define DISTANCE_TABLE_PLUGIN_H
+#ifndef DISTANCE_TABLE_HPP
+#define DISTANCE_TABLE_HPP
#include "plugin_base.hpp"
#include "../algorithms/object_encoder.hpp"
-#include "../data_structures/json_container.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 "../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>
@@ -52,28 +53,33 @@ 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) : descriptor_string("table"), facade(facade)
+ 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 final { return descriptor_string; }
+ const std::string GetDescriptor() const override final { return descriptor_string; }
- void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
+ int HandleRequest(const RouteParameters &route_parameters,
+ osrm::json::Object &json_result) override final
{
if (!check_all_coordinates(route_parameters.coordinates))
{
- reply = http::Reply::StockReply(http::Reply::badRequest);
- return;
+ return 400;
}
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
unsigned max_locations =
- std::min(100u, static_cast<unsigned>(route_parameters.coordinates.size()));
+ std::min(static_cast<unsigned>(max_locations_distance_table),
+ static_cast<unsigned>(route_parameters.coordinates.size()));
+
PhantomNodeArray phantom_node_vector(max_locations);
for (const auto i : osrm::irange(0u, max_locations))
{
@@ -89,8 +95,7 @@ template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
}
}
facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i],
- phantom_node_vector[i],
- 1);
+ phantom_node_vector[i], 1);
BOOST_ASSERT(phantom_node_vector[i].front().is_valid(facade->GetNumberOfNodes()));
}
@@ -102,23 +107,22 @@ template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
if (!result_table)
{
- reply = http::Reply::StockReply(http::Reply::badRequest);
- return;
+ return 400;
}
- JSON::Object json_object;
- JSON::Array json_array;
+ osrm::json::Array json_array;
const auto number_of_locations = phantom_node_vector.size();
for (const auto row : osrm::irange<std::size_t>(0, number_of_locations))
{
- JSON::Array json_row;
+ osrm::json::Array json_row;
auto row_begin_iterator = result_table->begin() + (row * number_of_locations);
auto row_end_iterator = result_table->begin() + ((row + 1) * number_of_locations);
json_row.values.insert(json_row.values.end(), row_begin_iterator, row_end_iterator);
json_array.values.push_back(json_row);
}
- json_object.values["distance_table"] = json_array;
- JSON::render(reply.content, json_object);
+ json_result.values["distance_table"] = json_array;
+ // osrm::json::render(reply.content, json_object);
+ return 200;
}
private:
@@ -126,4 +130,4 @@ template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
DataFacadeT *facade;
};
-#endif // DISTANCE_TABLE_PLUGIN_H
+#endif // DISTANCE_TABLE_HPP
diff --git a/plugins/hello_world.hpp b/plugins/hello_world.hpp
index c8b07b0..faf5b10 100644
--- a/plugins/hello_world.hpp
+++ b/plugins/hello_world.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,14 +25,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HELLO_WORLD_PLUGIN_H
-#define HELLO_WORLD_PLUGIN_H
+#ifndef HELLO_WORLD_HPP
+#define HELLO_WORLD_HPP
#include "plugin_base.hpp"
-#include "../data_structures/json_container.hpp"
-#include "../Util/cast.hpp"
-#include "../Util/json_renderer.hpp"
+#include "../util/cast.hpp"
+#include "../util/json_renderer.hpp"
+
+#include <osrm/json_container.hpp>
#include <string>
@@ -44,13 +45,11 @@ class HelloWorldPlugin final : public BasePlugin
public:
HelloWorldPlugin() : descriptor_string("hello") {}
virtual ~HelloWorldPlugin() {}
- const std::string GetDescriptor() const final { return descriptor_string; }
+ const std::string GetDescriptor() const override final { return descriptor_string; }
- void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply) final
+ int HandleRequest(const RouteParameters &routeParameters,
+ osrm::json::Object &json_result) override final
{
- reply.status = http::Reply::ok;
-
- JSON::Object json_result;
std::string temp_string;
json_result.values["title"] = "Hello World";
@@ -72,15 +71,17 @@ class HelloWorldPlugin final : public BasePlugin
temp_string = cast::integral_to_string(routeParameters.coordinates.size());
json_result.values["location_count"] = temp_string;
- JSON::Array json_locations;
+ osrm::json::Array json_locations;
unsigned counter = 0;
for (const FixedPointCoordinate &coordinate : routeParameters.coordinates)
{
- JSON::Object json_location;
- JSON::Array json_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_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[cast::integral_to_string(counter)] = json_coordinates;
json_locations.values.push_back(json_location);
++counter;
@@ -88,7 +89,7 @@ class HelloWorldPlugin final : public BasePlugin
json_result.values["locations"] = json_locations;
json_result.values["hint_count"] = routeParameters.hints.size();
- JSON::Array json_hints;
+ osrm::json::Array json_hints;
counter = 0;
for (const std::string ¤t_hint : routeParameters.hints)
{
@@ -96,12 +97,11 @@ class HelloWorldPlugin final : public BasePlugin
++counter;
}
json_result.values["hints"] = json_hints;
-
- JSON::render(reply.content, json_result);
+ return 200;
}
private:
std::string descriptor_string;
};
-#endif // HELLO_WORLD_PLUGIN_H
+#endif // HELLO_WORLD_HPP
diff --git a/plugins/locate.hpp b/plugins/locate.hpp
index 6171395..144765a 100644
--- a/plugins/locate.hpp
+++ b/plugins/locate.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,14 +25,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef LOCATE_PLUGIN_H
-#define LOCATE_PLUGIN_H
+#ifndef LOCATE_HPP
+#define LOCATE_HPP
#include "plugin_base.hpp"
-#include "../data_structures/json_container.hpp"
-#include "../Util/json_renderer.hpp"
-#include "../Util/string_util.hpp"
+#include "../util/json_renderer.hpp"
+#include "../util/string_util.hpp"
+
+#include <osrm/json_container.hpp>
#include <string>
@@ -41,18 +42,18 @@ template <class DataFacadeT> class LocatePlugin final : public BasePlugin
{
public:
explicit LocatePlugin(DataFacadeT *facade) : descriptor_string("locate"), facade(facade) {}
- const std::string GetDescriptor() const final { return descriptor_string; }
+ const std::string GetDescriptor() const override final { return descriptor_string; }
- void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
+ int 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())
+ if (route_parameters.coordinates.empty() ||
+ !route_parameters.coordinates.front().is_valid())
{
- reply = http::Reply::StockReply(http::Reply::badRequest);
- return;
+ return 400;
}
- JSON::Object json_result;
FixedPointCoordinate result;
if (!facade->LocateClosestEndPointForCoordinate(route_parameters.coordinates.front(),
result))
@@ -61,15 +62,13 @@ template <class DataFacadeT> class LocatePlugin final : public BasePlugin
}
else
{
- reply.status = http::Reply::ok;
json_result.values["status"] = 0;
- JSON::Array json_coordinate;
+ osrm::json::Array json_coordinate;
json_coordinate.values.push_back(result.lat / COORDINATE_PRECISION);
json_coordinate.values.push_back(result.lon / COORDINATE_PRECISION);
json_result.values["mapped_coordinate"] = json_coordinate;
}
-
- JSON::render(reply.content, json_result);
+ return 200;
}
private:
@@ -77,4 +76,4 @@ template <class DataFacadeT> class LocatePlugin final : public BasePlugin
DataFacadeT *facade;
};
-#endif /* LOCATE_PLUGIN_H */
+#endif /* LOCATE_HPP */
diff --git a/plugins/match.hpp b/plugins/match.hpp
new file mode 100644
index 0000000..a866947
--- /dev/null
+++ b/plugins/match.hpp
@@ -0,0 +1,314 @@
+/*
+
+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
+{
+ constexpr static const unsigned max_number_of_candidates = 10;
+
+ 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 { return descriptor_string; }
+
+ TraceClassification
+ classify(const float trace_length, const float matched_length, const int removed_points) const
+ {
+ 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;
+ }
+
+ bool getCandiates(const std::vector<FixedPointCoordinate> &input_coords,
+ std::vector<double> &sub_trace_lengths,
+ osrm::matching::CandidateLists &candidates_lists)
+ {
+ double last_distance =
+ coordinate_calculation::great_circle_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::great_circle_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;
+ }
+ }
+
+ std::vector<std::pair<PhantomNode, double>> candidates;
+ if (!facade->IncrementalFindPhantomNodeForCoordinateWithMaxDistance(
+ input_coords[current_coordinate], candidates, last_distance / 2.0, 5,
+ max_number_of_candidates))
+ {
+ return false;
+ }
+
+ if (allow_uturn)
+ {
+ candidates_lists.push_back(candidates);
+ }
+ else
+ {
+ 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].first.forward_node_id != SPECIAL_NODEID &&
+ candidates[i].first.reverse_node_id != SPECIAL_NODEID)
+ {
+ PhantomNode reverse_node(candidates[i].first);
+ reverse_node.forward_node_id = SPECIAL_NODEID;
+ candidates.push_back(std::make_pair(reverse_node, candidates[i].second));
+
+ candidates[i].first.reverse_node_id = SPECIAL_NODEID;
+ }
+ }
+ candidates_lists.push_back(candidates);
+ }
+ }
+
+ return true;
+ }
+
+ 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;
+ }
+
+ if (route_parameters.geometry)
+ {
+ 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));
+ }
+ // we need this because we don't run DP
+ for (auto &segment : factory.path_description)
+ {
+ segment.necessary = true;
+ }
+ subtrace.values["geometry"] =
+ factory.AppendGeometryString(route_parameters.compression);
+ }
+
+ 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;
+
+ return subtrace;
+ }
+
+ int HandleRequest(const RouteParameters &route_parameters,
+ osrm::json::Object &json_result) final
+ {
+ // check number of parameters
+ if (!check_all_coordinates(route_parameters.coordinates))
+ {
+ return 400;
+ }
+
+ std::vector<double> sub_trace_lengths;
+ osrm::matching::CandidateLists candidates_lists;
+ const auto &input_coords = route_parameters.coordinates;
+ const auto &input_timestamps = route_parameters.timestamps;
+ if (input_timestamps.size() > 0 && input_coords.size() != input_timestamps.size())
+ {
+ return 400;
+ }
+
+ // enforce maximum number of locations for performance reasons
+ if (max_locations_map_matching > 0 &&
+ static_cast<int>(input_coords.size()) < max_locations_map_matching)
+ {
+ return 400;
+ }
+
+ const bool found_candidates =
+ getCandiates(input_coords, sub_trace_lengths, candidates_lists);
+ if (!found_candidates)
+ {
+ return 400;
+ }
+
+ // 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);
+
+ if (sub_matchings.empty())
+ {
+ return 400;
+ }
+
+ 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];
+ 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(), true), raw_route);
+
+ 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;
+
+ return 200;
+ }
+
+ 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
index ac1079b..bf4cff3 100644
--- a/plugins/nearest.hpp
+++ b/plugins/nearest.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,15 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef NEAREST_PLUGIN_H
-#define NEAREST_PLUGIN_H
+#ifndef NEAREST_HPP
+#define NEAREST_HPP
#include "plugin_base.hpp"
-#include "../data_structures/json_container.hpp"
#include "../data_structures/phantom_node.hpp"
-#include "../Util/integer_range.hpp"
-#include "../Util/json_renderer.hpp"
+#include "../util/integer_range.hpp"
+#include "../util/json_renderer.hpp"
+
+#include <osrm/json_container.hpp>
#include <string>
@@ -46,15 +47,16 @@ template <class DataFacadeT> class NearestPlugin final : public BasePlugin
public:
explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest") {}
- const std::string GetDescriptor() const final { return descriptor_string; }
+ const std::string GetDescriptor() const override final { return descriptor_string; }
- void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
+ int 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())
+ if (route_parameters.coordinates.empty() ||
+ !route_parameters.coordinates.front().is_valid())
{
- reply = http::Reply::StockReply(http::Reply::badRequest);
- return;
+ return 400;
}
auto number_of_results = static_cast<std::size_t>(route_parameters.num_results);
std::vector<PhantomNode> phantom_node_vector;
@@ -62,51 +64,49 @@ template <class DataFacadeT> class NearestPlugin final : public BasePlugin
phantom_node_vector,
static_cast<int>(number_of_results));
- JSON::Object json_result;
if (phantom_node_vector.empty() || !phantom_node_vector.front().is_valid())
{
json_result.values["status"] = 207;
}
else
{
- reply.status = http::Reply::ok;
+ // reply.status = http::Reply::ok;
json_result.values["status"] = 0;
if (number_of_results > 1)
{
- JSON::Array results;
+ 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)))
+ for (const auto i :
+ osrm::irange<std::size_t>(0, std::min(number_of_results, vector_length)))
{
- JSON::Array json_coordinate;
- JSON::Object result;
+ osrm::json::Array json_coordinate;
+ osrm::json::Object result;
json_coordinate.values.push_back(phantom_node_vector.at(i).location.lat /
COORDINATE_PRECISION);
json_coordinate.values.push_back(phantom_node_vector.at(i).location.lon /
COORDINATE_PRECISION);
result.values["mapped coordinate"] = json_coordinate;
- std::string temp_string;
- facade->GetName(phantom_node_vector.at(i).name_id, temp_string);
- result.values["name"] = temp_string;
+ result.values["name"] =
+ facade->get_name_for_id(phantom_node_vector.at(i).name_id);
results.values.push_back(result);
}
json_result.values["results"] = results;
}
else
{
- JSON::Array json_coordinate;
+ osrm::json::Array json_coordinate;
json_coordinate.values.push_back(phantom_node_vector.front().location.lat /
COORDINATE_PRECISION);
json_coordinate.values.push_back(phantom_node_vector.front().location.lon /
COORDINATE_PRECISION);
json_result.values["mapped_coordinate"] = json_coordinate;
- std::string temp_string;
- facade->GetName(phantom_node_vector.front().name_id, temp_string);
- json_result.values["name"] = temp_string;
+ json_result.values["name"] =
+ facade->get_name_for_id(phantom_node_vector.front().name_id);
}
}
- JSON::render(reply.content, json_result);
+ return 200;
}
private:
@@ -114,4 +114,4 @@ template <class DataFacadeT> class NearestPlugin final : public BasePlugin
std::string descriptor_string;
};
-#endif /* NEAREST_PLUGIN_H */
+#endif /* NEAREST_HPP */
diff --git a/plugins/plugin_base.hpp b/plugins/plugin_base.hpp
index bb23a4d..acc8204 100644
--- a/plugins/plugin_base.hpp
+++ b/plugins/plugin_base.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,13 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef BASEPLUGIN_H_
-#define BASEPLUGIN_H_
+#ifndef BASE_PLUGIN_HPP
+#define BASE_PLUGIN_HPP
-#include <osrm/Coordinate.h>
-#include <osrm/Reply.h>
-#include <osrm/RouteParameters.h>
+#include <osrm/coordinate.hpp>
+#include <osrm/json_container.hpp>
+#include <osrm/route_parameters.hpp>
+#include <algorithm>
#include <string>
#include <vector>
@@ -42,16 +43,15 @@ class BasePlugin
// Maybe someone can explain the pure virtual destructor thing to me (dennis)
virtual ~BasePlugin() {}
virtual const std::string GetDescriptor() const = 0;
- virtual void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply) = 0;
- virtual bool check_all_coordinates(const std::vector<FixedPointCoordinate> coordinates) const final
+ virtual int HandleRequest(const RouteParameters &, osrm::json::Object &) = 0;
+ virtual bool
+ check_all_coordinates(const std::vector<FixedPointCoordinate> &coordinates) const final
{
- if (2 > coordinates.size() ||
- std::any_of(std::begin(coordinates),
- std::end(coordinates),
- [](const FixedPointCoordinate &coordinate)
- {
- return !coordinate.is_valid();
- }))
+ if (2 > coordinates.size() || std::any_of(std::begin(coordinates), std::end(coordinates),
+ [](const FixedPointCoordinate &coordinate)
+ {
+ return !coordinate.is_valid();
+ }))
{
return false;
}
@@ -59,4 +59,4 @@ class BasePlugin
}
};
-#endif /* BASEPLUGIN_H_ */
+#endif /* BASE_PLUGIN_HPP */
diff --git a/plugins/timestamp.hpp b/plugins/timestamp.hpp
index acdf32e..8a5d208 100644
--- a/plugins/timestamp.hpp
+++ b/plugins/timestamp.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,8 +30,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "plugin_base.hpp"
-#include "../data_structures/json_container.hpp"
-#include "../Util/json_renderer.hpp"
+#include "../util/json_renderer.hpp"
+
+#include <osrm/json_container.hpp>
#include <string>
@@ -42,15 +43,14 @@ template <class DataFacadeT> class TimestampPlugin final : public BasePlugin
: facade(facade), descriptor_string("timestamp")
{
}
- const std::string GetDescriptor() const final { return descriptor_string; }
- void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
+ const std::string GetDescriptor() const override final { return descriptor_string; }
+ int HandleRequest(const RouteParameters &route_parameters,
+ osrm::json::Object &json_result) override final
{
- reply.status = http::Reply::ok;
- JSON::Object json_result;
json_result.values["status"] = 0;
const std::string timestamp = facade->GetTimestamp();
json_result.values["timestamp"] = timestamp;
- JSON::render(reply.content, json_result);
+ return 200;
}
private:
diff --git a/plugins/viaroute.hpp b/plugins/viaroute.hpp
index 236ee39..335bda1 100644
--- a/plugins/viaroute.hpp
+++ b/plugins/viaroute.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -35,10 +35,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#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/integer_range.hpp"
+#include "../util/json_renderer.hpp"
+#include "../util/make_unique.hpp"
+#include "../util/simple_logger.hpp"
+
+#include <osrm/json_container.hpp>
#include <cstdlib>
@@ -67,16 +69,15 @@ template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
virtual ~ViaRoutePlugin() {}
- const std::string GetDescriptor() const final { return descriptor_string; }
+ const std::string GetDescriptor() const override final { return descriptor_string; }
- void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
+ int HandleRequest(const RouteParameters &route_parameters,
+ osrm::json::Object &json_result) override final
{
if (!check_all_coordinates(route_parameters.coordinates))
{
- reply = http::Reply::StockReply(http::Reply::badRequest);
- return;
+ return 400;
}
- reply.status = http::Reply::ok;
std::vector<phantom_node_pair> phantom_node_pair_list(route_parameters.coordinates.size());
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
@@ -143,7 +144,7 @@ template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
swap_phantom_from_big_cc_into_front);
}
- RawRouteData raw_route;
+ InternalRouteResult raw_route;
auto build_phantom_pairs =
[&raw_route](const phantom_node_pair &first_pair, const phantom_node_pair &second_pair)
{
@@ -183,7 +184,8 @@ template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
}
descriptor->SetConfig(route_parameters);
- descriptor->Run(raw_route, reply);
+ descriptor->Run(raw_route, json_result);
+ return 200;
}
};
diff --git a/prepare.cpp b/prepare.cpp
index e50f134..af10df0 100644
--- a/prepare.cpp
+++ b/prepare.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -26,8 +26,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "contractor/processing_chain.hpp"
+#include "util/simple_logger.hpp"
-#include <boost/program_options.hpp>
+#include <boost/program_options/errors.hpp>
+
+#include <exception>
+#include <ostream>
int main(int argc, char *argv[])
{
diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua
index 713c6b7..497321c 100644
--- a/profiles/bicycle.lua
+++ b/profiles/bicycle.lua
@@ -66,6 +66,10 @@ route_speeds = {
["ferry"] = 5
}
+bridge_speeds = {
+ ["movable"] = 5
+}
+
surface_speeds = {
["asphalt"] = default_speed,
["cobblestone:flattened"] = 10,
@@ -102,7 +106,7 @@ mode_normal = 1
mode_pushing = 2
mode_ferry = 3
mode_train = 4
-
+mode_movable_bridge = 5
local function parse_maxspeed(source)
if not source then
@@ -159,12 +163,14 @@ function way_function (way, result)
local railway = way:get_value_by_key("railway")
local amenity = way:get_value_by_key("amenity")
local public_transport = way:get_value_by_key("public_transport")
+ local bridge = way:get_value_by_key("bridge")
if (not highway or highway == '') and
(not route or route == '') and
(not railway or railway=='') and
(not amenity or amenity=='') and
(not man_made or man_made=='') and
- (not public_transport or public_transport=='')
+ (not public_transport or public_transport=='') and
+ (not bridge or bridge=='')
then
return
end
@@ -219,7 +225,17 @@ function way_function (way, result)
end
-- speed
- if route_speeds[route] then
+ local bridge_speed = bridge_speeds[bridge]
+ if (bridge_speed and bridge_speed > 0) then
+ highway = bridge;
+ 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_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
diff --git a/profiles/car.lua b/profiles/car.lua
index cd1f06b..813afd1 100644
--- a/profiles/car.lua
+++ b/profiles/car.lua
@@ -1,9 +1,9 @@
-- Begin of globals
--require("lib/access") --function temporarily inlined
-barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["checkpoint"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true, ["entrance"] = true }
+barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["checkpoint"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["lift_gate"] = true, ["no"] = true, ["entrance"] = true }
access_tag_whitelist = { ["yes"] = true, ["motorcar"] = true, ["motor_vehicle"] = true, ["vehicle"] = true, ["permissive"] = true, ["designated"] = true }
-access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["emergency"] = true }
+access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["emergency"] = true, ["psv"] = true }
access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
access_tags = { "motorcar", "motor_vehicle", "vehicle" }
access_tags_hierachy = { "motorcar", "motor_vehicle", "vehicle", "access" }
@@ -28,6 +28,7 @@ speed_profile = {
["service"] = 15,
-- ["track"] = 5,
["ferry"] = 5,
+ ["movable"] = 5,
["shuttle_train"] = 10,
["default"] = 10
}
@@ -144,6 +145,7 @@ local speed_reduction = 0.8
--modes
local mode_normal = 1
local mode_ferry = 2
+local mode_movable_bridge = 3
local function find_access_tag(source, access_tags_hierachy)
for i,v in ipairs(access_tags_hierachy) do
@@ -203,9 +205,7 @@ function node_function (node, result)
else
local barrier = node:get_value_by_key("barrier")
if barrier and "" ~= barrier then
- if barrier_whitelist[barrier] then
- return
- else
+ if not barrier_whitelist[barrier] then
result.barrier = true
end
end
@@ -221,8 +221,9 @@ end
function way_function (way, result)
local highway = way:get_value_by_key("highway")
local route = way:get_value_by_key("route")
+ local bridge = way:get_value_by_key("bridge")
- if not ((highway and highway ~= "") or (route and route ~= "")) then
+ if not ((highway and highway ~= "") or (route and route ~= "") or (bridge and bridge ~= "")) then
return
end
@@ -248,15 +249,21 @@ function way_function (way, result)
return
end
+ local width = math.huge
+ local width_string = way:get_value_by_key("width")
+ if width_string and tonumber(width_string:match("%d*")) then
+ width = tonumber(width_string:match("%d*"))
+ end
+
-- Check if we are allowed to access the way
local access = find_access_tag(way, access_tags_hierachy)
if access_tag_blacklist[access] then
return
end
- -- Handling ferries and piers
+ -- handling ferries and piers
local route_speed = speed_profile[route]
- if(route_speed and route_speed > 0) then
+ if (route_speed and route_speed > 0) then
highway = route;
local duration = way:get_value_by_key("duration")
if duration and durationIsValid(duration) then
@@ -268,6 +275,21 @@ function way_function (way, result)
result.backward_speed = route_speed
end
+ -- handling movable bridges
+ local bridge_speed = speed_profile[bridge]
+ local capacity_car = way:get_value_by_key("capacity:car")
+ if (bridge_speed and bridge_speed > 0) and (capacity_car ~= 0) then
+ highway = bridge;
+ local duration = way:get_value_by_key("duration")
+ 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_speed = bridge_speed
+ result.backward_speed = bridge_speed
+ end
+
-- leave early of this way is not accessible
if "" == highway then
return
@@ -385,12 +407,24 @@ function way_function (way, result)
result.ignore_in_grid = true
end
+
-- scale speeds to get better avg driving times
if result.forward_speed > 0 then
- result.forward_speed = result.forward_speed*speed_reduction + 11;
+ local scaled_speed = result.forward_speed*speed_reduction + 11;
+ local penalized_speed = math.huge
+ if width <= 3 then
+ penalized_speed = result.forward_speed / 2;
+ end
+ result.forward_speed = math.min(penalized_speed, scaled_speed)
end
+
if result.backward_speed > 0 then
- result.backward_speed = result.backward_speed*speed_reduction + 11;
+ local scaled_speed = result.backward_speed*speed_reduction + 11;
+ local penalized_speed = math.huge
+ if width <= 3 then
+ penalized_speed = result.backward_speed / 2;
+ end
+ result.backward_speed = math.min(penalized_speed, scaled_speed)
end
end
diff --git a/routed.cpp b/routed.cpp
index 1be6dd8..8b0e2e8 100644
--- a/routed.cpp
+++ b/routed.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,11 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "Library/OSRM.h"
-#include "Server/Server.h"
-#include "Util/git_sha.hpp"
-#include "Util/ProgramOptions.h"
-#include "Util/simple_logger.hpp"
+#include "library/osrm.hpp"
+#include "server/server.hpp"
+#include "util/git_sha.hpp"
+#include "util/routed_options.hpp"
+#include "util/simple_logger.hpp"
#ifdef __linux__
#include <sys/mman.h>
@@ -69,20 +69,16 @@ int main(int argc, const char *argv[])
{
LogPolicy::GetInstance().Unmute();
- bool use_shared_memory = false, trial_run = false;
+ bool trial_run = false;
std::string ip_address;
int ip_port, requested_thread_num;
- ServerPaths server_paths;
+ libosrm_config lib_config;
- const unsigned init_result = GenerateServerProgramOptions(argc,
- argv,
- server_paths,
- ip_address,
- ip_port,
- requested_thread_num,
- use_shared_memory,
- trial_run);
+ 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_distance_table,
+ lib_config.max_locations_map_matching);
if (init_result == INIT_OK_DO_NOT_START_ENGINE)
{
return 0;
@@ -101,7 +97,7 @@ int main(int argc, const char *argv[])
#endif
SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION;
- if (use_shared_memory)
+ if (lib_config.use_shared_memory)
{
SimpleLogger().Write(logDEBUG) << "Loading from shared memory";
}
@@ -117,9 +113,8 @@ int main(int argc, const char *argv[])
pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask);
#endif
- OSRM osrm_lib(server_paths, use_shared_memory);
- auto routing_server =
- Server::CreateServer(ip_address, ip_port, requested_thread_num);
+ OSRM osrm_lib(lib_config);
+ auto routing_server = Server::CreateServer(ip_address, ip_port, requested_thread_num);
routing_server->GetRequestHandlerPtr().RegisterRoutingMachine(&osrm_lib);
@@ -129,7 +124,11 @@ int main(int argc, const char *argv[])
}
else
{
- std::packaged_task<int()> server_task([&]()->int{ routing_server->Run(); return 0; });
+ 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));
@@ -158,7 +157,7 @@ int main(int argc, const char *argv[])
if (status == std::future_status::ready)
{
- server_thread.join();
+ server_thread.join();
}
else
{
diff --git a/routing_algorithms/alternative_path.hpp b/routing_algorithms/alternative_path.hpp
index 84b5856..1dcc020 100644
--- a/routing_algorithms/alternative_path.hpp
+++ b/routing_algorithms/alternative_path.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,8 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "routing_base.hpp"
#include "../data_structures/search_engine_data.hpp"
-#include "../Util/integer_range.hpp"
-#include "../Util/container.hpp"
+#include "../util/integer_range.hpp"
+#include "../util/container.hpp"
#include <boost/assert.hpp>
@@ -44,9 +44,11 @@ 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.
-template <class DataFacadeT> class AlternativeRouting final : private BasicRoutingInterface<DataFacadeT>
+template <class DataFacadeT>
+class AlternativeRouting final
+ : private BasicRoutingInterface<DataFacadeT, AlternativeRouting<DataFacadeT>>
{
- using super = BasicRoutingInterface<DataFacadeT>;
+ using super = BasicRoutingInterface<DataFacadeT, AlternativeRouting<DataFacadeT>>;
using EdgeData = typename DataFacadeT::EdgeData;
using QueryHeap = SearchEngineData::QueryHeap;
using SearchSpaceEdge = std::pair<NodeID, NodeID>;
@@ -78,7 +80,7 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
virtual ~AlternativeRouting() {}
- void operator()(const PhantomNodes &phantom_node_pair, RawRouteData &raw_route_data)
+ void operator()(const PhantomNodes &phantom_node_pair, InternalRouteResult &raw_route_data)
{
std::vector<NodeID> alternative_path;
std::vector<NodeID> via_node_candidate_list;
@@ -93,17 +95,16 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
engine_working_data.InitializeOrClearThirdThreadLocalStorage(
super::facade->GetNumberOfNodes());
- QueryHeap &forward_heap1 = *(engine_working_data.forwardHeap);
- QueryHeap &reverse_heap1 = *(engine_working_data.backwardHeap);
- QueryHeap &forward_heap2 = *(engine_working_data.forwardHeap2);
- QueryHeap &reverse_heap2 = *(engine_working_data.backwardHeap2);
+ QueryHeap &forward_heap1 = *(engine_working_data.forward_heap_1);
+ QueryHeap &reverse_heap1 = *(engine_working_data.reverse_heap_1);
+ QueryHeap &forward_heap2 = *(engine_working_data.forward_heap_2);
+ QueryHeap &reverse_heap2 = *(engine_working_data.reverse_heap_2);
int upper_bound_to_shortest_path_distance = INVALID_EDGE_WEIGHT;
NodeID middle_node = SPECIAL_NODEID;
- EdgeWeight min_edge_offset =
- std::min(0, -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset());
- min_edge_offset = std::min(min_edge_offset,
- -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
+ const EdgeWeight min_edge_offset =
+ std::min(phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
+ phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
if (phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID)
{
@@ -148,22 +149,16 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
{
if (0 < forward_heap1.Size())
{
- AlternativeRoutingStep<true>(forward_heap1,
- reverse_heap1,
- &middle_node,
+ AlternativeRoutingStep<true>(forward_heap1, reverse_heap1, &middle_node,
&upper_bound_to_shortest_path_distance,
- via_node_candidate_list,
- forward_search_space,
+ via_node_candidate_list, forward_search_space,
min_edge_offset);
}
if (0 < reverse_heap1.Size())
{
- AlternativeRoutingStep<false>(reverse_heap1,
- forward_heap1,
- &middle_node,
+ AlternativeRoutingStep<false>(forward_heap1, reverse_heap1, &middle_node,
&upper_bound_to_shortest_path_distance,
- via_node_candidate_list,
- reverse_search_space,
+ via_node_candidate_list, reverse_search_space,
min_edge_offset);
}
}
@@ -274,19 +269,16 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
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());
+ 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
for (const NodeID node : preselected_node_list)
{
int length_of_via_path = 0, sharing_of_via_path = 0;
- ComputeLengthAndSharingOfViaPath(node,
- &length_of_via_path,
- &sharing_of_via_path,
- packed_shortest_path,
- min_edge_offset);
+ ComputeLengthAndSharingOfViaPath(node, &length_of_via_path, &sharing_of_via_path,
+ packed_shortest_path, min_edge_offset);
const int maximum_allowed_sharing =
static_cast<int>(upper_bound_to_shortest_path_distance * VIAPATH_GAMMA);
if (sharing_of_via_path <= maximum_allowed_sharing &&
@@ -302,16 +294,10 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
NodeID s_v_middle = SPECIAL_NODEID, v_t_middle = SPECIAL_NODEID;
for (const RankedCandidateNode &candidate : ranked_candidates_list)
{
- if (ViaNodeCandidatePassesTTest(forward_heap1,
- reverse_heap1,
- forward_heap2,
- reverse_heap2,
- candidate,
- upper_bound_to_shortest_path_distance,
- &length_of_via_path,
- &s_v_middle,
- &v_t_middle,
- min_edge_offset))
+ if (ViaNodeCandidatePassesTTest(
+ forward_heap1, reverse_heap1, forward_heap2, reverse_heap2, candidate,
+ upper_bound_to_shortest_path_distance, &length_of_via_path, &s_v_middle,
+ &v_t_middle, min_edge_offset))
{
// select first admissable
selected_via_node = candidate.node;
@@ -343,13 +329,8 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
{
std::vector<NodeID> packed_alternate_path;
// retrieve alternate path
- RetrievePackedAlternatePath(forward_heap1,
- reverse_heap1,
- forward_heap2,
- reverse_heap2,
- s_v_middle,
- v_t_middle,
- packed_alternate_path);
+ RetrievePackedAlternatePath(forward_heap1, reverse_heap1, forward_heap2, reverse_heap2,
+ 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));
@@ -357,8 +338,8 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
(packed_alternate_path.back() != phantom_node_pair.target_phantom.forward_node_id));
// unpack the alternate path
- super::UnpackPath(
- packed_alternate_path, phantom_node_pair, raw_route_data.unpacked_alternative);
+ super::UnpackPath(packed_alternate_path, phantom_node_pair,
+ raw_route_data.unpacked_alternative);
raw_route_data.alternative_path_length = length_of_via_path;
}
@@ -370,13 +351,13 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
private:
// unpack alternate <s,..,v,..,t> by exploring search spaces from v
- inline void RetrievePackedAlternatePath(const QueryHeap &forward_heap1,
- const QueryHeap &reverse_heap1,
- const QueryHeap &forward_heap2,
- const QueryHeap &reverse_heap2,
- const NodeID s_v_middle,
- const NodeID v_t_middle,
- std::vector<NodeID> &packed_path) const
+ void RetrievePackedAlternatePath(const QueryHeap &forward_heap1,
+ const QueryHeap &reverse_heap1,
+ const QueryHeap &forward_heap2,
+ const QueryHeap &reverse_heap2,
+ const NodeID s_v_middle,
+ const NodeID v_t_middle,
+ std::vector<NodeID> &packed_path) const
{
// fetch packed path [s,v)
std::vector<NodeID> packed_v_t_path;
@@ -384,8 +365,8 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
packed_path.pop_back(); // remove middle node. It's in both half-paths
// fetch patched path [v,t]
- super::RetrievePackedPathFromHeap(
- forward_heap2, reverse_heap1, v_t_middle, packed_v_t_path);
+ super::RetrievePackedPathFromHeap(forward_heap2, reverse_heap1, v_t_middle,
+ packed_v_t_path);
packed_path.insert(packed_path.end(), packed_v_t_path.begin(), packed_v_t_path.end());
}
@@ -394,19 +375,19 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
// compute and unpack <s,..,v> and <v,..,t> by exploring search spaces
// from v and intersecting against queues. only half-searches have to be
// done at this stage
- inline void ComputeLengthAndSharingOfViaPath(const NodeID via_node,
- int *real_length_of_via_path,
- int *sharing_of_via_path,
- const std::vector<NodeID> &packed_shortest_path,
- const EdgeWeight min_edge_offset)
+ void ComputeLengthAndSharingOfViaPath(const NodeID via_node,
+ int *real_length_of_via_path,
+ int *sharing_of_via_path,
+ const std::vector<NodeID> &packed_shortest_path,
+ const EdgeWeight min_edge_offset)
{
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
super::facade->GetNumberOfNodes());
- QueryHeap &existing_forward_heap = *engine_working_data.forwardHeap;
- QueryHeap &existing_reverse_heap = *engine_working_data.backwardHeap;
- QueryHeap &new_forward_heap = *engine_working_data.forwardHeap2;
- QueryHeap &new_reverse_heap = *engine_working_data.backwardHeap2;
+ QueryHeap &existing_forward_heap = *engine_working_data.forward_heap_1;
+ QueryHeap &existing_reverse_heap = *engine_working_data.reverse_heap_1;
+ QueryHeap &new_forward_heap = *engine_working_data.forward_heap_2;
+ QueryHeap &new_reverse_heap = *engine_working_data.reverse_heap_2;
std::vector<NodeID> packed_s_v_path;
std::vector<NodeID> packed_v_t_path;
@@ -420,12 +401,8 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
// compute path <s,..,v> by reusing forward search from s
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);
+ super::RoutingStep(new_reverse_heap, existing_forward_heap, &s_v_middle,
+ &upper_bound_s_v_path_length, min_edge_offset, false);
}
// compute path <v,..,t> by reusing backward search from node t
NodeID v_t_middle = SPECIAL_NODEID;
@@ -433,12 +410,8 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
new_forward_heap.Insert(via_node, 0, via_node);
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);
+ super::RoutingStep(new_forward_heap, existing_reverse_heap, &v_t_middle,
+ &upper_bound_of_v_t_path_length, min_edge_offset, true);
}
*real_length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
@@ -448,10 +421,10 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
}
// retrieve packed paths
- super::RetrievePackedPathFromHeap(
- existing_forward_heap, new_reverse_heap, s_v_middle, packed_s_v_path);
- super::RetrievePackedPathFromHeap(
- new_forward_heap, existing_reverse_heap, v_t_middle, packed_v_t_path);
+ super::RetrievePackedPathFromHeap(existing_forward_heap, new_reverse_heap, s_v_middle,
+ packed_s_v_path);
+ super::RetrievePackedPathFromHeap(new_forward_heap, existing_reverse_heap, v_t_middle,
+ packed_v_t_path);
// partial unpacking, compute sharing
// First partially unpack s-->v until paths deviate, note length of common path.
@@ -484,12 +457,11 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
const int64_t packed_path_length =
std::min(partially_unpacked_via_path.size(), partially_unpacked_shortest_path.size()) -
1;
- for (int64_t current_node = 0;
- (current_node < packed_path_length) &&
- (partially_unpacked_via_path[current_node] ==
- partially_unpacked_shortest_path[current_node] &&
- partially_unpacked_via_path[current_node + 1] ==
- partially_unpacked_shortest_path[current_node + 1]);
+ for (int64_t current_node = 0; (current_node < packed_path_length) &&
+ (partially_unpacked_via_path[current_node] ==
+ partially_unpacked_shortest_path[current_node] &&
+ partially_unpacked_via_path[current_node + 1] ==
+ partially_unpacked_shortest_path[current_node + 1]);
++current_node)
{
EdgeID selected_edge =
@@ -517,8 +489,7 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
if (packed_v_t_path[via_path_index] == packed_shortest_path[shortest_path_index])
{
super::UnpackEdge(packed_v_t_path[via_path_index - 1],
- packed_v_t_path[via_path_index],
- partially_unpacked_via_path);
+ packed_v_t_path[via_path_index], partially_unpacked_via_path);
super::UnpackEdge(packed_shortest_path[shortest_path_index - 1],
packed_shortest_path[shortest_path_index],
partially_unpacked_shortest_path);
@@ -551,7 +522,7 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
// variable
}
- // inline int approximateAmountOfSharing(
+ // int approximateAmountOfSharing(
// const NodeID alternate_path_middle_node_id,
// QueryHeap & forward_heap,
// QueryHeap & reverse_heap,
@@ -598,14 +569,17 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
// todo: reorder parameters
template <bool is_forward_directed>
- inline void AlternativeRoutingStep(QueryHeap &forward_heap,
- QueryHeap &reverse_heap,
- NodeID *middle_node,
- int *upper_bound_to_shortest_path_distance,
- std::vector<NodeID> &search_space_intersection,
- std::vector<SearchSpaceEdge> &search_space,
- const EdgeWeight min_edge_offset) const
+ void AlternativeRoutingStep(QueryHeap &heap1,
+ QueryHeap &heap2,
+ NodeID *middle_node,
+ int *upper_bound_to_shortest_path_distance,
+ std::vector<NodeID> &search_space_intersection,
+ std::vector<SearchSpaceEdge> &search_space,
+ const EdgeWeight min_edge_offset) const
{
+ QueryHeap &forward_heap = (is_forward_directed ? heap1 : heap2);
+ QueryHeap &reverse_heap = (is_forward_directed ? heap2 : heap1);
+
const NodeID node = forward_heap.DeleteMin();
const int distance = forward_heap.GetKey(node);
// const NodeID parentnode = forward_heap.GetData(node).parent;
@@ -674,16 +648,16 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
}
// conduct T-Test
- inline bool ViaNodeCandidatePassesTTest(QueryHeap &existing_forward_heap,
- QueryHeap &existing_reverse_heap,
- QueryHeap &new_forward_heap,
- QueryHeap &new_reverse_heap,
- const RankedCandidateNode &candidate,
- const int length_of_shortest_path,
- int *length_of_via_path,
- NodeID *s_v_middle,
- NodeID *v_t_middle,
- const EdgeWeight min_edge_offset) const
+ bool ViaNodeCandidatePassesTTest(QueryHeap &existing_forward_heap,
+ QueryHeap &existing_reverse_heap,
+ QueryHeap &new_forward_heap,
+ QueryHeap &new_reverse_heap,
+ const RankedCandidateNode &candidate,
+ const int length_of_shortest_path,
+ int *length_of_via_path,
+ NodeID *s_v_middle,
+ NodeID *v_t_middle,
+ const EdgeWeight min_edge_offset) const
{
new_forward_heap.Clear();
new_reverse_heap.Clear();
@@ -696,12 +670,8 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
new_reverse_heap.Insert(candidate.node, 0, candidate.node);
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);
+ super::RoutingStep(new_reverse_heap, existing_forward_heap, s_v_middle,
+ &upper_bound_s_v_path_length, min_edge_offset, false);
}
if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_length)
@@ -715,12 +685,8 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
new_forward_heap.Insert(candidate.node, 0, candidate.node);
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);
+ super::RoutingStep(new_forward_heap, existing_reverse_heap, v_t_middle,
+ &upper_bound_of_v_t_path_length, min_edge_offset, true);
}
if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_length)
@@ -731,11 +697,11 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
*length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
// retrieve packed paths
- super::RetrievePackedPathFromHeap(
- existing_forward_heap, new_reverse_heap, *s_v_middle, packed_s_v_path);
+ super::RetrievePackedPathFromHeap(existing_forward_heap, new_reverse_heap, *s_v_middle,
+ packed_s_v_path);
- super::RetrievePackedPathFromHeap(
- new_forward_heap, existing_reverse_heap, *v_t_middle, packed_v_t_path);
+ super::RetrievePackedPathFromHeap(new_forward_heap, existing_reverse_heap, *v_t_middle,
+ packed_v_t_path);
NodeID s_P = *s_v_middle, t_P = *v_t_middle;
if (SPECIAL_NODEID == s_P)
@@ -815,8 +781,7 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
// Traverse path s-->v
BOOST_ASSERT(!packed_v_t_path.empty());
for (unsigned i = 0, packed_path_length = static_cast<unsigned>(packed_v_t_path.size() - 1);
- (i < packed_path_length) && unpack_stack.empty();
- ++i)
+ (i < packed_path_length) && unpack_stack.empty(); ++i)
{
const EdgeID edgeID =
facade->FindEdgeInEitherDirection(packed_v_t_path[i], packed_v_t_path[i + 1]);
@@ -876,8 +841,8 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
engine_working_data.InitializeOrClearThirdThreadLocalStorage(
super::facade->GetNumberOfNodes());
- QueryHeap &forward_heap3 = *engine_working_data.forwardHeap3;
- QueryHeap &reverse_heap3 = *engine_working_data.backwardHeap3;
+ QueryHeap &forward_heap3 = *engine_working_data.forward_heap_3;
+ QueryHeap &reverse_heap3 = *engine_working_data.reverse_heap_3;
int upper_bound = INVALID_EDGE_WEIGHT;
NodeID middle = SPECIAL_NODEID;
@@ -888,13 +853,13 @@ template <class DataFacadeT> class AlternativeRouting final : private BasicRouti
{
if (!forward_heap3.Empty())
{
- super::RoutingStep(
- forward_heap3, reverse_heap3, &middle, &upper_bound, min_edge_offset, true);
+ super::RoutingStep(forward_heap3, reverse_heap3, &middle, &upper_bound,
+ min_edge_offset, true);
}
if (!reverse_heap3.Empty())
{
- super::RoutingStep(
- reverse_heap3, forward_heap3, &middle, &upper_bound, min_edge_offset, false);
+ super::RoutingStep(reverse_heap3, forward_heap3, &middle, &upper_bound,
+ min_edge_offset, false);
}
}
return (upper_bound <= t_test_path_length);
diff --git a/routing_algorithms/many_to_many.hpp b/routing_algorithms/many_to_many.hpp
index f1e9960..2388804 100644
--- a/routing_algorithms/many_to_many.hpp
+++ b/routing_algorithms/many_to_many.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -39,9 +39,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unordered_map>
#include <vector>
-template <class DataFacadeT> class ManyToManyRouting final : public BasicRoutingInterface<DataFacadeT>
+template <class DataFacadeT>
+class ManyToManyRouting final
+ : public BasicRoutingInterface<DataFacadeT, ManyToManyRouting<DataFacadeT>>
{
- using super = BasicRoutingInterface<DataFacadeT>;
+ using super = BasicRoutingInterface<DataFacadeT, ManyToManyRouting<DataFacadeT>>;
using QueryHeap = SearchEngineData::QueryHeap;
SearchEngineData &engine_working_data;
@@ -64,8 +66,8 @@ template <class DataFacadeT> class ManyToManyRouting final : public BasicRouting
~ManyToManyRouting() {}
- std::shared_ptr<std::vector<EdgeWeight>> operator()(const PhantomNodeArray &phantom_nodes_array)
- const
+ std::shared_ptr<std::vector<EdgeWeight>>
+ operator()(const PhantomNodeArray &phantom_nodes_array) const
{
const auto number_of_locations = phantom_nodes_array.size();
std::shared_ptr<std::vector<EdgeWeight>> result_table =
@@ -75,7 +77,7 @@ template <class DataFacadeT> class ManyToManyRouting final : public BasicRouting
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
super::facade->GetNumberOfNodes());
- QueryHeap &query_heap = *(engine_working_data.forwardHeap);
+ QueryHeap &query_heap = *(engine_working_data.forward_heap_1);
SearchSpaceWithBuckets search_space_with_buckets;
@@ -134,11 +136,8 @@ template <class DataFacadeT> class ManyToManyRouting final : public BasicRouting
// explore search space
while (!query_heap.Empty())
{
- ForwardRoutingStep(source_id,
- number_of_locations,
- query_heap,
- search_space_with_buckets,
- result_table);
+ ForwardRoutingStep(source_id, number_of_locations, query_heap,
+ search_space_with_buckets, result_table);
}
++source_id;
@@ -237,8 +236,8 @@ template <class DataFacadeT> class ManyToManyRouting final : public BasicRouting
// Stalling
template <bool forward_direction>
- inline bool StallAtNode(const NodeID node, const EdgeWeight distance, QueryHeap &query_heap)
- const
+ inline bool
+ StallAtNode(const NodeID node, const EdgeWeight distance, QueryHeap &query_heap) const
{
for (auto edge : super::facade->GetAdjacentEdgeRange(node))
{
diff --git a/routing_algorithms/map_matching.hpp b/routing_algorithms/map_matching.hpp
new file mode 100644
index 0000000..737494b
--- /dev/null
+++ b/routing_algorithms/map_matching.hpp
@@ -0,0 +1,344 @@
+/*
+
+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 "../data_structures/coordinate_calculation.hpp"
+#include "../data_structures/hidden_markov_model.hpp"
+#include "../util/json_logger.hpp"
+#include "../util/matching_debug_info.hpp"
+
+#include <variant/variant.hpp>
+
+#include <algorithm>
+#include <iomanip>
+#include <numeric>
+
+namespace osrm
+{
+namespace matching
+{
+
+struct SubMatching
+{
+ std::vector<PhantomNode> nodes;
+ std::vector<unsigned> indices;
+ double length;
+ double confidence;
+};
+
+using CandidateList = std::vector<std::pair<PhantomNode, double>>;
+using CandidateLists = std::vector<CandidateList>;
+using HMM = HiddenMarkovModel<CandidateLists>;
+using SubMatchingList = std::vector<SubMatching>;
+
+constexpr static const unsigned MAX_BROKEN_STATES = 6;
+constexpr static const unsigned MAX_BROKEN_TIME = 60;
+
+constexpr static const unsigned MAX_DISTANCE_DELTA = 200;
+constexpr static const unsigned SUSPICIOUS_DISTANCE_DELTA = 100;
+
+constexpr static const double default_beta = 5.0;
+constexpr static const double default_sigma_z = 4.07;
+}
+}
+
+// implements a hidden markov model map matching algorithm
+template <class DataFacadeT>
+class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<DataFacadeT>>
+{
+ using super = BasicRoutingInterface<DataFacadeT, MapMatching<DataFacadeT>>;
+ using QueryHeap = SearchEngineData::QueryHeap;
+ SearchEngineData &engine_working_data;
+
+ public:
+ MapMatching(DataFacadeT *facade, SearchEngineData &engine_working_data)
+ : super(facade), engine_working_data(engine_working_data)
+ {
+ }
+
+ 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
+ {
+ BOOST_ASSERT(!candidates_list.empty() && !trace_coordinates.empty());
+
+ // TODO replace default values with table lookup based on sampling frequency
+ EmissionLogProbability emission_log_probability(
+ gps_precision > 0. ? gps_precision : osrm::matching::default_sigma_z);
+ TransitionLogProbability transition_log_probability(
+ matching_beta > 0. ? matching_beta : osrm::matching::default_beta);
+
+ osrm::matching::HMM model(candidates_list, emission_log_probability);
+
+ std::size_t initial_timestamp = model.initialize(0);
+ if (initial_timestamp == osrm::matching::INVALID_STATE)
+ {
+ return;
+ }
+
+ MatchingDebugInfo matching_debug(osrm::json::Logger::get());
+ matching_debug.initialize(candidates_list);
+
+ std::size_t breakage_begin = osrm::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());
+ prev_unbroken_timestamps.push_back(initial_timestamp);
+ for (auto t = initial_timestamp + 1; t < candidates_list.size(); ++t)
+ {
+ // breakage recover has removed all previous good points
+ bool trace_split = prev_unbroken_timestamps.empty();
+
+ // use temporal information if available to determine a split
+ if (!trace_timestamps.empty())
+ {
+ trace_split =
+ trace_split ||
+ (trace_timestamps[t] - trace_timestamps[prev_unbroken_timestamps.back()] >
+ osrm::matching::MAX_BROKEN_TIME);
+ }
+ else
+ {
+ trace_split = trace_split || (t - prev_unbroken_timestamps.back() >
+ osrm::matching::MAX_BROKEN_STATES);
+ }
+
+ if (trace_split)
+ {
+ std::size_t split_index = t;
+ if (breakage_begin != osrm::matching::INVALID_STATE)
+ {
+ split_index = breakage_begin;
+ breakage_begin = osrm::matching::INVALID_STATE;
+ }
+ split_points.push_back(split_index);
+
+ // note: this preserves everything before split_index
+ 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)
+ {
+ break;
+ }
+
+ prev_unbroken_timestamps.clear();
+ prev_unbroken_timestamps.push_back(new_start);
+ // Important: We potentially go back here!
+ // However since t > new_start >= breakge_begin
+ // we can only reset trace_coordindates.size() times.
+ t = new_start + 1;
+ }
+
+ BOOST_ASSERT(!prev_unbroken_timestamps.empty());
+ const std::size_t prev_unbroken_timestamp = prev_unbroken_timestamps.back();
+
+ const auto &prev_viterbi = model.viterbi[prev_unbroken_timestamp];
+ const auto &prev_pruned = model.pruned[prev_unbroken_timestamp];
+ const auto &prev_unbroken_timestamps_list = candidates_list[prev_unbroken_timestamp];
+ const auto &prev_coordinate = trace_coordinates[prev_unbroken_timestamp];
+
+ 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];
+ const auto ¤t_timestamps_list = candidates_list[t];
+ const auto ¤t_coordinate = trace_coordinates[t];
+
+ 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);
+
+ // compute d_t for this timestamp and the next one
+ for (const auto s : osrm::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()))
+ {
+ // how likely is candidate s_prime at time t to be emitted?
+ const double emission_pr =
+ emission_log_probability(candidates_list[t][s_prime].second);
+ double new_value = prev_viterbi[s] + emission_pr;
+ if (current_viterbi[s_prime] > new_value)
+ {
+ continue;
+ }
+
+ 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].first,
+ current_timestamps_list[s_prime].first);
+ const auto great_circle_distance =
+ coordinate_calculation::great_circle_distance(prev_coordinate,
+ current_coordinate);
+
+ const auto d_t = std::abs(network_distance - great_circle_distance);
+
+ // very low probability transition -> prune
+ if (d_t > osrm::matching::MAX_DISTANCE_DELTA)
+ {
+ continue;
+ }
+
+ 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, great_circle_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;
+ }
+ }
+ }
+
+ if (model.breakage[t])
+ {
+ // save start of breakage -> we need this as split point
+ if (t < breakage_begin)
+ {
+ breakage_begin = t;
+ }
+
+ BOOST_ASSERT(prev_unbroken_timestamps.size() > 0);
+ // remove both ends of the breakage
+ prev_unbroken_timestamps.pop_back();
+ }
+ else
+ {
+ prev_unbroken_timestamps.push_back(t);
+ }
+ }
+
+ matching_debug.set_viterbi(model.viterbi, model.pruned, model.suspicious);
+
+ if (!prev_unbroken_timestamps.empty())
+ {
+ split_points.push_back(prev_unbroken_timestamps.back() + 1);
+ }
+
+ std::size_t sub_matching_begin = initial_timestamp;
+ for (const auto sub_matching_end : split_points)
+ {
+ osrm::matching::SubMatching matching;
+
+ // find real end of trace
+ // not sure if this is really needed
+ std::size_t parent_timestamp_index = sub_matching_end - 1;
+ while (parent_timestamp_index >= sub_matching_begin &&
+ model.breakage[parent_timestamp_index])
+ {
+ --parent_timestamp_index;
+ }
+
+ // matchings that only consist of one candidate are invalid
+ if (parent_timestamp_index - sub_matching_begin + 1 < 2)
+ {
+ sub_matching_begin = sub_matching_end;
+ continue;
+ }
+
+ // loop through the columns, and only compare the last entry
+ const auto max_element_iter =
+ std::max_element(model.viterbi[parent_timestamp_index].begin(),
+ model.viterbi[parent_timestamp_index].end());
+
+ std::size_t parent_candidate_index =
+ std::distance(model.viterbi[parent_timestamp_index].begin(), max_element_iter);
+
+ std::deque<std::pair<std::size_t, std::size_t>> reconstructed_indices;
+ while (parent_timestamp_index > sub_matching_begin)
+ {
+ if (model.breakage[parent_timestamp_index])
+ {
+ continue;
+ }
+
+ reconstructed_indices.emplace_front(parent_timestamp_index, parent_candidate_index);
+ const auto &next = model.parents[parent_timestamp_index][parent_candidate_index];
+ parent_timestamp_index = next.first;
+ parent_candidate_index = next.second;
+ }
+ reconstructed_indices.emplace_front(parent_timestamp_index, parent_candidate_index);
+ if (reconstructed_indices.size() < 2)
+ {
+ sub_matching_begin = sub_matching_end;
+ 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()))
+ {
+ 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].first;
+ matching.length += model.path_lengths[timestamp_index][location_index];
+
+ matching_debug.add_chosen(timestamp_index, location_index);
+ }
+
+ sub_matchings.push_back(matching);
+ sub_matching_begin = sub_matching_end;
+ }
+ matching_debug.add_breakage(model.breakage);
+ }
+};
+
+//[1] "Hidden Markov Map Matching Through Noise and Sparseness"; P. Newson and J. Krumm; 2009; ACM
+// GIS
+
+#endif /* MAP_MATCHING_HPP */
diff --git a/routing_algorithms/routing_base.hpp b/routing_algorithms/routing_base.hpp
index 20610ea..52c16a7 100644
--- a/routing_algorithms/routing_base.hpp
+++ b/routing_algorithms/routing_base.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,26 +28,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ROUTING_BASE_HPP
#define ROUTING_BASE_HPP
-#include "../data_structures/raw_route_data.hpp"
+#include "../data_structures/coordinate_calculation.hpp"
+#include "../data_structures/internal_route_result.hpp"
#include "../data_structures/search_engine_data.hpp"
#include "../data_structures/turn_instructions.hpp"
-// #include "../Util/simple_logger.hpp.h"
+// #include "../util/simple_logger.hpp"
#include <boost/assert.hpp>
#include <stack>
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap2;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap2;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap3;
-SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap3;
+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 BasicRoutingInterface
+template <class DataFacadeT, class Derived> class BasicRoutingInterface
{
private:
- typedef typename DataFacadeT::EdgeData EdgeData;
+ using EdgeData = typename DataFacadeT::EdgeData;
protected:
DataFacadeT *facade;
@@ -56,20 +57,21 @@ template <class DataFacadeT> class BasicRoutingInterface
BasicRoutingInterface() = delete;
BasicRoutingInterface(const BasicRoutingInterface &) = delete;
explicit BasicRoutingInterface(DataFacadeT *facade) : facade(facade) {}
- virtual ~BasicRoutingInterface() {};
-
- inline void RoutingStep(SearchEngineData::QueryHeap &forward_heap,
- SearchEngineData::QueryHeap &reverse_heap,
- NodeID *middle_node_id,
- int *upper_bound,
- const int min_edge_offset,
- const bool forward_direction) const
+ ~BasicRoutingInterface() {}
+
+ void RoutingStep(SearchEngineData::QueryHeap &forward_heap,
+ SearchEngineData::QueryHeap &reverse_heap,
+ NodeID *middle_node_id,
+ int *upper_bound,
+ const int min_edge_offset,
+ const bool forward_direction) const
{
const NodeID node = forward_heap.DeleteMin();
const int distance = forward_heap.GetKey(node);
// const NodeID parentnode = forward_heap.GetData(node).parent;
- // SimpleLogger().Write() << (forward_direction ? "[fwd] " : "[rev] ") << "settled edge (" << parentnode << "," << node << "), dist: " << distance;
+ // SimpleLogger().Write() << (forward_direction ? "[fwd] " : "[rev] ") << "settled edge ("
+ // << parentnode << "," << node << "), dist: " << distance;
if (reverse_heap.WasInserted(node))
{
@@ -80,9 +82,11 @@ template <class DataFacadeT> class BasicRoutingInterface
{
*middle_node_id = node;
*upper_bound = new_distance;
- // SimpleLogger().Write() << "accepted middle node " << node << " at distance " << new_distance;
- // } else {
- // SimpleLogger().Write() << "discared middle node " << node << " at distance " << new_distance;
+ // SimpleLogger().Write() << "accepted middle node " << node << " at
+ // distance " << new_distance;
+ // } else {
+ // SimpleLogger().Write() << "discared middle node " << node << " at
+ // distance " << new_distance;
}
}
}
@@ -145,9 +149,9 @@ template <class DataFacadeT> class BasicRoutingInterface
}
}
- inline void UnpackPath(const std::vector<NodeID> &packed_path,
- const PhantomNodes &phantom_node_pair,
- std::vector<PathData> &unpacked_path) const
+ void UnpackPath(const std::vector<NodeID> &packed_path,
+ const PhantomNodes &phantom_node_pair,
+ std::vector<PathData> &unpacked_path) const
{
const bool start_traversed_in_reverse =
(packed_path.front() != phantom_node_pair.source_phantom.forward_node_id);
@@ -228,15 +232,11 @@ template <class DataFacadeT> class BasicRoutingInterface
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);
+ unpacked_path.emplace_back(facade->GetGeometryIndexForEdgeID(ed.id), name_index,
+ turn_instruction, ed.distance, travel_mode);
}
else
{
@@ -257,7 +257,8 @@ template <class DataFacadeT> class BasicRoutingInterface
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.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;
@@ -294,18 +295,19 @@ template <class DataFacadeT> class BasicRoutingInterface
if (start_index > end_index)
{
- start_index = std::min(start_index, id_vector.size()-1);
+ 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});
+ 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});
}
}
@@ -330,7 +332,7 @@ template <class DataFacadeT> class BasicRoutingInterface
}
}
- inline void UnpackEdge(const NodeID s, const NodeID t, std::vector<NodeID> &unpacked_path) const
+ 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);
@@ -367,7 +369,8 @@ template <class DataFacadeT> class BasicRoutingInterface
}
}
}
- BOOST_ASSERT_MSG(edge_weight != std::numeric_limits<EdgeWeight>::max(), "edge weight invalid");
+ BOOST_ASSERT_MSG(edge_weight != std::numeric_limits<EdgeWeight>::max(),
+ "edge weight invalid");
const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
if (ed.shortcut)
@@ -386,10 +389,10 @@ template <class DataFacadeT> class BasicRoutingInterface
unpacked_path.emplace_back(t);
}
- inline void RetrievePackedPathFromHeap(const SearchEngineData::QueryHeap &forward_heap,
- const SearchEngineData::QueryHeap &reverse_heap,
- const NodeID middle_node_id,
- std::vector<NodeID> &packed_path) const
+ 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());
@@ -397,9 +400,9 @@ template <class DataFacadeT> class BasicRoutingInterface
RetrievePackedPathFromSingleHeap(reverse_heap, middle_node_id, packed_path);
}
- inline void RetrievePackedPathFromSingleHeap(const SearchEngineData::QueryHeap &search_heap,
- const NodeID middle_node_id,
- std::vector<NodeID> &packed_path) const
+ 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)
@@ -408,6 +411,84 @@ template <class DataFacadeT> class BasicRoutingInterface
packed_path.emplace_back(current_node_id);
}
}
+
+ 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, 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::great_circle_distance(previous_coordinate,
+ current_coordinate);
+ previous_coordinate = current_coordinate;
+ }
+ distance += coordinate_calculation::great_circle_distance(previous_coordinate,
+ target_phantom.location);
+ }
+ return distance;
+ }
};
#endif // ROUTING_BASE_HPP
diff --git a/routing_algorithms/shortest_path.hpp b/routing_algorithms/shortest_path.hpp
index cab09ab..3dedc2b 100644
--- a/routing_algorithms/shortest_path.hpp
+++ b/routing_algorithms/shortest_path.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -32,12 +32,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "routing_base.hpp"
#include "../data_structures/search_engine_data.hpp"
-#include "../Util/integer_range.hpp"
+#include "../util/integer_range.hpp"
#include "../typedefs.h"
-template <class DataFacadeT> class ShortestPathRouting final : public BasicRoutingInterface<DataFacadeT>
+template <class DataFacadeT>
+class ShortestPathRouting final
+ : public BasicRoutingInterface<DataFacadeT, ShortestPathRouting<DataFacadeT>>
{
- using super = BasicRoutingInterface<DataFacadeT>;
+ using super = BasicRoutingInterface<DataFacadeT, ShortestPathRouting<DataFacadeT>>;
using QueryHeap = SearchEngineData::QueryHeap;
SearchEngineData &engine_working_data;
@@ -51,7 +53,7 @@ template <class DataFacadeT> class ShortestPathRouting final : public BasicRouti
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
const std::vector<bool> &uturn_indicators,
- RawRouteData &raw_route_data) const
+ InternalRouteResult &raw_route_data) const
{
int distance1 = 0;
int distance2 = 0;
@@ -69,10 +71,10 @@ template <class DataFacadeT> class ShortestPathRouting final : public BasicRouti
engine_working_data.InitializeOrClearThirdThreadLocalStorage(
super::facade->GetNumberOfNodes());
- QueryHeap &forward_heap1 = *(engine_working_data.forwardHeap);
- QueryHeap &reverse_heap1 = *(engine_working_data.backwardHeap);
- QueryHeap &forward_heap2 = *(engine_working_data.forwardHeap2);
- QueryHeap &reverse_heap2 = *(engine_working_data.backwardHeap2);
+ QueryHeap &forward_heap1 = *(engine_working_data.forward_heap_1);
+ QueryHeap &reverse_heap1 = *(engine_working_data.reverse_heap_1);
+ QueryHeap &forward_heap2 = *(engine_working_data.forward_heap_2);
+ QueryHeap &reverse_heap2 = *(engine_working_data.reverse_heap_2);
std::size_t current_leg = 0;
// Get distance to next pair of target nodes.
@@ -88,8 +90,11 @@ template <class DataFacadeT> class ShortestPathRouting final : public BasicRouti
middle1 = SPECIAL_NODEID;
middle2 = SPECIAL_NODEID;
- const bool allow_u_turn = current_leg > 0 && uturn_indicators.size() > current_leg && uturn_indicators[current_leg-1];
- EdgeWeight min_edge_offset = 0;
+ const bool allow_u_turn = current_leg > 0 && uturn_indicators.size() > current_leg &&
+ uturn_indicators[current_leg - 1];
+ const EdgeWeight min_edge_offset =
+ std::min(phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
+ phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
// insert new starting nodes into forward heap, adjusted by previous distances.
if ((allow_u_turn || search_from_1st_node) &&
@@ -97,35 +102,32 @@ template <class DataFacadeT> class ShortestPathRouting final : public BasicRouti
{
forward_heap1.Insert(
phantom_node_pair.source_phantom.forward_node_id,
- (allow_u_turn ? 0 : distance1) - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
+ -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
phantom_node_pair.source_phantom.forward_node_id);
- min_edge_offset = std::min(min_edge_offset, (allow_u_turn ? 0 : distance1) - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset());
- // SimpleLogger().Write(logDEBUG) << "fwd-a2 insert: " << phantom_node_pair.source_phantom.forward_node_id << ", w: " << (allow_u_turn ? 0 : distance1) - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset();
+ // SimpleLogger().Write(logDEBUG) << "fwd-a2 insert: " <<
+ // phantom_node_pair.source_phantom.forward_node_id << ", w: " << -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset();
forward_heap2.Insert(
phantom_node_pair.source_phantom.forward_node_id,
- (allow_u_turn ? 0 : distance1) - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
+ -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
phantom_node_pair.source_phantom.forward_node_id);
- min_edge_offset = std::min(min_edge_offset, (allow_u_turn ? 0 : distance1) - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset());
- // SimpleLogger().Write(logDEBUG) << "fwd-b2 insert: " << phantom_node_pair.source_phantom.forward_node_id << ", w: " << (allow_u_turn ? 0 : distance1) - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset();
-
+ // SimpleLogger().Write(logDEBUG) << "fwd-b2 insert: " <<
+ // phantom_node_pair.source_phantom.forward_node_id << ", w: " << -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset();
}
if ((allow_u_turn || search_from_2nd_node) &&
phantom_node_pair.source_phantom.reverse_node_id != SPECIAL_NODEID)
{
forward_heap1.Insert(
phantom_node_pair.source_phantom.reverse_node_id,
- (allow_u_turn ? 0 : distance2) - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
+ -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
phantom_node_pair.source_phantom.reverse_node_id);
- min_edge_offset = std::min(min_edge_offset, (allow_u_turn ? 0 : distance2) - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
- // SimpleLogger().Write(logDEBUG) << "fwd-a2 insert: " << phantom_node_pair.source_phantom.reverse_node_id <<
- // ", w: " << (allow_u_turn ? 0 : distance2) - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset();
+ // SimpleLogger().Write(logDEBUG) << "fwd-a2 insert: " <<
+ // phantom_node_pair.source_phantom.reverse_node_id << ", w: " << -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset();
forward_heap2.Insert(
phantom_node_pair.source_phantom.reverse_node_id,
- (allow_u_turn ? 0 : distance2) - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
+ -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
phantom_node_pair.source_phantom.reverse_node_id);
- min_edge_offset = std::min(min_edge_offset, (allow_u_turn ? 0 : distance2) - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
- // SimpleLogger().Write(logDEBUG) << "fwd-b2 insert: " << phantom_node_pair.source_phantom.reverse_node_id <<
- // ", w: " << (allow_u_turn ? 0 : distance2) - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset();
+ // SimpleLogger().Write(logDEBUG) << "fwd-b2 insert: " <<
+ // phantom_node_pair.source_phantom.reverse_node_id << ", w: " << -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset();
}
// insert new backward nodes into backward heap, unadjusted.
@@ -134,17 +136,17 @@ template <class DataFacadeT> class ShortestPathRouting final : public BasicRouti
reverse_heap1.Insert(phantom_node_pair.target_phantom.forward_node_id,
phantom_node_pair.target_phantom.GetForwardWeightPlusOffset(),
phantom_node_pair.target_phantom.forward_node_id);
- // SimpleLogger().Write(logDEBUG) << "rev-a insert: " << phantom_node_pair.target_phantom.forward_node_id <<
- // ", w: " << phantom_node_pair.target_phantom.GetForwardWeightPlusOffset();
- }
+ // SimpleLogger().Write(logDEBUG) << "rev-a insert: " <<
+ // phantom_node_pair.target_phantom.forward_node_id << ", w: " << phantom_node_pair.target_phantom.GetForwardWeightPlusOffset();
+ }
if (phantom_node_pair.target_phantom.reverse_node_id != SPECIAL_NODEID)
{
reverse_heap2.Insert(phantom_node_pair.target_phantom.reverse_node_id,
phantom_node_pair.target_phantom.GetReverseWeightPlusOffset(),
phantom_node_pair.target_phantom.reverse_node_id);
- // SimpleLogger().Write(logDEBUG) << "rev-a insert: " << phantom_node_pair.target_phantom.reverse_node_id <<
- // ", w: " << phantom_node_pair.target_phantom.GetReverseWeightPlusOffset();
+ // SimpleLogger().Write(logDEBUG) << "rev-a insert: " <<
+ // phantom_node_pair.target_phantom.reverse_node_id << ", w: " << phantom_node_pair.target_phantom.GetReverseWeightPlusOffset();
}
// run two-Target Dijkstra routing step.
@@ -152,13 +154,13 @@ template <class DataFacadeT> class ShortestPathRouting final : public BasicRouti
{
if (!forward_heap1.Empty())
{
- super::RoutingStep(
- forward_heap1, reverse_heap1, &middle1, &local_upper_bound1, min_edge_offset, true);
+ super::RoutingStep(forward_heap1, reverse_heap1, &middle1, &local_upper_bound1,
+ min_edge_offset, true);
}
if (!reverse_heap1.Empty())
{
- super::RoutingStep(
- reverse_heap1, forward_heap1, &middle1, &local_upper_bound1, min_edge_offset, false);
+ super::RoutingStep(reverse_heap1, forward_heap1, &middle1, &local_upper_bound1,
+ min_edge_offset, false);
}
}
@@ -168,13 +170,13 @@ template <class DataFacadeT> class ShortestPathRouting final : public BasicRouti
{
if (!forward_heap2.Empty())
{
- super::RoutingStep(
- forward_heap2, reverse_heap2, &middle2, &local_upper_bound2, min_edge_offset, true);
+ super::RoutingStep(forward_heap2, reverse_heap2, &middle2,
+ &local_upper_bound2, min_edge_offset, true);
}
if (!reverse_heap2.Empty())
{
- super::RoutingStep(
- reverse_heap2, forward_heap2, &middle2, &local_upper_bound2, min_edge_offset, false);
+ super::RoutingStep(reverse_heap2, forward_heap2, &middle2,
+ &local_upper_bound2, min_edge_offset, false);
}
}
}
@@ -200,29 +202,31 @@ template <class DataFacadeT> class ShortestPathRouting final : public BasicRouti
}
// Was at most one of the two paths not found?
- BOOST_ASSERT_MSG((INVALID_EDGE_WEIGHT != distance1 || INVALID_EDGE_WEIGHT != distance2), "no path found");
+ BOOST_ASSERT_MSG((INVALID_EDGE_WEIGHT != distance1 || INVALID_EDGE_WEIGHT != distance2),
+ "no path found");
// Unpack paths if they exist
std::vector<NodeID> temporary_packed_leg1;
std::vector<NodeID> temporary_packed_leg2;
- BOOST_ASSERT((unsigned)current_leg < packed_legs1.size());
- BOOST_ASSERT((unsigned)current_leg < packed_legs2.size());
+ BOOST_ASSERT(current_leg < packed_legs1.size());
+ BOOST_ASSERT(current_leg < packed_legs2.size());
if (INVALID_EDGE_WEIGHT != local_upper_bound1)
{
- super::RetrievePackedPathFromHeap(
- forward_heap1, reverse_heap1, middle1, temporary_packed_leg1);
+ super::RetrievePackedPathFromHeap(forward_heap1, reverse_heap1, middle1,
+ temporary_packed_leg1);
}
if (INVALID_EDGE_WEIGHT != local_upper_bound2)
{
- super::RetrievePackedPathFromHeap(
- forward_heap2, reverse_heap2, middle2, temporary_packed_leg2);
+ super::RetrievePackedPathFromHeap(forward_heap2, reverse_heap2, middle2,
+ temporary_packed_leg2);
}
// if one of the paths was not found, replace it with the other one.
- if ((allow_u_turn && local_upper_bound1 > local_upper_bound2) || temporary_packed_leg1.empty())
+ if ((allow_u_turn && local_upper_bound1 > local_upper_bound2) ||
+ temporary_packed_leg1.empty())
{
temporary_packed_leg1.clear();
temporary_packed_leg1.insert(temporary_packed_leg1.end(),
@@ -230,7 +234,8 @@ template <class DataFacadeT> class ShortestPathRouting final : public BasicRouti
temporary_packed_leg2.end());
local_upper_bound1 = local_upper_bound2;
}
- if ((allow_u_turn && local_upper_bound2 > local_upper_bound1) || temporary_packed_leg2.empty())
+ if ((allow_u_turn && local_upper_bound2 > local_upper_bound1) ||
+ temporary_packed_leg2.empty())
{
temporary_packed_leg2.clear();
temporary_packed_leg2.insert(temporary_packed_leg2.end(),
@@ -287,7 +292,8 @@ template <class DataFacadeT> class ShortestPathRouting final : public BasicRouti
temporary_packed_leg2.end());
BOOST_ASSERT(packed_legs2[current_leg].size() == temporary_packed_leg2.size());
- if (!allow_u_turn && (packed_legs1[current_leg].back() == packed_legs2[current_leg].back()) &&
+ if (!allow_u_turn &&
+ (packed_legs1[current_leg].back() == packed_legs2[current_leg].back()) &&
phantom_node_pair.target_phantom.is_bidirected())
{
const NodeID last_node_id = packed_legs2[current_leg].back();
@@ -298,8 +304,8 @@ template <class DataFacadeT> class ShortestPathRouting final : public BasicRouti
BOOST_ASSERT(search_from_1st_node != search_from_2nd_node);
}
- distance1 = local_upper_bound1;
- distance2 = local_upper_bound2;
+ distance1 += local_upper_bound1;
+ distance2 += local_upper_bound2;
++current_leg;
}
@@ -324,9 +330,11 @@ template <class DataFacadeT> class ShortestPathRouting final : public BasicRouti
raw_route_data.unpacked_path_segments[index]);
raw_route_data.source_traversed_in_reverse.push_back(
- (packed_legs1[index].front() != phantom_nodes_vector[index].source_phantom.forward_node_id));
+ (packed_legs1[index].front() !=
+ phantom_nodes_vector[index].source_phantom.forward_node_id));
raw_route_data.target_traversed_in_reverse.push_back(
- (packed_legs1[index].back() != phantom_nodes_vector[index].target_phantom.forward_node_id));
+ (packed_legs1[index].back() !=
+ phantom_nodes_vector[index].target_phantom.forward_node_id));
}
raw_route_data.shortest_path_length = std::min(distance1, distance2);
}
diff --git a/server/api_grammar.hpp b/server/api_grammar.hpp
new file mode 100644
index 0000000..a629cfb
--- /dev/null
+++ b/server/api_grammar.hpp
@@ -0,0 +1,101 @@
+/*
+
+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) >> -(uturns);
+ query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | timestamp | u | cmp |
+ language | instruction | geometry | alt_route | old_API | num_results |
+ matching_beta | gps_precision | classify));
+
+ 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)];
+ 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)];
+ 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::short_[boost::bind(&HandlerT::setMatchingBeta, handler, ::_1)];
+ gps_precision = (-qi::lit('&')) >> qi::lit("gps_precision") >> '=' >>
+ qi::short_[boost::bind(&HandlerT::setGPSPrecision, handler, ::_1)];
+ classify = (-qi::lit('&')) >> qi::lit("classify") >> '=' >>
+ qi::bool_[boost::bind(&HandlerT::setClassify, 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")));
+ }
+
+ qi::rule<Iterator> api_call, query;
+ qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location,
+ hint, timestamp, stringwithDot, stringwithPercent, language, instruction, geometry, cmp, alt_route, u,
+ uturns, old_API, num_results, matching_beta, gps_precision, classify;
+
+ HandlerT *handler;
+};
+
+#endif /* API_GRAMMAR_HPP */
diff --git a/Server/Connection.cpp b/server/connection.cpp
similarity index 60%
rename from Server/Connection.cpp
rename to server/connection.cpp
index 82402a6..41b653e 100644
--- a/Server/Connection.cpp
+++ b/server/connection.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,9 +25,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "Connection.h"
-#include "RequestHandler.h"
-#include "RequestParser.h"
+#include "connection.hpp"
+#include "request_handler.hpp"
+#include "request_parser.hpp"
#include <boost/assert.hpp>
#include <boost/bind.hpp>
@@ -52,8 +52,7 @@ void Connection::start()
{
TCP_socket.async_read_some(
boost::asio::buffer(incoming_data_buffer),
- strand.wrap(boost::bind(&Connection::handle_read,
- this->shared_from_this(),
+ strand.wrap(boost::bind(&Connection::handle_read, this->shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)));
}
@@ -66,19 +65,17 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
}
// no error detected, let's parse the request
- CompressionType compression_type(noCompression);
- boost::tribool result;
- boost::tie(result, boost::tuples::ignore) =
- RequestParser().Parse(request,
- incoming_data_buffer.data(),
- incoming_data_buffer.data() + bytes_transferred,
- compression_type);
+ compression_type compression_type(no_compression);
+ osrm::tribool 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)
+ if (result == osrm::tribool::yes)
{
- request.endpoint = TCP_socket.remote_endpoint().address();
- request_handler.handle_request(request, reply);
+ current_request.endpoint = TCP_socket.remote_endpoint().address();
+ request_handler.handle_request(current_request, current_reply);
// Header compression_header;
std::vector<char> compressed_output;
@@ -87,52 +84,51 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
// compress the result w/ gzip/deflate if requested
switch (compression_type)
{
- case deflateRFC1951:
+ case deflate_rfc1951:
// use deflate for compression
- reply.headers.insert(reply.headers.begin(), {"Content-Encoding", "deflate"});
- CompressBufferCollection(reply.content, compression_type, compressed_output);
- reply.SetSize(static_cast<unsigned>(compressed_output.size()));
- output_buffer = reply.HeaderstoBuffers();
+ current_reply.headers.insert(current_reply.headers.begin(),
+ {"Content-Encoding", "deflate"});
+ compressed_output = compress_buffers(current_reply.content, compression_type);
+ current_reply.set_size(static_cast<unsigned>(compressed_output.size()));
+ output_buffer = current_reply.headers_to_buffers();
output_buffer.push_back(boost::asio::buffer(compressed_output));
break;
- case gzipRFC1952:
+ case gzip_rfc1952:
// use gzip for compression
- reply.headers.insert(reply.headers.begin(), {"Content-Encoding", "gzip"});
- CompressBufferCollection(reply.content, compression_type, compressed_output);
- reply.SetSize(static_cast<unsigned>(compressed_output.size()));
- output_buffer = reply.HeaderstoBuffers();
+ current_reply.headers.insert(current_reply.headers.begin(),
+ {"Content-Encoding", "gzip"});
+ compressed_output = compress_buffers(current_reply.content, compression_type);
+ current_reply.set_size(static_cast<unsigned>(compressed_output.size()));
+ output_buffer = current_reply.headers_to_buffers();
output_buffer.push_back(boost::asio::buffer(compressed_output));
break;
- case noCompression:
+ case no_compression:
// don't use any compression
- reply.SetUncompressedSize();
- output_buffer = reply.ToBuffers();
+ current_reply.set_uncompressed_size();
+ output_buffer = current_reply.to_buffers();
break;
}
// write result to stream
- boost::asio::async_write(TCP_socket,
- output_buffer,
- strand.wrap(boost::bind(&Connection::handle_write,
- this->shared_from_this(),
- boost::asio::placeholders::error)));
+ boost::asio::async_write(
+ TCP_socket, output_buffer,
+ strand.wrap(boost::bind(&Connection::handle_write, this->shared_from_this(),
+ boost::asio::placeholders::error)));
}
- else if (!result)
+ else if (result == osrm::tribool::no)
{ // request is not parseable
- reply = Reply::StockReply(Reply::badRequest);
+ current_reply = reply::stock_reply(reply::bad_request);
- boost::asio::async_write(TCP_socket,
- reply.ToBuffers(),
- strand.wrap(boost::bind(&Connection::handle_write,
- this->shared_from_this(),
- boost::asio::placeholders::error)));
+ boost::asio::async_write(
+ TCP_socket, current_reply.to_buffers(),
+ strand.wrap(boost::bind(&Connection::handle_write, this->shared_from_this(),
+ boost::asio::placeholders::error)));
}
else
{
// we don't have a result yet, so continue reading
TCP_socket.async_read_some(
boost::asio::buffer(incoming_data_buffer),
- strand.wrap(boost::bind(&Connection::handle_read,
- this->shared_from_this(),
+ strand.wrap(boost::bind(&Connection::handle_read, this->shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)));
}
@@ -149,26 +145,27 @@ void Connection::handle_write(const boost::system::error_code &error)
}
}
-void Connection::CompressBufferCollection(std::vector<char> uncompressed_data,
- CompressionType compression_type,
- std::vector<char> &compressed_data)
+std::vector<char> Connection::compress_buffers(const std::vector<char> &uncompressed_data,
+ const 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 (deflateRFC1951 == compression_type)
+ if (deflate_rfc1951 == compression_type)
{
compression_parameters.noheader = true;
}
- BOOST_ASSERT(compressed_data.empty());
+ std::vector<char> compressed_data;
// plug data into boost's compression stream
boost::iostreams::filtering_ostream gzip_stream;
gzip_stream.push(boost::iostreams::gzip_compressor(compression_parameters));
gzip_stream.push(boost::iostreams::back_inserter(compressed_data));
gzip_stream.write(&uncompressed_data[0], uncompressed_data.size());
boost::iostreams::close(gzip_stream);
+
+ return compressed_data;
}
}
diff --git a/Server/Connection.h b/server/connection.hpp
similarity index 74%
rename from Server/Connection.h
rename to server/connection.hpp
index 41b06d3..9228a18 100644
--- a/Server/Connection.h
+++ b/server/connection.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,44 +25,34 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CONNECTION_H
-#define CONNECTION_H
+#ifndef CONNECTION_HPP
+#define CONNECTION_HPP
-// #include "RequestParser.h"
-#include "Http/CompressionType.h"
-#include "Http/Request.h"
-
-#include <osrm/Reply.h>
+#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>
+#include <memory>
+#include <vector>
-//workaround for incomplete std::shared_ptr compatibility in old boost versions
+// 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)
+namespace boost
{
- return p.get();
-}
+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();
-}
+template <class T> T *get_pointer(std::shared_ptr<T> &p) { return p.get(); }
} // namespace boost
#endif
-
-
class RequestHandler;
namespace http
@@ -87,18 +77,18 @@ class Connection : public std::enable_shared_from_this<Connection>
/// Handle completion of a write operation.
void handle_write(const boost::system::error_code &e);
- void CompressBufferCollection(std::vector<char> uncompressed_data,
- CompressionType compression_type,
- std::vector<char> &compressed_data);
+ 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 request;
- Reply reply;
+ request current_request;
+ reply current_reply;
};
} // namespace http
-#endif // CONNECTION_H
+#endif // CONNECTION_HPP
diff --git a/Server/DataStructures/BaseDataFacade.h b/server/data_structures/datafacade_base.hpp
similarity index 83%
rename from Server/DataStructures/BaseDataFacade.h
rename to server/data_structures/datafacade_base.hpp
index 3ea391c..20d0430 100644
--- a/Server/DataStructures/BaseDataFacade.h
+++ b/server/data_structures/datafacade_base.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef BASE_DATA_FACADE_H
-#define BASE_DATA_FACADE_H
+#ifndef DATAFACADE_BASE_HPP
+#define DATAFACADE_BASE_HPP
// Exposes all data access interfaces to the algorithms via base class ptr
@@ -34,22 +34,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#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 "../../util/integer_range.hpp"
+#include "../../util/osrm_exception.hpp"
+#include "../../util/string_util.hpp"
#include "../../typedefs.h"
-#include <osrm/Coordinate.h>
+#include <osrm/coordinate.hpp>
#include <string>
-typedef osrm::range<EdgeID> EdgeRange;
+using EdgeRange = osrm::range<EdgeID>;
template <class EdgeDataT> class BaseDataFacade
{
public:
- typedef EdgeBasedNode RTreeLeaf;
- typedef EdgeDataT EdgeData;
+ using RTreeLeaf = EdgeBasedNode;
+ using EdgeData = EdgeDataT;
BaseDataFacade() {}
virtual ~BaseDataFacade() {}
@@ -62,8 +62,6 @@ template <class EdgeDataT> class BaseDataFacade
virtual NodeID GetTarget(const EdgeID e) const = 0;
- // virtual EdgeDataT &GetEdgeData(const EdgeID e) = 0;
-
virtual const EdgeDataT &GetEdgeData(const EdgeID e) const = 0;
virtual EdgeID BeginEdges(const NodeID n) const = 0;
@@ -106,21 +104,20 @@ template <class EdgeDataT> class BaseDataFacade
virtual bool
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
PhantomNode &resulting_phantom_node) = 0;
+ virtual bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance(
+ const FixedPointCoordinate &input_coordinate,
+ std::vector<std::pair<PhantomNode, double>> &resulting_phantom_node_vector,
+ const double max_distance,
+ const unsigned min_number_of_phantom_nodes,
+ const unsigned max_number_of_phantom_nodes) = 0;
virtual unsigned GetCheckSum() const = 0;
virtual unsigned GetNameIndexFromEdgeID(const unsigned id) const = 0;
- virtual void GetName(const unsigned name_id, std::string &result) const = 0;
-
- std::string GetEscapedNameForNameID(const unsigned name_id) const
- {
- std::string temporary_string;
- GetName(name_id, temporary_string);
- return EscapeJSONString(temporary_string);
- }
+ virtual std::string get_name_for_id(const unsigned name_id) const = 0;
virtual std::string GetTimestamp() const = 0;
};
-#endif // BASE_DATA_FACADE_H
+#endif // DATAFACADE_BASE_HPP
diff --git a/Server/DataStructures/InternalDataFacade.h b/server/data_structures/internal_datafacade.hpp
similarity index 80%
rename from Server/DataStructures/InternalDataFacade.h
rename to server/data_structures/internal_datafacade.hpp
index d4f715c..823ac33 100644
--- a/Server/DataStructures/InternalDataFacade.h
+++ b/server/data_structures/internal_datafacade.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,12 +25,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef INTERNAL_DATA_FACADE
-#define INTERNAL_DATA_FACADE
+#ifndef INTERNAL_DATAFACADE_HPP
+#define INTERNAL_DATAFACADE_HPP
// implements all data storage when shared memory is _NOT_ used
-#include "BaseDataFacade.h"
+#include "datafacade_base.hpp"
#include "../../data_structures/original_edge_data.hpp"
#include "../../data_structures/query_node.hpp"
@@ -39,21 +39,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../../data_structures/static_graph.hpp"
#include "../../data_structures/static_rtree.hpp"
#include "../../data_structures/range_table.hpp"
-#include "../../Util/BoostFileSystemFix.h"
-#include "../../Util/graph_loader.hpp"
-#include "../../Util/simple_logger.hpp"
+#include "../../util/boost_filesystem_2_fix.hpp"
+#include "../../util/graph_loader.hpp"
+#include "../../util/simple_logger.hpp"
-#include <osrm/Coordinate.h>
-#include <osrm/ServerPaths.h>
+#include <osrm/coordinate.hpp>
+#include <osrm/server_paths.hpp>
-template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<EdgeDataT>
+#include <limits>
+
+template <class EdgeDataT> class InternalDataFacade final : public BaseDataFacade<EdgeDataT>
{
private:
- typedef BaseDataFacade<EdgeDataT> super;
- typedef StaticGraph<typename super::EdgeData> QueryGraph;
- typedef typename QueryGraph::InputEdge InputEdge;
- typedef typename super::RTreeLeaf RTreeLeaf;
+ using super = BaseDataFacade<EdgeDataT>;
+ using QueryGraph = StaticGraph<typename super::EdgeData>;
+ using InputEdge = typename QueryGraph::InputEdge;
+ using RTreeLeaf = typename super::RTreeLeaf;
InternalDataFacade() {}
@@ -309,94 +311,101 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
}
// search graph access
- unsigned GetNumberOfNodes() const final { return m_query_graph->GetNumberOfNodes(); }
-
- unsigned GetNumberOfEdges() const final { return m_query_graph->GetNumberOfEdges(); }
+ unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); }
- unsigned GetOutDegree(const NodeID n) const final { return m_query_graph->GetOutDegree(n); }
+ unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); }
- NodeID GetTarget(const EdgeID e) const final { return m_query_graph->GetTarget(e); }
+ unsigned GetOutDegree(const NodeID n) const override final
+ {
+ return m_query_graph->GetOutDegree(n);
+ }
- // EdgeDataT &GetEdgeData(const EdgeID e) final { return m_query_graph->GetEdgeData(e); }
+ NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
- EdgeDataT &GetEdgeData(const EdgeID e) const final { return m_query_graph->GetEdgeData(e); }
+ EdgeDataT &GetEdgeData(const EdgeID e) const override final
+ {
+ return m_query_graph->GetEdgeData(e);
+ }
- EdgeID BeginEdges(const NodeID n) const final { return m_query_graph->BeginEdges(n); }
+ EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); }
- EdgeID EndEdges(const NodeID n) const final { return m_query_graph->EndEdges(n); }
+ EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); }
- EdgeRange GetAdjacentEdgeRange(const NodeID node) const final
+ 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 final
+ 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 final
+ 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 final
+ 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 final
+ FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const override final
{
return m_coordinate_list->at(id);
};
- bool EdgeIsCompressed(const unsigned id) const { return m_edge_is_compressed.at(id); }
+ bool EdgeIsCompressed(const unsigned id) const override final
+ {
+ return m_edge_is_compressed.at(id);
+ }
- TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const final
+ TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const override final
{
return m_turn_instruction_list.at(id);
}
- TravelMode GetTravelModeForEdgeID(const unsigned id) const
+ TravelMode GetTravelModeForEdgeID(const unsigned id) const override final
{
- return m_travel_mode_list.at(id);
+ return m_travel_mode_list.at(id);
}
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
FixedPointCoordinate &result,
- const unsigned zoom_level = 18) final
+ const unsigned zoom_level = 18) override final
{
if (!m_static_rtree.get())
{
LoadRTree();
}
- return m_static_rtree->LocateClosestEndPointForCoordinate(
- input_coordinate, result, zoom_level);
+ return m_static_rtree->LocateClosestEndPointForCoordinate(input_coordinate, result,
+ zoom_level);
}
- bool
- IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
- PhantomNode &resulting_phantom_node) final
+ bool IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ PhantomNode &resulting_phantom_node) override final
{
std::vector<PhantomNode> resulting_phantom_node_vector;
auto result = IncrementalFindPhantomNodeForCoordinate(input_coordinate,
- resulting_phantom_node_vector,
- 1);
+ resulting_phantom_node_vector, 1);
if (result)
{
BOOST_ASSERT(!resulting_phantom_node_vector.empty());
resulting_phantom_node = resulting_phantom_node_vector.front();
}
+
return result;
}
bool
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
std::vector<PhantomNode> &resulting_phantom_node_vector,
- const unsigned number_of_results) final
+ const unsigned number_of_results) override final
{
if (!m_static_rtree.get())
{
@@ -407,49 +416,66 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
input_coordinate, resulting_phantom_node_vector, number_of_results);
}
- unsigned GetCheckSum() const final { return m_check_sum; }
+ bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance(
+ const FixedPointCoordinate &input_coordinate,
+ std::vector<std::pair<PhantomNode, double>> &resulting_phantom_node_vector,
+ const double max_distance,
+ const unsigned min_number_of_phantom_nodes,
+ const unsigned max_number_of_phantom_nodes) override final
+ {
+ if (!m_static_rtree.get())
+ {
+ LoadRTree();
+ }
- unsigned GetNameIndexFromEdgeID(const unsigned id) const final
+ return m_static_rtree->IncrementalFindPhantomNodeForCoordinateWithDistance(
+ input_coordinate, resulting_phantom_node_vector, max_distance,
+ min_number_of_phantom_nodes, max_number_of_phantom_nodes);
+ }
+
+ unsigned GetCheckSum() const override final { return m_check_sum; }
+
+ unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
{
return m_name_ID_list.at(id);
- };
+ }
- void GetName(const unsigned name_id, std::string &result) const final
+ std::string get_name_for_id(const unsigned name_id) const override final
{
- if (UINT_MAX == name_id)
+ if (std::numeric_limits<unsigned>::max() == name_id)
{
- result = "";
- return;
+ return "";
}
auto range = m_name_table.GetRange(name_id);
- result.clear();
+ 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());
+ m_names_char_list.begin() + range.back() + 1, result.begin());
}
+ return result;
}
- virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const final
+ virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const override final
{
return m_via_node_list.at(id);
}
virtual void GetUncompressedGeometry(const unsigned id,
- std::vector<unsigned> &result_nodes) const final
+ 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);
+ result_nodes.insert(result_nodes.begin(), m_geometry_list.begin() + begin,
+ m_geometry_list.begin() + end);
}
- std::string GetTimestamp() const final { return m_timestamp; }
+ std::string GetTimestamp() const override final { return m_timestamp; }
};
-#endif // INTERNAL_DATA_FACADE
+#endif // INTERNAL_DATAFACADE_HPP
diff --git a/Server/DataStructures/SharedBarriers.h b/server/data_structures/shared_barriers.hpp
similarity index 94%
rename from Server/DataStructures/SharedBarriers.h
rename to server/data_structures/shared_barriers.hpp
index 36ba08b..e6f1234 100644
--- a/Server/DataStructures/SharedBarriers.h
+++ b/server/data_structures/shared_barriers.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SHARED_BARRIER_H
-#define SHARED_BARRIER_H
+#ifndef SHARED_BARRIERS_HPP
+#define SHARED_BARRIERS_HPP
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/named_condition.hpp>
@@ -57,4 +57,4 @@ struct SharedBarriers
int number_of_queries;
};
-#endif // SHARED_BARRIER_H
+#endif // SHARED_BARRIERS_HPP
diff --git a/Server/DataStructures/SharedDataFacade.h b/server/data_structures/shared_datafacade.hpp
similarity index 75%
rename from Server/DataStructures/SharedDataFacade.h
rename to server/data_structures/shared_datafacade.hpp
index 9120f82..b156423 100644
--- a/Server/DataStructures/SharedDataFacade.h
+++ b/server/data_structures/shared_datafacade.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,36 +25,37 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SHARED_DATA_FACADE_H
-#define SHARED_DATA_FACADE_H
+#ifndef SHARED_DATAFACADE_HPP
+#define SHARED_DATAFACADE_HPP
// implements all data storage when shared memory _IS_ used
-#include "BaseDataFacade.h"
-#include "SharedDataType.h"
+#include "datafacade_base.hpp"
+#include "shared_datatype.hpp"
#include "../../data_structures/range_table.hpp"
#include "../../data_structures/static_graph.hpp"
#include "../../data_structures/static_rtree.hpp"
-#include "../../Util/BoostFileSystemFix.h"
-#include "../../Util/make_unique.hpp"
-#include "../../Util/simple_logger.hpp"
+#include "../../util/boost_filesystem_2_fix.hpp"
+#include "../../util/make_unique.hpp"
+#include "../../util/simple_logger.hpp"
#include <algorithm>
+#include <limits>
#include <memory>
-template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDataT>
+template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<EdgeDataT>
{
private:
- typedef EdgeDataT EdgeData;
- typedef BaseDataFacade<EdgeData> super;
- typedef StaticGraph<EdgeData, true> QueryGraph;
- typedef typename StaticGraph<EdgeData, true>::NodeArrayEntry GraphNode;
- typedef typename StaticGraph<EdgeData, true>::EdgeArrayEntry GraphEdge;
- typedef typename RangeTable<16, true>::BlockT NameIndexBlock;
- typedef typename QueryGraph::InputEdge InputEdge;
- typedef typename super::RTreeLeaf RTreeLeaf;
+ 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 TimeStampedRTreePair = std::pair<unsigned, std::shared_ptr<SharedRTree>>;
using RTreeNode = typename SharedRTree::TreeNode;
@@ -112,12 +113,11 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
RTreeNode *tree_ptr =
data_layout->GetBlockPtr<RTreeNode>(shared_memory, SharedDataLayout::R_SEARCH_TREE);
- m_static_rtree.reset(new TimeStampedRTreePair(CURRENT_TIMESTAMP,
+ 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)));
+ tree_ptr, data_layout->num_entries[SharedDataLayout::R_SEARCH_TREE],
+ file_index_path, m_coordinate_list)));
}
void LoadGraph()
@@ -143,11 +143,10 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
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);
+ 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]);
+ 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>(
@@ -259,7 +258,7 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
{
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?");
+ "Is any data loaded into shared memory?");
}
LoadGraph();
@@ -284,111 +283,117 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
}
// search graph access
- unsigned GetNumberOfNodes() const final { return m_query_graph->GetNumberOfNodes(); }
+ unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); }
- unsigned GetNumberOfEdges() const final { return m_query_graph->GetNumberOfEdges(); }
+ unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); }
- unsigned GetOutDegree(const NodeID n) const final { return m_query_graph->GetOutDegree(n); }
+ unsigned GetOutDegree(const NodeID n) const override final
+ {
+ return m_query_graph->GetOutDegree(n);
+ }
- NodeID GetTarget(const EdgeID e) const final { return m_query_graph->GetTarget(e); }
+ NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
- EdgeDataT &GetEdgeData(const EdgeID e) const final { return m_query_graph->GetEdgeData(e); }
+ EdgeDataT &GetEdgeData(const EdgeID e) const override final
+ {
+ return m_query_graph->GetEdgeData(e);
+ }
- EdgeID BeginEdges(const NodeID n) const final { return m_query_graph->BeginEdges(n); }
+ EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); }
- EdgeID EndEdges(const NodeID n) const final { return m_query_graph->EndEdges(n); }
+ EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); }
- EdgeRange GetAdjacentEdgeRange(const NodeID node) const final
+ 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 final
+ 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 final
+ 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 final
+ 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 final
+ FixedPointCoordinate GetCoordinateOfNode(const NodeID id) const override final
{
return m_coordinate_list->at(id);
};
- virtual bool EdgeIsCompressed(const unsigned id) const final
+ 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 final
+ 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);
+ result_nodes.insert(result_nodes.begin(), m_geometry_list.begin() + begin,
+ m_geometry_list.begin() + end);
}
- virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const final
+ virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const override final
{
return m_via_node_list.at(id);
}
- TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const final
+ TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const override final
{
return m_turn_instruction_list.at(id);
}
- TravelMode GetTravelModeForEdgeID(const unsigned id) const
+ TravelMode GetTravelModeForEdgeID(const unsigned id) const override final
{
return m_travel_mode_list.at(id);
}
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
FixedPointCoordinate &result,
- const unsigned zoom_level = 18) final
+ const unsigned zoom_level = 18) override final
{
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
{
LoadRTree();
}
- return m_static_rtree->second->LocateClosestEndPointForCoordinate(
- input_coordinate, result, zoom_level);
+ return m_static_rtree->second->LocateClosestEndPointForCoordinate(input_coordinate, result,
+ zoom_level);
}
- bool
- IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
- PhantomNode &resulting_phantom_node) final
+ bool IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ PhantomNode &resulting_phantom_node) override final
{
std::vector<PhantomNode> resulting_phantom_node_vector;
auto result = IncrementalFindPhantomNodeForCoordinate(input_coordinate,
- resulting_phantom_node_vector,
- 1);
+ resulting_phantom_node_vector, 1);
if (result)
{
BOOST_ASSERT(!resulting_phantom_node_vector.empty());
resulting_phantom_node = resulting_phantom_node_vector.front();
}
+
return result;
}
bool
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
std::vector<PhantomNode> &resulting_phantom_node_vector,
- const unsigned number_of_results) final
+ const unsigned number_of_results) override final
{
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
{
@@ -399,33 +404,50 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
input_coordinate, resulting_phantom_node_vector, number_of_results);
}
- unsigned GetCheckSum() const final { return m_check_sum; }
+ bool IncrementalFindPhantomNodeForCoordinateWithMaxDistance(
+ const FixedPointCoordinate &input_coordinate,
+ std::vector<std::pair<PhantomNode, double>> &resulting_phantom_node_vector,
+ const double max_distance,
+ const unsigned min_number_of_phantom_nodes,
+ const unsigned max_number_of_phantom_nodes) override final
+ {
+ if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+ {
+ LoadRTree();
+ }
+
+ return m_static_rtree->second->IncrementalFindPhantomNodeForCoordinateWithDistance(
+ input_coordinate, resulting_phantom_node_vector, max_distance,
+ min_number_of_phantom_nodes, max_number_of_phantom_nodes);
+ }
+
+ unsigned GetCheckSum() const override final { return m_check_sum; }
- unsigned GetNameIndexFromEdgeID(const unsigned id) const final
+ unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
{
return m_name_ID_list.at(id);
};
- void GetName(const unsigned name_id, std::string &result) const final
+ std::string get_name_for_id(const unsigned name_id) const override final
{
- if (UINT_MAX == name_id)
+ if (std::numeric_limits<unsigned>::max() == name_id)
{
- result = "";
- return;
+ return "";
}
auto range = m_name_table->GetRange(name_id);
- result.clear();
+ 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());
+ m_names_char_list.begin() + range.back() + 1, result.begin());
}
+ return result;
}
- std::string GetTimestamp() const final { return m_timestamp; }
+ std::string GetTimestamp() const override final { return m_timestamp; }
};
-#endif // SHARED_DATA_FACADE_H
+#endif // SHARED_DATAFACADE_HPP
diff --git a/Server/DataStructures/SharedDataType.h b/server/data_structures/shared_datatype.hpp
similarity index 52%
rename from Server/DataStructures/SharedDataType.h
rename to server/data_structures/shared_datatype.hpp
index 6357fd7..3261573 100644
--- a/Server/DataStructures/SharedDataType.h
+++ b/server/data_structures/shared_datatype.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,22 +25,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SHARED_DATA_TYPE_H_
-#define SHARED_DATA_TYPE_H_
+#ifndef SHARED_DATA_TYPE_HPP
+#define SHARED_DATA_TYPE_HPP
-#include "../../Util/osrm_exception.hpp"
-#include "../../Util/simple_logger.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 {
+ enum BlockID
+ {
NAME_OFFSETS = 0,
NAME_BLOCKS,
NAME_CHAR_LIST,
@@ -64,54 +68,81 @@ struct SharedDataLayout
std::array<uint64_t, NUM_BLOCKS> num_entries;
std::array<uint64_t, NUM_BLOCKS> entry_size;
- SharedDataLayout()
- : num_entries()
- , entry_size()
- {
- }
+ SharedDataLayout() : num_entries(), entry_size() {}
void PrintInformation() const
{
SimpleLogger().Write(logDEBUG) << "-";
- SimpleLogger().Write(logDEBUG) << "name_offsets_size: " << num_entries[NAME_OFFSETS];
- SimpleLogger().Write(logDEBUG) << "name_blocks_size: " << num_entries[NAME_BLOCKS];
- SimpleLogger().Write(logDEBUG) << "name_char_list_size: " << num_entries[NAME_CHAR_LIST];
- SimpleLogger().Write(logDEBUG) << "name_id_list_size: " << num_entries[NAME_ID_LIST];
- SimpleLogger().Write(logDEBUG) << "via_node_list_size: " << num_entries[VIA_NODE_LIST];
- SimpleLogger().Write(logDEBUG) << "graph_node_list_size: " << num_entries[GRAPH_NODE_LIST];
- SimpleLogger().Write(logDEBUG) << "graph_edge_list_size: " << num_entries[GRAPH_EDGE_LIST];
+ SimpleLogger().Write(logDEBUG)
+ << "name_offsets_size: " << num_entries[NAME_OFFSETS];
+ SimpleLogger().Write(logDEBUG)
+ << "name_blocks_size: " << num_entries[NAME_BLOCKS];
+ SimpleLogger().Write(logDEBUG)
+ << "name_char_list_size: " << num_entries[NAME_CHAR_LIST];
+ SimpleLogger().Write(logDEBUG)
+ << "name_id_list_size: " << num_entries[NAME_ID_LIST];
+ SimpleLogger().Write(logDEBUG)
+ << "via_node_list_size: " << num_entries[VIA_NODE_LIST];
+ SimpleLogger().Write(logDEBUG)
+ << "graph_node_list_size: " << num_entries[GRAPH_NODE_LIST];
+ SimpleLogger().Write(logDEBUG)
+ << "graph_edge_list_size: " << num_entries[GRAPH_EDGE_LIST];
SimpleLogger().Write(logDEBUG) << "timestamp_length: " << num_entries[TIMESTAMP];
- SimpleLogger().Write(logDEBUG) << "coordinate_list_size: " << num_entries[COORDINATE_LIST];
- SimpleLogger().Write(logDEBUG) << "turn_instruction_list_size: " << num_entries[TURN_INSTRUCTION];
- SimpleLogger().Write(logDEBUG) << "travel_mode_list_size: " << num_entries[TRAVEL_MODE];
- SimpleLogger().Write(logDEBUG) << "r_search_tree_size: " << num_entries[R_SEARCH_TREE];
- SimpleLogger().Write(logDEBUG) << "geometries_indicators: " << num_entries[GEOMETRIES_INDICATORS]
- << "/" << ((num_entries[GEOMETRIES_INDICATORS] / 8) + 1);
- SimpleLogger().Write(logDEBUG) << "geometries_index_list_size: " << num_entries[GEOMETRIES_INDEX];
- SimpleLogger().Write(logDEBUG) << "geometries_list_size: " << num_entries[GEOMETRIES_LIST];
- SimpleLogger().Write(logDEBUG) << "sizeof(checksum): " << entry_size[HSGR_CHECKSUM];
-
- 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)
+ << "coordinate_list_size: " << num_entries[COORDINATE_LIST];
+ SimpleLogger().Write(logDEBUG)
+ << "turn_instruction_list_size: " << num_entries[TURN_INSTRUCTION];
+ SimpleLogger().Write(logDEBUG)
+ << "travel_mode_list_size: " << num_entries[TRAVEL_MODE];
+ SimpleLogger().Write(logDEBUG)
+ << "r_search_tree_size: " << num_entries[R_SEARCH_TREE];
+ SimpleLogger().Write(logDEBUG)
+ << "geometries_indicators: " << num_entries[GEOMETRIES_INDICATORS] << "/"
+ << ((num_entries[GEOMETRIES_INDICATORS] / 8) + 1);
+ SimpleLogger().Write(logDEBUG)
+ << "geometries_index_list_size: " << num_entries[GEOMETRIES_INDEX];
+ SimpleLogger().Write(logDEBUG)
+ << "geometries_list_size: " << num_entries[GEOMETRIES_LIST];
+ SimpleLogger().Write(logDEBUG)
+ << "sizeof(checksum): " << entry_size[HSGR_CHECKSUM];
+
+ 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);
}
- template<typename T>
- inline void SetBlockSize(BlockID bid, uint64_t entries)
+ template <typename T> inline void SetBlockSize(BlockID bid, uint64_t entries)
{
num_entries[bid] = entries;
entry_size[bid] = sizeof(T);
@@ -122,7 +153,8 @@ struct SharedDataLayout
// special encoding
if (bid == GEOMETRIES_INDICATORS)
{
- return (num_entries[GEOMETRIES_INDICATORS]/32 + 1) * entry_size[GEOMETRIES_INDICATORS];
+ return (num_entries[GEOMETRIES_INDICATORS] / 32 + 1) *
+ entry_size[GEOMETRIES_INDICATORS];
}
return num_entries[bid] * entry_size[bid];
@@ -130,7 +162,7 @@ struct SharedDataLayout
inline uint64_t GetSizeOfLayout() const
{
- return GetBlockOffset(NUM_BLOCKS) + NUM_BLOCKS*2*sizeof(CANARY);
+ return GetBlockOffset(NUM_BLOCKS) + NUM_BLOCKS * 2 * sizeof(CANARY);
}
inline uint64_t GetBlockOffset(BlockID bid) const
@@ -138,26 +170,26 @@ struct SharedDataLayout
uint64_t result = sizeof(CANARY);
for (auto i = 0; i < bid; i++)
{
- result += GetBlockSize((BlockID) i) + 2*sizeof(CANARY);
+ result += GetBlockSize((BlockID)i) + 2 * sizeof(CANARY);
}
return result;
}
- template<typename T, bool WRITE_CANARY=false>
- inline T* GetBlockPtr(char* shared_memory, BlockID bid)
+ template <typename T, bool WRITE_CANARY = false>
+ inline T *GetBlockPtr(char *shared_memory, BlockID bid)
{
- T* ptr = (T*)(shared_memory + GetBlockOffset(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);
+ 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);
+ 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)
@@ -175,13 +207,15 @@ struct SharedDataLayout
};
enum SharedDataType
-{ CURRENT_REGIONS,
- LAYOUT_1,
- DATA_1,
- LAYOUT_2,
- DATA_2,
- LAYOUT_NONE,
- DATA_NONE };
+{
+ CURRENT_REGIONS,
+ LAYOUT_1,
+ DATA_1,
+ LAYOUT_2,
+ DATA_2,
+ LAYOUT_NONE,
+ DATA_NONE
+};
struct SharedDataTimestamp
{
@@ -190,4 +224,4 @@ struct SharedDataTimestamp
unsigned timestamp;
};
-#endif /* SHARED_DATA_TYPE_H_ */
+#endif /* SHARED_DATA_TYPE_HPP */
diff --git a/Server/Http/CompressionType.h b/server/http/compression_type.hpp
similarity index 85%
rename from Server/Http/CompressionType.h
rename to server/http/compression_type.hpp
index 3836cd7..f0dc692 100644
--- a/Server/Http/CompressionType.h
+++ b/server/http/compression_type.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,17 +25,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef COMPRESSION_TYPE_H
-#define COMPRESSION_TYPE_H
+#ifndef COMPRESSION_TYPE_HPP
+#define COMPRESSION_TYPE_HPP
namespace http
{
-enum CompressionType
-{ noCompression,
- gzipRFC1952,
- deflateRFC1951 };
-
+enum compression_type
+{
+ no_compression,
+ gzip_rfc1952,
+ deflate_rfc1951
+};
}
-#endif // COMPRESSION_TYPE_H
+#endif // COMPRESSION_TYPE_HPP
diff --git a/Include/osrm/Header.h b/server/http/header.hpp
similarity index 76%
rename from Include/osrm/Header.h
rename to server/http/header.hpp
index d126c4c..08d2476 100644
--- a/Include/osrm/Header.h
+++ b/server/http/header.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,21 +25,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTTP_HEADER_H
-#define HTTP_HEADER_H
+#ifndef HEADER_HPP
+#define HEADER_HPP
#include <string>
#include <algorithm>
namespace http
{
-struct Header
+struct header
{
- Header& operator=(const Header& other) = default;
- Header(const std::string & name, const std::string & value) : name(name), value(value) {}
- Header(Header && other) : name(std::move(other.name)), value(std::move(other.value)) {}
+ // explicitly use default copy c'tor as adding move c'tor
+ header &operator=(const header &other) = default;
+ header(const std::string &name, const std::string &value) : name(name), value(value) {}
+ header(header &&other) : name(std::move(other.name)), value(std::move(other.value)) {}
- void Clear()
+ void clear()
{
name.clear();
value.clear();
@@ -50,4 +51,4 @@ struct Header
};
}
-#endif // HTTP_HEADER_H
+#endif // HEADER_HPP
diff --git a/Server/Http/Reply.cpp b/server/http/reply.cpp
similarity index 59%
rename from Server/Http/Reply.cpp
rename to server/http/reply.cpp
index e2cf0ae..036d1ae 100644
--- a/Server/Http/Reply.cpp
+++ b/server/http/reply.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <osrm/Reply.h>
+#include "reply.hpp"
-#include "../../Util/cast.hpp"
+#include "../../util/cast.hpp"
namespace http
{
-void Reply::SetSize(const unsigned size)
+const char ok_html[] = "";
+const char bad_request_html[] = "{\"status\": 400,\"status_message\":\"Bad Request\"}";
+const char internal_server_error_html[] =
+ "{\"status\": 500,\"status_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";
+const std::string http_bad_request_string = "HTTP/1.0 400 Bad Request\r\n";
+const std::string http_internal_server_error_string = "HTTP/1.0 500 Internal Server Error\r\n";
+
+void reply::set_size(const std::size_t size)
{
- for (Header &h : headers)
+ for (header &h : headers)
{
if ("Content-Length" == h.name)
{
@@ -43,14 +53,13 @@ void Reply::SetSize(const unsigned size)
}
}
-// Sets the size of the uncompressed output.
-void Reply::SetUncompressedSize() { SetSize(static_cast<unsigned>(content.size())); }
+void reply::set_uncompressed_size() { set_size(content.size()); }
-std::vector<boost::asio::const_buffer> Reply::ToBuffers()
+std::vector<boost::asio::const_buffer> reply::to_buffers()
{
std::vector<boost::asio::const_buffer> buffers;
- buffers.push_back(ToBuffer(status));
- for (const Header &h : headers)
+ buffers.push_back(status_to_buffer(status));
+ for (const header &h : headers)
{
buffers.push_back(boost::asio::buffer(h.name));
buffers.push_back(boost::asio::buffer(seperators));
@@ -62,13 +71,12 @@ std::vector<boost::asio::const_buffer> Reply::ToBuffers()
return buffers;
}
-std::vector<boost::asio::const_buffer> Reply::HeaderstoBuffers()
+std::vector<boost::asio::const_buffer> reply::headers_to_buffers()
{
std::vector<boost::asio::const_buffer> buffers;
- buffers.push_back(ToBuffer(status));
- for (std::size_t i = 0; i < headers.size(); ++i)
+ buffers.push_back(status_to_buffer(status));
+ for (const header ¤t_header : headers)
{
- Header ¤t_header = headers[i];
buffers.push_back(boost::asio::buffer(current_header.name));
buffers.push_back(boost::asio::buffer(seperators));
buffers.push_back(boost::asio::buffer(current_header.value));
@@ -78,13 +86,13 @@ std::vector<boost::asio::const_buffer> Reply::HeaderstoBuffers()
return buffers;
}
-Reply Reply::StockReply(Reply::status_type status)
+reply reply::stock_reply(const reply::status_type status)
{
- Reply reply;
+ reply reply;
reply.status = status;
reply.content.clear();
- const std::string status_string = reply.ToString(status);
+ const std::string status_string = reply.status_to_string(status);
reply.content.insert(reply.content.end(), status_string.begin(), status_string.end());
reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
reply.headers.emplace_back("Content-Length", cast::integral_to_string(reply.content.size()));
@@ -92,31 +100,31 @@ Reply Reply::StockReply(Reply::status_type status)
return reply;
}
-std::string Reply::ToString(Reply::status_type status)
+std::string reply::status_to_string(const reply::status_type status)
{
- if (Reply::ok == status)
+ if (reply::ok == status)
{
- return okHTML;
+ return ok_html;
}
- if (Reply::badRequest == status)
+ if (reply::bad_request == status)
{
- return badRequestHTML;
+ return bad_request_html;
}
- return internalServerErrorHTML;
+ return internal_server_error_html;
}
-boost::asio::const_buffer Reply::ToBuffer(Reply::status_type status)
+boost::asio::const_buffer reply::status_to_buffer(const reply::status_type status)
{
- if (Reply::ok == status)
+ if (reply::ok == status)
{
- return boost::asio::buffer(okString);
+ return boost::asio::buffer(http_ok_string);
}
- if (Reply::internalServerError == status)
+ if (reply::internal_server_error == status)
{
- return boost::asio::buffer(internalServerErrorString);
+ return boost::asio::buffer(http_internal_server_error_string);
}
- return boost::asio::buffer(badRequestString);
+ return boost::asio::buffer(http_bad_request_string);
}
-Reply::Reply() : status(ok) {}
+reply::reply() : status(ok) {}
}
diff --git a/Server/Http/Request.h b/server/http/reply.hpp
similarity index 63%
copy from Server/Http/Request.h
copy to server/http/reply.hpp
index 4746a5e..733818c 100644
--- a/Server/Http/Request.h
+++ b/server/http/reply.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,24 +25,41 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef REQUEST_H
-#define REQUEST_H
+#ifndef REPLY_HPP
+#define REPLY_HPP
+
+#include "header.hpp"
#include <boost/asio.hpp>
-#include <string>
+#include <vector>
namespace http
{
-
-struct Request
+class reply
{
- std::string uri;
- std::string referrer;
- std::string agent;
- boost::asio::ip::address endpoint;
-};
+ public:
+ enum status_type
+ {
+ ok = 200,
+ bad_request = 400,
+ internal_server_error = 500
+ } status;
-} // namespace http
+ 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 // REQUEST_H
+#endif // REPLY_HPP
diff --git a/Server/Http/Request.h b/server/http/request.hpp
similarity index 92%
rename from Server/Http/Request.h
rename to server/http/request.hpp
index 4746a5e..c487fba 100644
--- a/Server/Http/Request.h
+++ b/server/http/request.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef REQUEST_H
-#define REQUEST_H
+#ifndef REQUEST_HPP
+#define REQUEST_HPP
#include <boost/asio.hpp>
@@ -35,7 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace http
{
-struct Request
+struct request
{
std::string uri;
std::string referrer;
@@ -45,4 +45,4 @@ struct Request
} // namespace http
-#endif // REQUEST_H
+#endif // REQUEST_HPP
diff --git a/server/request_handler.cpp b/server/request_handler.cpp
new file mode 100644
index 0000000..d1c6e62
--- /dev/null
+++ b/server/request_handler.cpp
@@ -0,0 +1,175 @@
+/*
+
+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 "../library/osrm.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 <ctime>
+
+#include <algorithm>
+#include <iostream>
+
+RequestHandler::RequestHandler() : routing_machine(nullptr) {}
+
+void RequestHandler::handle_request(const http::request ¤t_request,
+ http::reply ¤t_reply)
+{
+ // 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);
+
+ osrm::json::Object json_result;
+ // check if the was an error with the request
+ if (!result || (api_iterator != request_string.end()))
+ {
+ current_reply = http::reply::stock_reply(http::reply::bad_request);
+ current_reply.content.clear();
+ const auto position = std::distance(request_string.begin(), api_iterator);
+
+ json_result.values["status"] = 400;
+ std::string message = "Query string malformed close to position ";
+ message += cast::integral_to_string(position);
+ json_result.values["status_message"] = message;
+ osrm::json::render(current_reply.content, json_result);
+ return;
+ }
+
+ // 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 auto return_code = routing_machine->RunQuery(route_parameters, json_result);
+ if (200 != return_code)
+ {
+ current_reply = http::reply::stock_reply(http::reply::bad_request);
+ current_reply.content.clear();
+ json_result.values["status"] = 400;
+ std::string message = "Bad Request";
+ json_result.values["status_message"] = message;
+ osrm::json::render(current_reply.content, json_result);
+ return;
+ }
+
+ 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",
+ cast::integral_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;
+ return;
+ }
+}
+
+void RequestHandler::RegisterRoutingMachine(OSRM *osrm) { routing_machine = osrm; }
diff --git a/Server/RequestHandler.h b/server/request_handler.hpp
similarity index 86%
rename from Server/RequestHandler.h
rename to server/request_handler.hpp
index 7263dad..b4019db 100644
--- a/Server/RequestHandler.h
+++ b/server/request_handler.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef REQUEST_HANDLER_H
-#define REQUEST_HANDLER_H
+#ifndef REQUEST_HANDLER_HPP
+#define REQUEST_HANDLER_HPP
#include <string>
@@ -36,8 +36,8 @@ class OSRM;
namespace http
{
-class Reply;
-struct Request;
+class reply;
+struct request;
}
class RequestHandler
@@ -49,11 +49,11 @@ class RequestHandler
RequestHandler();
RequestHandler(const RequestHandler &) = delete;
- void handle_request(const http::Request &req, http::Reply &rep);
+ void handle_request(const http::request ¤t_request, http::reply ¤t_reply);
void RegisterRoutingMachine(OSRM *osrm);
private:
OSRM *routing_machine;
};
-#endif // REQUEST_HANDLER_H
+#endif // REQUEST_HANDLER_HPP
diff --git a/server/request_parser.cpp b/server/request_parser.cpp
new file mode 100644
index 0000000..584dcbe
--- /dev/null
+++ b/server/request_parser.cpp
@@ -0,0 +1,323 @@
+/*
+
+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)
+{
+}
+
+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;
+ 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;
+ }
+ state = internal_state::method;
+ 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 (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;
+ default: // expecting_newline_3
+ 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/RequestParser.h b/server/request_parser.hpp
similarity index 51%
rename from Server/RequestParser.h
rename to server/request_parser.hpp
index 7f302a2..2b6bf69 100644
--- a/Server/RequestParser.h
+++ b/server/request_parser.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,66 +25,68 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef REQUEST_PARSER_H
-#define REQUEST_PARSER_H
+#ifndef REQUEST_PARSER_HPP
+#define REQUEST_PARSER_HPP
-#include "Http/CompressionType.h"
-#include <osrm/Header.h>
+#include "http/compression_type.hpp"
+#include "http/header.hpp"
+#include "../data_structures/tribool.hpp"
-#include <boost/logic/tribool.hpp>
-#include <boost/tuple/tuple.hpp>
+#include <tuple>
namespace http
{
-struct Request;
+struct request;
class RequestParser
{
public:
RequestParser();
- void Reset();
- boost::tuple<boost::tribool, char *>
- Parse(Request &req, char *begin, char *end, CompressionType &compression_type);
+ std::tuple<osrm::tribool, compression_type>
+ parse(request ¤t_request, char *begin, char *end);
private:
- boost::tribool consume(Request &req, char input, CompressionType &compression_type);
-
- inline bool isChar(int c);
-
- inline bool isCTL(int c);
-
- inline bool isTSpecial(int c);
-
- inline bool isDigit(int c);
-
- enum state
- { 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_;
-
- Header header;
+ 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
+ } state;
+
+ header current_header;
+ compression_type selected_compression;
};
} // namespace http
-#endif // REQUEST_PARSER_H
+#endif // REQUEST_PARSER_HPP
diff --git a/Server/Server.h b/server/server.hpp
similarity index 90%
rename from Server/Server.h
rename to server/server.hpp
index 8e0b101..0ec3163 100644
--- a/Server/Server.h
+++ b/server/server.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,15 +25,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SERVER_H
-#define SERVER_H
+#ifndef SERVER_HPP
+#define SERVER_HPP
-#include "Connection.h"
-#include "RequestHandler.h"
+#include "connection.hpp"
+#include "request_handler.hpp"
-#include "../Util/cast.hpp"
-#include "../Util/make_unique.hpp"
-#include "../Util/simple_logger.hpp"
+#include "../util/cast.hpp"
+#include "../util/integer_range.hpp"
+#include "../util/simple_logger.hpp"
#include <boost/asio.hpp>
#include <boost/bind.hpp>
@@ -48,9 +48,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
class Server
{
public:
-
// Note: returns a shared instead of a unique ptr as it is captured in a lambda somewhere else
- static std::shared_ptr<Server> CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads)
+ 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();
const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
@@ -60,7 +60,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)), request_handler()
+ new_connection(std::make_shared<http::Connection>(io_service, request_handler))
{
const std::string port_string = cast::integral_to_string(port);
@@ -116,4 +116,4 @@ class Server
RequestHandler request_handler;
};
-#endif // SERVER_H
+#endif // SERVER_HPP
diff --git a/third_party/libosmium/.gitignore b/third_party/libosmium/.gitignore
new file mode 100644
index 0000000..5013903
--- /dev/null
+++ b/third_party/libosmium/.gitignore
@@ -0,0 +1,2 @@
+*.swp
+.ycm_extra_conf.pyc
diff --git a/third_party/libosmium/.travis.yml b/third_party/libosmium/.travis.yml
new file mode 100644
index 0000000..73dff72
--- /dev/null
+++ b/third_party/libosmium/.travis.yml
@@ -0,0 +1,51 @@
+#-----------------------------------------------------------------------------
+#
+# Configuration for continuous integration service at travis-ci.org
+#
+#-----------------------------------------------------------------------------
+
+language: cpp
+
+compiler:
+ - gcc
+ - clang
+
+env:
+ - CONFIGURATION=Dev
+ - CONFIGURATION=Release
+
+before_install:
+ # we need at least g++-4.8 for c++11 features
+ - sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test
+ - sudo apt-get update --yes --quiet
+
+install:
+ - cd ..
+ # upgrade compilers
+ - sudo apt-get install --yes gcc-4.8 g++-4.8
+ # make sure 'cpp' is the just installed current one
+ - sudo rm /usr/bin/cpp
+ - sudo ln -s /usr/bin/cpp-4.8 /usr/bin/cpp
+ # upgrade libosmium dependencies
+ - sudo apt-get install --yes make libboost-dev libboost-program-options-dev libsparsehash-dev libprotobuf-dev protobuf-compiler libgeos++-dev libproj-dev libgdal1h libgdal-dev
+ - git clone https://github.com/osmcode/osm-testdata.git
+ # OSMPBF is too old, install from git
+ #- sudo apt-get install --yes libosmpbf-dev
+ - git clone https://github.com/scrosby/OSM-binary.git
+ - cd OSM-binary/src
+ - make
+ - sudo make install
+ - cd ../..
+ - cd libosmium
+
+before_script:
+ - true
+
+script:
+ - if [ "${CXX}" = 'g++' ]; then export CXX=g++-4.8; fi;
+ - mkdir build
+ - cd build
+ - cmake -LA -DCMAKE_BUILD_TYPE=${CONFIGURATION} ..
+ - make VERBOSE=1
+ - ctest --output-on-failure
+
diff --git a/third_party/libosmium/.ycm_extra_conf.py b/third_party/libosmium/.ycm_extra_conf.py
new file mode 100644
index 0000000..2b87306
--- /dev/null
+++ b/third_party/libosmium/.ycm_extra_conf.py
@@ -0,0 +1,48 @@
+#-----------------------------------------------------------------------------
+#
+# 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',
+'-Wno-return-type',
+'-Wno-unused-parameter',
+'-Wno-unused-variable',
+
+'-std=c++11',
+
+# '-x' and 'c++' also required
+# use 'c' for C projects
+'-x',
+'c++',
+
+# libosmium include dirs
+'-I%s/include' % basedir,
+'-I%s/test/include' % basedir,
+'-I%s/test/data-test/include' % basedir,
+
+# include third party libraries
+'-I/usr/include/gdal',
+]
+
+# 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/libosmium/CHANGELOG.md b/third_party/libosmium/CHANGELOG.md
new file mode 100644
index 0000000..4c345a4
--- /dev/null
+++ b/third_party/libosmium/CHANGELOG.md
@@ -0,0 +1,31 @@
+
+# Change Log
+
+All notable changes to this project will be documented in this file.
+This project adheres to [Semantic Versioning](http://semver.org/).
+
+## [unreleased] -
+
+## [2.1.0] - 2015-03-31
+
+### Added
+
+- When writing PBF files, sorting the PBF stringtables is now optional.
+- More tests and documentation.
+
+### Changed
+
+- Some functions are now declared `noexcept`.
+- XML parser fails now if the top-level element is not `osm` or `osmChange`.
+
+### Fixed
+
+- Race condition in PBF reader.
+- Multipolygon collector was accessing non-existent NodeRef.
+- Doxygen documentation wan't showing all classes/functions due to a bug in
+ Doxygen (up to version 1.8.8). This version contains a workaround to fix
+ this.
+
+[unreleased]: https://github.com/osmcode/libosmium/compare/v2.1.0...HEAD
+[2.1.0]: https://github.com/osmcode/libosmium/compare/v2.0.0...v2.1.0
+
diff --git a/third_party/libosmium/CMakeLists.txt b/third_party/libosmium/CMakeLists.txt
new file mode 100644
index 0000000..5e70a99
--- /dev/null
+++ b/third_party/libosmium/CMakeLists.txt
@@ -0,0 +1,333 @@
+#-----------------------------------------------------------------------------
+#
+# CMake Config
+#
+# Libosmium
+#
+#-----------------------------------------------------------------------------
+
+cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+
+#-----------------------------------------------------------------------------
+#
+# Project version
+#
+#-----------------------------------------------------------------------------
+
+set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel;Dev"
+ CACHE STRING
+ "List of available configuration types"
+ FORCE)
+
+project(libosmium)
+
+set(LIBOSMIUM_VERSION_MAJOR 2)
+set(LIBOSMIUM_VERSION_MINOR 1)
+set(LIBOSMIUM_VERSION_PATCH 0)
+
+set(LIBOSMIUM_VERSION
+ ${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH})
+
+
+#-----------------------------------------------------------------------------
+#
+# Build options
+#
+# (Change with -DOPTION=VALUE on cmake command line.)
+#
+#-----------------------------------------------------------------------------
+
+if(CMAKE_BUILD_TYPE STREQUAL "Dev")
+ set(dev_build ON)
+else()
+ set(dev_build OFF)
+endif()
+
+option(BUILD_EXAMPLES "compile example programs" ON)
+option(BUILD_TESTING "compile unit tests, please run them with ctest" ON)
+
+option(BUILD_HEADERS "compile every header file on its own" ${dev_build})
+option(BUILD_BENCHMARKS "compile benchmark programs" ${dev_build})
+option(BUILD_DATA_TESTS "compile data tests, please run them with ctest" ${dev_build})
+
+
+#-----------------------------------------------------------------------------
+#
+# Find external dependencies
+#
+#-----------------------------------------------------------------------------
+
+find_package(Boost 1.38)
+mark_as_advanced(CLEAR BOOST_ROOT)
+
+if(Boost_FOUND)
+ include_directories(${Boost_INCLUDE_DIRS})
+else()
+ set(BOOST_ROOT "NOT FOUND: please choose" CACHE PATH "")
+ message(FATAL_ERROR "PLEASE, specify the directory where the Boost library is installed in BOOST_ROOT")
+endif()
+
+set(OSMIUM_INCLUDE_DIR include)
+find_package(Osmium COMPONENTS io gdal geos proj sparsehash)
+include_directories(${OSMIUM_INCLUDE_DIRS})
+
+if(MSVC)
+ find_path(GETOPT_INCLUDE_DIR getopt.h)
+ find_library(GETOPT_LIBRARY NAMES wingetopt)
+ if(GETOPT_INCLUDE_DIR AND GETOPT_LIBRARY)
+ include_directories(${GETOPT_INCLUDE_DIR})
+ list(APPEND OSMIUM_LIBRARIES ${GETOPT_LIBRARY})
+ else()
+ set(GETOPT_MISSING 1)
+ endif()
+endif()
+
+include_directories(include)
+
+
+#-----------------------------------------------------------------------------
+#
+# Decide which C++ version to use (Minimum/default: C++11).
+#
+#-----------------------------------------------------------------------------
+if(NOT MSVC)
+ if(NOT USE_CPP_VERSION)
+ set(USE_CPP_VERSION c++11)
+ endif()
+ message(STATUS "Use C++ version: ${USE_CPP_VERSION}")
+ # following only available from cmake 2.8.12:
+ # add_compile_options(-std=${USE_CPP_VERSION})
+ # so using this instead:
+ add_definitions(-std=${USE_CPP_VERSION})
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+# Compiler and Linker flags
+#
+#-----------------------------------------------------------------------------
+if(MSVC)
+ set(USUAL_COMPILE_OPTIONS "/Ox")
+else()
+ set(USUAL_COMPILE_OPTIONS "-O3 -g")
+endif()
+
+if(WIN32)
+ add_definitions(-DWIN32 -D_WIN32 -DMSWIN32 -DBGDWIN32
+ -DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -D_WIN32_IE=0x0600)
+endif()
+
+set(CMAKE_CXX_FLAGS_DEV "${USUAL_COMPILE_OPTIONS}"
+ CACHE STRING "Flags used by the compiler during developer builds."
+ FORCE)
+
+set(CMAKE_EXE_LINKER_FLAGS_DEV ""
+ CACHE STRING "Flags used by the linker during developer builds."
+ FORCE)
+mark_as_advanced(
+ CMAKE_CXX_FLAGS_DEV
+ CMAKE_EXE_LINKER_FLAGS_DEV
+)
+
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${USUAL_COMPILE_OPTIONS}"
+ CACHE STRING "Flags used by the compiler during RELWITHDEBINFO builds."
+ FORCE)
+
+
+#-----------------------------------------------------------------------------
+#
+# Build Type
+#
+#-----------------------------------------------------------------------------
+# In 'Dev' mode: compile with very strict warnings and turn them into errors.
+if(CMAKE_BUILD_TYPE STREQUAL "Dev")
+ if(NOT MSVC)
+ add_definitions(-Werror)
+ endif()
+ add_definitions(${OSMIUM_WARNING_OPTIONS})
+endif()
+
+# Force RelWithDebInfo build type if none was given
+if(CMAKE_BUILD_TYPE)
+ set(build_type ${CMAKE_BUILD_TYPE})
+else()
+ set(build_type "RelWithDebInfo")
+endif()
+
+set(CMAKE_BUILD_TYPE ${build_type}
+ CACHE STRING
+ "Choose the type of build, options are: ${CMAKE_CONFIGURATION_TYPES}."
+ FORCE)
+
+
+#-----------------------------------------------------------------------------
+#
+# Unit and data tests
+#
+#-----------------------------------------------------------------------------
+enable_testing()
+
+if(BUILD_TESTING OR BUILD_DATA_TESTS)
+ find_program(MEMORYCHECK_COMMAND valgrind)
+
+ set(MEMORYCHECK_COMMAND_OPTIONS
+ "--trace-children=yes --leak-check=full --show-reachable=yes --error-exitcode=1")
+
+ set(MEMORYCHECK_SUPPRESSIONS_FILE "${PROJECT_SOURCE_DIR}/test/valgrind.supp")
+endif()
+
+if(BUILD_TESTING)
+ add_subdirectory(test)
+endif()
+
+if(BUILD_DATA_TESTS)
+ add_subdirectory(test/data-tests)
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+# Optional "cppcheck" target that checks C++ code
+#
+#-----------------------------------------------------------------------------
+message(STATUS "Looking for cppcheck")
+find_program(CPPCHECK cppcheck)
+
+if(CPPCHECK)
+ message(STATUS "Looking for cppcheck - found")
+ set(CPPCHECK_OPTIONS
+ --enable=warning,style,performance,portability,information,missingInclude)
+
+ # cpp doesn't find system includes for some reason, suppress that report
+ set(CPPCHECK_OPTIONS ${CPPCHECK_OPTIONS} --suppress=missingIncludeSystem)
+
+ file(GLOB_RECURSE ALL_INCLUDES include/osmium/*.hpp)
+ file(GLOB ALL_EXAMPLES examples/*.cpp)
+ file(GLOB ALL_UNIT_TESTS test/t/*/test_*.cpp)
+ file(GLOB ALL_DATA_TESTS test/data-tests/*.cpp)
+
+ if(Osmium_DEBUG)
+ message(STATUS "Checking includes : ${ALL_INCLUDES}")
+ message(STATUS "Checking example code : ${ALL_EXAMPLES}")
+ message(STATUS "Checking unit test code: ${ALL_UNIT_TESTS}")
+ message(STATUS "Checking data test code: ${ALL_DATA_TESTS}")
+ endif()
+
+ set(CPPCHECK_FILES
+ ${ALL_INCLUDES}
+ ${ALL_EXAMPLES}
+ ${ALL_UNIT_TESTS}
+ ${ALL_DATA_TESTS})
+
+ add_custom_target(cppcheck
+ ${CPPCHECK}
+ --std=c++11 ${CPPCHECK_OPTIONS}
+ -I ${CMAKE_SOURCE_DIR}/include
+ ${CPPCHECK_FILES}
+ )
+else()
+ message(STATUS "Looking for cppcheck - not found")
+ message(STATUS " Build target 'cppcheck' will not be available.")
+endif(CPPCHECK)
+
+
+#-----------------------------------------------------------------------------
+#
+# Examples, benchmarks and documentation
+#
+#-----------------------------------------------------------------------------
+
+if(BUILD_EXAMPLES)
+ add_subdirectory(examples)
+endif()
+
+if(BUILD_BENCHMARKS)
+ add_subdirectory(benchmarks)
+endif()
+
+add_subdirectory(doc)
+
+
+#-----------------------------------------------------------------------------
+#
+# Headers
+#
+# This will try to compile include files on their own to detect missing
+# include directives and other dependency-related problems. Note that if this
+# work, it is not enough to be sure it will compile in production code.
+# But if it reports an error we know we are missing something.
+#
+#-----------------------------------------------------------------------------
+if(BUILD_HEADERS)
+ file(GLOB_RECURSE
+ ALL_HPPS
+ RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/include"
+ include/osmium/*.hpp)
+
+ file(MAKE_DIRECTORY header_check)
+
+ foreach(hpp ${ALL_HPPS})
+ string(REPLACE ".hpp" "" tmp ${hpp})
+ string(REPLACE "/" "__" libname ${tmp})
+
+ # Create a dummy .cpp file that includes the header file we want to
+ # check.
+ set(DUMMYCPP ${CMAKE_BINARY_DIR}/header_check/${libname}.cpp)
+ file(WRITE ${DUMMYCPP} "#include <${hpp}>\n")
+
+ # There is no way in CMake to just compile but not link a C++ file,
+ # so we pretend to build a library here.
+ add_library(${libname} STATIC ${DUMMYCPP} include/${hpp})
+
+ #### this is better but only supported from cmake 3.0:
+ ###add_library(${libname} OBJECT ${DUMMYCPP} include/${hpp})
+
+ endforeach()
+endif()
+
+install(DIRECTORY include/osmium DESTINATION include)
+
+# We only have a copy of this file so we can use older boost versions which
+# don't have it. We probably don't want to install it.
+#install(FILES include/boost_unicode_iterator.hpp DESTINATION include)
+
+
+#-----------------------------------------------------------------------------
+#
+# Packaging
+#
+#-----------------------------------------------------------------------------
+
+set(CPACK_PACKAGE_VERSION_MAJOR ${LIBOSMIUM_VERSION_MAJOR})
+set(CPACK_PACKAGE_VERSION_MINOR ${LIBOSMIUM_VERSION_MINOR})
+set(CPACK_PACKAGE_VERSION_PATCH ${LIBOSMIUM_VERSION_PATCH})
+
+if(WIN32)
+ set(CPACK_GENERATOR ZIP)
+else()
+ set(CPACK_GENERATOR TGZ)
+endif()
+
+include(CPack)
+
+
+#-----------------------------------------------------------------------------
+#
+# Print warnings at the end
+#
+#-----------------------------------------------------------------------------
+if(BUILD_DATA_TESTS AND OSM_TESTDATA STREQUAL "OSM_TESTDATA-NOTFOUND")
+ message("\n========================== WARNING ==========================")
+ message("osm-testdata directory not found, data tests were disabled!\n")
+ message("You can get it from https://github.com/osmcode/osm-testdata")
+ message("Clone it into the same directory libosmium is in")
+ message("or set the OSM_TESTDATA cmake variable to its path.")
+ message("=============================================================\n")
+endif()
+
+#-----------------------------------------------------------------------------
diff --git a/third_party/libosmium/CONTRIBUTING.md b/third_party/libosmium/CONTRIBUTING.md
new file mode 100644
index 0000000..323c847
--- /dev/null
+++ b/third_party/libosmium/CONTRIBUTING.md
@@ -0,0 +1,132 @@
+
+# Notes for Developers
+
+Read this if you want to contribute to Libosmium.
+
+
+## Versioning
+
+Osmium is currently considered in beta and doesn't use versioning yet. Proper
+versions will be introduced as soon as it is somewhat stable.
+
+
+## Namespace
+
+All Osmium code MUST be in the `osmium` namespace or one of its sub-namespaces.
+
+
+## Include-Only
+
+Osmium is a include-only library. You can't compile the library itself. There
+is no libosmium.so.
+
+One drawback ist that you can't have static data in classes, because there
+is no place to put this data.
+
+All free functions must be declared `inline`.
+
+
+## Coding Conventions
+
+These coding conventions have been changing over time and some code is still
+different.
+
+* All include files have `#ifdef` guards around them, macros are the path name
+ in all uppercase where the slashes (`/`) have been changed to underscore (`_`).
+* Class names begin with uppercase chars and use CamelCase. Smaller helper
+ classes are usually defined as struct and have lowercase names.
+* Macros (and only macros) are all uppercase. Use macros sparingly, usually
+ a constexpr is better.
+* Variables, attributes, and function names are lowercase with
+ `underscores_between_words`.
+* Class attribute names start with `m_` (member).
+* Template parameters are single uppercase letters or start with uppercase `T`
+ and use CamelCase.
+* Typedefs have `names_like_this_type` which end in `_type`.
+* Macros should only be used for controlling which parts of the code should be
+ included when compiling.
+* Use `descriptive_variable_names`, exceptions are well-established conventions
+ like `i` for a loop variable. Iterators are usually called `it`.
+* Declare variables where they are first used (C++ style), not at the beginning
+ of a function (old C style).
+* Names from external namespaces (even `std`) are always mentioned explicitly.
+ Do not use `using` (except for `std::swap`). This way we can't even by
+ accident pollute the namespace of the code including Osmium.
+* `#include` directives appear in three "blocks" after the copyright notice.
+ The blocks are separated by blank lines. First block contains `#include`s for
+ standard C/C++ includes, second block for any external libs used, third
+ block for osmium internal includes. Within each block `#include`s are usually
+ sorted by path name. All `#include`s use `<>` syntax not `""`.
+* Names not to be used from outside the library should be in a namespace
+ called `detail` under the namespace where they would otherwise appear. If
+ whole include files are never meant to be included from outside they should
+ be in a subdirectory called `detail`.
+* All files have suffix `.hpp`.
+* Closing } of all classes and namespaces should have a trailing comment
+ with the name of the class/namespace.
+* All constructors with one or more arguments should be declared "explicit"
+ unless there is a reason for them not to be. Document that reason.
+
+Keep to the indentation and other styles used in the code. Use `make indent`
+in the toplevel directory to fix indentation and styling. It calls `astyle`
+with the right parameters. This program is in the `astyle` Debian package.
+
+
+## C++11
+
+Osmium uses C++11 and you can use its features such as auto, lambdas,
+threading, etc. There are a few features we do not use, because even modern
+compilers don't support them yet. This list might change as we get more data
+about which compilers support which feature and what operating system versions
+or distributions have which versions of these compilers installed.
+
+GCC 4.6 - too old, not supported (Ubuntu 12.04 LTS)
+GCC 4.7.2 - can probably not be supported (Debian wheezy/stable)
+GCC 4.7.3 - works
+GCC 4.8 - works
+clang 3.0 - too old, not supported (Debian wheezy/stable, Ubuntu 12.04 LTS)
+clang 3.2 - works
+
+C++11 features you should not use:
+* Inherited Constructors (works only in GCC 4.8+ and clang 3.3+, not in Visual
+ Studio)
+
+
+## Checking your code
+
+The Osmium makefiles use pretty draconian warning options for the compiler.
+This is good. Code MUST never produce any warnings, even with those settings.
+If absolutely necessary pragmas can be used to disable certain warnings in
+specific areas of the code.
+
+If the static code checker `cppcheck` is installed, the CMake configuration
+will add a new build target `cppcheck` that will check all `.cpp` and `.hpp`
+files. Cppcheck finds some bugs that gcc/clang doesn't. But take the result
+with a grain of salt, it also sometimes produces wrong warnings.
+
+Set `BUILD_HEADERS=ON` in the CMake config to enable compiling all include
+files on their own to check whether dependencies are all okay. All include
+files MUST include all other include files they depend on.
+
+Call `cmake/iwyu.sh` to check for proper includes and forward declarations.
+This uses the clang-based `include-what-you-use` program. Note that it does
+produce some false reports and crashes often. The `osmium.imp` file can be
+used to define mappings for iwyu. See the IWYU tool at
+<http://code.google.com/p/include-what-you-use/>.
+
+
+## Testing
+
+There are a unit tests using the Catch Unit Test Framework in the `test`
+directory and some data tests in `test/osm-testdata`. They are built by the
+default cmake config. Run `ctest` to run them. Many more tests are needed.
+
+
+## Documenting the code
+
+All namespaces, classes, functions, attributes, etc. should be documented.
+
+Osmium uses the Doxygen (www.doxygen.org) source code documentation system.
+If it is installed, the CMake configuration will add a new build target, so
+you can build it with `make doc`.
+
diff --git a/third_party/osmium/io/xml_input.hpp b/third_party/libosmium/LICENSE.txt
similarity index 78%
copy from third_party/osmium/io/xml_input.hpp
copy to third_party/libosmium/LICENSE.txt
index f33d37e..36b7cd9 100644
--- a/third_party/osmium/io/xml_input.hpp
+++ b/third_party/libosmium/LICENSE.txt
@@ -1,12 +1,3 @@
-#ifndef OSMIUM_IO_XML_INPUT_HPP
-#define OSMIUM_IO_XML_INPUT_HPP
-
-/*
-
-This file is part of Osmium (http://osmcode.org/libosmium).
-
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
-
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
@@ -30,10 +21,3 @@ 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.
-
-*/
-
-#include <osmium/io/reader.hpp> // IWYU pragma: export
-#include <osmium/io/detail/xml_input_format.hpp> // IWYU pragma: export
-
-#endif // OSMIUM_IO_XML_INPUT_HPP
diff --git a/third_party/libosmium/Makefile b/third_party/libosmium/Makefile
new file mode 100644
index 0000000..7b2b83d
--- /dev/null
+++ b/third_party/libosmium/Makefile
@@ -0,0 +1,25 @@
+
+all:
+ mkdir -p build && cd build && cmake .. && $(MAKE)
+
+doc:
+ mkdir -p build && cd build && cmake .. && $(MAKE) doc
+
+clean:
+ if test -d build; then cd build && $(MAKE) clean; fi
+
+distclean:
+ rm -fr build
+
+#deb:
+# debuild -I -us -uc
+#
+#deb-clean:
+# debuild clean
+
+indent:
+ astyle --style=java --indent-namespaces --indent-switches --pad-header --lineend=linux --suffix=none --recursive include/\*.hpp examples/\*.cpp test/\*.cpp
+# astyle --style=java --indent-namespaces --indent-switches --pad-header --unpad-paren --align-pointer=type --lineend=linux --suffix=none --recursive include/\*.hpp examples/\*.cpp test/\*.cpp
+
+.PHONY: clean distclean deb deb-clean doc indent
+
diff --git a/third_party/libosmium/README.md b/third_party/libosmium/README.md
new file mode 100644
index 0000000..503440e
--- /dev/null
+++ b/third_party/libosmium/README.md
@@ -0,0 +1,104 @@
+# Libosmium
+
+http://osmcode.org/libosmium
+
+A fast and flexible C++ library for working with OpenStreetMap data.
+
+[![Build Status](https://secure.travis-ci.org/osmcode/libosmium.png)](http://travis-ci.org/osmcode/libosmium)
+[![Build status](https://ci.appveyor.com/api/projects/status/mkbg6e6stdgq7c1b?svg=true)](https://ci.appveyor.com/project/Mapbox/libosmium)
+
+Libosmium is developed on Linux, but also works on OSX and Windows (with some
+limitations).
+
+There are a few applications that use the Osmium library in the examples
+directory. See the [osmium-contrib](http://github.com/osmcode/osmium-contrib)
+repository for more example code.
+
+## Prerequisites
+
+Because Libosmium uses many C++11 features you need a modern compiler and
+standard C++ library. Osmium needs at least GCC 4.8 or clang (LLVM) 3.4.
+(Some parts may work with older versions.)
+
+Different parts of Libosmium (and the applications built on top of it) need
+different libraries. You DO NOT NEED to install all of them, just install those
+you need for your programs.
+
+For details see the
+[list of dependencies](https://github.com/osmcode/libosmium/wiki/Libosmium-dependencies).
+
+
+## Directories
+
+* benchmarks: Some benchmarks checking different parts of Libosmium.
+
+* cmake: CMake configuration scripts.
+
+* doc: Config for documentation.
+
+* examples: Osmium example applications.
+
+* include: C/C++ include files. All of Libosmium is in those header files
+ which are needed for building Osmium applications.
+
+* test: Tests (see below).
+
+
+## Building
+
+Osmium is a header-only library, so there is nothing to build for the
+library itself.
+
+But there are some tests and examples that can be build. Libosmium uses
+cmake:
+
+ mkdir build
+ cd build
+ cmake ..
+ make
+
+This will build the examples and tests. Call `ctest` to run the tests.
+
+For more see the
+[Libosmium Wiki](https://github.com/osmcode/libosmium/wiki/Building-Libosmium).
+
+
+## Testing
+
+See the
+[Libosmium Wiki](https://github.com/osmcode/libosmium/wiki/Testing-Libosmium)
+for instructions.
+
+
+## Osmium on 32bit Machines
+
+Osmium works well on 64 bit machines, but on 32 bit machines there are some
+problems. Be aware that not everything will work on 32 bit architectures.
+This is mostly due to the 64 bit needed for node IDs. Also Osmium hasn't been
+tested well on 32 bit systems. Here are some issues you might run into:
+
+* Google Sparsehash does not work on 32 bit machines in our use case.
+* The `mmap` system call is called with a `size_t` argument, so it can't
+ give you more than 4GByte of memory on 32 bit systems. This might be a
+ problem.
+
+Please report any issues you have and we might be able to solve them.
+
+
+## Switching from the old Osmium
+
+If you have been using the old version of Osmium at
+https://github.com/joto/osmium you might want to read about the
+[changes needed](https://github.com/osmcode/libosmium/wiki/Changes-from-old-versions-of-Osmium).
+
+
+## License
+
+Libosmium is available under the Boost Software License. See LICENSE.txt.
+
+
+## Authors
+
+Libosmium was mainly written and is maintained by Jochen Topf
+(jochen at topf.org). See the git commit log for other authors.
+
diff --git a/third_party/libosmium/appveyor.yml b/third_party/libosmium/appveyor.yml
new file mode 100644
index 0000000..06c8e69
--- /dev/null
+++ b/third_party/libosmium/appveyor.yml
@@ -0,0 +1,77 @@
+#-----------------------------------------------------------------------------
+#
+# Configuration for continuous integration service at appveyor.com
+#
+#-----------------------------------------------------------------------------
+
+environment:
+ matrix:
+ - config: Dev
+ - config: RelWithDebInfo
+
+# branches to build
+branches:
+ # whitelist
+ only:
+ - master
+
+# Operating system (build VM template)
+os: Visual Studio 2014 CTP4
+
+# scripts that are called at very beginning, before repo cloning
+init:
+
+# clone directory
+clone_folder: c:\projects\libosmium
+
+platform: x64
+
+install:
+ # show all availble env vars
+ - set
+ - echo cmake on AppVeyor
+ - cmake -version
+ - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
+ - set PATH=c:\projects\libosmium\cmake-3.1.0-win32-x86\bin;%PATH%
+ - set LODEPSDIR=c:\projects\libosmium\libosmium-deps
+ - set PROJ_LIB=%LODEPSDIR%\proj\share
+ - set GDAL_DATA=%LODEPSDIR%\gdal\data
+ #geos.dll
+ - set PATH=%LODEPSDIR%\geos\lib;%PATH%
+ #gdal.dll
+ - set PATH=%LODEPSDIR%\gdal\lib;%PATH%
+ #libexpat.dll
+ - set PATH=%LODEPSDIR%\expat\lib;%PATH%
+ #libtiff.dll
+ - set PATH=%LODEPSDIR%\libtiff\lib;%PATH%
+ #zlibwapi.dll
+ - set PATH=%LODEPSDIR%\zlib\lib;%PATH%
+ #convert backslashes in bzip2 path to forward slashes
+ #cmake cannot find it otherwise
+ - set LIBBZIP2=%LODEPSDIR%\bzip2\lib\libbz2.lib
+ - set LIBBZIP2=%LIBBZIP2:\=/%
+ - ps: Start-FileDownload https://mapnik.s3.amazonaws.com/deps/cmake-3.1.0-win32-x86.7z -FileName cm.7z
+ - ps: Start-FileDownload https://mapnik.s3.amazonaws.com/dist/dev/libosmium-deps-win-14.0-x64.7z -FileName lodeps.7z
+ - 7z x cm.7z | %windir%\system32\find "ing archive"
+ - 7z x lodeps.7z | %windir%\system32\find "ing archive"
+ - echo %LODEPSDIR%
+ - dir %LODEPSDIR%
+ - echo our own cmake
+ - cmake -version
+ - cd c:\projects
+ - git clone https://github.com/osmcode/osm-testdata.git
+
+build_script:
+ - cd c:\projects\libosmium
+ - mkdir build
+ - cd build
+ - echo %config%
+ - cmake .. -LA -G "Visual Studio 14 Win64" -DOsmium_DEBUG=TRUE -DCMAKE_BUILD_TYPE=%config% -DBUILD_BENCHMARKS=OFF -DBOOST_ROOT=%LODEPSDIR%\boost -DBoost_PROGRAM_OPTIONS_LIBRARY=%LODEPSDIR%\boost\lib\libboost_program_options-vc140-mt-1_57.lib -DOSMPBF_LIBRARY=%LODEPSDIR%\osmpbf\lib\osmpbf.lib -DOSMPBF_INCLUDE_DIR=%LODEPSDIR%\osmpbf\include -DPROTOBUF_LIBRARY=%LODEPSDIR%\protobuf\lib\libprotobuf.lib -DPROTOBUF_LITE_LIBRARY=%LODEPSDIR%\protobuf\lib\libprotobuf-lite.lib -DPROTOBUF_INCLUDE_ [...]
+ - msbuild libosmium.sln /p:Configuration=%config% /toolsversion:14.0 /p:Platform=x64 /p:PlatformToolset=v140
+ #- cmake .. -LA -G "NMake Makefiles" -DOsmium_DEBUG=TRUE -DCMAKE_BUILD_TYPE=%config% -DBOOST_ROOT=%LODEPSDIR%\boost -DBoost_PROGRAM_OPTIONS_LIBRARY=%LODEPSDIR%\boost\lib\libboost_program_options-vc140-mt-1_57.lib -DOSMPBF_LIBRARY=%LODEPSDIR%\osmpbf\lib\osmpbf.lib -DOSMPBF_INCLUDE_DIR=%LODEPSDIR%\osmpbf\include -DPROTOBUF_LIBRARY=%LODEPSDIR%\protobuf\lib\libprotobuf.lib -DPROTOBUF_LITE_LIBRARY=%LODEPSDIR%\protobuf\lib\libprotobuf-lite.lib -DPROTOBUF_INCLUDE_DIR=%LODEPSDIR%\protobuf\incl [...]
+ #- nmake
+
+test_script:
+ # -LE fails_on_windows exempts tests we know will fail
+ - ctest --output-on-failure -C %config% -LE fails_on_windows
+
diff --git a/third_party/libosmium/benchmarks/CMakeLists.txt b/third_party/libosmium/benchmarks/CMakeLists.txt
new file mode 100644
index 0000000..6a4ca16
--- /dev/null
+++ b/third_party/libosmium/benchmarks/CMakeLists.txt
@@ -0,0 +1,48 @@
+#-----------------------------------------------------------------------------
+#
+# CMake Config
+#
+# Libosmium benchmarks
+#
+#-----------------------------------------------------------------------------
+
+message(STATUS "Configuring benchmarks")
+
+set(BENCHMARKS
+ count
+ count_tag
+ index_map
+ static_vs_dynamic_index
+ CACHE STRING "Benchmark programs"
+)
+
+
+#-----------------------------------------------------------------------------
+#
+# Configure benchmarks
+#
+#-----------------------------------------------------------------------------
+
+message(STATUS "Configuring benchmarks - Building these benchmarks:")
+foreach(benchmark ${BENCHMARKS})
+ message(STATUS " - osmium_benchmark_${benchmark}")
+ add_executable(osmium_benchmark_${benchmark}
+ "osmium_benchmark_${benchmark}.cpp")
+ target_link_libraries(osmium_benchmark_${benchmark}
+ ${OSMIUM_IO_LIBRARIES}
+ ${BENCHMARK_LIBS_${benchmark}})
+ configure_file(run_benchmark_${benchmark}.sh
+ ${CMAKE_CURRENT_BINARY_DIR}/run_benchmark_${benchmark}.sh
+ @ONLY)
+endforeach()
+
+foreach(file setup run_benchmarks)
+ configure_file(${file}.sh ${CMAKE_CURRENT_BINARY_DIR}/${file}.sh @ONLY)
+endforeach()
+
+
+#-----------------------------------------------------------------------------
+message(STATUS "Configuring benchmarks - done")
+
+
+#-----------------------------------------------------------------------------
diff --git a/third_party/libosmium/benchmarks/README.md b/third_party/libosmium/benchmarks/README.md
new file mode 100644
index 0000000..f10045c
--- /dev/null
+++ b/third_party/libosmium/benchmarks/README.md
@@ -0,0 +1,41 @@
+
+# Benchmarks
+
+Benchmarks check the performance of different parts of Libosmium.
+
+## Preparations
+
+To run the benchmarks first make a directory for the data files somewhere
+(outside the repository) and set the `DATA_DIR` environment variable:
+
+ export DATA_DIR=benchmark_data
+ mkdir $DATA_DIR
+
+Then copy the OSM files you want to do the benchmarks with into this directory.
+You can use the `download_data.sh` script to download a selection of OSM files
+in different sizes, but you can use a different selection, too. The benchmarks
+will use whatever files you have in the `DATA_DIR` directory.
+
+The download script will start the data files names with a number in order of
+the size of the file from smallest to largest. You can use the same convention
+or use a different one. Benchmarks will be run on the files in alphabetical
+order.
+
+The files don't have to be in that directory, you can add soft links from that
+directory to the real file locations if that suits you.
+
+## Compiling the benchmarks
+
+To build the benchmarks set the `BUILD_BENCHMARKS` option when configuring with
+CMake and run the compilation by calling `make` (or whatever build tool you
+are using).
+
+## Running the benchmarks
+
+Go to the build directory and run `benchmarks/run_benchmarks.sh`. You can also
+run each benchmark on its own by calling the respective script in the
+`benchmarks` directory.
+
+Results of the benchmarks will be printed to stdout, you might want to redirect
+them into a file.
+
diff --git a/third_party/libosmium/benchmarks/download_data.sh b/third_party/libosmium/benchmarks/download_data.sh
new file mode 100755
index 0000000..8a6a8ff
--- /dev/null
+++ b/third_party/libosmium/benchmarks/download_data.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+#
+# download_data.sh
+#
+
+cd $DATA_DIR
+curl --location --output 1_liechtenstein.osm.pbf http://download.geofabrik.de/europe/liechtenstein-latest.osm.pbf # about 1 MB
+curl --location --output 2_bremen.osm.pbf http://download.geofabrik.de/europe/germany/bremen-latest.osm.pbf # about 13 MB
+curl --location --output 3_sachsen.osm.pbf http://download.geofabrik.de/europe/germany/sachsen-latest.osm.pbf # about 120 MB
+curl --location --output 4_germany.osm.pbf http://download.geofabrik.de/europe/germany-latest.osm.pbf # about 2 GB
+curl --location --output 5_planet.osm.pbf http://planet.osm.org/pbf/planet-latest.osm.pbf # about 26 GB
+
diff --git a/third_party/libosmium/benchmarks/osmium_benchmark_count.cpp b/third_party/libosmium/benchmarks/osmium_benchmark_count.cpp
new file mode 100644
index 0000000..701d6fa
--- /dev/null
+++ b/third_party/libosmium/benchmarks/osmium_benchmark_count.cpp
@@ -0,0 +1,54 @@
+/*
+
+ The code in this file is released into the Public Domain.
+
+*/
+
+#include <iostream>
+
+#include <osmium/io/any_input.hpp>
+#include <osmium/handler.hpp>
+#include <osmium/visitor.hpp>
+
+struct CountHandler : public osmium::handler::Handler {
+
+ int nodes = 0;
+ int ways = 0;
+ int relations = 0;
+
+ void node(osmium::Node&) {
+ ++nodes;
+ }
+
+ void way(osmium::Way&) {
+ ++ways;
+ }
+
+ void relation(osmium::Relation&) {
+ ++relations;
+ }
+
+};
+
+
+int main(int argc, char* argv[]) {
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
+ exit(1);
+ }
+
+ std::string input_filename = argv[1];
+
+ osmium::io::Reader reader(input_filename);
+
+ CountHandler handler;
+ osmium::apply(reader, handler);
+ reader.close();
+
+ std::cout << "Nodes: " << handler.nodes << "\n";
+ std::cout << "Ways: " << handler.ways << "\n";
+ std::cout << "Relations: " << handler.relations << "\n";
+
+ google::protobuf::ShutdownProtobufLibrary();
+}
+
diff --git a/third_party/libosmium/benchmarks/osmium_benchmark_count_tag.cpp b/third_party/libosmium/benchmarks/osmium_benchmark_count_tag.cpp
new file mode 100644
index 0000000..4a77c34
--- /dev/null
+++ b/third_party/libosmium/benchmarks/osmium_benchmark_count_tag.cpp
@@ -0,0 +1,55 @@
+/*
+
+ The code in this file is released into the Public Domain.
+
+*/
+
+#include <iostream>
+
+#include <osmium/io/any_input.hpp>
+#include <osmium/handler.hpp>
+#include <osmium/visitor.hpp>
+
+struct CountHandler : public osmium::handler::Handler {
+
+ int counter = 0;
+ int all = 0;
+
+ void node(osmium::Node& node) {
+ ++all;
+ const char* amenity = node.tags().get_value_by_key("amenity");
+ if (amenity && !strcmp(amenity, "post_box")) {
+ ++counter;
+ }
+ }
+
+ void way(osmium::Way&) {
+ ++all;
+ }
+
+ void relation(osmium::Relation&) {
+ ++all;
+ }
+
+};
+
+
+int main(int argc, char* argv[]) {
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
+ exit(1);
+ }
+
+ std::string input_filename = argv[1];
+
+ osmium::io::Reader reader(input_filename);
+
+ CountHandler handler;
+ osmium::apply(reader, handler);
+ reader.close();
+
+ std::cout << "r_all=" << handler.all << " r_counter=" << handler.counter << "\n";
+
+ google::protobuf::ShutdownProtobufLibrary();
+}
+
diff --git a/third_party/libosmium/benchmarks/osmium_benchmark_index_map.cpp b/third_party/libosmium/benchmarks/osmium_benchmark_index_map.cpp
new file mode 100644
index 0000000..fa75fb2
--- /dev/null
+++ b/third_party/libosmium/benchmarks/osmium_benchmark_index_map.cpp
@@ -0,0 +1,41 @@
+/*
+
+ The code in this file is released into the Public Domain.
+
+*/
+
+#include <iostream>
+
+#include <osmium/index/map/all.hpp>
+#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/visitor.hpp>
+
+#include <osmium/io/any_input.hpp>
+#include <osmium/handler.hpp>
+
+typedef osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location> index_type;
+
+typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type;
+
+int main(int argc, char* argv[]) {
+ if (argc != 3) {
+ std::cerr << "Usage: " << argv[0] << " OSMFILE FORMAT\n";
+ exit(1);
+ }
+
+ std::string input_filename = argv[1];
+ std::string location_store = argv[2];
+
+ osmium::io::Reader reader(input_filename);
+
+ const auto& map_factory = osmium::index::MapFactory<osmium::unsigned_object_id_type, osmium::Location>::instance();
+ std::unique_ptr<index_type> index = map_factory.create_map(location_store);
+ location_handler_type location_handler(*index);
+ location_handler.ignore_errors();
+
+ osmium::apply(reader, location_handler);
+ reader.close();
+
+ google::protobuf::ShutdownProtobufLibrary();
+}
+
diff --git a/third_party/libosmium/benchmarks/osmium_benchmark_static_vs_dynamic_index.cpp b/third_party/libosmium/benchmarks/osmium_benchmark_static_vs_dynamic_index.cpp
new file mode 100644
index 0000000..9c47c84
--- /dev/null
+++ b/third_party/libosmium/benchmarks/osmium_benchmark_static_vs_dynamic_index.cpp
@@ -0,0 +1,136 @@
+/*
+
+ This benchmarks compares the run time for statically vs. dynamically
+ configured index maps. You can configure index maps at compile-time using
+ typedefs or at run-time using polymorphism.
+
+ This will read the input file into a buffer and then run the
+ NodeLocationForWays handler multiple times over the complete data. The
+ number of runs depends on the size of the input, but is never smaller
+ than 10.
+
+ Do not run this with very large input files! It will need about 10 times
+ as much RAM as the file size of the input file.
+
+ The code in this file is released into the Public Domain.
+
+*/
+
+#include <algorithm>
+#include <chrono>
+#include <cmath>
+#include <iostream>
+#include <limits>
+
+#include <osmium/index/map/all.hpp>
+#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/visitor.hpp>
+
+#include <osmium/io/any_input.hpp>
+#include <osmium/handler.hpp>
+
+typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> static_index_type;
+const std::string location_store="sparse_mem_array";
+
+typedef osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location> dynamic_index_type;
+
+typedef osmium::handler::NodeLocationsForWays<static_index_type> static_location_handler_type;
+typedef osmium::handler::NodeLocationsForWays<dynamic_index_type> dynamic_location_handler_type;
+
+int main(int argc, char* argv[]) {
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
+ exit(1);
+ }
+
+ std::string input_filename = argv[1];
+
+ osmium::memory::Buffer buffer = osmium::io::read_file(input_filename);
+ google::protobuf::ShutdownProtobufLibrary();
+
+ const auto& map_factory = osmium::index::MapFactory<osmium::unsigned_object_id_type, osmium::Location>::instance();
+
+ const auto buffer_size = buffer.committed() / (1024*1024); // buffer size in MBytes
+ const int runs = std::max(10, static_cast<int>(5000ull / buffer_size));
+
+ std::cout << "input: filename=" << input_filename << " buffer_size=" << buffer_size << "MBytes\n";
+ std::cout << "runs: " << runs << "\n";
+
+ double static_min = std::numeric_limits<double>::max();
+ double static_sum = 0;
+ double static_max = 0;
+
+ double dynamic_min = std::numeric_limits<double>::max();
+ double dynamic_sum = 0;
+ double dynamic_max = 0;
+
+ for (int i = 0; i < runs; ++i) {
+
+ {
+ // static index
+ osmium::memory::Buffer tmp_buffer(buffer.committed());
+ for (const auto& item : buffer) {
+ tmp_buffer.add_item(item);
+ tmp_buffer.commit();
+ }
+
+ static_index_type static_index;
+ static_location_handler_type static_location_handler(static_index);
+
+ auto start = std::chrono::steady_clock::now();
+ osmium::apply(tmp_buffer, static_location_handler);
+ auto end = std::chrono::steady_clock::now();
+
+ double duration = std::chrono::duration<double, std::milli>(end-start).count();
+
+ if (duration < static_min) static_min = duration;
+ if (duration > static_max) static_max = duration;
+ static_sum += duration;
+ }
+
+ {
+ // dynamic index
+ osmium::memory::Buffer tmp_buffer(buffer.committed());
+ for (const auto& item : buffer) {
+ tmp_buffer.add_item(item);
+ tmp_buffer.commit();
+ }
+
+ std::unique_ptr<dynamic_index_type> index = map_factory.create_map(location_store);
+ dynamic_location_handler_type dynamic_location_handler(*index);
+ dynamic_location_handler.ignore_errors();
+
+ auto start = std::chrono::steady_clock::now();
+ osmium::apply(tmp_buffer, dynamic_location_handler);
+ auto end = std::chrono::steady_clock::now();
+
+ double duration = std::chrono::duration<double, std::milli>(end-start).count();
+
+ if (duration < dynamic_min) dynamic_min = duration;
+ if (duration > dynamic_max) dynamic_max = duration;
+ dynamic_sum += duration;
+ }
+ }
+
+ double static_avg = static_sum/runs;
+ double dynamic_avg = dynamic_sum/runs;
+
+ std::cout << "static min=" << static_min << "ms avg=" << static_avg << "ms max=" << static_max << "ms\n";
+ std::cout << "dynamic min=" << dynamic_min << "ms avg=" << dynamic_avg << "ms max=" << dynamic_max << "ms\n";
+
+ double rfactor = 100.0;
+ double diff_min = std::round((dynamic_min - static_min) * rfactor) / rfactor;
+ double diff_avg = std::round((dynamic_avg - static_avg) * rfactor) / rfactor;
+ double diff_max = std::round((dynamic_max - static_max) * rfactor) / rfactor;
+
+ double prfactor = 10.0;
+ double percent_min = std::round((100.0 * diff_min / static_min) * prfactor) / prfactor;
+ double percent_avg = std::round((100.0 * diff_avg / static_avg) * prfactor) / prfactor;
+ double percent_max = std::round((100.0 * diff_max / static_max) * prfactor) / prfactor;
+
+ std::cout << "difference:";
+ std::cout << " min=" << diff_min << "ms (" << percent_min << "%)";
+ std::cout << " avg=" << diff_avg << "ms (" << percent_avg << "%)";
+ std::cout << " max=" << diff_max << "ms (" << percent_max << "%)\n";
+}
+
diff --git a/third_party/libosmium/benchmarks/run_benchmark_count.sh b/third_party/libosmium/benchmarks/run_benchmark_count.sh
new file mode 100755
index 0000000..d71508f
--- /dev/null
+++ b/third_party/libosmium/benchmarks/run_benchmark_count.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# run_benchmark_count.sh
+#
+
+set -e
+
+BENCHMARK_NAME=count
+
+. @CMAKE_BINARY_DIR@/benchmarks/setup.sh
+
+CMD=$OB_DIR/osmium_benchmark_$BENCHMARK_NAME
+
+echo "# file size num mem time cpu_kernel cpu_user cpu_percent cmd options"
+for data in $OB_DATA_FILES; do
+ filename=`basename $data`
+ filesize=`stat --format="%s" --dereference $data`
+ for n in $OB_SEQ; do
+ $OB_TIME_CMD -f "$filename $filesize $n $OB_TIME_FORMAT" $CMD $data 2>&1 >/dev/null | sed -e "s%$DATA_DIR/%%" | sed -e "s%$OB_DIR/%%"
+ done
+done
+
diff --git a/third_party/libosmium/benchmarks/run_benchmark_count_tag.sh b/third_party/libosmium/benchmarks/run_benchmark_count_tag.sh
new file mode 100755
index 0000000..4fa6a10
--- /dev/null
+++ b/third_party/libosmium/benchmarks/run_benchmark_count_tag.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# run_benchmark_count_tag.sh
+#
+
+set -e
+
+BENCHMARK_NAME=count_tag
+
+. @CMAKE_BINARY_DIR@/benchmarks/setup.sh
+
+CMD=$OB_DIR/osmium_benchmark_$BENCHMARK_NAME
+
+echo "# file size num mem time cpu_kernel cpu_user cpu_percent cmd options"
+for data in $OB_DATA_FILES; do
+ filename=`basename $data`
+ filesize=`stat --format="%s" --dereference $data`
+ for n in $OB_SEQ; do
+ $OB_TIME_CMD -f "$filename $filesize $n $OB_TIME_FORMAT" $CMD $data 2>&1 >/dev/null | sed -e "s%$DATA_DIR/%%" | sed -e "s%$OB_DIR/%%"
+ done
+done
+
diff --git a/third_party/libosmium/benchmarks/run_benchmark_index_map.sh b/third_party/libosmium/benchmarks/run_benchmark_index_map.sh
new file mode 100755
index 0000000..30984d4
--- /dev/null
+++ b/third_party/libosmium/benchmarks/run_benchmark_index_map.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# run_benchmark_index_map.sh
+#
+
+set -e
+
+BENCHMARK_NAME=index_map
+
+. @CMAKE_BINARY_DIR@/benchmarks/setup.sh
+
+CMD=$OB_DIR/osmium_benchmark_$BENCHMARK_NAME
+
+#MAPS="sparse_mem_map sparse_mem_table sparse_mem_array sparse_mmap_array sparse_file_array dense_mem_array dense_mmap_array dense_file_array"
+MAPS="sparse_mem_map sparse_mem_table sparse_mem_array sparse_mmap_array sparse_file_array"
+
+echo "# file size num mem time cpu_kernel cpu_user cpu_percent cmd options"
+for data in $OB_DATA_FILES; do
+ filename=`basename $data`
+ filesize=`stat --format="%s" --dereference $data`
+ for map in $MAPS; do
+ for n in $OB_SEQ; do
+ $OB_TIME_CMD -f "$filename $filesize $n $OB_TIME_FORMAT" $CMD $data $map 2>&1 >/dev/null | sed -e "s%$DATA_DIR/%%" | sed -e "s%$OB_DIR/%%"
+ done
+ done
+done
+
diff --git a/third_party/libosmium/benchmarks/run_benchmark_static_vs_dynamic_index.sh b/third_party/libosmium/benchmarks/run_benchmark_static_vs_dynamic_index.sh
new file mode 100755
index 0000000..05e32f1
--- /dev/null
+++ b/third_party/libosmium/benchmarks/run_benchmark_static_vs_dynamic_index.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+#
+# run_benchmark_static_vs_dynamic_index.sh
+#
+
+set -e
+
+BENCHMARK_NAME=static_vs_dynamic_index
+
+. @CMAKE_BINARY_DIR@/benchmarks/setup.sh
+
+CMD=$OB_DIR/osmium_benchmark_$BENCHMARK_NAME
+
+for data in $OB_DATA_FILES; do
+ filesize=`stat --format="%s" --dereference $data`
+ if [ $filesize -lt 500000000 ]; then
+ echo "========================"
+ $CMD $data
+ fi
+done
+
diff --git a/third_party/libosmium/benchmarks/run_benchmarks.sh b/third_party/libosmium/benchmarks/run_benchmarks.sh
new file mode 100755
index 0000000..6a20c02
--- /dev/null
+++ b/third_party/libosmium/benchmarks/run_benchmarks.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# run_benchmarks.sh
+#
+# Run all benchmarks.
+#
+
+set -e
+
+for benchmark in @CMAKE_BINARY_DIR@/benchmarks/run_benchmark_*.sh; do
+ name=`basename $benchmark`
+ echo "Running $name..."
+ $benchmark
+done
+
diff --git a/third_party/libosmium/benchmarks/setup.sh b/third_party/libosmium/benchmarks/setup.sh
new file mode 100755
index 0000000..9733bfe
--- /dev/null
+++ b/third_party/libosmium/benchmarks/setup.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# setup.sh
+#
+
+if [ -z $DATA_DIR ]; then
+ echo "Please set DATA_DIR environment variable before running benchmark"
+ exit 1
+fi
+
+OB_DIR=@CMAKE_BINARY_DIR@/benchmarks
+
+OB_RUNS=3
+OB_SEQ=`seq -s' ' 1 $OB_RUNS`
+
+OB_TIME_CMD=/usr/bin/time
+OB_TIME_FORMAT="%M %e %S %U %P %C"
+
+OB_DATA_FILES=`find -L $DATA_DIR -mindepth 1 -maxdepth 1 -type f | sort`
+
+echo "BENCHMARK: $BENCHMARK_NAME"
+echo "---------------------"
+echo "CPU:"
+grep '^model name' /proc/cpuinfo | tail -1
+grep '^cpu MHz' /proc/cpuinfo | tail -1
+grep '^cpu cores' /proc/cpuinfo | tail -1
+grep '^siblings' /proc/cpuinfo | tail -1
+
+echo "---------------------"
+echo "MEMORY:"
+free
+echo "---------------------"
+echo "RESULTS:"
+
diff --git a/third_party/libosmium/cmake/FindGem.cmake b/third_party/libosmium/cmake/FindGem.cmake
new file mode 100644
index 0000000..f5389d1
--- /dev/null
+++ b/third_party/libosmium/cmake/FindGem.cmake
@@ -0,0 +1,153 @@
+# Author thomas.roehr at dfki.de
+#
+# Version 0.3 2013-07-02
+# - rely on `gem content` to find library and header
+# - introduce GEM_OS_PKG to allow search via pkgconfig
+# Version 0.2 2010-01-14
+# - add support for searching for multiple gems
+# Version 0.1 2010-12-15
+# - support basic search functionality
+# - tested to find rice
+#
+# OUTPUT:
+#
+# GEM_INCLUDE_DIRS After successful search contains the include directores
+#
+# GEM_LIBRARIES After successful search contains the full path of each found library
+#
+#
+# Usage:
+# set(GEM_DEBUG TRUE)
+# find_package(Gem COMPONENTS rice hoe)
+# include_directories(${GEM_INCLUDE_DIRS})
+# target_link_libraries(${GEM_LIBRARIES}
+#
+# in case pkg-config should be used to search for the os pkg, set GEM_OS_PKG, i.e.
+# set(GEM_OS_PKG TRUE)
+#
+# Check for how 'gem' should be called
+include(FindPackageHandleStandardArgs)
+find_program(GEM_EXECUTABLE
+ NAMES "gem${RUBY_VERSION_MAJOR}${RUBY_VERSION_MINOR}"
+ "gem${RUBY_VERSION_MAJOR}.${RUBY_VERSION_MINOR}"
+ "gem-${RUBY_VERSION_MAJOR}${RUBY_VERSION_MINOR}"
+ "gem-${RUBY_VERSION_MAJOR}.${RUBY_VERSION_MINOR}"
+ "gem${RUBY_VERSION_MAJOR}${RUBY_VERSION_MINOR}${RUBY_VERSION_PATCH}"
+ "gem${RUBY_VERSION_MAJOR}.${RUBY_VERSION_MINOR}.${RUBY_VERSION_PATCH}"
+ "gem-${RUBY_VERSION_MAJOR}${RUBY_VERSION_MINOR}${RUBY_VERSION_PATCH}"
+ "gem-${RUBY_VERSION_MAJOR}.${RUBY_VERSION_MINOR}.${RUBY_VERSION_PATCH}"
+ "gem")
+
+# Making backward compatible
+if(Gem_DEBUG)
+ set(GEM_DEBUG TRUE)
+endif()
+
+if(NOT GEM_EXECUTABLE)
+ MESSAGE(FATAL_ERROR "Could not find the gem executable - install 'gem' first")
+endif()
+
+if(NOT Gem_FIND_COMPONENTS)
+ MESSAGE(FATAL_ERROR "If searching for a Gem you have to provide COMPONENTS with the name of the gem")
+endif()
+
+foreach(Gem_NAME ${Gem_FIND_COMPONENTS})
+ set(GEM_${Gem_NAME}_FOUND TRUE)
+ list(APPEND components_found_vars GEM_${Gem_NAME}_FOUND)
+ # If the gem is installed as a gem
+ if(NOT GEM_OS_PKG)
+ set(GEM_HOME ENV{GEM_HOME})
+
+ # Use `gem content <gem-name>` to extract current information about installed gems
+ # Store the information into ${GEM_LOCAL_INFO}
+ EXECUTE_PROCESS(COMMAND ${GEM_EXECUTABLE} content ${Gem_NAME}
+ RESULT_VARIABLE GEM_RUN_RESULT
+ OUTPUT_VARIABLE GEM_LOCAL_INFO)
+
+ if(GEM_RUN_RESULT STREQUAL "0")
+ list(APPEND FOUND_GEMS ${Gem_NAME})
+ set(_library_NAME_PATTERN lib${Gem_NAME}.a
+ lib${Gem_NAME}.so
+ lib${Gem_NAME}.dylib
+ ${Gem_NAME}.a
+ ${Gem_NAME}.so
+ ${Gem_NAME}.dylib
+ .*.a
+ .*.so
+ .*.dylib
+ )
+
+ set(_header_SUFFIX_PATTERN
+ .h
+ .hh
+ .hpp
+ )
+
+ # Create a list from the output results of the gem command
+ string(REPLACE "\n" ";" GEM_CONTENT_LIST "${GEM_LOCAL_INFO}")
+ foreach(_gem_CONTENT_PATH ${GEM_CONTENT_LIST})
+
+ # Convert so that only '/' Unix path separator are being using
+ # needed to do proper regex matching
+ FILE(TO_CMAKE_PATH ${_gem_CONTENT_PATH} gem_CONTENT_PATH)
+
+ # Identify library -- checking for a library in the gems 'lib' (sub)directory
+ # Search for an existing library, but only within the gems folder
+ foreach(_library_NAME ${_library_NAME_PATTERN})
+ STRING(REGEX MATCH ".*${Gem_NAME}.*/lib/.*${_library_NAME}$" GEM_PATH_INFO "${gem_CONTENT_PATH}")
+ if(NOT "${GEM_PATH_INFO}" STREQUAL "")
+ list(APPEND GEM_LIBRARIES ${GEM_PATH_INFO})
+ break()
+ endif()
+ endforeach()
+
+ # Identify headers
+ # Checking for available headers in an include directory
+ foreach(_header_PATTERN ${_header_SUFFIX_PATTERN})
+ STRING(REGEX MATCH ".*${Gem_NAME}.*/include/.*${_header_PATTERN}$" GEM_PATH_INFO "${gem_CONTENT_PATH}")
+ if(NOT "${GEM_PATH_INFO}" STREQUAL "")
+ STRING(REGEX REPLACE "(.*${Gem_NAME}.*/include/).*${_header_PATTERN}$" "\\1" GEM_PATH_INFO "${gem_CONTENT_PATH}")
+ list(APPEND GEM_INCLUDE_DIRS ${GEM_PATH_INFO})
+ break()
+ endif()
+ endforeach()
+ endforeach()
+ else()
+ set(GEM_${Gem_NAME}_FOUND FALSE)
+ endif()
+ else(NOT GEM_OS_PKG)
+ pkg_check_modules(GEM_PKG ${Gem_NAME})
+ set(GEM_${GEM_NAME}_FOUND GEM_PKG_FOUND)
+ set(GEM_INCLUDE_DIRS ${GEM_PKG_INCLUDE_DIRS})
+ set(GEM_LIBRARIES ${GEM_PKG_LIBRARIES} ${GEM_PKG_STATIC_LIBRARIES})
+ list(APPEND GEM_LIBRARIES ${GEM_PKG_LDFLAGS} ${GEM_PKG_STATIC_LDFLAGS})
+ list(APPEND GEM_LIBRARIES ${GEM_PKG_LDFLAGS_OTHER} ${GEM_PKG_STATIC_LDFLAGS_OTHER})
+
+ if(GEM_DEBUG)
+ message(STATUS "GEM_OS_PKG is defined")
+ message(STATUS "GEM_INCLUDE_DIRS ${GEM_INCLUDE_DIRS}")
+ message(STATUS "GEM_STATIC_LIBRARY_DIRS ${GEM_PKG_STATIC_LIBRARY_DIRS}")
+ message(STATUS "GEM_LIBRARY_DIRS ${GEM_PKG_STATIC_LIBRARY_DIRS}")
+ message(STATUS "GEM_STATIC_LIBRARIES ${GEM_PKG_STATIC_LIBRARIES}")
+ message(STATUS "GEM_LIBRARIES ${GEM_LIBRARIES}")
+ endif()
+ endif()
+
+ if(GEM_DEBUG)
+ message(STATUS "${Gem_NAME} library dir: ${GEM_LIBRARIES}")
+ message(STATUS "${Gem_NAME} include dir: ${GEM_INCLUDE_DIRS}")
+ endif()
+endforeach()
+
+# Compact the lists
+if(DEFINED GEM_LIBRARIES)
+ LIST(REMOVE_DUPLICATES GEM_LIBRARIES)
+endif()
+if(DEFINED GEM_INCLUDE_DIRS)
+ LIST(REMOVE_DUPLICATES GEM_INCLUDE_DIRS)
+endif()
+
+find_package_handle_standard_args(GEM
+ REQUIRED_VARS ${components_found_vars}
+ FAIL_MESSAGE "Could not find all required gems")
+
diff --git a/third_party/libosmium/cmake/FindOSMPBF.cmake b/third_party/libosmium/cmake/FindOSMPBF.cmake
new file mode 100644
index 0000000..deeebd8
--- /dev/null
+++ b/third_party/libosmium/cmake/FindOSMPBF.cmake
@@ -0,0 +1,50 @@
+#
+# Locate OSMPBF library
+#
+# This module defines
+# OSMPBF_FOUND - if false, do not try to link to OSMPBF
+# OSMPBF_LIBRARIES - full library path name
+# OSMPBF_INCLUDE_DIRS - where to find OSMPBF.hpp
+#
+# Note that the expected include convention is
+# #include <osmpbf/osmpbf.h>
+# and not
+# #include <osmpbf.h>
+#
+
+find_path(OSMPBF_INCLUDE_DIR osmpbf/osmpbf.h
+ HINTS $ENV{OSMPBF_DIR}
+ PATH_SUFFIXES include
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local
+ /usr
+ /opt/local # DarwinPorts
+ /opt
+)
+
+find_library(OSMPBF_LIBRARY
+ NAMES osmpbf
+ HINTS $ENV{OSMPBF_DIR}
+ PATH_SUFFIXES lib64 lib
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local
+ /usr
+ /opt/local
+ /opt
+)
+
+# Handle the QUIETLY and REQUIRED arguments and set OSMPBF_FOUND to TRUE if
+# all listed variables are TRUE.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(OSMPBF DEFAULT_MSG OSMPBF_LIBRARY OSMPBF_INCLUDE_DIR)
+
+# Copy the results to the output variables.
+if(OSMPBF_FOUND)
+ set(OSMPBF_INCLUDE_DIRS ${OSMPBF_INCLUDE_DIR})
+ set(OSMPBF_LIBRARIES ${OSMPBF_LIBRARY})
+endif()
+
diff --git a/third_party/libosmium/cmake/FindOsmium.cmake b/third_party/libosmium/cmake/FindOsmium.cmake
new file mode 100644
index 0000000..1de41a0
--- /dev/null
+++ b/third_party/libosmium/cmake/FindOsmium.cmake
@@ -0,0 +1,340 @@
+#----------------------------------------------------------------------
+#
+# FindOsmium.cmake
+#
+# Find the Libosmium headers and, optionally, several components needed for
+# different Libosmium functions.
+#
+#----------------------------------------------------------------------
+#
+# Usage:
+#
+# Copy this file somewhere into your project directory, where cmake can
+# find it. Usually this will be a directory called "cmake" which you can
+# add to the CMake module search path with the following line in your
+# CMakeLists.txt:
+#
+# list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+#
+# Then add the following in your CMakeLists.txt:
+#
+# find_package(Osmium REQUIRED COMPONENTS <XXX>)
+# include_directories(${OSMIUM_INCLUDE_DIRS})
+#
+# For the <XXX> substitute a space separated list of one or more of the
+# following components:
+#
+# pbf - include libraries needed for PBF input and output
+# xml - include libraries needed for XML input and output
+# io - include libraries needed for any type of input/output
+# geos - include if you want to use any of the GEOS functions
+# gdal - include if you want to use any of the OGR functions
+# proj - include if you want to use any of the Proj.4 functions
+# sparsehash - include if you use the sparsehash index
+#
+# You can check for success with something like this:
+#
+# if(NOT OSMIUM_FOUND)
+# message(WARNING "Libosmium not found!\n")
+# endif()
+#
+#----------------------------------------------------------------------
+#
+# Variables:
+#
+# OSMIUM_FOUND - True if Osmium found.
+# OSMIUM_INCLUDE_DIRS - Where to find include files.
+# OSMIUM_XML_LIBRARIES - Libraries needed for XML I/O.
+# OSMIUM_PBF_LIBRARIES - Libraries needed for PBF I/O.
+# OSMIUM_IO_LIBRARIES - Libraries needed for XML or PBF I/O.
+# OSMIUM_LIBRARIES - All libraries Osmium uses somewhere.
+#
+#----------------------------------------------------------------------
+
+# Look for the header file.
+find_path(OSMIUM_INCLUDE_DIR osmium/osm.hpp
+ PATH_SUFFIXES include
+ PATHS
+ ../libosmium
+ ../../libosmium
+ libosmium
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local
+ /usr/
+ /opt/local # DarwinPorts
+ /opt
+)
+
+# Handle the QUIETLY and REQUIRED arguments and set OSMIUM_FOUND to TRUE if
+# all listed variables are TRUE.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(OSMIUM REQUIRED_VARS OSMIUM_INCLUDE_DIR)
+
+# Copy the results to the output variables.
+if(OSMIUM_FOUND)
+ set(OSMIUM_INCLUDE_DIRS ${OSMIUM_INCLUDE_DIR})
+else()
+ set(OSMIUM_INCLUDE_DIRS "")
+endif()
+
+if(Osmium_FIND_REQUIRED AND NOT OSMIUM_FOUND)
+ message(FATAL_ERROR "Can not find libosmium headers, please install them or configure the paths")
+endif()
+
+#----------------------------------------------------------------------
+#
+# Check for optional components
+#
+#----------------------------------------------------------------------
+if(Osmium_FIND_COMPONENTS)
+ foreach(_component ${Osmium_FIND_COMPONENTS})
+ string(TOUPPER ${_component} _component_uppercase)
+ set(Osmium_USE_${_component_uppercase} TRUE)
+ endforeach()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'io' is an alias for 'pbf' and 'xml'
+if(Osmium_USE_IO)
+ set(Osmium_USE_PBF TRUE)
+ set(Osmium_USE_XML TRUE)
+endif()
+
+#----------------------------------------------------------------------
+# Component 'ogr' is an alias for 'gdal'
+if(Osmium_USE_OGR)
+ set(Osmium_USE_GDAL TRUE)
+endif()
+
+#----------------------------------------------------------------------
+# Component 'pbf'
+if(Osmium_USE_PBF)
+ find_package(OSMPBF)
+ find_package(Protobuf)
+ find_package(ZLIB)
+ find_package(Threads)
+
+ if(OSMPBF_FOUND AND PROTOBUF_FOUND AND ZLIB_FOUND AND Threads_FOUND)
+ list(APPEND OSMIUM_PBF_LIBRARIES
+ ${OSMPBF_LIBRARIES}
+ ${PROTOBUF_LITE_LIBRARY}
+ ${ZLIB_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ )
+ if(WIN32)
+ list(APPEND OSMIUM_PBF_LIBRARIES ws2_32)
+ endif()
+ list(APPEND OSMIUM_INCLUDE_DIRS
+ ${OSMPBF_INCLUDE_DIRS}
+ ${PROTOBUF_INCLUDE_DIR}
+ ${ZLIB_INCLUDE_DIR}
+ )
+ else()
+ set(_missing_libraries 1)
+ message(WARNING "Osmium: Can not find some libraries for PBF input/output, please install them or configure the paths.")
+ endif()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'xml'
+if(Osmium_USE_XML)
+ find_package(EXPAT)
+ find_package(BZip2)
+ find_package(ZLIB)
+ find_package(Threads)
+
+ if(EXPAT_FOUND AND BZIP2_FOUND AND ZLIB_FOUND AND Threads_FOUND)
+ list(APPEND OSMIUM_XML_LIBRARIES
+ ${EXPAT_LIBRARIES}
+ ${BZIP2_LIBRARIES}
+ ${ZLIB_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ )
+ list(APPEND OSMIUM_INCLUDE_DIRS
+ ${EXPAT_INCLUDE_DIR}
+ ${BZIP2_INCLUDE_DIR}
+ ${ZLIB_INCLUDE_DIR}
+ )
+ else()
+ set(_missing_libraries 1)
+ message(WARNING "Osmium: Can not find some libraries for XML input/output, please install them or configure the paths.")
+ endif()
+endif()
+
+#----------------------------------------------------------------------
+list(APPEND OSMIUM_IO_LIBRARIES
+ ${OSMIUM_PBF_LIBRARIES}
+ ${OSMIUM_XML_LIBRARIES}
+)
+
+list(APPEND OSMIUM_LIBRARIES
+ ${OSMIUM_IO_LIBRARIES}
+)
+
+#----------------------------------------------------------------------
+# Component 'geos'
+if(Osmium_USE_GEOS)
+ find_path(GEOS_INCLUDE_DIR geos/geom.h)
+ find_library(GEOS_LIBRARY NAMES geos)
+
+ if(GEOS_INCLUDE_DIR AND GEOS_LIBRARY)
+ SET(GEOS_FOUND 1)
+ list(APPEND OSMIUM_LIBRARIES ${GEOS_LIBRARY})
+ list(APPEND OSMIUM_INCLUDE_DIRS ${GEOS_INCLUDE_DIR})
+ else()
+ set(_missing_libraries 1)
+ message(WARNING "Osmium: GEOS library is required but not found, please install it or configure the paths.")
+ endif()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'gdal' (alias 'ogr')
+if(Osmium_USE_GDAL)
+ find_package(GDAL)
+
+ if(GDAL_FOUND)
+ list(APPEND OSMIUM_LIBRARIES ${GDAL_LIBRARIES})
+ list(APPEND OSMIUM_INCLUDE_DIRS ${GDAL_INCLUDE_DIRS})
+ else()
+ set(_missing_libraries 1)
+ message(WARNING "Osmium: GDAL library is required but not found, please install it or configure the paths.")
+ endif()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'proj'
+if(Osmium_USE_PROJ)
+ find_path(PROJ_INCLUDE_DIR proj_api.h)
+ find_library(PROJ_LIBRARY NAMES proj)
+
+ if(PROJ_INCLUDE_DIR AND PROJ_LIBRARY)
+ set(PROJ_FOUND 1)
+ list(APPEND OSMIUM_LIBRARIES ${PROJ_LIBRARY})
+ list(APPEND OSMIUM_INCLUDE_DIRS ${PROJ_INCLUDE_DIR})
+ else()
+ set(_missing_libraries 1)
+ message(WARNING "Osmium: PROJ.4 library is required but not found, please install it or configure the paths.")
+ endif()
+endif()
+
+#----------------------------------------------------------------------
+# Component 'sparsehash'
+if(Osmium_USE_SPARSEHASH)
+ find_path(SPARSEHASH_INCLUDE_DIR google/sparsetable)
+
+ if(SPARSEHASH_INCLUDE_DIR)
+ # Find size of sparsetable::size_type. This does not work on older
+ # CMake versions because they can do this check only in C, not in C++.
+ include(CheckTypeSize)
+ set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR})
+ set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable")
+ check_type_size("google::sparsetable<int>::size_type" SPARSETABLE_SIZE_TYPE LANGUAGE CXX)
+ set(CMAKE_EXTRA_INCLUDE_FILES)
+ set(CMAKE_REQUIRED_INCLUDES)
+
+ # Falling back to checking size_t if google::sparsetable<int>::size_type
+ # could not be checked.
+ if(SPARSETABLE_SIZE_TYPE STREQUAL "")
+ check_type_size("void*" VOID_PTR_SIZE)
+ set(SPARSETABLE_SIZE_TYPE ${VOID_PTR_SIZE})
+ endif()
+
+ # Sparsetable::size_type must be at least 8 bytes (64bit), otherwise
+ # OSM object IDs will not fit.
+ if(SPARSETABLE_SIZE_TYPE GREATER 7)
+ set(SPARSEHASH_FOUND 1)
+ add_definitions(-DOSMIUM_WITH_SPARSEHASH=${SPARSEHASH_FOUND})
+ list(APPEND OSMIUM_INCLUDE_DIRS ${SPARSEHASH_INCLUDE_DIR})
+ else()
+ message(WARNING "Osmium: Disabled Google SparseHash library on 32bit system (size_type=${SPARSETABLE_SIZE_TYPE}).")
+ endif()
+ else()
+ set(_missing_libraries 1)
+ message(WARNING "Osmium: Google SparseHash library is required but not found, please install it or configure the paths.")
+ endif()
+endif()
+
+#----------------------------------------------------------------------
+
+list(REMOVE_DUPLICATES OSMIUM_INCLUDE_DIRS)
+
+if(OSMIUM_XML_LIBRARIES)
+ list(REMOVE_DUPLICATES OSMIUM_XML_LIBRARIES)
+endif()
+
+if(OSMIUM_PBF_LIBRARIES)
+ list(REMOVE_DUPLICATES OSMIUM_PBF_LIBRARIES)
+endif()
+
+if(OSMIUM_IO_LIBRARIES)
+ list(REMOVE_DUPLICATES OSMIUM_IO_LIBRARIES)
+endif()
+
+if(OSMIUM_LIBRARIES)
+ list(REMOVE_DUPLICATES OSMIUM_LIBRARIES)
+endif()
+
+#----------------------------------------------------------------------
+#
+# Check that all required libraries are available
+#
+#----------------------------------------------------------------------
+if(Osmium_FIND_REQUIRED AND _missing_libraries)
+ message(FATAL_ERROR "Required library or libraries missing. Aborting.")
+endif()
+
+#----------------------------------------------------------------------
+#
+# Add compiler flags
+#
+#----------------------------------------------------------------------
+add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64)
+
+if(MSVC)
+ add_definitions(-wd4996)
+
+ # Disable warning C4068: "unknown pragma" because we want it to ignore
+ # pragmas for other compilers.
+ add_definitions(-wd4068)
+
+ # Disable warning C4715: "not all control paths return a value" because
+ # it generates too many false positives.
+ add_definitions(-wd4715)
+
+ # Disable warning C4351: new behavior: elements of array '...' will be
+ # default initialized. The new behaviour is correct and we don't support
+ # old compilers anyway.
+ add_definitions(-wd4351)
+
+ add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS)
+endif()
+
+if(APPLE)
+# following only available from cmake 2.8.12:
+# add_compile_options(-stdlib=libc++)
+# so using this instead:
+ add_definitions(-stdlib=libc++)
+ set(LDFLAGS ${LDFLAGS} -stdlib=libc++)
+endif()
+
+#----------------------------------------------------------------------
+
+# This is a set of recommended warning options that can be added when compiling
+# libosmium code.
+if(MSVC)
+ set(OSMIUM_WARNING_OPTIONS "/W3 /wd4514" CACHE STRING "Recommended warning options for libosmium")
+else()
+ set(OSMIUM_WARNING_OPTIONS "-Wall -Wextra -pedantic -Wredundant-decls -Wdisabled-optimization -Wctor-dtor-privacy -Wnon-virtual-dtor -Woverloaded-virtual -Wsign-promo -Wold-style-cast -Wno-return-type" CACHE STRING "Recommended warning options for libosmium")
+endif()
+
+set(OSMIUM_DRACONIC_CLANG_OPTIONS "-Wdocumentation -Wunused-exception-parameter -Wmissing-declarations -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-unused-macros -Wno-exit-time-destructors -Wno-global-constructors -Wno-padded -Wno-switch-enum -Wno-missing-prototypes -Wno-weak-vtables -Wno-cast-align -Wno-float-equal")
+
+if(Osmium_DEBUG)
+ message(STATUS "OSMIUM_XML_LIBRARIES=" ${OSMIUM_XML_LIBRARIES})
+ message(STATUS "OSMIUM_PBF_LIBRARIES=" ${OSMIUM_PBF_LIBRARIES})
+ message(STATUS "OSMIUM_IO_LIBRARIES=" ${OSMIUM_IO_LIBRARIES})
+ message(STATUS "OSMIUM_LIBRARIES=" ${OSMIUM_LIBRARIES})
+ message(STATUS "OSMIUM_INCLUDE_DIRS=" ${OSMIUM_INCLUDE_DIRS})
+endif()
+
diff --git a/third_party/libosmium/cmake/README b/third_party/libosmium/cmake/README
new file mode 100644
index 0000000..4a035f7
--- /dev/null
+++ b/third_party/libosmium/cmake/README
@@ -0,0 +1,3 @@
+
+FindGem.cmake from https://github.com/rock-core/base-cmake
+
diff --git a/third_party/libosmium/cmake/build.bat b/third_party/libosmium/cmake/build.bat
new file mode 100644
index 0000000..5ffab12
--- /dev/null
+++ b/third_party/libosmium/cmake/build.bat
@@ -0,0 +1,15 @@
+call "%VS120COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64
+set CMAKE_PREFIX_PATH=C:\PROJ
+set VERSION=Debug
+set TESTS=ON
+set ALLHPPS=ON
+set PREFIX=d:\libs18d
+set BOOST_ROOT=d:\boost
+
+cmake .. -G "Visual Studio 12 Win64" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=%PREFIX% -DBOOST_ROOT=%BOOST_ROOT% -DBoost_USE_STATIC_LIBS=ON -DBUILD_TESTING=%TESTS% -DBUILD_TRY_HPPS=%ALLHPPS$ -T CTP_Nov2013
+msbuild /clp:Verbosity=minimal /nologo libosmium.sln /flp1:logfile=build_errors.txt;errorsonly /flp2:logfile=build_warnings.txt;warningsonly
+set PATH=%PATH%;%PREFIX%/bin
+
+del test\osm-testdata\*.db
+del test\osm-testdata\*.json
+if "%TESTS%"=="ON" ctest -VV >build_tests.log
diff --git a/third_party/libosmium/cmake/iwyu.sh b/third_party/libosmium/cmake/iwyu.sh
new file mode 100755
index 0000000..d203844
--- /dev/null
+++ b/third_party/libosmium/cmake/iwyu.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# This will run IWYU (Include What You Use) on includes files. The iwyu
+# program isn't very reliable and crashes often, but is still useful.
+#
+# TODO: This script should be integrated with cmake in some way...
+#
+
+cmdline="iwyu -Xiwyu --mapping_file=osmium.imp -std=c++11 -I include"
+
+log=build/iwyu.log
+
+echo "INCLUDE WHAT YOU USE REPORT:" >$log
+
+allok=yes
+
+mkdir -p build/check_reports
+
+for file in `find include/osmium -name \*.hpp`; do
+ mkdir -p `dirname build/check_reports/$file`
+ ifile="build/check_reports/${file%.hpp}.iwyu"
+ $cmdline $file >$ifile 2>&1
+ if grep -q 'has correct #includes/fwd-decls' ${ifile}; then
+ echo "\n\033[1m\033[32m========\033[0m \033[1m${file}\033[0m" >>$log
+ echo "[OK] ${file}"
+ elif grep -q 'Assertion failed' ${ifile}; then
+ echo "\n\033[1m======== ${file}\033[0m" >>$log
+ echo "[--] ${file}"
+ allok=no
+ else
+ echo "\n\033[1m\033[31m========\033[0m \033[1m${file}\033[0m" >>$log
+ echo "[ ] ${file}"
+ allok=no
+ fi
+ cat $ifile >>$log
+done
+
+if [ "$allok" = "yes" ]; then
+ echo "All files OK"
+else
+ echo "There were errors"
+fi
+
diff --git a/third_party/libosmium/doc/CMakeLists.txt b/third_party/libosmium/doc/CMakeLists.txt
new file mode 100644
index 0000000..9d69a16
--- /dev/null
+++ b/third_party/libosmium/doc/CMakeLists.txt
@@ -0,0 +1,35 @@
+#-----------------------------------------------------------------------------
+#
+# CMake Config
+#
+# Libosmium documentation
+#
+#-----------------------------------------------------------------------------
+
+message(STATUS "Configuring documentation")
+
+message(STATUS "Looking for doxygen")
+find_package(Doxygen)
+
+if(DOXYGEN_FOUND)
+ message(STATUS "Looking for doxygen - found")
+ configure_file(header.html ${CMAKE_CURRENT_BINARY_DIR}/header.html @ONLY)
+ configure_file(Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
+ add_custom_target(doc
+ ${DOXYGEN_EXECUTABLE}
+ ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Generating API documentation with Doxygen" VERBATIM
+ )
+# install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html"
+# DESTINATION "share/doc/libosmium-dev")
+else()
+ message(STATUS "Looking for doxygen - not found")
+ message(STATUS " Disabled making of documentation.")
+endif()
+
+#-----------------------------------------------------------------------------
+message(STATUS "Configuring documentation - done")
+
+
+#-----------------------------------------------------------------------------
diff --git a/third_party/libosmium/doc/Doxyfile.in b/third_party/libosmium/doc/Doxyfile.in
new file mode 100644
index 0000000..c03e255
--- /dev/null
+++ b/third_party/libosmium/doc/Doxyfile.in
@@ -0,0 +1,2313 @@
+# Doxyfile 1.8.7
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "Libosmium"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = @LIBOSMIUM_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "Fast and flexible C++ library for working with OpenStreetMap data"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = "@PROJECT_BINARY_DIR@/doc"
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@/include
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = @PROJECT_SOURCE_DIR@/include/osmium \
+ @PROJECT_SOURCE_DIR@/doc/doc.txt
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.hpp
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = detail
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS = *::detail
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER = "grep -v static_assert"
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = YES
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER = header.html
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET = "@PROJECT_SOURCE_DIR@/doc/osmium.css"
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NONE
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = __linux__
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/third_party/libosmium/doc/README.md b/third_party/libosmium/doc/README.md
new file mode 100644
index 0000000..7ca8e7c
--- /dev/null
+++ b/third_party/libosmium/doc/README.md
@@ -0,0 +1,8 @@
+
+The `header.html` is created with:
+
+`doxygen -w html header.html footer.html stylesheet.css`
+
+This might have to be rn again for newer Doxygen versions. After that add
+changes back in.
+
diff --git a/third_party/libosmium/doc/doc.txt b/third_party/libosmium/doc/doc.txt
new file mode 100644
index 0000000..1f06f4f
--- /dev/null
+++ b/third_party/libosmium/doc/doc.txt
@@ -0,0 +1,26 @@
+
+/**
+ * @mainpage
+ *
+ * Osmium is a fast and flexible C++ library for working with OpenStreetMap
+ * data.
+ *
+ * This is the API documentation that was automatically created from the
+ * source code. For more information about the Osmium Library see
+ * http://osmcode.org/libosmium .
+ *
+ * Osmium is free software and available under the Boost Software License.
+ * The source code is available at https://github.com/osmcode/libosmium .
+ *
+ * Osmium is a header-only library. You do not need to compile and link it,
+ * just include the headers you need.
+ *
+ * Everything in namespaces called "detail" is for internal Osmium use only,
+ * do not depend on it in your code. Do not include any include files in
+ * directories named "detail" directly. Include files in directories called
+ * "experimental" and everything in namespaces called "experimental" is
+ * unsupported and may change at any time regardless of the status of the rest
+ * of the library.
+ *
+ */
+
diff --git a/third_party/libosmium/doc/header.html b/third_party/libosmium/doc/header.html
new file mode 100644
index 0000000..495d500
--- /dev/null
+++ b/third_party/libosmium/doc/header.html
@@ -0,0 +1,56 @@
+<!-- HTML header for doxygen 1.8.8-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<meta name="viewport" content="width=device-width, initial-scale=1"/>
+<meta name="generator" content="Doxygen $doxygenversion"/>
+<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="$relpath^jquery.js"></script>
+<script type="text/javascript" src="$relpath^dynsections.js"></script>
+$treeview
+$search
+$mathjax
+<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
+$extrastylesheet
+</head>
+<body>
+<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+
+<!--BEGIN TITLEAREA-->
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+ <!--BEGIN PROJECT_LOGO-->
+ <td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
+ <!--END PROJECT_LOGO-->
+ <!--BEGIN PROJECT_NAME-->
+ <td style="padding-left: 0.5em;">
+ <div id="projectname">$projectname
+ <!--BEGIN PROJECT_NUMBER--> <span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
+ </div>
+ <!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
+ </td>
+ <!--END PROJECT_NAME-->
+ <!--BEGIN !PROJECT_NAME-->
+ <!--BEGIN PROJECT_BRIEF-->
+ <td style="padding-left: 0.5em;">
+ <div id="projectbrief">$projectbrief</div>
+ </td>
+ <!--END PROJECT_BRIEF-->
+ <!--END !PROJECT_NAME-->
+ <!--BEGIN DISABLE_INDEX-->
+ <!--BEGIN SEARCHENGINE-->
+ <td>$searchbox</td>
+ <!--END SEARCHENGINE-->
+ <!--END DISABLE_INDEX-->
+ </tr>
+ </tbody>
+</table>
+</div>
+<!--END TITLEAREA-->
+<!-- end header part -->
diff --git a/third_party/libosmium/doc/osmium.css b/third_party/libosmium/doc/osmium.css
new file mode 100644
index 0000000..6256e84
--- /dev/null
+++ b/third_party/libosmium/doc/osmium.css
@@ -0,0 +1,22 @@
+
+body {
+ font-family: "Droid Sans",Helvetica,Arial,sans-serif;
+ background-color: #ffffff;
+ color: #202060;
+}
+
+.tabs, .tabs2, .tabs3, .navpath ul, .tablist li {
+ background-image: none;
+}
+
+.tabs, .tabs2, .tabs3 {
+ border-top: 1px solid #202060;
+}
+
+div.contents {
+ margin: 0px;
+ padding-top: 10px;
+ padding-left: 12px;
+ padding-right: 8px;
+}
+
diff --git a/third_party/libosmium/examples/CMakeLists.txt b/third_party/libosmium/examples/CMakeLists.txt
new file mode 100644
index 0000000..c9f5960
--- /dev/null
+++ b/third_party/libosmium/examples/CMakeLists.txt
@@ -0,0 +1,115 @@
+#-----------------------------------------------------------------------------
+#
+# CMake Config
+#
+# Libosmium examples
+#
+#-----------------------------------------------------------------------------
+
+message(STATUS "Configuring examples")
+
+set(EXAMPLES
+ area_test
+ convert
+ count
+ create_node_cache
+ debug
+ index
+ read
+ serdump
+ toogr
+ toogr2
+ toogr2_exp
+ use_node_cache
+ CACHE STRING "Example programs"
+)
+
+
+#-----------------------------------------------------------------------------
+#
+# Examples depending on wingetopt
+#
+#-----------------------------------------------------------------------------
+set(GETOPT_EXAMPLES area_test convert serdump toogr toogr2 toogr2_exp)
+if(NOT GETOPT_MISSING)
+ foreach(example ${GETOPT_EXAMPLES})
+ list(APPEND EXAMPLE_LIBS_${example} ${GETOPT_LIBRARY})
+ endforeach()
+else()
+ message(STATUS "Configuring examples - Skipping examples because on Visual Studio the wingetopt library is needed and was not found:")
+ foreach(example ${GETOPT_EXAMPLES})
+ message(STATUS " - osmium_${example}")
+ list(REMOVE_ITEM EXAMPLES ${example})
+ endforeach()
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+# Examples depending on SparseHash
+#
+#-----------------------------------------------------------------------------
+if(NOT SPARSEHASH_FOUND)
+ list(REMOVE_ITEM EXAMPLES area_test)
+ message(STATUS "Configuring examples - Skipping examples because Google SparseHash not found:")
+ message(STATUS " - osmium_area_test")
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+# Examples depending on Boost Program Options
+#
+#-----------------------------------------------------------------------------
+unset(Boost_LIBRARIES)
+unset(Boost_FOUND)
+find_package(Boost 1.38 COMPONENTS program_options)
+
+if(Boost_PROGRAM_OPTIONS_FOUND)
+ list(APPEND EXAMPLE_LIBS_index ${Boost_PROGRAM_OPTIONS_LIBRARY})
+else()
+ list(REMOVE_ITEM EXAMPLES index)
+ message(STATUS "Configuring examples - Skipping examples because Boost program_options not found:")
+ message(STATUS " - osmium_index")
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+# Examples depending on GDAL/PROJ.4/SparseHash
+#
+#-----------------------------------------------------------------------------
+set(OGR_EXAMPLES toogr toogr2 toogr2_exp)
+
+if(GDAL_FOUND AND PROJ_FOUND AND SPARSEHASH_FOUND)
+ foreach(example ${OGR_EXAMPLES})
+ list(APPEND EXAMPLE_LIBS_${example} ${GDAL_LIBRARIES})
+ list(APPEND EXAMPLE_LIBS_${example} ${PROJ_LIBRARIES})
+ endforeach()
+else()
+ message(STATUS "Configuring examples - Skipping examples because GDAL and/or Proj.4 and/or SparseHash not found:")
+ foreach(example ${OGR_EXAMPLES})
+ message(STATUS " - osmium_${example}")
+ list(REMOVE_ITEM EXAMPLES ${example})
+ endforeach()
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+# Configure examples
+#
+#-----------------------------------------------------------------------------
+message(STATUS "Configuring examples - Building these examples:")
+foreach(example ${EXAMPLES})
+ message(STATUS " - osmium_${example}")
+ add_executable(osmium_${example} "osmium_${example}.cpp")
+ target_link_libraries(osmium_${example} ${OSMIUM_IO_LIBRARIES} ${EXAMPLE_LIBS_${example}})
+endforeach()
+
+
+#-----------------------------------------------------------------------------
+message(STATUS "Configuring examples - done")
+
+
+#-----------------------------------------------------------------------------
diff --git a/third_party/libosmium/examples/osmium_area_test.cpp b/third_party/libosmium/examples/osmium_area_test.cpp
new file mode 100644
index 0000000..ee2ba12
--- /dev/null
+++ b/third_party/libosmium/examples/osmium_area_test.cpp
@@ -0,0 +1,138 @@
+/*
+
+ This is an example tool that creates multipolygons from OSM data
+ and dumps them to stdout.
+
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <iostream>
+
+#include <getopt.h>
+
+#include <osmium/area/assembler.hpp>
+#include <osmium/area/multipolygon_collector.hpp>
+#include <osmium/dynamic_handler.hpp>
+#include <osmium/geom/wkt.hpp>
+#include <osmium/handler/dump.hpp>
+#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/index/map/dummy.hpp>
+#include <osmium/index/map/sparse_mem_array.hpp>
+#include <osmium/io/any_input.hpp>
+#include <osmium/visitor.hpp>
+
+typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
+typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
+typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
+
+class WKTDump : public osmium::handler::Handler {
+
+ osmium::geom::WKTFactory<> m_factory ;
+
+ std::ostream& m_out;
+
+public:
+
+ WKTDump(std::ostream& out) :
+ m_out(out) {
+ }
+
+ void area(const osmium::Area& area) {
+ try {
+ m_out << m_factory.create_multipolygon(area) << "\n";
+ } catch (osmium::geometry_error& e) {
+ m_out << "GEOMETRY ERROR: " << e.what() << "\n";
+ }
+ }
+
+}; // class WKTDump
+
+void print_help() {
+ std::cout << "osmium_area_test [OPTIONS] OSMFILE\n\n"
+ << "Read OSMFILE and build multipolygons from it.\n"
+ << "\nOptions:\n"
+ << " -h, --help This help message\n"
+ << " -w, --dump-wkt Dump area geometries as WKT\n"
+ << " -o, --dump-objects Dump area objects\n";
+}
+
+int main(int argc, char* argv[]) {
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"dump-wkt", no_argument, 0, 'w'},
+ {"dump-objects", no_argument, 0, 'o'},
+ {0, 0, 0, 0}
+ };
+
+ osmium::handler::DynamicHandler handler;
+
+ while (true) {
+ int c = getopt_long(argc, argv, "hwo", long_options, 0);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'h':
+ print_help();
+ exit(0);
+ case 'w':
+ handler.set<WKTDump>(std::cout);
+ break;
+ case 'o':
+ handler.set<osmium::handler::Dump>(std::cout);
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ int remaining_args = argc - optind;
+ if (remaining_args != 1) {
+ std::cerr << "Usage: " << argv[0] << " [OPTIONS] OSMFILE\n";
+ exit(1);
+ }
+
+ osmium::io::File infile(argv[optind]);
+
+ osmium::area::Assembler::config_type assembler_config;
+ osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config);
+
+ std::cout << "Pass 1...\n";
+ osmium::io::Reader reader1(infile, osmium::osm_entity_bits::relation);
+ collector.read_relations(reader1);
+ reader1.close();
+ std::cout << "Pass 1 done\n";
+
+ std::cout << "Memory:\n";
+ collector.used_memory();
+
+ index_pos_type index_pos;
+ index_neg_type index_neg;
+ location_handler_type location_handler(index_pos, index_neg);
+ location_handler.ignore_errors(); // XXX
+
+ std::cout << "Pass 2...\n";
+ osmium::io::Reader reader2(infile);
+ osmium::apply(reader2, location_handler, collector.handler([&handler](osmium::memory::Buffer&& buffer) {
+ osmium::apply(buffer, handler);
+ }));
+ reader2.close();
+ std::cout << "Pass 2 done\n";
+
+ std::cout << "Memory:\n";
+ collector.used_memory();
+
+ std::vector<const osmium::Relation*> incomplete_relations = collector.get_incomplete_relations();
+ if (!incomplete_relations.empty()) {
+ std::cerr << "Warning! Some member ways missing for these multipolygon relations:";
+ for (const auto* relation : incomplete_relations) {
+ std::cerr << " " << relation->id();
+ }
+ std::cerr << "\n";
+ }
+
+ google::protobuf::ShutdownProtobufLibrary();
+}
+
diff --git a/third_party/libosmium/examples/osmium_convert.cpp b/third_party/libosmium/examples/osmium_convert.cpp
new file mode 100644
index 0000000..7956e11
--- /dev/null
+++ b/third_party/libosmium/examples/osmium_convert.cpp
@@ -0,0 +1,112 @@
+/*
+
+ Convert OSM files from one format into another.
+
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <iostream>
+#include <getopt.h>
+
+#include <osmium/io/any_input.hpp>
+
+#include <osmium/io/any_output.hpp>
+
+void print_help() {
+ std::cout << "osmium_convert [OPTIONS] [INFILE [OUTFILE]]\n\n" \
+ << "If INFILE or OUTFILE is not given stdin/stdout is assumed.\n" \
+ << "File format is autodetected from file name suffix.\n" \
+ << "Use -f and -t options to force file format.\n" \
+ << "\nFile types:\n" \
+ << " osm normal OSM file\n" \
+ << " osc OSM change file\n" \
+ << " osh OSM file with history information\n" \
+ << "\nFile format:\n" \
+ << " (default) XML encoding\n" \
+ << " pbf binary PBF encoding\n" \
+ << " opl OPL encoding\n" \
+ << "\nFile compression\n" \
+ << " gz compressed with gzip\n" \
+ << " bz2 compressed with bzip2\n" \
+ << "\nOptions:\n" \
+ << " -h, --help This help message\n" \
+ << " -f, --from-format=FORMAT Input format\n" \
+ << " -t, --to-format=FORMAT Output format\n";
+}
+
+int main(int argc, char* argv[]) {
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"from-format", required_argument, 0, 'f'},
+ {"to-format", required_argument, 0, 't'},
+ {0, 0, 0, 0}
+ };
+
+ std::string input_format;
+ std::string output_format;
+
+ while (true) {
+ int c = getopt_long(argc, argv, "dhf:t:", long_options, 0);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'h':
+ print_help();
+ exit(0);
+ case 'f':
+ input_format = optarg;
+ break;
+ case 't':
+ output_format = optarg;
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ std::string input;
+ std::string output;
+ int remaining_args = argc - optind;
+ if (remaining_args > 2) {
+ std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]" << std::endl;
+ exit(1);
+ } else if (remaining_args == 2) {
+ input = argv[optind];
+ output = argv[optind+1];
+ } else if (remaining_args == 1) {
+ input = argv[optind];
+ }
+
+ osmium::io::File infile(input, input_format);
+
+ osmium::io::File outfile(output, output_format);
+
+ if (infile.has_multiple_object_versions() && !outfile.has_multiple_object_versions()) {
+ std::cerr << "Warning! You are converting from an OSM file with (potentially) several versions of the same object to one that is not marked as such.\n";
+ }
+
+ int exit_code = 0;
+
+ try {
+ osmium::io::Reader reader(infile);
+ osmium::io::Header header = reader.header();
+ header.set("generator", "osmium_convert");
+
+ osmium::io::Writer writer(outfile, header, osmium::io::overwrite::allow);
+ while (osmium::memory::Buffer buffer = reader.read()) {
+ writer(std::move(buffer));
+ }
+ writer.close();
+ reader.close();
+ } catch (std::exception& e) {
+ std::cerr << e.what() << "\n";
+ exit_code = 1;
+ }
+
+ google::protobuf::ShutdownProtobufLibrary();
+ return exit_code;
+}
+
diff --git a/third_party/libosmium/examples/osmium_count.cpp b/third_party/libosmium/examples/osmium_count.cpp
new file mode 100644
index 0000000..dca18bf
--- /dev/null
+++ b/third_party/libosmium/examples/osmium_count.cpp
@@ -0,0 +1,57 @@
+/*
+
+ This is a small tool that counts the number of nodes, ways, and relations in
+ the input file.
+
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <iostream>
+
+#include <osmium/io/any_input.hpp>
+#include <osmium/handler.hpp>
+#include <osmium/visitor.hpp>
+
+struct CountHandler : public osmium::handler::Handler {
+
+ int nodes = 0;
+ int ways = 0;
+ int relations = 0;
+
+ void node(osmium::Node&) {
+ ++nodes;
+ }
+
+ void way(osmium::Way&) {
+ ++ways;
+ }
+
+ void relation(osmium::Relation&) {
+ ++relations;
+ }
+
+};
+
+
+int main(int argc, char* argv[]) {
+
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
+ exit(1);
+ }
+
+ osmium::io::File infile(argv[1]);
+ osmium::io::Reader reader(infile);
+
+ CountHandler handler;
+ osmium::apply(reader, handler);
+ reader.close();
+
+ std::cout << "Nodes: " << handler.nodes << "\n";
+ std::cout << "Ways: " << handler.ways << "\n";
+ std::cout << "Relations: " << handler.relations << "\n";
+
+ google::protobuf::ShutdownProtobufLibrary();
+}
+
diff --git a/third_party/libosmium/examples/osmium_create_node_cache.cpp b/third_party/libosmium/examples/osmium_create_node_cache.cpp
new file mode 100644
index 0000000..74f7596
--- /dev/null
+++ b/third_party/libosmium/examples/osmium_create_node_cache.cpp
@@ -0,0 +1,58 @@
+/*
+
+ This reads an OSM file and writes out the node locations to a cache
+ file.
+
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <iostream>
+
+#include <osmium/io/pbf_input.hpp>
+#include <osmium/io/xml_input.hpp>
+
+#include <osmium/index/map/dummy.hpp>
+#include <osmium/index/map/dense_mmap_array.hpp>
+#include <osmium/index/map/dense_file_array.hpp>
+
+#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/visitor.hpp>
+
+typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
+//typedef osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
+typedef osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
+
+typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
+
+int main(int argc, char* argv[]) {
+ if (argc != 3) {
+ std::cerr << "Usage: " << argv[0] << " OSM_FILE CACHE_FILE\n";
+ return 1;
+ }
+
+ std::string input_filename(argv[1]);
+ osmium::io::Reader reader(input_filename, osmium::osm_entity_bits::node);
+
+ int fd = open(argv[2], O_RDWR | O_CREAT, 0666);
+ if (fd == -1) {
+ std::cerr << "Can not open node cache file '" << argv[2] << "': " << strerror(errno) << "\n";
+ return 1;
+ }
+
+ index_pos_type index_pos {fd};
+ index_neg_type index_neg;
+ location_handler_type location_handler(index_pos, index_neg);
+ location_handler.ignore_errors();
+
+ osmium::apply(reader, location_handler);
+ reader.close();
+
+ google::protobuf::ShutdownProtobufLibrary();
+
+ return 0;
+}
+
diff --git a/third_party/libosmium/examples/osmium_debug.cpp b/third_party/libosmium/examples/osmium_debug.cpp
new file mode 100644
index 0000000..6878ed1
--- /dev/null
+++ b/third_party/libosmium/examples/osmium_debug.cpp
@@ -0,0 +1,52 @@
+/*
+
+ This is a small tool to dump the contents of the input file.
+
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <iostream>
+
+#include <osmium/handler/dump.hpp>
+#include <osmium/io/any_input.hpp>
+
+int main(int argc, char* argv[]) {
+ std::ios_base::sync_with_stdio(false);
+
+ if (argc < 2 || argc > 3) {
+ std::cerr << "Usage: " << argv[0] << " OSMFILE [TYPES]\n";
+ std::cerr << "TYPES can be any combination of 'n', 'w', 'r', and 'c' to indicate what types of OSM entities you want (default: all).\n";
+ exit(1);
+ }
+
+ osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all;
+
+ if (argc == 3) {
+ read_types = osmium::osm_entity_bits::nothing;
+ std::string types = argv[2];
+ if (types.find('n') != std::string::npos) read_types |= osmium::osm_entity_bits::node;
+ if (types.find('w') != std::string::npos) read_types |= osmium::osm_entity_bits::way;
+ if (types.find('r') != std::string::npos) read_types |= osmium::osm_entity_bits::relation;
+ if (types.find('c') != std::string::npos) read_types |= osmium::osm_entity_bits::changeset;
+ }
+
+ osmium::io::Reader reader(argv[1], read_types);
+ osmium::io::Header header = reader.header();
+
+ std::cout << "HEADER:\n generator=" << header.get("generator") << "\n";
+
+ for (auto& bbox : header.boxes()) {
+ std::cout << " bbox=" << bbox << "\n";
+ }
+
+ osmium::handler::Dump dump(std::cout);
+ while (osmium::memory::Buffer buffer = reader.read()) {
+ osmium::apply(buffer, dump);
+ }
+
+ reader.close();
+
+ google::protobuf::ShutdownProtobufLibrary();
+}
+
diff --git a/third_party/libosmium/examples/osmium_index.cpp b/third_party/libosmium/examples/osmium_index.cpp
new file mode 100644
index 0000000..b612140
--- /dev/null
+++ b/third_party/libosmium/examples/osmium_index.cpp
@@ -0,0 +1,237 @@
+/*
+
+ Example program to look at Osmium indexes on disk.
+
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <fcntl.h>
+#include <iomanip>
+#include <iostream>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <boost/program_options.hpp>
+
+#include <osmium/index/map/dense_file_array.hpp>
+#include <osmium/index/map/sparse_file_array.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+template <typename TKey, typename TValue>
+class IndexSearch {
+
+ typedef typename osmium::index::map::DenseFileArray<TKey, TValue> dense_index_type;
+ typedef typename osmium::index::map::SparseFileArray<TKey, TValue> sparse_index_type;
+
+ int m_fd;
+ bool m_dense_format;
+
+ void dump_dense() {
+ dense_index_type index(m_fd);
+
+ for (size_t i = 0; i < index.size(); ++i) {
+ if (index.get(i) != TValue()) {
+ std::cout << i << " " << index.get(i) << "\n";
+ }
+ }
+ }
+
+ void dump_sparse() {
+ sparse_index_type index(m_fd);
+
+ for (auto& element : index) {
+ std::cout << element.first << " " << element.second << "\n";
+ }
+ }
+
+ bool search_dense(TKey key) {
+ dense_index_type index(m_fd);
+
+ try {
+ TValue value = index.get(key);
+ std::cout << key << " " << value << std::endl;
+ } catch (...) {
+ std::cout << key << " not found" << std::endl;
+ return false;
+ }
+
+ return true;
+ }
+
+ bool search_sparse(TKey key) {
+ typedef typename sparse_index_type::element_type element_type;
+ sparse_index_type index(m_fd);
+
+ element_type elem {key, TValue()};
+ auto positions = std::equal_range(index.begin(), index.end(), elem, [](const element_type& lhs, const element_type& rhs) {
+ return lhs.first < rhs.first;
+ });
+ if (positions.first == positions.second) {
+ std::cout << key << " not found" << std::endl;
+ return false;
+ }
+
+ for (auto& it = positions.first; it != positions.second; ++it) {
+ std::cout << it->first << " " << it->second << "\n";
+ }
+
+ return true;
+ }
+
+public:
+
+ IndexSearch(int fd, bool dense_format) :
+ m_fd(fd),
+ m_dense_format(dense_format) {
+ }
+
+ void dump() {
+ if (m_dense_format) {
+ dump_dense();
+ } else {
+ dump_sparse();
+ }
+ }
+
+ bool search(TKey key) {
+ if (m_dense_format) {
+ return search_dense(key);
+ } else {
+ return search_sparse(key);
+ }
+ }
+
+ bool search(std::vector<TKey> keys) {
+ bool found_all = true;
+
+ for (const auto key : keys) {
+ if (!search(key)) {
+ found_all = false;
+ }
+ }
+
+ return found_all;
+ }
+
+}; // class IndexSearch
+
+enum return_code : int {
+ okay = 0,
+ not_found = 1,
+ error = 2,
+ fatal = 3
+};
+
+namespace po = boost::program_options;
+
+class Options {
+
+ po::variables_map vm;
+
+public:
+
+ Options(int argc, char* argv[]) {
+ try {
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help,h", "Print this help message")
+ ("array,a", po::value<std::string>(), "Read given index file in array format")
+ ("list,l", po::value<std::string>(), "Read given index file in list format")
+ ("dump,d", "Dump contents of index file to STDOUT")
+ ("search,s", po::value<std::vector<osmium::unsigned_object_id_type>>(), "Search for given id (Option can appear multiple times)")
+ ("type,t", po::value<std::string>(), "Type of value ('location' or 'offset')")
+ ;
+
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ if (vm.count("help")) {
+ std::cout << desc << "\n";
+ exit(return_code::okay);
+ }
+
+ if (vm.count("array") && vm.count("list")) {
+ std::cerr << "Only option --array or --list allowed." << std::endl;
+ exit(return_code::fatal);
+ }
+
+ if (!vm.count("array") && !vm.count("list")) {
+ std::cerr << "Need one of option --array or --list." << std::endl;
+ exit(return_code::fatal);
+ }
+
+ if (!vm.count("type")) {
+ std::cerr << "Need --type argument." << std::endl;
+ exit(return_code::fatal);
+ }
+
+ const std::string& type = vm["type"].as<std::string>();
+ if (type != "location" && type != "offset") {
+ std::cerr << "Unknown type '" << type << "'. Must be 'location' or 'offset'." << std::endl;
+ exit(return_code::fatal);
+ }
+ } catch (boost::program_options::error& e) {
+ std::cerr << "Error parsing command line: " << e.what() << std::endl;
+ exit(return_code::fatal);
+ }
+ }
+
+ const std::string& filename() const {
+ if (vm.count("array")) {
+ return vm["array"].as<std::string>();
+ } else {
+ return vm["list"].as<std::string>();
+ }
+ }
+
+ bool dense_format() const {
+ return vm.count("array") != 0;
+ }
+
+ bool do_dump() const {
+ return vm.count("dump") != 0;
+ }
+
+ std::vector<osmium::unsigned_object_id_type> search_keys() const {
+ return vm["search"].as<std::vector<osmium::unsigned_object_id_type>>();
+ }
+
+ bool type_is(const char* type) const {
+ return vm["type"].as<std::string>() == type;
+ }
+
+}; // class Options
+
+int main(int argc, char* argv[]) {
+ std::ios_base::sync_with_stdio(false);
+
+ Options options(argc, argv);
+
+ std::cout << std::fixed << std::setprecision(7);
+ int fd = open(options.filename().c_str(), O_RDWR);
+
+ bool result_okay = true;
+
+ if (options.type_is("location")) {
+ IndexSearch<osmium::unsigned_object_id_type, osmium::Location> is(fd, options.dense_format());
+
+ if (options.do_dump()) {
+ is.dump();
+ } else {
+ result_okay = is.search(options.search_keys());
+ }
+ } else {
+ IndexSearch<osmium::unsigned_object_id_type, size_t> is(fd, options.dense_format());
+
+ if (options.do_dump()) {
+ is.dump();
+ } else {
+ result_okay = is.search(options.search_keys());
+ }
+ }
+
+ exit(result_okay ? return_code::okay : return_code::not_found);
+}
+
diff --git a/third_party/libosmium/examples/osmium_read.cpp b/third_party/libosmium/examples/osmium_read.cpp
new file mode 100644
index 0000000..1bb0299
--- /dev/null
+++ b/third_party/libosmium/examples/osmium_read.cpp
@@ -0,0 +1,32 @@
+/*
+
+ This is a small tool that reads and discards the contents of the input file.
+ (Used for timing.)
+
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <iostream>
+
+#include <osmium/io/any_input.hpp>
+
+int main(int argc, char* argv[]) {
+
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
+ exit(1);
+ }
+
+ osmium::io::File infile(argv[1]);
+ osmium::io::Reader reader(infile);
+
+ while (osmium::memory::Buffer buffer = reader.read()) {
+ // do nothing
+ }
+
+ reader.close();
+
+ google::protobuf::ShutdownProtobufLibrary();
+}
+
diff --git a/third_party/libosmium/examples/osmium_serdump.cpp b/third_party/libosmium/examples/osmium_serdump.cpp
new file mode 100644
index 0000000..a774a8d
--- /dev/null
+++ b/third_party/libosmium/examples/osmium_serdump.cpp
@@ -0,0 +1,209 @@
+/*
+
+ This is a small tool to dump the contents of the input file
+ in serialized format to stdout.
+
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <cerrno>
+#include <cstring>
+#include <getopt.h>
+#include <iostream>
+#include <string>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifdef _MSC_VER
+# include <direct.h>
+#endif
+
+#include <osmium/io/pbf_input.hpp>
+#include <osmium/io/xml_input.hpp>
+#include <osmium/handler/disk_store.hpp>
+#include <osmium/handler/object_relations.hpp>
+
+#include <osmium/index/map/sparse_mem_array.hpp>
+#include <osmium/index/multimap/sparse_mem_multimap.hpp>
+#include <osmium/index/multimap/sparse_mem_array.hpp>
+#include <osmium/index/multimap/hybrid.hpp>
+
+// ==============================================================================
+// Choose the following depending on the size of the input OSM files:
+// ==============================================================================
+// for smaller OSM files (extracts)
+typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, size_t> offset_index_type;
+//typedef osmium::index::map::SparseMapMmap<osmium::unsigned_object_id_type, size_t> offset_index_type;
+//typedef osmium::index::map::SparseMapFile<osmium::unsigned_object_id_type, size_t> offset_index_type;
+
+typedef osmium::index::multimap::SparseMemArray<osmium::unsigned_object_id_type, osmium::unsigned_object_id_type> map_type;
+//typedef osmium::index::multimap::SparseMemMultimap<osmium::unsigned_object_id_type, osmium::unsigned_object_id_type> map_type;
+//typedef osmium::index::multimap::Hybrid<osmium::unsigned_object_id_type, osmium::unsigned_object_id_type> map_type;
+
+// ==============================================================================
+// for very large OSM files (planet)
+//typedef osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, size_t> offset_index_type;
+// ==============================================================================
+
+void print_help() {
+ std::cout << "osmium_serdump OSMFILE DIR\n" \
+ << "Serialize content of OSMFILE into data file in DIR.\n" \
+ << "\nOptions:\n" \
+ << " -h, --help This help message\n";
+}
+
+int main(int argc, char* argv[]) {
+ std::ios_base::sync_with_stdio(false);
+
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ while (true) {
+ int c = getopt_long(argc, argv, "h", long_options, 0);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'h':
+ print_help();
+ exit(0);
+ default:
+ exit(2);
+ }
+ }
+
+ int remaining_args = argc - optind;
+
+ if (remaining_args != 2) {
+ std::cerr << "Usage: " << argv[0] << " OSMFILE DIR\n";
+ exit(2);
+ }
+
+ std::string dir(argv[optind+1]);
+#ifndef _WIN32
+ int result = ::mkdir(dir.c_str(), 0777);
+#else
+ int result = mkdir(dir.c_str());
+#endif
+ if (result == -1 && errno != EEXIST) {
+ std::cerr << "Problem creating directory '" << dir << "': " << strerror(errno) << "\n";
+ exit(2);
+ }
+
+ std::string data_file(dir + "/data.osm.ser");
+ int data_fd = ::open(data_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (data_fd < 0) {
+ std::cerr << "Can't open data file '" << data_file << "': " << strerror(errno) << "\n";
+ exit(2);
+ }
+
+ offset_index_type node_index;
+ offset_index_type way_index;
+ offset_index_type relation_index;
+
+ osmium::handler::DiskStore disk_store_handler(data_fd, node_index, way_index, relation_index);
+
+ map_type map_node2way;
+ map_type map_node2relation;
+ map_type map_way2relation;
+ map_type map_relation2relation;
+
+ osmium::handler::ObjectRelations object_relations_handler(map_node2way, map_node2relation, map_way2relation, map_relation2relation);
+
+ osmium::io::Reader reader(argv[1]);
+
+ while (osmium::memory::Buffer buffer = reader.read()) {
+ disk_store_handler(buffer); // XXX
+ osmium::apply(buffer, object_relations_handler);
+ }
+
+ reader.close();
+
+ {
+ std::string index_file(dir + "/nodes.idx");
+ int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0) {
+ std::cerr << "Can't open nodes index file '" << index_file << "': " << strerror(errno) << "\n";
+ exit(2);
+ }
+ node_index.dump_as_list(fd);
+ close(fd);
+ }
+
+ {
+ std::string index_file(dir + "/ways.idx");
+ int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0) {
+ std::cerr << "Can't open ways index file '" << index_file << "': " << strerror(errno) << "\n";
+ exit(2);
+ }
+ way_index.dump_as_list(fd);
+ close(fd);
+ }
+
+ {
+ std::string index_file(dir + "/relations.idx");
+ int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0) {
+ std::cerr << "Can't open relations index file '" << index_file << "': " << strerror(errno) << "\n";
+ exit(2);
+ }
+ relation_index.dump_as_list(fd);
+ close(fd);
+ }
+
+ {
+ map_node2way.sort();
+ std::string index_file(dir + "/node2way.map");
+ int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0) {
+ std::cerr << "Can't open node->way map file '" << index_file << "': " << strerror(errno) << "\n";
+ exit(2);
+ }
+ map_node2way.dump_as_list(fd);
+ close(fd);
+ }
+
+ {
+ map_node2relation.sort();
+ std::string index_file(dir + "/node2rel.map");
+ int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0) {
+ std::cerr << "Can't open node->rel map file '" << index_file << "': " << strerror(errno) << "\n";
+ exit(2);
+ }
+ map_node2relation.dump_as_list(fd);
+ close(fd);
+ }
+
+ {
+ map_way2relation.sort();
+ std::string index_file(dir + "/way2rel.map");
+ int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0) {
+ std::cerr << "Can't open way->rel map file '" << index_file << "': " << strerror(errno) << "\n";
+ exit(2);
+ }
+ map_way2relation.dump_as_list(fd);
+ close(fd);
+ }
+
+ {
+ map_relation2relation.sort();
+ std::string index_file(dir + "/rel2rel.map");
+ int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0) {
+ std::cerr << "Can't open rel->rel map file '" << index_file << "': " << strerror(errno) << "\n";
+ exit(2);
+ }
+ map_relation2relation.dump_as_list(fd);
+ close(fd);
+ }
+
+ google::protobuf::ShutdownProtobufLibrary();
+}
+
diff --git a/third_party/libosmium/examples/osmium_toogr.cpp b/third_party/libosmium/examples/osmium_toogr.cpp
new file mode 100644
index 0000000..6d8ab8d
--- /dev/null
+++ b/third_party/libosmium/examples/osmium_toogr.cpp
@@ -0,0 +1,246 @@
+/*
+
+ This is an example tool that converts OSM data to some output format
+ like Spatialite or Shapefiles using the OGR library.
+
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <iostream>
+#include <getopt.h>
+
+#include <osmium/index/map/all.hpp>
+#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/visitor.hpp>
+
+#include <osmium/geom/ogr.hpp>
+#include <osmium/io/any_input.hpp>
+#include <osmium/handler.hpp>
+
+typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
+typedef osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
+
+typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
+
+class MyOGRHandler : public osmium::handler::Handler {
+
+ OGRDataSource* m_data_source;
+ OGRLayer* m_layer_point;
+ OGRLayer* m_layer_linestring;
+
+ osmium::geom::OGRFactory<> m_factory;
+
+public:
+
+ MyOGRHandler(const std::string& driver_name, const std::string& filename) {
+
+ OGRRegisterAll();
+
+ OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str());
+ if (!driver) {
+ std::cerr << driver_name << " driver not available.\n";
+ exit(1);
+ }
+
+ CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
+ const char* options[] = { "SPATIALITE=TRUE", nullptr };
+ m_data_source = driver->CreateDataSource(filename.c_str(), const_cast<char**>(options));
+ if (!m_data_source) {
+ std::cerr << "Creation of output file failed.\n";
+ exit(1);
+ }
+
+ OGRSpatialReference sparef;
+ sparef.SetWellKnownGeogCS("WGS84");
+ m_layer_point = m_data_source->CreateLayer("postboxes", &sparef, wkbPoint, nullptr);
+ if (!m_layer_point) {
+ std::cerr << "Layer creation failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_point_field_id("id", OFTReal);
+ layer_point_field_id.SetWidth(10);
+
+ if (m_layer_point->CreateField(&layer_point_field_id) != OGRERR_NONE) {
+ std::cerr << "Creating id field failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_point_field_operator("operator", OFTString);
+ layer_point_field_operator.SetWidth(30);
+
+ if (m_layer_point->CreateField(&layer_point_field_operator) != OGRERR_NONE) {
+ std::cerr << "Creating operator field failed.\n";
+ exit(1);
+ }
+
+ /* Transactions might make things faster, then again they might not.
+ Feel free to experiment and benchmark and report back. */
+ m_layer_point->StartTransaction();
+
+ m_layer_linestring = m_data_source->CreateLayer("roads", &sparef, wkbLineString, nullptr);
+ if (!m_layer_linestring) {
+ std::cerr << "Layer creation failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_linestring_field_id("id", OFTReal);
+ layer_linestring_field_id.SetWidth(10);
+
+ if (m_layer_linestring->CreateField(&layer_linestring_field_id) != OGRERR_NONE) {
+ std::cerr << "Creating id field failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_linestring_field_type("type", OFTString);
+ layer_linestring_field_type.SetWidth(30);
+
+ if (m_layer_linestring->CreateField(&layer_linestring_field_type) != OGRERR_NONE) {
+ std::cerr << "Creating type field failed.\n";
+ exit(1);
+ }
+
+ m_layer_linestring->StartTransaction();
+ }
+
+ ~MyOGRHandler() {
+ m_layer_linestring->CommitTransaction();
+ m_layer_point->CommitTransaction();
+ OGRDataSource::DestroyDataSource(m_data_source);
+ OGRCleanupAll();
+ }
+
+ void node(const osmium::Node& node) {
+ const char* amenity = node.tags().get_value_by_key("amenity");
+ if (amenity && !strcmp(amenity, "post_box")) {
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_point->GetLayerDefn());
+ std::unique_ptr<OGRPoint> ogr_point = m_factory.create_point(node);
+ feature->SetGeometry(ogr_point.get());
+ feature->SetField("id", static_cast<double>(node.id()));
+ feature->SetField("operator", node.tags().get_value_by_key("operator"));
+
+ if (m_layer_point->CreateFeature(feature) != OGRERR_NONE) {
+ std::cerr << "Failed to create feature.\n";
+ exit(1);
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ }
+ }
+
+ void way(const osmium::Way& way) {
+ const char* highway = way.tags().get_value_by_key("highway");
+ if (highway) {
+ try {
+ std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way);
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_linestring->GetLayerDefn());
+ feature->SetGeometry(ogr_linestring.get());
+ feature->SetField("id", static_cast<double>(way.id()));
+ feature->SetField("type", highway);
+
+ if (m_layer_linestring->CreateFeature(feature) != OGRERR_NONE) {
+ std::cerr << "Failed to create feature.\n";
+ exit(1);
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ } catch (osmium::geometry_error&) {
+ std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
+ }
+ }
+ }
+
+};
+
+/* ================================================== */
+
+void print_help() {
+ std::cout << "osmium_toogr [OPTIONS] [INFILE [OUTFILE]]\n\n" \
+ << "If INFILE is not given stdin is assumed.\n" \
+ << "If OUTFILE is not given 'ogr_out' is used.\n" \
+ << "\nOptions:\n" \
+ << " -h, --help This help message\n" \
+ << " -l, --location_store=TYPE Set location store\n" \
+ << " -f, --format=FORMAT Output OGR format (Default: 'SQLite')\n" \
+ << " -L See available location stores\n";
+}
+
+int main(int argc, char* argv[]) {
+ const auto& map_factory = osmium::index::MapFactory<osmium::unsigned_object_id_type, osmium::Location>::instance();
+
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"format", required_argument, 0, 'f'},
+ {"location_store", required_argument, 0, 'l'},
+ {"list_location_stores", no_argument, 0, 'L'},
+ {0, 0, 0, 0}
+ };
+
+ std::string output_format { "SQLite" };
+ std::string location_store { "sparse_mem_array" };
+
+ while (true) {
+ int c = getopt_long(argc, argv, "hf:l:L", long_options, 0);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'h':
+ print_help();
+ exit(0);
+ case 'f':
+ output_format = optarg;
+ break;
+ case 'l':
+ location_store = optarg;
+ break;
+ case 'L':
+ std::cout << "Available map types:\n";
+ for (const auto& map_type : map_factory.map_types()) {
+ std::cout << " " << map_type << "\n";
+ }
+ exit(0);
+ default:
+ exit(1);
+ }
+ }
+
+ std::string input_filename;
+ std::string output_filename("ogr_out");
+ int remaining_args = argc - optind;
+ if (remaining_args > 2) {
+ std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]" << std::endl;
+ exit(1);
+ } else if (remaining_args == 2) {
+ input_filename = argv[optind];
+ output_filename = argv[optind+1];
+ } else if (remaining_args == 1) {
+ input_filename = argv[optind];
+ } else {
+ input_filename = "-";
+ }
+
+ osmium::io::Reader reader(input_filename);
+
+ std::unique_ptr<index_pos_type> index_pos = map_factory.create_map(location_store);
+ index_neg_type index_neg;
+ location_handler_type location_handler(*index_pos, index_neg);
+ location_handler.ignore_errors();
+
+ MyOGRHandler ogr_handler(output_format, output_filename);
+
+ osmium::apply(reader, location_handler, ogr_handler);
+ reader.close();
+
+ google::protobuf::ShutdownProtobufLibrary();
+
+ int locations_fd = open("locations.dump", O_WRONLY | O_CREAT, 0644);
+ if (locations_fd < 0) {
+ throw std::system_error(errno, std::system_category(), "Open failed");
+ }
+ index_pos->dump_as_list(locations_fd);
+ close(locations_fd);
+}
+
diff --git a/third_party/libosmium/examples/osmium_toogr2.cpp b/third_party/libosmium/examples/osmium_toogr2.cpp
new file mode 100644
index 0000000..a966c5e
--- /dev/null
+++ b/third_party/libosmium/examples/osmium_toogr2.cpp
@@ -0,0 +1,333 @@
+/*
+
+ This is an example tool that converts OSM data to some output format
+ like Spatialite or Shapefiles using the OGR library.
+
+ This version does multipolygon handling (in contrast to the osmium_toogr
+ example which doesn't).
+
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <iostream>
+#include <getopt.h>
+
+// usually you only need one or two of these
+#include <osmium/index/map/dummy.hpp>
+#include <osmium/index/map/sparse_mem_array.hpp>
+
+#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/visitor.hpp>
+#include <osmium/area/multipolygon_collector.hpp>
+#include <osmium/area/assembler.hpp>
+
+#include <osmium/geom/mercator_projection.hpp>
+//#include <osmium/geom/projection.hpp>
+#include <osmium/geom/ogr.hpp>
+#include <osmium/io/any_input.hpp>
+#include <osmium/handler.hpp>
+
+typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
+
+typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
+
+typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
+
+class MyOGRHandler : public osmium::handler::Handler {
+
+ OGRDataSource* m_data_source;
+ OGRLayer* m_layer_point;
+ OGRLayer* m_layer_linestring;
+ OGRLayer* m_layer_polygon;
+
+ // Choose one of the following:
+
+ // 1. Use WGS84, do not project coordinates.
+ //osmium::geom::OGRFactory<> m_factory {};
+
+ // 2. Project coordinates into "Web Mercator".
+ osmium::geom::OGRFactory<osmium::geom::MercatorProjection> m_factory;
+
+ // 3. Use any projection that the proj library can handle.
+ // (Initialize projection with EPSG code or proj string).
+ // In addition you need to link with "-lproj" and add
+ // #include <osmium/geom/projection.hpp>.
+ //osmium::geom::OGRFactory<osmium::geom::Projection> m_factory {osmium::geom::Projection(3857)};
+
+public:
+
+ MyOGRHandler(const std::string& driver_name, const std::string& filename) {
+
+ OGRRegisterAll();
+
+ OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str());
+ if (!driver) {
+ std::cerr << driver_name << " driver not available.\n";
+ exit(1);
+ }
+
+ CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
+ const char* options[] = { "SPATIALITE=TRUE", nullptr };
+ m_data_source = driver->CreateDataSource(filename.c_str(), const_cast<char**>(options));
+ if (!m_data_source) {
+ std::cerr << "Creation of output file failed.\n";
+ exit(1);
+ }
+
+ OGRSpatialReference sparef;
+ sparef.importFromProj4(m_factory.proj_string().c_str());
+
+ m_layer_point = m_data_source->CreateLayer("postboxes", &sparef, wkbPoint, nullptr);
+ if (!m_layer_point) {
+ std::cerr << "Layer creation failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_point_field_id("id", OFTReal);
+ layer_point_field_id.SetWidth(10);
+
+ if (m_layer_point->CreateField(&layer_point_field_id) != OGRERR_NONE) {
+ std::cerr << "Creating id field failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_point_field_operator("operator", OFTString);
+ layer_point_field_operator.SetWidth(30);
+
+ if (m_layer_point->CreateField(&layer_point_field_operator) != OGRERR_NONE) {
+ std::cerr << "Creating operator field failed.\n";
+ exit(1);
+ }
+
+ /* Transactions might make things faster, then again they might not.
+ Feel free to experiment and benchmark and report back. */
+ m_layer_point->StartTransaction();
+
+ m_layer_linestring = m_data_source->CreateLayer("roads", &sparef, wkbLineString, nullptr);
+ if (!m_layer_linestring) {
+ std::cerr << "Layer creation failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_linestring_field_id("id", OFTReal);
+ layer_linestring_field_id.SetWidth(10);
+
+ if (m_layer_linestring->CreateField(&layer_linestring_field_id) != OGRERR_NONE) {
+ std::cerr << "Creating id field failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_linestring_field_type("type", OFTString);
+ layer_linestring_field_type.SetWidth(30);
+
+ if (m_layer_linestring->CreateField(&layer_linestring_field_type) != OGRERR_NONE) {
+ std::cerr << "Creating type field failed.\n";
+ exit(1);
+ }
+
+ m_layer_linestring->StartTransaction();
+
+ m_layer_polygon = m_data_source->CreateLayer("buildings", &sparef, wkbMultiPolygon, nullptr);
+ if (!m_layer_polygon) {
+ std::cerr << "Layer creation failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_polygon_field_id("id", OFTInteger);
+ layer_polygon_field_id.SetWidth(10);
+
+ if (m_layer_polygon->CreateField(&layer_polygon_field_id) != OGRERR_NONE) {
+ std::cerr << "Creating id field failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_polygon_field_type("type", OFTString);
+ layer_polygon_field_type.SetWidth(30);
+
+ if (m_layer_polygon->CreateField(&layer_polygon_field_type) != OGRERR_NONE) {
+ std::cerr << "Creating type field failed.\n";
+ exit(1);
+ }
+
+ m_layer_polygon->StartTransaction();
+ }
+
+ ~MyOGRHandler() {
+ m_layer_polygon->CommitTransaction();
+ m_layer_linestring->CommitTransaction();
+ m_layer_point->CommitTransaction();
+ OGRDataSource::DestroyDataSource(m_data_source);
+ OGRCleanupAll();
+ }
+
+ void node(const osmium::Node& node) {
+ const char* amenity = node.tags()["amenity"];
+ if (amenity && !strcmp(amenity, "post_box")) {
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_point->GetLayerDefn());
+ std::unique_ptr<OGRPoint> ogr_point = m_factory.create_point(node);
+ feature->SetGeometry(ogr_point.get());
+ feature->SetField("id", static_cast<double>(node.id()));
+ feature->SetField("operator", node.tags()["operator"]);
+
+ if (m_layer_point->CreateFeature(feature) != OGRERR_NONE) {
+ std::cerr << "Failed to create feature.\n";
+ exit(1);
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ }
+ }
+
+ void way(const osmium::Way& way) {
+ const char* highway = way.tags()["highway"];
+ if (highway) {
+ try {
+ std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way);
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_linestring->GetLayerDefn());
+ feature->SetGeometry(ogr_linestring.get());
+ feature->SetField("id", static_cast<double>(way.id()));
+ feature->SetField("type", highway);
+
+ if (m_layer_linestring->CreateFeature(feature) != OGRERR_NONE) {
+ std::cerr << "Failed to create feature.\n";
+ exit(1);
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ } catch (osmium::geometry_error&) {
+ std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
+ }
+ }
+ }
+
+ void area(const osmium::Area& area) {
+ const char* building = area.tags()["building"];
+ if (building) {
+ try {
+ std::unique_ptr<OGRMultiPolygon> ogr_polygon = m_factory.create_multipolygon(area);
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_polygon->GetLayerDefn());
+ feature->SetGeometry(ogr_polygon.get());
+ feature->SetField("id", static_cast<int>(area.id()));
+ feature->SetField("type", building);
+
+ std::string type = "";
+ if (area.from_way()) {
+ type += "w";
+ } else {
+ type += "r";
+ }
+ feature->SetField("type", type.c_str());
+
+ if (m_layer_polygon->CreateFeature(feature) != OGRERR_NONE) {
+ std::cerr << "Failed to create feature.\n";
+ exit(1);
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ } catch (osmium::geometry_error&) {
+ std::cerr << "Ignoring illegal geometry for area " << area.id() << " created from " << (area.from_way() ? "way" : "relation") << " with id=" << area.orig_id() << ".\n";
+ }
+ }
+ }
+
+};
+
+/* ================================================== */
+
+void print_help() {
+ std::cout << "osmium_toogr [OPTIONS] [INFILE [OUTFILE]]\n\n" \
+ << "If INFILE is not given stdin is assumed.\n" \
+ << "If OUTFILE is not given 'ogr_out' is used.\n" \
+ << "\nOptions:\n" \
+ << " -h, --help This help message\n" \
+ << " -d, --debug Enable debug output\n" \
+ << " -f, --format=FORMAT Output OGR format (Default: 'SQLite')\n";
+}
+
+int main(int argc, char* argv[]) {
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"debug", no_argument, 0, 'd'},
+ {"format", required_argument, 0, 'f'},
+ {0, 0, 0, 0}
+ };
+
+ std::string output_format("SQLite");
+ bool debug = false;
+
+ while (true) {
+ int c = getopt_long(argc, argv, "hdf:", long_options, 0);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'h':
+ print_help();
+ exit(0);
+ case 'd':
+ debug = true;
+ break;
+ case 'f':
+ output_format = optarg;
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ std::string input_filename;
+ std::string output_filename("ogr_out");
+ int remaining_args = argc - optind;
+ if (remaining_args > 2) {
+ std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]" << std::endl;
+ exit(1);
+ } else if (remaining_args == 2) {
+ input_filename = argv[optind];
+ output_filename = argv[optind+1];
+ } else if (remaining_args == 1) {
+ input_filename = argv[optind];
+ } else {
+ input_filename = "-";
+ }
+
+ osmium::area::Assembler::config_type assembler_config;
+ assembler_config.enable_debug_output(debug);
+ osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config);
+
+ std::cerr << "Pass 1...\n";
+ osmium::io::Reader reader1(input_filename);
+ collector.read_relations(reader1);
+ reader1.close();
+ std::cerr << "Pass 1 done\n";
+
+ index_pos_type index_pos;
+ index_neg_type index_neg;
+ location_handler_type location_handler(index_pos, index_neg);
+ location_handler.ignore_errors();
+
+ MyOGRHandler ogr_handler(output_format, output_filename);
+
+ std::cerr << "Pass 2...\n";
+ osmium::io::Reader reader2(input_filename);
+
+ osmium::apply(reader2, location_handler, ogr_handler, collector.handler([&ogr_handler](const osmium::memory::Buffer& area_buffer) {
+ osmium::apply(area_buffer, ogr_handler);
+ }));
+
+ reader2.close();
+ std::cerr << "Pass 2 done\n";
+
+ std::vector<const osmium::Relation*> incomplete_relations = collector.get_incomplete_relations();
+ if (!incomplete_relations.empty()) {
+ std::cerr << "Warning! Some member ways missing for these multipolygon relations:";
+ for (const auto* relation : incomplete_relations) {
+ std::cerr << " " << relation->id();
+ }
+ std::cerr << "\n";
+ }
+
+ google::protobuf::ShutdownProtobufLibrary();
+}
+
diff --git a/third_party/libosmium/examples/osmium_toogr2_exp.cpp b/third_party/libosmium/examples/osmium_toogr2_exp.cpp
new file mode 100644
index 0000000..474da96
--- /dev/null
+++ b/third_party/libosmium/examples/osmium_toogr2_exp.cpp
@@ -0,0 +1,307 @@
+/*
+
+ This is an example tool that converts OSM data to some output format
+ like Spatialite or Shapefiles using the OGR library.
+
+ This version does multipolygon handling (in contrast to the osmium_toogr
+ example which doesn't).
+
+ This version (..._exp) uses a new experimental unsupported interface.
+
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <iostream>
+#include <getopt.h>
+
+#include <osmium/index/map/sparse_mem_array.hpp>
+
+#include <osmium/visitor.hpp>
+
+#include <osmium/geom/mercator_projection.hpp>
+//#include <osmium/geom/projection.hpp>
+#include <osmium/geom/ogr.hpp>
+#include <osmium/io/any_input.hpp>
+#include <osmium/handler.hpp>
+#include <osmium/experimental/flex_reader.hpp>
+
+typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
+typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type;
+
+class MyOGRHandler : public osmium::handler::Handler {
+
+ OGRDataSource* m_data_source;
+ OGRLayer* m_layer_point;
+ OGRLayer* m_layer_linestring;
+ OGRLayer* m_layer_polygon;
+
+ // Choose one of the following:
+
+ // 1. Use WGS84, do not project coordinates.
+ //osmium::geom::OGRFactory<> m_factory {};
+
+ // 2. Project coordinates into "Web Mercator".
+ osmium::geom::OGRFactory<osmium::geom::MercatorProjection> m_factory;
+
+ // 3. Use any projection that the proj library can handle.
+ // (Initialize projection with EPSG code or proj string).
+ // In addition you need to link with "-lproj" and add
+ // #include <osmium/geom/projection.hpp>.
+ //osmium::geom::OGRFactory<osmium::geom::Projection> m_factory {osmium::geom::Projection(3857)};
+
+public:
+
+ MyOGRHandler(const std::string& driver_name, const std::string& filename) {
+
+ OGRRegisterAll();
+
+ OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str());
+ if (!driver) {
+ std::cerr << driver_name << " driver not available.\n";
+ exit(1);
+ }
+
+ CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
+ const char* options[] = { "SPATIALITE=TRUE", nullptr };
+ m_data_source = driver->CreateDataSource(filename.c_str(), const_cast<char**>(options));
+ if (!m_data_source) {
+ std::cerr << "Creation of output file failed.\n";
+ exit(1);
+ }
+
+ OGRSpatialReference sparef;
+ sparef.importFromProj4(m_factory.proj_string().c_str());
+
+ m_layer_point = m_data_source->CreateLayer("postboxes", &sparef, wkbPoint, nullptr);
+ if (!m_layer_point) {
+ std::cerr << "Layer creation failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_point_field_id("id", OFTReal);
+ layer_point_field_id.SetWidth(10);
+
+ if (m_layer_point->CreateField(&layer_point_field_id) != OGRERR_NONE) {
+ std::cerr << "Creating id field failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_point_field_operator("operator", OFTString);
+ layer_point_field_operator.SetWidth(30);
+
+ if (m_layer_point->CreateField(&layer_point_field_operator) != OGRERR_NONE) {
+ std::cerr << "Creating operator field failed.\n";
+ exit(1);
+ }
+
+ /* Transactions might make things faster, then again they might not.
+ Feel free to experiment and benchmark and report back. */
+ m_layer_point->StartTransaction();
+
+ m_layer_linestring = m_data_source->CreateLayer("roads", &sparef, wkbLineString, nullptr);
+ if (!m_layer_linestring) {
+ std::cerr << "Layer creation failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_linestring_field_id("id", OFTReal);
+ layer_linestring_field_id.SetWidth(10);
+
+ if (m_layer_linestring->CreateField(&layer_linestring_field_id) != OGRERR_NONE) {
+ std::cerr << "Creating id field failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_linestring_field_type("type", OFTString);
+ layer_linestring_field_type.SetWidth(30);
+
+ if (m_layer_linestring->CreateField(&layer_linestring_field_type) != OGRERR_NONE) {
+ std::cerr << "Creating type field failed.\n";
+ exit(1);
+ }
+
+ m_layer_linestring->StartTransaction();
+
+ m_layer_polygon = m_data_source->CreateLayer("buildings", &sparef, wkbMultiPolygon, nullptr);
+ if (!m_layer_polygon) {
+ std::cerr << "Layer creation failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_polygon_field_id("id", OFTInteger);
+ layer_polygon_field_id.SetWidth(10);
+
+ if (m_layer_polygon->CreateField(&layer_polygon_field_id) != OGRERR_NONE) {
+ std::cerr << "Creating id field failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_polygon_field_type("type", OFTString);
+ layer_polygon_field_type.SetWidth(30);
+
+ if (m_layer_polygon->CreateField(&layer_polygon_field_type) != OGRERR_NONE) {
+ std::cerr << "Creating type field failed.\n";
+ exit(1);
+ }
+
+ m_layer_polygon->StartTransaction();
+ }
+
+ ~MyOGRHandler() {
+ m_layer_polygon->CommitTransaction();
+ m_layer_linestring->CommitTransaction();
+ m_layer_point->CommitTransaction();
+ OGRDataSource::DestroyDataSource(m_data_source);
+ OGRCleanupAll();
+ }
+
+ void node(const osmium::Node& node) {
+ const char* amenity = node.tags()["amenity"];
+ if (amenity && !strcmp(amenity, "post_box")) {
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_point->GetLayerDefn());
+ std::unique_ptr<OGRPoint> ogr_point = m_factory.create_point(node);
+ feature->SetGeometry(ogr_point.get());
+ feature->SetField("id", static_cast<double>(node.id()));
+ feature->SetField("operator", node.tags()["operator"]);
+
+ if (m_layer_point->CreateFeature(feature) != OGRERR_NONE) {
+ std::cerr << "Failed to create feature.\n";
+ exit(1);
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ }
+ }
+
+ void way(const osmium::Way& way) {
+ const char* highway = way.tags()["highway"];
+ if (highway) {
+ try {
+ std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way);
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_linestring->GetLayerDefn());
+ feature->SetGeometry(ogr_linestring.get());
+ feature->SetField("id", static_cast<double>(way.id()));
+ feature->SetField("type", highway);
+
+ if (m_layer_linestring->CreateFeature(feature) != OGRERR_NONE) {
+ std::cerr << "Failed to create feature.\n";
+ exit(1);
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ } catch (osmium::geometry_error&) {
+ std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
+ }
+ }
+ }
+
+ void area(const osmium::Area& area) {
+ const char* building = area.tags()["building"];
+ if (building) {
+ try {
+ std::unique_ptr<OGRMultiPolygon> ogr_polygon = m_factory.create_multipolygon(area);
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_polygon->GetLayerDefn());
+ feature->SetGeometry(ogr_polygon.get());
+ feature->SetField("id", static_cast<int>(area.id()));
+ feature->SetField("type", building);
+
+ std::string type = "";
+ if (area.from_way()) {
+ type += "w";
+ } else {
+ type += "r";
+ }
+ feature->SetField("type", type.c_str());
+
+ if (m_layer_polygon->CreateFeature(feature) != OGRERR_NONE) {
+ std::cerr << "Failed to create feature.\n";
+ exit(1);
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ } catch (osmium::geometry_error&) {
+ std::cerr << "Ignoring illegal geometry for area " << area.id() << " created from " << (area.from_way() ? "way" : "relation") << " with id=" << area.orig_id() << ".\n";
+ }
+ }
+ }
+
+};
+
+/* ================================================== */
+
+void print_help() {
+ std::cout << "osmium_toogr [OPTIONS] [INFILE [OUTFILE]]\n\n" \
+ << "If INFILE is not given stdin is assumed.\n" \
+ << "If OUTFILE is not given 'ogr_out' is used.\n" \
+ << "\nOptions:\n" \
+ << " -h, --help This help message\n" \
+ << " -f, --format=FORMAT Output OGR format (Default: 'SQLite')\n";
+}
+
+int main(int argc, char* argv[]) {
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"format", required_argument, 0, 'f'},
+ {0, 0, 0, 0}
+ };
+
+ std::string output_format("SQLite");
+
+ while (true) {
+ int c = getopt_long(argc, argv, "hf:", long_options, 0);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'h':
+ print_help();
+ exit(0);
+ case 'f':
+ output_format = optarg;
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ std::string input_filename;
+ std::string output_filename("ogr_out");
+ int remaining_args = argc - optind;
+ if (remaining_args > 2) {
+ std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]" << std::endl;
+ exit(1);
+ } else if (remaining_args == 2) {
+ input_filename = argv[optind];
+ output_filename = argv[optind+1];
+ } else if (remaining_args == 1) {
+ input_filename = argv[optind];
+ } else {
+ input_filename = "-";
+ }
+
+ index_type index_pos;
+ location_handler_type location_handler(index_pos);
+ osmium::experimental::FlexReader<location_handler_type> exr(input_filename, location_handler, osmium::osm_entity_bits::object);
+
+ MyOGRHandler ogr_handler(output_format, output_filename);
+
+ while (auto buffer = exr.read()) {
+ osmium::apply(buffer, ogr_handler);
+ }
+
+ exr.close();
+
+ std::vector<const osmium::Relation*> incomplete_relations = exr.collector().get_incomplete_relations();
+ if (!incomplete_relations.empty()) {
+ std::cerr << "Warning! Some member ways missing for these multipolygon relations:";
+ for (const auto* relation : incomplete_relations) {
+ std::cerr << " " << relation->id();
+ }
+ std::cerr << "\n";
+ }
+
+ google::protobuf::ShutdownProtobufLibrary();
+}
+
diff --git a/third_party/libosmium/examples/osmium_use_node_cache.cpp b/third_party/libosmium/examples/osmium_use_node_cache.cpp
new file mode 100644
index 0000000..6b8f964
--- /dev/null
+++ b/third_party/libosmium/examples/osmium_use_node_cache.cpp
@@ -0,0 +1,71 @@
+/*
+
+ This reads ways from an OSM file and writes out the node locations
+ it got from a node cache generated with osmium_create_node_cache.
+
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <iostream>
+
+#include <osmium/io/pbf_input.hpp>
+#include <osmium/io/xml_input.hpp>
+
+#include <osmium/index/map/dummy.hpp>
+#include <osmium/index/map/dense_file_array.hpp>
+#include <osmium/index/map/dense_mmap_array.hpp>
+
+#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/visitor.hpp>
+
+typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
+//typedef osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
+typedef osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
+
+typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
+
+class MyHandler : public osmium::handler::Handler {
+
+public:
+
+ void way(osmium::Way& way) {
+ for (auto& nr : way.nodes()) {
+ std::cout << nr << "\n";
+ }
+ }
+
+}; // class MyHandler
+
+int main(int argc, char* argv[]) {
+ if (argc != 3) {
+ std::cerr << "Usage: " << argv[0] << " OSM_FILE CACHE_FILE\n";
+ return 1;
+ }
+
+ std::string input_filename(argv[1]);
+ osmium::io::Reader reader(input_filename, osmium::osm_entity_bits::way);
+
+ int fd = open(argv[2], O_RDWR);
+ if (fd == -1) {
+ std::cerr << "Can not open node cache file '" << argv[2] << "': " << strerror(errno) << "\n";
+ return 1;
+ }
+
+ index_pos_type index_pos {fd};
+ index_neg_type index_neg;
+ location_handler_type location_handler(index_pos, index_neg);
+ location_handler.ignore_errors();
+
+ MyHandler handler;
+ osmium::apply(reader, location_handler, handler);
+ reader.close();
+
+ google::protobuf::ShutdownProtobufLibrary();
+
+ return 0;
+}
+
diff --git a/third_party/libosmium/include/boost_unicode_iterator.hpp b/third_party/libosmium/include/boost_unicode_iterator.hpp
new file mode 100644
index 0000000..3a7b68f
--- /dev/null
+++ b/third_party/libosmium/include/boost_unicode_iterator.hpp
@@ -0,0 +1,776 @@
+/*
+ *
+ * Copyright (c) 2004
+ * John Maddock
+ *
+ * Use, modification and distribution are subject to 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)
+ *
+ */
+
+ /*
+ * LOCATION: see http://www.boost.org for most recent version.
+ * FILE unicode_iterator.hpp
+ * VERSION see <boost/version.hpp>
+ * DESCRIPTION: Iterator adapters for converting between different Unicode encodings.
+ */
+
+/****************************************************************************
+
+Contents:
+~~~~~~~~~
+
+1) Read Only, Input Adapters:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+template <class BaseIterator, class U8Type = ::boost::uint8_t>
+class u32_to_u8_iterator;
+
+Adapts sequence of UTF-32 code points to "look like" a sequence of UTF-8.
+
+template <class BaseIterator, class U32Type = ::boost::uint32_t>
+class u8_to_u32_iterator;
+
+Adapts sequence of UTF-8 code points to "look like" a sequence of UTF-32.
+
+template <class BaseIterator, class U16Type = ::boost::uint16_t>
+class u32_to_u16_iterator;
+
+Adapts sequence of UTF-32 code points to "look like" a sequence of UTF-16.
+
+template <class BaseIterator, class U32Type = ::boost::uint32_t>
+class u16_to_u32_iterator;
+
+Adapts sequence of UTF-16 code points to "look like" a sequence of UTF-32.
+
+2) Single pass output iterator adapters:
+
+template <class BaseIterator>
+class utf8_output_iterator;
+
+Accepts UTF-32 code points and forwards them on as UTF-8 code points.
+
+template <class BaseIterator>
+class utf16_output_iterator;
+
+Accepts UTF-32 code points and forwards them on as UTF-16 code points.
+
+****************************************************************************/
+
+#ifndef BOOST_REGEX_UNICODE_ITERATOR_HPP
+#define BOOST_REGEX_UNICODE_ITERATOR_HPP
+#include <boost/cstdint.hpp>
+#include <boost/assert.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/throw_exception.hpp>
+#include <stdexcept>
+#ifndef BOOST_NO_STD_LOCALE
+#include <sstream>
+#include <ios>
+#endif
+#include <limits.h> // CHAR_BIT
+
+namespace boost{
+
+namespace detail{
+
+static const ::boost::uint16_t high_surrogate_base = 0xD7C0u;
+static const ::boost::uint16_t low_surrogate_base = 0xDC00u;
+static const ::boost::uint32_t ten_bit_mask = 0x3FFu;
+
+inline bool is_high_surrogate(::boost::uint16_t v)
+{
+ return (v & 0xFFFFFC00u) == 0xd800u;
+}
+inline bool is_low_surrogate(::boost::uint16_t v)
+{
+ return (v & 0xFFFFFC00u) == 0xdc00u;
+}
+template <class T>
+inline bool is_surrogate(T v)
+{
+ return (v & 0xFFFFF800u) == 0xd800;
+}
+
+inline unsigned utf8_byte_count(boost::uint8_t c)
+{
+ // if the most significant bit with a zero in it is in position
+ // 8-N then there are N bytes in this UTF-8 sequence:
+ boost::uint8_t mask = 0x80u;
+ unsigned result = 0;
+ while(c & mask)
+ {
+ ++result;
+ mask >>= 1;
+ }
+ return (result == 0) ? 1 : ((result > 4) ? 4 : result);
+}
+
+inline unsigned utf8_trailing_byte_count(boost::uint8_t c)
+{
+ return utf8_byte_count(c) - 1;
+}
+
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#pragma warning(disable:4100)
+#endif
+inline void invalid_utf32_code_point(::boost::uint32_t val)
+{
+#ifndef BOOST_NO_STD_LOCALE
+ std::stringstream ss;
+ ss << "Invalid UTF-32 code point U+" << std::showbase << std::hex << val << " encountered while trying to encode UTF-16 sequence";
+ std::out_of_range e(ss.str());
+#else
+ std::out_of_range e("Invalid UTF-32 code point encountered while trying to encode UTF-16 sequence");
+#endif
+ boost::throw_exception(e);
+}
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+
+
+} // namespace detail
+
+template <class BaseIterator, class U16Type = ::boost::uint16_t>
+class u32_to_u16_iterator
+ : public boost::iterator_facade<u32_to_u16_iterator<BaseIterator, U16Type>, U16Type, std::bidirectional_iterator_tag, const U16Type>
+{
+ typedef boost::iterator_facade<u32_to_u16_iterator<BaseIterator, U16Type>, U16Type, std::bidirectional_iterator_tag, const U16Type> base_type;
+
+#if !defined(BOOST_NO_STD_ITERATOR_TRAITS) && !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
+ typedef typename std::iterator_traits<BaseIterator>::value_type base_value_type;
+
+ BOOST_STATIC_ASSERT(sizeof(base_value_type)*CHAR_BIT == 32);
+ BOOST_STATIC_ASSERT(sizeof(U16Type)*CHAR_BIT == 16);
+#endif
+
+public:
+ typename base_type::reference
+ dereference()const
+ {
+ if(m_current == 2)
+ extract_current();
+ return m_values[m_current];
+ }
+ bool equal(const u32_to_u16_iterator& that)const
+ {
+ if(m_position == that.m_position)
+ {
+ // Both m_currents must be equal, or both even
+ // this is the same as saying their sum must be even:
+ return (m_current + that.m_current) & 1u ? false : true;
+ }
+ return false;
+ }
+ void increment()
+ {
+ // if we have a pending read then read now, so that we know whether
+ // to skip a position, or move to a low-surrogate:
+ if(m_current == 2)
+ {
+ // pending read:
+ extract_current();
+ }
+ // move to the next surrogate position:
+ ++m_current;
+ // if we've reached the end skip a position:
+ if(m_values[m_current] == 0)
+ {
+ m_current = 2;
+ ++m_position;
+ }
+ }
+ void decrement()
+ {
+ if(m_current != 1)
+ {
+ // decrementing an iterator always leads to a valid position:
+ --m_position;
+ extract_current();
+ m_current = m_values[1] ? 1 : 0;
+ }
+ else
+ {
+ m_current = 0;
+ }
+ }
+ BaseIterator base()const
+ {
+ return m_position;
+ }
+ // construct:
+ u32_to_u16_iterator() : m_position(), m_current(0)
+ {
+ m_values[0] = 0;
+ m_values[1] = 0;
+ m_values[2] = 0;
+ }
+ u32_to_u16_iterator(BaseIterator b) : m_position(b), m_current(2)
+ {
+ m_values[0] = 0;
+ m_values[1] = 0;
+ m_values[2] = 0;
+ }
+private:
+
+ void extract_current()const
+ {
+ // begin by checking for a code point out of range:
+ ::boost::uint32_t v = *m_position;
+ if(v >= 0x10000u)
+ {
+ if(v > 0x10FFFFu)
+ detail::invalid_utf32_code_point(*m_position);
+ // split into two surrogates:
+ m_values[0] = static_cast<U16Type>(v >> 10) + detail::high_surrogate_base;
+ m_values[1] = static_cast<U16Type>(v & detail::ten_bit_mask) + detail::low_surrogate_base;
+ m_current = 0;
+ BOOST_ASSERT(detail::is_high_surrogate(m_values[0]));
+ BOOST_ASSERT(detail::is_low_surrogate(m_values[1]));
+ }
+ else
+ {
+ // 16-bit code point:
+ m_values[0] = static_cast<U16Type>(*m_position);
+ m_values[1] = 0;
+ m_current = 0;
+ // value must not be a surrogate:
+ if(detail::is_surrogate(m_values[0]))
+ detail::invalid_utf32_code_point(*m_position);
+ }
+ }
+ BaseIterator m_position;
+ mutable U16Type m_values[3];
+ mutable unsigned m_current;
+};
+
+template <class BaseIterator, class U32Type = ::boost::uint32_t>
+class u16_to_u32_iterator
+ : public boost::iterator_facade<u16_to_u32_iterator<BaseIterator, U32Type>, U32Type, std::bidirectional_iterator_tag, const U32Type>
+{
+ typedef boost::iterator_facade<u16_to_u32_iterator<BaseIterator, U32Type>, U32Type, std::bidirectional_iterator_tag, const U32Type> base_type;
+ // special values for pending iterator reads:
+ BOOST_STATIC_CONSTANT(U32Type, pending_read = 0xffffffffu);
+
+#if !defined(BOOST_NO_STD_ITERATOR_TRAITS) && !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
+ typedef typename std::iterator_traits<BaseIterator>::value_type base_value_type;
+
+ BOOST_STATIC_ASSERT(sizeof(base_value_type)*CHAR_BIT == 16);
+ BOOST_STATIC_ASSERT(sizeof(U32Type)*CHAR_BIT == 32);
+#endif
+
+public:
+ typename base_type::reference
+ dereference()const
+ {
+ if(m_value == pending_read)
+ extract_current();
+ return m_value;
+ }
+ bool equal(const u16_to_u32_iterator& that)const
+ {
+ return m_position == that.m_position;
+ }
+ void increment()
+ {
+ // skip high surrogate first if there is one:
+ if(detail::is_high_surrogate(*m_position)) ++m_position;
+ ++m_position;
+ m_value = pending_read;
+ }
+ void decrement()
+ {
+ --m_position;
+ // if we have a low surrogate then go back one more:
+ if(detail::is_low_surrogate(*m_position))
+ --m_position;
+ m_value = pending_read;
+ }
+ BaseIterator base()const
+ {
+ return m_position;
+ }
+ // construct:
+ u16_to_u32_iterator() : m_position()
+ {
+ m_value = pending_read;
+ }
+ u16_to_u32_iterator(BaseIterator b) : m_position(b)
+ {
+ m_value = pending_read;
+ }
+ //
+ // Range checked version:
+ //
+ u16_to_u32_iterator(BaseIterator b, BaseIterator start, BaseIterator end) : m_position(b)
+ {
+ m_value = pending_read;
+ //
+ // The range must not start with a low surrogate, or end in a high surrogate,
+ // otherwise we run the risk of running outside the underlying input range.
+ // Likewise b must not be located at a low surrogate.
+ //
+ boost::uint16_t val;
+ if(start != end)
+ {
+ if((b != start) && (b != end))
+ {
+ val = *b;
+ if(detail::is_surrogate(val) && ((val & 0xFC00u) == 0xDC00u))
+ invalid_code_point(val);
+ }
+ val = *start;
+ if(detail::is_surrogate(val) && ((val & 0xFC00u) == 0xDC00u))
+ invalid_code_point(val);
+ val = *--end;
+ if(detail::is_high_surrogate(val))
+ invalid_code_point(val);
+ }
+ }
+private:
+ static void invalid_code_point(::boost::uint16_t val)
+ {
+#ifndef BOOST_NO_STD_LOCALE
+ std::stringstream ss;
+ ss << "Misplaced UTF-16 surrogate U+" << std::showbase << std::hex << val << " encountered while trying to encode UTF-32 sequence";
+ std::out_of_range e(ss.str());
+#else
+ std::out_of_range e("Misplaced UTF-16 surrogate encountered while trying to encode UTF-32 sequence");
+#endif
+ boost::throw_exception(e);
+ }
+ void extract_current()const
+ {
+ m_value = static_cast<U32Type>(static_cast< ::boost::uint16_t>(*m_position));
+ // if the last value is a high surrogate then adjust m_position and m_value as needed:
+ if(detail::is_high_surrogate(*m_position))
+ {
+ // precondition; next value must have be a low-surrogate:
+ BaseIterator next(m_position);
+ ::boost::uint16_t t = *++next;
+ if((t & 0xFC00u) != 0xDC00u)
+ invalid_code_point(t);
+ m_value = (m_value - detail::high_surrogate_base) << 10;
+ m_value |= (static_cast<U32Type>(static_cast< ::boost::uint16_t>(t)) & detail::ten_bit_mask);
+ }
+ // postcondition; result must not be a surrogate:
+ if(detail::is_surrogate(m_value))
+ invalid_code_point(static_cast< ::boost::uint16_t>(m_value));
+ }
+ BaseIterator m_position;
+ mutable U32Type m_value;
+};
+
+template <class BaseIterator, class U8Type = ::boost::uint8_t>
+class u32_to_u8_iterator
+ : public boost::iterator_facade<u32_to_u8_iterator<BaseIterator, U8Type>, U8Type, std::bidirectional_iterator_tag, const U8Type>
+{
+ typedef boost::iterator_facade<u32_to_u8_iterator<BaseIterator, U8Type>, U8Type, std::bidirectional_iterator_tag, const U8Type> base_type;
+
+#if !defined(BOOST_NO_STD_ITERATOR_TRAITS) && !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
+ typedef typename std::iterator_traits<BaseIterator>::value_type base_value_type;
+
+ BOOST_STATIC_ASSERT(sizeof(base_value_type)*CHAR_BIT == 32);
+ BOOST_STATIC_ASSERT(sizeof(U8Type)*CHAR_BIT == 8);
+#endif
+
+public:
+ typename base_type::reference
+ dereference()const
+ {
+ if(m_current == 4)
+ extract_current();
+ return m_values[m_current];
+ }
+ bool equal(const u32_to_u8_iterator& that)const
+ {
+ if(m_position == that.m_position)
+ {
+ // either the m_current's must be equal, or one must be 0 and
+ // the other 4: which means neither must have bits 1 or 2 set:
+ return (m_current == that.m_current)
+ || (((m_current | that.m_current) & 3) == 0);
+ }
+ return false;
+ }
+ void increment()
+ {
+ // if we have a pending read then read now, so that we know whether
+ // to skip a position, or move to a low-surrogate:
+ if(m_current == 4)
+ {
+ // pending read:
+ extract_current();
+ }
+ // move to the next surrogate position:
+ ++m_current;
+ // if we've reached the end skip a position:
+ if(m_values[m_current] == 0)
+ {
+ m_current = 4;
+ ++m_position;
+ }
+ }
+ void decrement()
+ {
+ if((m_current & 3) == 0)
+ {
+ --m_position;
+ extract_current();
+ m_current = 3;
+ while(m_current && (m_values[m_current] == 0))
+ --m_current;
+ }
+ else
+ --m_current;
+ }
+ BaseIterator base()const
+ {
+ return m_position;
+ }
+ // construct:
+ u32_to_u8_iterator() : m_position(), m_current(0)
+ {
+ m_values[0] = 0;
+ m_values[1] = 0;
+ m_values[2] = 0;
+ m_values[3] = 0;
+ m_values[4] = 0;
+ }
+ u32_to_u8_iterator(BaseIterator b) : m_position(b), m_current(4)
+ {
+ m_values[0] = 0;
+ m_values[1] = 0;
+ m_values[2] = 0;
+ m_values[3] = 0;
+ m_values[4] = 0;
+ }
+private:
+
+ void extract_current()const
+ {
+ boost::uint32_t c = *m_position;
+ if(c > 0x10FFFFu)
+ detail::invalid_utf32_code_point(c);
+ if(c < 0x80u)
+ {
+ m_values[0] = static_cast<unsigned char>(c);
+ m_values[1] = static_cast<unsigned char>(0u);
+ m_values[2] = static_cast<unsigned char>(0u);
+ m_values[3] = static_cast<unsigned char>(0u);
+ }
+ else if(c < 0x800u)
+ {
+ m_values[0] = static_cast<unsigned char>(0xC0u + (c >> 6));
+ m_values[1] = static_cast<unsigned char>(0x80u + (c & 0x3Fu));
+ m_values[2] = static_cast<unsigned char>(0u);
+ m_values[3] = static_cast<unsigned char>(0u);
+ }
+ else if(c < 0x10000u)
+ {
+ m_values[0] = static_cast<unsigned char>(0xE0u + (c >> 12));
+ m_values[1] = static_cast<unsigned char>(0x80u + ((c >> 6) & 0x3Fu));
+ m_values[2] = static_cast<unsigned char>(0x80u + (c & 0x3Fu));
+ m_values[3] = static_cast<unsigned char>(0u);
+ }
+ else
+ {
+ m_values[0] = static_cast<unsigned char>(0xF0u + (c >> 18));
+ m_values[1] = static_cast<unsigned char>(0x80u + ((c >> 12) & 0x3Fu));
+ m_values[2] = static_cast<unsigned char>(0x80u + ((c >> 6) & 0x3Fu));
+ m_values[3] = static_cast<unsigned char>(0x80u + (c & 0x3Fu));
+ }
+ m_current= 0;
+ }
+ BaseIterator m_position;
+ mutable U8Type m_values[5];
+ mutable unsigned m_current;
+};
+
+template <class BaseIterator, class U32Type = ::boost::uint32_t>
+class u8_to_u32_iterator
+ : public boost::iterator_facade<u8_to_u32_iterator<BaseIterator, U32Type>, U32Type, std::bidirectional_iterator_tag, const U32Type>
+{
+ typedef boost::iterator_facade<u8_to_u32_iterator<BaseIterator, U32Type>, U32Type, std::bidirectional_iterator_tag, const U32Type> base_type;
+ // special values for pending iterator reads:
+ BOOST_STATIC_CONSTANT(U32Type, pending_read = 0xffffffffu);
+
+#if !defined(BOOST_NO_STD_ITERATOR_TRAITS) && !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
+ typedef typename std::iterator_traits<BaseIterator>::value_type base_value_type;
+
+ BOOST_STATIC_ASSERT(sizeof(base_value_type)*CHAR_BIT == 8);
+ BOOST_STATIC_ASSERT(sizeof(U32Type)*CHAR_BIT == 32);
+#endif
+
+public:
+ typename base_type::reference
+ dereference()const
+ {
+ if(m_value == pending_read)
+ extract_current();
+ return m_value;
+ }
+ bool equal(const u8_to_u32_iterator& that)const
+ {
+ return m_position == that.m_position;
+ }
+ void increment()
+ {
+ // We must not start with a continuation character:
+ if((static_cast<boost::uint8_t>(*m_position) & 0xC0) == 0x80)
+ invalid_sequence();
+ // skip high surrogate first if there is one:
+ unsigned c = detail::utf8_byte_count(*m_position);
+ if(m_value == pending_read)
+ {
+ // Since we haven't read in a value, we need to validate the code points:
+ for(unsigned i = 0; i < c; ++i)
+ {
+ ++m_position;
+ // We must have a continuation byte:
+ if((i != c - 1) && ((static_cast<boost::uint8_t>(*m_position) & 0xC0) != 0x80))
+ invalid_sequence();
+ }
+ }
+ else
+ {
+ std::advance(m_position, c);
+ }
+ m_value = pending_read;
+ }
+ void decrement()
+ {
+ // Keep backtracking until we don't have a trailing character:
+ unsigned count = 0;
+ while((*--m_position & 0xC0u) == 0x80u) ++count;
+ // now check that the sequence was valid:
+ if(count != detail::utf8_trailing_byte_count(*m_position))
+ invalid_sequence();
+ m_value = pending_read;
+ }
+ BaseIterator base()const
+ {
+ return m_position;
+ }
+ // construct:
+ u8_to_u32_iterator() : m_position()
+ {
+ m_value = pending_read;
+ }
+ u8_to_u32_iterator(BaseIterator b) : m_position(b)
+ {
+ m_value = pending_read;
+ }
+ //
+ // Checked constructor:
+ //
+ u8_to_u32_iterator(BaseIterator b, BaseIterator start, BaseIterator end) : m_position(b)
+ {
+ m_value = pending_read;
+ //
+ // We must not start with a continuation character, or end with a
+ // truncated UTF-8 sequence otherwise we run the risk of going past
+ // the start/end of the underlying sequence:
+ //
+ if(start != end)
+ {
+ unsigned char v = *start;
+ if((v & 0xC0u) == 0x80u)
+ invalid_sequence();
+ if((b != start) && (b != end) && ((*b & 0xC0u) == 0x80u))
+ invalid_sequence();
+ BaseIterator pos = end;
+ do
+ {
+ v = *--pos;
+ }
+ while((start != pos) && ((v & 0xC0u) == 0x80u));
+ std::ptrdiff_t extra = detail::utf8_byte_count(v);
+ if(std::distance(pos, end) < extra)
+ invalid_sequence();
+ }
+ }
+private:
+ static void invalid_sequence()
+ {
+ std::out_of_range e("Invalid UTF-8 sequence encountered while trying to encode UTF-32 character");
+ boost::throw_exception(e);
+ }
+ void extract_current()const
+ {
+ m_value = static_cast<U32Type>(static_cast< ::boost::uint8_t>(*m_position));
+ // we must not have a continuation character:
+ if((m_value & 0xC0u) == 0x80u)
+ invalid_sequence();
+ // see how many extra bytes we have:
+ unsigned extra = detail::utf8_trailing_byte_count(*m_position);
+ // extract the extra bits, 6 from each extra byte:
+ BaseIterator next(m_position);
+ for(unsigned c = 0; c < extra; ++c)
+ {
+ ++next;
+ m_value <<= 6;
+ // We must have a continuation byte:
+ if((static_cast<boost::uint8_t>(*next) & 0xC0) != 0x80)
+ invalid_sequence();
+ m_value += static_cast<boost::uint8_t>(*next) & 0x3Fu;
+ }
+ // we now need to remove a few of the leftmost bits, but how many depends
+ // upon how many extra bytes we've extracted:
+ static const boost::uint32_t masks[4] =
+ {
+ 0x7Fu,
+ 0x7FFu,
+ 0xFFFFu,
+ 0x1FFFFFu,
+ };
+ m_value &= masks[extra];
+ // check the result:
+ if(m_value > static_cast<U32Type>(0x10FFFFu))
+ invalid_sequence();
+ }
+ BaseIterator m_position;
+ mutable U32Type m_value;
+};
+
+template <class BaseIterator>
+class utf16_output_iterator
+{
+public:
+ typedef void difference_type;
+ typedef void value_type;
+ typedef boost::uint32_t* pointer;
+ typedef boost::uint32_t& reference;
+ typedef std::output_iterator_tag iterator_category;
+
+ utf16_output_iterator(const BaseIterator& b)
+ : m_position(b){}
+ utf16_output_iterator(const utf16_output_iterator& that)
+ : m_position(that.m_position){}
+ utf16_output_iterator& operator=(const utf16_output_iterator& that)
+ {
+ m_position = that.m_position;
+ return *this;
+ }
+ const utf16_output_iterator& operator*()const
+ {
+ return *this;
+ }
+ void operator=(boost::uint32_t val)const
+ {
+ push(val);
+ }
+ utf16_output_iterator& operator++()
+ {
+ return *this;
+ }
+ utf16_output_iterator& operator++(int)
+ {
+ return *this;
+ }
+ BaseIterator base()const
+ {
+ return m_position;
+ }
+private:
+ void push(boost::uint32_t v)const
+ {
+ if(v >= 0x10000u)
+ {
+ // begin by checking for a code point out of range:
+ if(v > 0x10FFFFu)
+ detail::invalid_utf32_code_point(v);
+ // split into two surrogates:
+ *m_position++ = static_cast<boost::uint16_t>(v >> 10) + detail::high_surrogate_base;
+ *m_position++ = static_cast<boost::uint16_t>(v & detail::ten_bit_mask) + detail::low_surrogate_base;
+ }
+ else
+ {
+ // 16-bit code point:
+ // value must not be a surrogate:
+ if(detail::is_surrogate(v))
+ detail::invalid_utf32_code_point(v);
+ *m_position++ = static_cast<boost::uint16_t>(v);
+ }
+ }
+ mutable BaseIterator m_position;
+};
+
+template <class BaseIterator>
+class utf8_output_iterator
+{
+public:
+ typedef void difference_type;
+ typedef void value_type;
+ typedef boost::uint32_t* pointer;
+ typedef boost::uint32_t& reference;
+ typedef std::output_iterator_tag iterator_category;
+
+ utf8_output_iterator(const BaseIterator& b)
+ : m_position(b){}
+ utf8_output_iterator(const utf8_output_iterator& that)
+ : m_position(that.m_position){}
+ utf8_output_iterator& operator=(const utf8_output_iterator& that)
+ {
+ m_position = that.m_position;
+ return *this;
+ }
+ const utf8_output_iterator& operator*()const
+ {
+ return *this;
+ }
+ void operator=(boost::uint32_t val)const
+ {
+ push(val);
+ }
+ utf8_output_iterator& operator++()
+ {
+ return *this;
+ }
+ utf8_output_iterator& operator++(int)
+ {
+ return *this;
+ }
+ BaseIterator base()const
+ {
+ return m_position;
+ }
+private:
+ void push(boost::uint32_t c)const
+ {
+ if(c > 0x10FFFFu)
+ detail::invalid_utf32_code_point(c);
+ if(c < 0x80u)
+ {
+ *m_position++ = static_cast<unsigned char>(c);
+ }
+ else if(c < 0x800u)
+ {
+ *m_position++ = static_cast<unsigned char>(0xC0u + (c >> 6));
+ *m_position++ = static_cast<unsigned char>(0x80u + (c & 0x3Fu));
+ }
+ else if(c < 0x10000u)
+ {
+ *m_position++ = static_cast<unsigned char>(0xE0u + (c >> 12));
+ *m_position++ = static_cast<unsigned char>(0x80u + ((c >> 6) & 0x3Fu));
+ *m_position++ = static_cast<unsigned char>(0x80u + (c & 0x3Fu));
+ }
+ else
+ {
+ *m_position++ = static_cast<unsigned char>(0xF0u + (c >> 18));
+ *m_position++ = static_cast<unsigned char>(0x80u + ((c >> 12) & 0x3Fu));
+ *m_position++ = static_cast<unsigned char>(0x80u + ((c >> 6) & 0x3Fu));
+ *m_position++ = static_cast<unsigned char>(0x80u + (c & 0x3Fu));
+ }
+ }
+ mutable BaseIterator m_position;
+};
+
+} // namespace boost
+
+#endif // BOOST_REGEX_UNICODE_ITERATOR_HPP
+
diff --git a/third_party/libosmium/include/mmap_for_windows.hpp b/third_party/libosmium/include/mmap_for_windows.hpp
new file mode 100644
index 0000000..abe62d6
--- /dev/null
+++ b/third_party/libosmium/include/mmap_for_windows.hpp
@@ -0,0 +1,103 @@
+#ifndef MMAP_FOR_WINDOWS_HPP
+#define MMAP_FOR_WINDOWS_HPP
+
+/* mmap() replacement for Windows
+ *
+ * Author: Mike Frysinger <vapier at gentoo.org>
+ * Placed into the public domain
+ */
+
+/* References:
+ * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx
+ * CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx
+ * MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx
+ * UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx
+ */
+
+#include <io.h>
+#include <windows.h>
+#include <sys/types.h>
+
+#define PROT_READ 0x1
+#define PROT_WRITE 0x2
+/* This flag is only available in WinXP+ */
+#ifdef FILE_MAP_EXECUTE
+#define PROT_EXEC 0x4
+#else
+#define PROT_EXEC 0x0
+#define FILE_MAP_EXECUTE 0
+#endif
+
+#define MAP_SHARED 0x01
+#define MAP_PRIVATE 0x02
+#define MAP_ANONYMOUS 0x20
+#define MAP_ANON MAP_ANONYMOUS
+#define MAP_FAILED ((void *) -1)
+
+static DWORD dword_hi(uint64_t x) {
+ return static_cast<DWORD>(x >> 32);
+}
+
+static DWORD dword_lo(uint64_t x) {
+ return static_cast<DWORD>(x & 0xffffffff);
+}
+
+static void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
+{
+ if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
+ return MAP_FAILED;
+ if (fd == -1) {
+ if (!(flags & MAP_ANON) || offset)
+ return MAP_FAILED;
+ } else if (flags & MAP_ANON)
+ return MAP_FAILED;
+
+ DWORD flProtect;
+ if (prot & PROT_WRITE) {
+ if (prot & PROT_EXEC)
+ flProtect = PAGE_EXECUTE_READWRITE;
+ else
+ flProtect = PAGE_READWRITE;
+ } else if (prot & PROT_EXEC) {
+ if (prot & PROT_READ)
+ flProtect = PAGE_EXECUTE_READ;
+ else if (prot & PROT_EXEC)
+ flProtect = PAGE_EXECUTE;
+ } else
+ flProtect = PAGE_READONLY;
+
+ uint64_t end = static_cast<uint64_t>(length) + offset;
+ HANDLE mmap_fd;
+ if (fd == -1)
+ mmap_fd = INVALID_HANDLE_VALUE;
+ else
+ mmap_fd = (HANDLE)_get_osfhandle(fd);
+
+ HANDLE h = CreateFileMapping(mmap_fd, NULL, flProtect, dword_hi(end), dword_lo(end), NULL);
+ if (h == NULL)
+ return MAP_FAILED;
+
+ DWORD dwDesiredAccess;
+ if (prot & PROT_WRITE)
+ dwDesiredAccess = FILE_MAP_WRITE;
+ else
+ dwDesiredAccess = FILE_MAP_READ;
+ if (prot & PROT_EXEC)
+ dwDesiredAccess |= FILE_MAP_EXECUTE;
+ if (flags & MAP_PRIVATE)
+ dwDesiredAccess |= FILE_MAP_COPY;
+ void *ret = MapViewOfFile(h, dwDesiredAccess, dword_hi(offset), dword_lo(offset), length);
+ if (ret == NULL) {
+ CloseHandle(h);
+ ret = MAP_FAILED;
+ }
+ return ret;
+}
+
+static int munmap(void *addr, size_t length)
+{
+ return UnmapViewOfFile(addr) ? 0 : -1;
+ /* ruh-ro, we leaked handle from CreateFileMapping() ... */
+}
+
+#endif
diff --git a/third_party/osmium/area/assembler.hpp b/third_party/libosmium/include/osmium/area/assembler.hpp
similarity index 99%
rename from third_party/osmium/area/assembler.hpp
rename to third_party/libosmium/include/osmium/area/assembler.hpp
index 155fa24..0a5f123 100644
--- a/third_party/osmium/area/assembler.hpp
+++ b/third_party/libosmium/include/osmium/area/assembler.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -65,7 +65,7 @@ namespace osmium {
// Enables debug output to stderr
bool debug;
- explicit AssemblerConfig(osmium::area::ProblemReporter* pr = nullptr, bool d=false) :
+ explicit AssemblerConfig(osmium::area::ProblemReporter* pr = nullptr, bool d = false) :
problem_reporter(pr),
debug(d) {
}
@@ -74,7 +74,7 @@ namespace osmium {
* Enable or disable debug output to stderr. This is for Osmium
* developers only.
*/
- void enable_debug_output(bool d=true) {
+ void enable_debug_output(bool d = true) {
debug = d;
}
@@ -445,7 +445,7 @@ namespace osmium {
}
bool add_to_existing_ring(osmium::area::detail::NodeRefSegment segment) {
- int n=0;
+ int n = 0;
for (auto& ring : m_rings) {
if (debug()) {
std::cerr << " check against ring " << n << " " << ring;
diff --git a/third_party/osmium/area/detail/node_ref_segment.hpp b/third_party/libosmium/include/osmium/area/detail/node_ref_segment.hpp
similarity index 99%
rename from third_party/osmium/area/detail/node_ref_segment.hpp
rename to third_party/libosmium/include/osmium/area/detail/node_ref_segment.hpp
index 5b251bb..43569a8 100644
--- a/third_party/osmium/area/detail/node_ref_segment.hpp
+++ b/third_party/libosmium/include/osmium/area/detail/node_ref_segment.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/area/detail/proto_ring.hpp b/third_party/libosmium/include/osmium/area/detail/proto_ring.hpp
similarity index 98%
rename from third_party/osmium/area/detail/proto_ring.hpp
rename to third_party/libosmium/include/osmium/area/detail/proto_ring.hpp
index 63fec5b..c0f545c 100644
--- a/third_party/osmium/area/detail/proto_ring.hpp
+++ b/third_party/libosmium/include/osmium/area/detail/proto_ring.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -155,7 +155,7 @@ namespace osmium {
m_inner.push_back(ring);
}
- const std::vector<ProtoRing*> inner_rings() const {
+ const std::vector<ProtoRing*>& inner_rings() const {
return m_inner;
}
diff --git a/third_party/osmium/area/detail/segment_list.hpp b/third_party/libosmium/include/osmium/area/detail/segment_list.hpp
similarity index 98%
rename from third_party/osmium/area/detail/segment_list.hpp
rename to third_party/libosmium/include/osmium/area/detail/segment_list.hpp
index a14f792..ca6071e 100644
--- a/third_party/osmium/area/detail/segment_list.hpp
+++ b/third_party/libosmium/include/osmium/area/detail/segment_list.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -99,7 +99,7 @@ namespace osmium {
* Enable or disable debug output to stderr. This is for Osmium
* developers only.
*/
- void enable_debug_output(bool debug=true) noexcept {
+ void enable_debug_output(bool debug = true) noexcept {
m_debug = debug;
}
diff --git a/third_party/osmium/area/multipolygon_collector.hpp b/third_party/libosmium/include/osmium/area/multipolygon_collector.hpp
similarity index 98%
rename from third_party/osmium/area/multipolygon_collector.hpp
rename to third_party/libosmium/include/osmium/area/multipolygon_collector.hpp
index af48176..84a5262 100644
--- a/third_party/osmium/area/multipolygon_collector.hpp
+++ b/third_party/libosmium/include/osmium/area/multipolygon_collector.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -142,7 +142,7 @@ namespace osmium {
* Overwritten from the base class.
*/
void way_not_in_any_relation(const osmium::Way& way) {
- if (way.ends_have_same_location() && way.nodes().size() > 3) {
+ if (way.nodes().size() > 3 && way.ends_have_same_location()) {
// way is closed and has enough nodes, build simple multipolygon
try {
TAssembler assembler(m_assembler_config);
diff --git a/third_party/osmium/area/problem_reporter.hpp b/third_party/libosmium/include/osmium/area/problem_reporter.hpp
similarity index 98%
rename from third_party/osmium/area/problem_reporter.hpp
rename to third_party/libosmium/include/osmium/area/problem_reporter.hpp
index 5e255db..4ae4bb2 100644
--- a/third_party/osmium/area/problem_reporter.hpp
+++ b/third_party/libosmium/include/osmium/area/problem_reporter.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/area/problem_reporter_exception.hpp b/third_party/libosmium/include/osmium/area/problem_reporter_exception.hpp
similarity index 98%
rename from third_party/osmium/area/problem_reporter_exception.hpp
rename to third_party/libosmium/include/osmium/area/problem_reporter_exception.hpp
index 29c7ad4..5e743c6 100644
--- a/third_party/osmium/area/problem_reporter_exception.hpp
+++ b/third_party/libosmium/include/osmium/area/problem_reporter_exception.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/area/problem_reporter_ogr.hpp b/third_party/libosmium/include/osmium/area/problem_reporter_ogr.hpp
similarity index 91%
rename from third_party/osmium/area/problem_reporter_ogr.hpp
rename to third_party/libosmium/include/osmium/area/problem_reporter_ogr.hpp
index a9eb135..c437a3f 100644
--- a/third_party/osmium/area/problem_reporter_ogr.hpp
+++ b/third_party/libosmium/include/osmium/area/problem_reporter_ogr.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,21 +33,38 @@ DEALINGS IN THE SOFTWARE.
*/
-#define OSMIUM_COMPILE_WITH_CFLAGS_OGR `gdal-config --cflags`
-#define OSMIUM_LINK_WITH_LIBS_OGR `gdal-config --libs`
+/**
+ * @file
+ *
+ * This file contains code for reporting problems through OGR when
+ * assembling multipolygons.
+ *
+ * @attention If you include this file, you'll need to link with `libgdal`.
+ */
+
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable : 4458)
+#else
+# pragma GCC diagnostic push
+# ifdef __clang__
+# pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
+# endif
+# pragma GCC diagnostic ignored "-Wfloat-equal"
+# pragma GCC diagnostic ignored "-Wold-style-cast"
+# pragma GCC diagnostic ignored "-Wpadded"
+# pragma GCC diagnostic ignored "-Wredundant-decls"
+# pragma GCC diagnostic ignored "-Wshadow"
+#endif
+
+#include <ogr_api.h>
+#include <ogrsf_frmts.h>
-#pragma GCC diagnostic push
-#ifdef __clang__
-# pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
+#ifdef _MSC_VER
+# pragma warning(pop)
+#else
+# pragma GCC diagnostic pop
#endif
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#pragma GCC diagnostic ignored "-Wpadded"
-#pragma GCC diagnostic ignored "-Wredundant-decls"
-#pragma GCC diagnostic ignored "-Wshadow"
-# include <ogr_api.h>
-# include <ogrsf_frmts.h>
-#pragma GCC diagnostic pop
#include <memory>
#include <stdexcept>
diff --git a/third_party/osmium/area/problem_reporter_stream.hpp b/third_party/libosmium/include/osmium/area/problem_reporter_stream.hpp
similarity index 98%
rename from third_party/osmium/area/problem_reporter_stream.hpp
rename to third_party/libosmium/include/osmium/area/problem_reporter_stream.hpp
index 6bee568..ddcb343 100644
--- a/third_party/osmium/area/problem_reporter_stream.hpp
+++ b/third_party/libosmium/include/osmium/area/problem_reporter_stream.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/builder/builder.hpp b/third_party/libosmium/include/osmium/builder/builder.hpp
similarity index 91%
rename from third_party/osmium/builder/builder.hpp
rename to third_party/libosmium/include/osmium/builder/builder.hpp
index 61e853e..dcb95e2 100644
--- a/third_party/osmium/builder/builder.hpp
+++ b/third_party/libosmium/include/osmium/builder/builder.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,11 +33,13 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <new>
+#include <string>
#include <type_traits>
#include <osmium/memory/buffer.hpp>
@@ -98,10 +100,10 @@ namespace osmium {
* parent item (if any).
*
*/
- void add_padding(bool self=false) {
+ void add_padding(bool self = false) {
auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
if (padding != osmium::memory::align_bytes) {
- std::memset(m_buffer.reserve_space(padding), 0, padding);
+ std::fill_n(m_buffer.reserve_space(padding), padding, 0);
if (self) {
add_size(padding);
} else if (m_parent) {
@@ -123,7 +125,8 @@ namespace osmium {
}
void add_item(const osmium::memory::Item* item) {
- std::memcpy(m_buffer.reserve_space(item->padded_size()), item, item->padded_size());
+ unsigned char* target = m_buffer.reserve_space(item->padded_size());
+ std::copy_n(reinterpret_cast<const unsigned char*>(item), item->padded_size(), target);
add_size(item->padded_size());
}
@@ -146,7 +149,8 @@ namespace osmium {
* \0 byte.
*/
osmium::memory::item_size_type append(const char* data, const osmium::memory::item_size_type length) {
- std::memcpy(m_buffer.reserve_space(length), data, length);
+ unsigned char* target = m_buffer.reserve_space(length);
+ std::copy_n(reinterpret_cast<const unsigned char*>(data), length, target);
return length;
}
@@ -167,12 +171,11 @@ namespace osmium {
template <class TItem>
class ObjectBuilder : public Builder {
- static_assert(std::is_base_of<osmium::memory::Item, TItem>::value,
- "ObjectBuilder can only build objects derived from osmium::memory::Item");
+ static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "ObjectBuilder can only build objects derived from osmium::memory::Item");
public:
- explicit ObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+ explicit ObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(TItem)) {
new (&item()) TItem();
}
diff --git a/third_party/osmium/builder/builder_helper.hpp b/third_party/libosmium/include/osmium/builder/builder_helper.hpp
similarity index 98%
rename from third_party/osmium/builder/builder_helper.hpp
rename to third_party/libosmium/include/osmium/builder/builder_helper.hpp
index 3e00f81..eebdf33 100644
--- a/third_party/osmium/builder/builder_helper.hpp
+++ b/third_party/libosmium/include/osmium/builder/builder_helper.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/builder/osm_object_builder.hpp b/third_party/libosmium/include/osmium/builder/osm_object_builder.hpp
similarity index 96%
rename from third_party/osmium/builder/osm_object_builder.hpp
rename to third_party/libosmium/include/osmium/builder/osm_object_builder.hpp
index 851eb85..058f89e 100644
--- a/third_party/osmium/builder/osm_object_builder.hpp
+++ b/third_party/libosmium/include/osmium/builder/osm_object_builder.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -36,6 +36,7 @@ DEALINGS IN THE SOFTWARE.
#include <cstring>
#include <initializer_list>
#include <new>
+#include <string>
#include <utility>
#include <osmium/builder/builder.hpp>
@@ -60,7 +61,7 @@ namespace osmium {
public:
- explicit TagListBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+ explicit TagListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
ObjectBuilder<TagList>(buffer, parent) {
}
@@ -96,7 +97,7 @@ namespace osmium {
public:
- explicit NodeRefListBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+ explicit NodeRefListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
ObjectBuilder<T>(buffer, parent) {
}
@@ -109,7 +110,7 @@ namespace osmium {
static_cast<Builder*>(this)->add_size(sizeof(osmium::NodeRef));
}
- void add_node_ref(const object_id_type ref, const osmium::Location location=Location()) {
+ void add_node_ref(const object_id_type ref, const osmium::Location location = Location()) {
add_node_ref(NodeRef(ref, location));
}
@@ -159,7 +160,7 @@ namespace osmium {
public:
- explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+ explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
ObjectBuilder<RelationMemberList>(buffer, parent) {
}
@@ -214,7 +215,7 @@ namespace osmium {
public:
- explicit OSMObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+ explicit OSMObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
ObjectBuilder<T>(buffer, parent) {
static_cast<Builder*>(this)->reserve_space_for<string_size_type>();
static_cast<Builder*>(this)->add_size(sizeof(string_size_type));
@@ -236,7 +237,7 @@ namespace osmium {
public:
- explicit WayBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+ explicit WayBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
OSMObjectBuilder<osmium::Way>(buffer, parent) {
}
@@ -253,7 +254,7 @@ namespace osmium {
public:
- explicit AreaBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+ explicit AreaBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
OSMObjectBuilder<osmium::Area>(buffer, parent) {
}
diff --git a/third_party/osmium/diff_handler.hpp b/third_party/libosmium/include/osmium/diff_handler.hpp
similarity index 97%
copy from third_party/osmium/diff_handler.hpp
copy to third_party/libosmium/include/osmium/diff_handler.hpp
index 9864df5..4f9b3a1 100644
--- a/third_party/osmium/diff_handler.hpp
+++ b/third_party/libosmium/include/osmium/diff_handler.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/diff_iterator.hpp b/third_party/libosmium/include/osmium/diff_iterator.hpp
similarity index 98%
rename from third_party/osmium/diff_iterator.hpp
rename to third_party/libosmium/include/osmium/diff_iterator.hpp
index 576834c..0ddf7ff 100644
--- a/third_party/osmium/diff_iterator.hpp
+++ b/third_party/libosmium/include/osmium/diff_iterator.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/diff_visitor.hpp b/third_party/libosmium/include/osmium/diff_visitor.hpp
similarity index 98%
rename from third_party/osmium/diff_visitor.hpp
rename to third_party/libosmium/include/osmium/diff_visitor.hpp
index b8db697..5e72a7b 100644
--- a/third_party/osmium/diff_visitor.hpp
+++ b/third_party/libosmium/include/osmium/diff_visitor.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/dynamic_handler.hpp b/third_party/libosmium/include/osmium/dynamic_handler.hpp
similarity index 98%
rename from third_party/osmium/dynamic_handler.hpp
rename to third_party/libosmium/include/osmium/dynamic_handler.hpp
index bc59313..9d0bd66 100644
--- a/third_party/osmium/dynamic_handler.hpp
+++ b/third_party/libosmium/include/osmium/dynamic_handler.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/experimental/flex_reader.hpp b/third_party/libosmium/include/osmium/experimental/flex_reader.hpp
similarity index 69%
rename from third_party/osmium/experimental/flex_reader.hpp
rename to third_party/libosmium/include/osmium/experimental/flex_reader.hpp
index 8dca152..f00a5ec 100644
--- a/third_party/osmium/experimental/flex_reader.hpp
+++ b/third_party/libosmium/include/osmium/experimental/flex_reader.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -41,7 +41,7 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
/**
- * Experimental code that is not "officially" supported.
+ * @brief Experimental code that is not "officially" supported.
*/
namespace experimental {
@@ -51,9 +51,7 @@ namespace osmium {
bool m_with_areas;
osmium::osm_entity_bits::type m_entities;
- typename TLocationHandler::index_pos_type m_index_pos;
- typename TLocationHandler::index_neg_type m_index_neg;
- TLocationHandler m_location_handler;
+ TLocationHandler& m_location_handler;
osmium::io::Reader m_reader;
osmium::area::Assembler::config_type m_assembler_config;
@@ -61,12 +59,10 @@ namespace osmium {
public:
- explicit FlexReader(const osmium::io::File& file, osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::nwr) :
- m_with_areas(entities & osmium::osm_entity_bits::area),
+ explicit FlexReader(const osmium::io::File& file, TLocationHandler& location_handler, osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::nwr) :
+ m_with_areas((entities & osmium::osm_entity_bits::area) != 0),
m_entities((entities & ~osmium::osm_entity_bits::area) | (m_with_areas ? osmium::osm_entity_bits::node | osmium::osm_entity_bits::way : osmium::osm_entity_bits::nothing)),
- m_index_pos(),
- m_index_neg(),
- m_location_handler(m_index_pos, m_index_neg),
+ m_location_handler(location_handler),
m_reader(file, m_entities),
m_assembler_config(),
m_collector(m_assembler_config)
@@ -79,31 +75,33 @@ namespace osmium {
}
}
- explicit FlexReader(const std::string& filename, osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::nwr) :
- FlexReader(osmium::io::File(filename), entities) {
+ explicit FlexReader(const std::string& filename, TLocationHandler& location_handler, osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::nwr) :
+ FlexReader(osmium::io::File(filename), location_handler, entities) {
}
- explicit FlexReader(const char* filename, osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::nwr) :
- FlexReader(osmium::io::File(filename), entities) {
+ explicit FlexReader(const char* filename, TLocationHandler& location_handler, osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::nwr) :
+ FlexReader(osmium::io::File(filename), location_handler, entities) {
}
- std::vector<osmium::memory::Buffer> read() {
- std::vector<osmium::memory::Buffer> buffers;
-
+ osmium::memory::Buffer read() {
osmium::memory::Buffer buffer = m_reader.read();
if (buffer) {
- buffers.push_back(std::move(buffer));
if (m_with_areas) {
- osmium::apply(buffers[0], m_location_handler, m_collector.handler([&buffers](osmium::memory::Buffer&& area_buffer) {
- buffers.push_back(std::move(area_buffer));
+ std::vector<osmium::memory::Buffer> area_buffers;
+ osmium::apply(buffer, m_location_handler, m_collector.handler([&area_buffers](osmium::memory::Buffer&& area_buffer) {
+ area_buffers.push_back(std::move(area_buffer));
}));
+ for (const osmium::memory::Buffer& b : area_buffers) {
+ buffer.add_buffer(b);
+ buffer.commit();
+ }
} else if (m_entities & (osmium::osm_entity_bits::node | osmium::osm_entity_bits::way)) {
- osmium::apply(buffers[0], m_location_handler);
+ osmium::apply(buffer, m_location_handler);
}
}
- return buffers;
+ return buffer;
}
osmium::io::Header header() const {
diff --git a/third_party/osmium/geom/coordinates.hpp b/third_party/libosmium/include/osmium/geom/coordinates.hpp
similarity index 98%
rename from third_party/osmium/geom/coordinates.hpp
rename to third_party/libosmium/include/osmium/geom/coordinates.hpp
index 1ff27fe..2bad57e 100644
--- a/third_party/osmium/geom/coordinates.hpp
+++ b/third_party/libosmium/include/osmium/geom/coordinates.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/geom/factory.hpp b/third_party/libosmium/include/osmium/geom/factory.hpp
similarity index 98%
rename from third_party/osmium/geom/factory.hpp
rename to third_party/libosmium/include/osmium/geom/factory.hpp
index 4097b5d..518cbfb 100644
--- a/third_party/osmium/geom/factory.hpp
+++ b/third_party/libosmium/include/osmium/geom/factory.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -214,7 +214,7 @@ namespace osmium {
return m_impl.linestring_finish(num_points);
}
- linestring_type create_linestring(const osmium::WayNodeList& wnl, use_nodes un=use_nodes::unique, direction dir=direction::forward) {
+ linestring_type create_linestring(const osmium::WayNodeList& wnl, use_nodes un = use_nodes::unique, direction dir = direction::forward) {
linestring_start();
size_t num_points = 0;
diff --git a/third_party/osmium/geom/geojson.hpp b/third_party/libosmium/include/osmium/geom/geojson.hpp
similarity index 95%
rename from third_party/osmium/geom/geojson.hpp
rename to third_party/libosmium/include/osmium/geom/geojson.hpp
index f6d7ee6..7d59535 100644
--- a/third_party/osmium/geom/geojson.hpp
+++ b/third_party/libosmium/include/osmium/geom/geojson.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -133,9 +133,11 @@ namespace osmium {
multipolygon_type multipolygon_finish() {
assert(!m_str.empty());
- m_str.back() = ']';
- m_str += "}";
- return std::move(m_str);
+ std::string str;
+ std::swap(str, m_str);
+ str.back() = ']';
+ str += "}";
+ return str;
}
}; // class GeoJSONFactoryImpl
diff --git a/third_party/osmium/geom/geos.hpp b/third_party/libosmium/include/osmium/geom/geos.hpp
similarity index 97%
rename from third_party/osmium/geom/geos.hpp
rename to third_party/libosmium/include/osmium/geom/geos.hpp
index 877520b..3c73637 100644
--- a/third_party/osmium/geom/geos.hpp
+++ b/third_party/libosmium/include/osmium/geom/geos.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,8 +33,14 @@ DEALINGS IN THE SOFTWARE.
*/
-#define OSMIUM_COMPILE_WITH_CFLAGS_GEOS `geos-config --cflags`
-#define OSMIUM_LINK_WITH_LIBS_GEOS `geos-config --libs`
+/**
+ * @file
+ *
+ * This file contains code for conversion of OSM geometries into GDAL
+ * geometries.
+ *
+ * @attention If you include this file, you'll need to link with `libgeos`.
+ */
#include <utility>
diff --git a/third_party/osmium/geom/haversine.hpp b/third_party/libosmium/include/osmium/geom/haversine.hpp
similarity index 97%
rename from third_party/osmium/geom/haversine.hpp
rename to third_party/libosmium/include/osmium/geom/haversine.hpp
index b8d0134..e62a31b 100644
--- a/third_party/osmium/geom/haversine.hpp
+++ b/third_party/libosmium/include/osmium/geom/haversine.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -74,7 +74,7 @@ namespace osmium {
* Calculate length of way.
*/
inline double distance(const osmium::WayNodeList& wnl) {
- double sum_length=0;
+ double sum_length = 0;
for (auto it = wnl.begin(); it != wnl.end(); ++it) {
if (std::next(it) != wnl.end()) {
diff --git a/third_party/osmium/geom/mercator_projection.hpp b/third_party/libosmium/include/osmium/geom/mercator_projection.hpp
similarity index 98%
rename from third_party/osmium/geom/mercator_projection.hpp
rename to third_party/libosmium/include/osmium/geom/mercator_projection.hpp
index d170017..a6d1d57 100644
--- a/third_party/osmium/geom/mercator_projection.hpp
+++ b/third_party/libosmium/include/osmium/geom/mercator_projection.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/geom/ogr.hpp b/third_party/libosmium/include/osmium/geom/ogr.hpp
similarity index 83%
rename from third_party/osmium/geom/ogr.hpp
rename to third_party/libosmium/include/osmium/geom/ogr.hpp
index 2727f2f..f33971c 100644
--- a/third_party/osmium/geom/ogr.hpp
+++ b/third_party/libosmium/include/osmium/geom/ogr.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,22 +33,49 @@ DEALINGS IN THE SOFTWARE.
*/
-#define OSMIUM_COMPILE_WITH_CFLAGS_OGR `gdal-config --cflags`
-#define OSMIUM_LINK_WITH_LIBS_OGR `gdal-config --libs`
+/**
+ * @file
+ *
+ * This file contains code for conversion of OSM geometries into OGR
+ * geometries.
+ *
+ * @attention If you include this file, you'll need to link with `libgdal`.
+ */
#include <cassert>
#include <cstddef>
#include <memory>
#include <utility>
-#pragma GCC diagnostic push
-#ifdef __clang__
-# pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable : 4458)
+# pragma warning(disable : 4251)
+#else
+# pragma GCC diagnostic push
+# ifdef __clang__
+# pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
+# endif
+# pragma GCC diagnostic ignored "-Wfloat-equal"
+# pragma GCC diagnostic ignored "-Wold-style-cast"
+# pragma GCC diagnostic ignored "-Wpadded"
+# pragma GCC diagnostic ignored "-Wredundant-decls"
+# pragma GCC diagnostic ignored "-Wshadow"
+#endif
+
+/* Strictly speaking the following include would be enough here,
+ but everybody using this file will very likely need the other includes,
+ so we are adding them here, so that not everybody will need all those
+ pragmas to disable warnings. */
+//#include <ogr_geometry.h>
+#include <ogr_api.h>
+#include <ogrsf_frmts.h>
+
+#ifdef _MSC_VER
+# pragma warning(pop)
+#else
+# pragma GCC diagnostic pop
#endif
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#pragma GCC diagnostic ignored "-Wpadded"
-# include <ogr_geometry.h>
-#pragma GCC diagnostic pop
#include <osmium/geom/coordinates.hpp>
#include <osmium/geom/factory.hpp>
diff --git a/third_party/osmium/geom/projection.hpp b/third_party/libosmium/include/osmium/geom/projection.hpp
similarity index 86%
rename from third_party/osmium/geom/projection.hpp
rename to third_party/libosmium/include/osmium/geom/projection.hpp
index 72ff945..6419101 100644
--- a/third_party/osmium/geom/projection.hpp
+++ b/third_party/libosmium/include/osmium/geom/projection.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,7 +33,14 @@ DEALINGS IN THE SOFTWARE.
*/
-#define OSMIUM_LINK_WITH_LIBS_PROJ -lproj
+/**
+ * @file
+ *
+ * This file contains code for projecting OSM locations to arbitrary
+ * coordinate reference systems. It is based on the Proj.4 library.
+ *
+ * @attention If you include this file, you'll need to link with `libproj`.
+ */
#include <memory>
#include <string>
@@ -79,11 +86,11 @@ namespace osmium {
}
bool is_latlong() const {
- return pj_is_latlong(m_crs.get());
+ return pj_is_latlong(m_crs.get()) != 0;
}
bool is_geocent() const {
- return pj_is_geocent(m_crs.get());
+ return pj_is_geocent(m_crs.get()) != 0;
}
/**
@@ -105,7 +112,7 @@ namespace osmium {
}; // class CRS
/**
- * Functor that does projection from WGS84 (EPSG:4326) in to the given
+ * Functor that does projection from WGS84 (EPSG:4326) to the given
* CRS.
*/
class Projection {
@@ -130,16 +137,17 @@ namespace osmium {
}
Coordinates operator()(osmium::Location location) const {
- if (m_epsg == 4326) {
- return Coordinates(location.lon(), location.lat());
- } else {
- Coordinates c = transform(m_crs_wgs84, m_crs_user, Coordinates(deg_to_rad(location.lon()), deg_to_rad(location.lat())));
+ Coordinates c {location.lon(), location.lat()};
+
+ if (m_epsg != 4326) {
+ c = transform(m_crs_wgs84, m_crs_user, Coordinates(deg_to_rad(location.lon()), deg_to_rad(location.lat())));
if (m_crs_user.is_latlong()) {
c.x = rad_to_deg(c.x);
c.y = rad_to_deg(c.y);
}
- return c;
}
+
+ return c;
}
int epsg() const noexcept {
diff --git a/third_party/osmium/geom/relations.hpp b/third_party/libosmium/include/osmium/geom/relations.hpp
similarity index 97%
rename from third_party/osmium/geom/relations.hpp
rename to third_party/libosmium/include/osmium/geom/relations.hpp
index e57e2f4..e9e2aa4 100644
--- a/third_party/osmium/geom/relations.hpp
+++ b/third_party/libosmium/include/osmium/geom/relations.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/geom/util.hpp b/third_party/libosmium/include/osmium/geom/util.hpp
similarity index 97%
rename from third_party/osmium/geom/util.hpp
rename to third_party/libosmium/include/osmium/geom/util.hpp
index 1f1a50d..5e9f822 100644
--- a/third_party/osmium/geom/util.hpp
+++ b/third_party/libosmium/include/osmium/geom/util.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/geom/wkb.hpp b/third_party/libosmium/include/osmium/geom/wkb.hpp
similarity index 94%
rename from third_party/osmium/geom/wkb.hpp
rename to third_party/libosmium/include/osmium/geom/wkb.hpp
index 0748ede..2f32fe3 100644
--- a/third_party/osmium/geom/wkb.hpp
+++ b/third_party/libosmium/include/osmium/geom/wkb.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <cstdint>
-#include <cstring>
#include <string>
// Windows is only available for little endian architectures
@@ -71,10 +70,10 @@ namespace osmium {
inline void str_push(std::string& str, T data) {
size_t size = str.size();
str.resize(size + sizeof(T));
- std::memcpy(const_cast<char *>(&str[size]), reinterpret_cast<char*>(&data), sizeof(T));
+ std::copy_n(reinterpret_cast<char*>(&data), sizeof(T), &str[size]);
}
- inline std::string convert_to_hex(std::string& str) {
+ inline std::string convert_to_hex(const std::string& str) {
static const char* lookup_hex = "0123456789ABCDEF";
std::string out;
@@ -151,8 +150,7 @@ namespace osmium {
}
void set_size(const size_t offset, const size_t size) {
- const uint32_t s = static_cast_with_assert<uint32_t>(size);
- memcpy(&m_data[offset], &s, sizeof(uint32_t));
+ *reinterpret_cast<uint32_t*>(&m_data[offset]) = static_cast_with_assert<uint32_t>(size);
}
public:
@@ -163,7 +161,7 @@ namespace osmium {
typedef std::string multipolygon_type;
typedef std::string ring_type;
- explicit WKBFactoryImpl(wkb_type wtype=wkb_type::wkb, out_type otype=out_type::binary) :
+ explicit WKBFactoryImpl(wkb_type wtype = wkb_type::wkb, out_type otype = out_type::binary) :
m_wkb_type(wtype),
m_out_type(otype) {
}
diff --git a/third_party/osmium/geom/wkt.hpp b/third_party/libosmium/include/osmium/geom/wkt.hpp
similarity index 95%
rename from third_party/osmium/geom/wkt.hpp
rename to third_party/libosmium/include/osmium/geom/wkt.hpp
index 0ef304a..4fea96b 100644
--- a/third_party/osmium/geom/wkt.hpp
+++ b/third_party/libosmium/include/osmium/geom/wkt.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -130,8 +130,10 @@ namespace osmium {
multipolygon_type multipolygon_finish() {
assert(!m_str.empty());
- m_str.back() = ')';
- return std::move(m_str);
+ std::string str;
+ std::swap(str, m_str);
+ str.back() = ')';
+ return str;
}
}; // class WKTFactoryImpl
diff --git a/third_party/osmium/handler.hpp b/third_party/libosmium/include/osmium/handler.hpp
similarity index 97%
rename from third_party/osmium/handler.hpp
rename to third_party/libosmium/include/osmium/handler.hpp
index 62e59f8..34d8785 100644
--- a/third_party/osmium/handler.hpp
+++ b/third_party/libosmium/include/osmium/handler.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/handler/chain.hpp b/third_party/libosmium/include/osmium/handler/chain.hpp
similarity index 98%
rename from third_party/osmium/handler/chain.hpp
rename to third_party/libosmium/include/osmium/handler/chain.hpp
index 868632d..1af3962 100644
--- a/third_party/osmium/handler/chain.hpp
+++ b/third_party/libosmium/include/osmium/handler/chain.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/handler/disk_store.hpp b/third_party/libosmium/include/osmium/handler/disk_store.hpp
similarity index 98%
rename from third_party/osmium/handler/disk_store.hpp
rename to third_party/libosmium/include/osmium/handler/disk_store.hpp
index 2b7ffcf..ccae596 100644
--- a/third_party/osmium/handler/disk_store.hpp
+++ b/third_party/libosmium/include/osmium/handler/disk_store.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/handler/dump.hpp b/third_party/libosmium/include/osmium/handler/dump.hpp
similarity index 98%
rename from third_party/osmium/handler/dump.hpp
rename to third_party/libosmium/include/osmium/handler/dump.hpp
index e62c4b0..a23236e 100644
--- a/third_party/osmium/handler/dump.hpp
+++ b/third_party/libosmium/include/osmium/handler/dump.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -136,7 +136,7 @@ namespace osmium {
public:
- explicit Dump(std::ostream& out, bool with_size=true, const std::string& prefix="") :
+ explicit Dump(std::ostream& out, bool with_size = true, const std::string& prefix = "") :
m_out(&out),
m_with_size(with_size),
m_prefix(prefix) {
diff --git a/third_party/osmium/handler/node_locations_for_ways.hpp b/third_party/libosmium/include/osmium/handler/node_locations_for_ways.hpp
similarity index 92%
rename from third_party/osmium/handler/node_locations_for_ways.hpp
rename to third_party/libosmium/include/osmium/handler/node_locations_for_ways.hpp
index a273082..9b9fcbf 100644
--- a/third_party/osmium/handler/node_locations_for_ways.hpp
+++ b/third_party/libosmium/include/osmium/handler/node_locations_for_ways.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -44,6 +44,8 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
+#include <osmium/index/node_locations_map.hpp>
+
namespace osmium {
namespace handler {
@@ -61,11 +63,9 @@ namespace osmium {
template <class TStoragePosIDs, class TStorageNegIDs = dummy_type>
class NodeLocationsForWays : public osmium::handler::Handler {
- static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStoragePosIDs>::value,
- "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
+ static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStoragePosIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
- static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStorageNegIDs>::value,
- "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
+ static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStorageNegIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
public:
@@ -102,6 +102,9 @@ namespace osmium {
NodeLocationsForWays(const NodeLocationsForWays&) = delete;
NodeLocationsForWays& operator=(const NodeLocationsForWays&) = delete;
+ NodeLocationsForWays(NodeLocationsForWays&&) = default;
+ NodeLocationsForWays& operator=(NodeLocationsForWays&&) = default;
+
~NodeLocationsForWays() noexcept = default;
void ignore_errors() {
diff --git a/third_party/osmium/handler/object_relations.hpp b/third_party/libosmium/include/osmium/handler/object_relations.hpp
similarity index 98%
rename from third_party/osmium/handler/object_relations.hpp
rename to third_party/libosmium/include/osmium/handler/object_relations.hpp
index e73ce87..dc4aa45 100644
--- a/third_party/osmium/handler/object_relations.hpp
+++ b/third_party/libosmium/include/osmium/handler/object_relations.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/index/multimap/stl_vector.hpp b/third_party/libosmium/include/osmium/index/detail/create_map_with_fd.hpp
similarity index 58%
copy from third_party/osmium/index/multimap/stl_vector.hpp
copy to third_party/libosmium/include/osmium/index/detail/create_map_with_fd.hpp
index 2102824..29dc1dc 100644
--- a/third_party/osmium/index/multimap/stl_vector.hpp
+++ b/third_party/libosmium/include/osmium/index/detail/create_map_with_fd.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MULTIMAP_STL_VECTOR_HPP
-#define OSMIUM_INDEX_MULTIMAP_STL_VECTOR_HPP
+#ifndef OSMIUM_INDEX_DETAIL_CREATE_MAP_WITH_FD_HPP
+#define OSMIUM_INDEX_DETAIL_CREATE_MAP_WITH_FD_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,26 +33,41 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <cassert>
+#include <cerrno>
+#include <cstring>
+#include <fcntl.h>
+#include <stdexcept>
+#include <string>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <vector>
-#include <osmium/index/multimap/vector.hpp>
-
namespace osmium {
namespace index {
- namespace multimap {
-
- template <typename T>
- using StdVectorWrap = std::vector<T>;
-
- template <typename TId, typename TValue>
- using SparseMultimapMem = VectorBasedSparseMultimap<TId, TValue, StdVectorWrap>;
-
- } // namespace multimap
+ namespace detail {
+
+ template <class T>
+ inline T* create_map_with_fd(const std::vector<std::string>& config) {
+ if (config.size() == 1) {
+ return new T();
+ } else {
+ assert(config.size() > 1);
+ const std::string& filename = config[1];
+ int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644);
+ if (fd == -1) {
+ throw std::runtime_error(std::string("can't open file '") + filename + "': " + strerror(errno));
+ }
+ return new T(fd);
+ }
+ }
+
+ } // namespace detail
} // namespace index
} // namespace osmium
-#endif // OSMIUM_INDEX_MULTIMAP_STL_VECTOR_HPP
+#endif // OSMIUM_INDEX_DETAIL_CREATE_MAP_WITH_FD_HPP
diff --git a/third_party/osmium/index/detail/mmap_vector_anon.hpp b/third_party/libosmium/include/osmium/index/detail/mmap_vector_anon.hpp
similarity index 88%
rename from third_party/osmium/index/detail/mmap_vector_anon.hpp
rename to third_party/libosmium/include/osmium/index/detail/mmap_vector_anon.hpp
index f066961..0ea4f9d 100644
--- a/third_party/osmium/index/detail/mmap_vector_anon.hpp
+++ b/third_party/libosmium/include/osmium/index/detail/mmap_vector_anon.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_DETAIL_MMAP_VECTOR_ANON_HPP
-#define OSMIUM_DETAIL_MMAP_VECTOR_ANON_HPP
+#ifndef OSMIUM_INDEX_DETAIL_MMAP_VECTOR_ANON_HPP
+#define OSMIUM_INDEX_DETAIL_MMAP_VECTOR_ANON_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -45,8 +45,8 @@ namespace osmium {
namespace detail {
/**
- * This class looks and behaves like STL vector, but uses mmap internally.
- */
+ * This class looks and behaves like STL vector, but uses mmap internally.
+ */
template <typename T>
class mmap_vector_anon : public mmap_vector_base<T, mmap_vector_anon> {
@@ -75,4 +75,4 @@ namespace osmium {
#endif // __linux__
-#endif // OSMIUM_DETAIL_MMAP_VECTOR_ANON_HPP
+#endif // OSMIUM_INDEX_DETAIL_MMAP_VECTOR_ANON_HPP
diff --git a/third_party/osmium/index/detail/mmap_vector_base.hpp b/third_party/libosmium/include/osmium/index/detail/mmap_vector_base.hpp
similarity index 95%
rename from third_party/osmium/index/detail/mmap_vector_base.hpp
rename to third_party/libosmium/include/osmium/index/detail/mmap_vector_base.hpp
index fc96b27..3aff26d 100644
--- a/third_party/osmium/index/detail/mmap_vector_base.hpp
+++ b/third_party/libosmium/include/osmium/index/detail/mmap_vector_base.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_DETAIL_MMAP_VECTOR_BASE_HPP
-#define OSMIUM_DETAIL_MMAP_VECTOR_BASE_HPP
+#ifndef OSMIUM_INDEX_DETAIL_MMAP_VECTOR_BASE_HPP
+#define OSMIUM_INDEX_DETAIL_MMAP_VECTOR_BASE_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -38,6 +38,7 @@ DEALINGS IN THE SOFTWARE.
#include <stdexcept>
#include <osmium/index/detail/typed_mmap.hpp>
+#include <osmium/util/compatibility.hpp>
namespace osmium {
@@ -180,4 +181,4 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_DETAIL_MMAP_VECTOR_BASE_HPP
+#endif // OSMIUM_INDEX_DETAIL_MMAP_VECTOR_BASE_HPP
diff --git a/third_party/osmium/index/detail/mmap_vector_file.hpp b/third_party/libosmium/include/osmium/index/detail/mmap_vector_file.hpp
similarity index 80%
rename from third_party/osmium/index/detail/mmap_vector_file.hpp
rename to third_party/libosmium/include/osmium/index/detail/mmap_vector_file.hpp
index ca8f0eb..55077d1 100644
--- a/third_party/osmium/index/detail/mmap_vector_file.hpp
+++ b/third_party/libosmium/include/osmium/index/detail/mmap_vector_file.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_DETAIL_MMAP_VECTOR_FILE_HPP
-#define OSMIUM_DETAIL_MMAP_VECTOR_FILE_HPP
+#ifndef OSMIUM_INDEX_DETAIL_MMAP_VECTOR_FILE_HPP
+#define OSMIUM_INDEX_DETAIL_MMAP_VECTOR_FILE_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -44,8 +44,9 @@ namespace osmium {
namespace detail {
/**
- * This class looks and behaves like STL vector, but mmap's a file internally.
- */
+ * This class looks and behaves like STL vector, but mmap's a file
+ * internally.
+ */
template <typename T>
class mmap_vector_file : public mmap_vector_base<T, mmap_vector_file> {
@@ -61,14 +62,16 @@ namespace osmium {
explicit mmap_vector_file(int fd) :
mmap_vector_base<T, osmium::detail::mmap_vector_file>(
fd,
- osmium::detail::typed_mmap<T>::file_size(fd) == 0 ? osmium::detail::mmap_vector_size_increment : osmium::detail::typed_mmap<T>::file_size(fd),
+ osmium::detail::typed_mmap<T>::file_size(fd) == 0 ?
+ osmium::detail::mmap_vector_size_increment :
+ osmium::detail::typed_mmap<T>::file_size(fd),
osmium::detail::typed_mmap<T>::file_size(fd)) {
}
void reserve(size_t new_capacity) {
if (new_capacity > this->capacity()) {
- osmium::detail::typed_mmap<T>::unmap(this->data(), this->capacity());
- this->data(osmium::detail::typed_mmap<T>::grow_and_map(new_capacity, this->m_fd));
+ typed_mmap<T>::unmap(this->data(), this->capacity());
+ this->data(typed_mmap<T>::grow_and_map(new_capacity, this->m_fd));
this->m_capacity = new_capacity;
}
}
@@ -79,4 +82,4 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_DETAIL_MMAP_VECTOR_FILE_HPP
+#endif // OSMIUM_INDEX_DETAIL_MMAP_VECTOR_FILE_HPP
diff --git a/third_party/osmium/index/detail/tmpfile.hpp b/third_party/libosmium/include/osmium/index/detail/tmpfile.hpp
similarity index 91%
rename from third_party/osmium/index/detail/tmpfile.hpp
rename to third_party/libosmium/include/osmium/index/detail/tmpfile.hpp
index 3d00c50..06cab65 100644
--- a/third_party/osmium/index/detail/tmpfile.hpp
+++ b/third_party/libosmium/include/osmium/index/detail/tmpfile.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_DETAIL_TMPFILE_HPP
-#define OSMIUM_DETAIL_TMPFILE_HPP
+#ifndef OSMIUM_INDEX_DETAIL_TMPFILE_HPP
+#define OSMIUM_INDEX_DETAIL_TMPFILE_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -59,4 +59,4 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_DETAIL_TMPFILE
+#endif // OSMIUM_INDEX_DETAIL_TMPFILE_HPP
diff --git a/third_party/osmium/index/detail/typed_mmap.hpp b/third_party/libosmium/include/osmium/index/detail/typed_mmap.hpp
similarity index 97%
rename from third_party/osmium/index/detail/typed_mmap.hpp
rename to third_party/libosmium/include/osmium/index/detail/typed_mmap.hpp
index 8a952a4..77b065e 100644
--- a/third_party/osmium/index/detail/typed_mmap.hpp
+++ b/third_party/libosmium/include/osmium/index/detail/typed_mmap.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_DETAIL_TYPED_MMAP_HPP
-#define OSMIUM_DETAIL_TYPED_MMAP_HPP
+#ifndef OSMIUM_INDEX_DETAIL_TYPED_MMAP_HPP
+#define OSMIUM_INDEX_DETAIL_TYPED_MMAP_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -226,4 +226,4 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_DETAIL_TYPED_MMAP_HPP
+#endif // OSMIUM_INDEX_DETAIL_TYPED_MMAP_HPP
diff --git a/third_party/osmium/index/map/vector.hpp b/third_party/libosmium/include/osmium/index/detail/vector_map.hpp
similarity index 85%
rename from third_party/osmium/index/map/vector.hpp
rename to third_party/libosmium/include/osmium/index/detail/vector_map.hpp
index 7e47ccf..73c5a37 100644
--- a/third_party/osmium/index/map/vector.hpp
+++ b/third_party/libosmium/include/osmium/index/detail/vector_map.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MAP_VECTOR_HPP
-#define OSMIUM_INDEX_MAP_VECTOR_HPP
+#ifndef OSMIUM_INDEX_DETAIL_VECTOR_MAP_HPP
+#define OSMIUM_INDEX_DETAIL_VECTOR_MAP_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -38,6 +38,7 @@ DEALINGS IN THE SOFTWARE.
#include <stdexcept>
#include <utility>
+#include <osmium/index/index.hpp>
#include <osmium/index/map.hpp>
#include <osmium/io/detail/read_write.hpp>
@@ -54,6 +55,11 @@ namespace osmium {
public:
+ typedef TValue element_type;
+ typedef TVector vector_type;
+ typedef typename vector_type::iterator iterator;
+ typedef typename vector_type::const_iterator const_iterator;
+
VectorBasedDenseMap() :
m_vector() {
}
@@ -100,6 +106,30 @@ namespace osmium {
m_vector.shrink_to_fit();
}
+ iterator begin() {
+ return m_vector.begin();
+ }
+
+ iterator end() {
+ return m_vector.end();
+ }
+
+ const_iterator cbegin() const {
+ return m_vector.cbegin();
+ }
+
+ const_iterator cend() const {
+ return m_vector.cend();
+ }
+
+ const_iterator begin() const {
+ return m_vector.cbegin();
+ }
+
+ const_iterator end() const {
+ return m_vector.cend();
+ }
+
}; // class VectorBasedDenseMap
@@ -169,7 +199,7 @@ namespace osmium {
std::sort(m_vector.begin(), m_vector.end());
}
- void dump_as_list(int fd) const override final {
+ void dump_as_list(const int fd) override final {
osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size());
}
@@ -205,4 +235,4 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_INDEX_MAP_VECTOR_HPP
+#endif // OSMIUM_INDEX_DETAIL_VECTOR_MAP_HPP
diff --git a/third_party/osmium/index/multimap/vector.hpp b/third_party/libosmium/include/osmium/index/detail/vector_multimap.hpp
similarity index 94%
rename from third_party/osmium/index/multimap/vector.hpp
rename to third_party/libosmium/include/osmium/index/detail/vector_multimap.hpp
index b9dae43..c2b2e1f 100644
--- a/third_party/osmium/index/multimap/vector.hpp
+++ b/third_party/libosmium/include/osmium/index/detail/vector_multimap.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MULTIMAP_VECTOR_HPP
-#define OSMIUM_INDEX_MULTIMAP_VECTOR_HPP
+#ifndef OSMIUM_INDEX_DETAIL_VECTOR_MULTIMAP_HPP
+#define OSMIUM_INDEX_DETAIL_VECTOR_MULTIMAP_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -37,6 +37,7 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <utility>
+#include <osmium/index/index.hpp>
#include <osmium/index/multimap.hpp>
#include <osmium/io/detail/read_write.hpp>
@@ -136,7 +137,7 @@ namespace osmium {
);
}
- void dump_as_list(int fd) const override final {
+ void dump_as_list(const int fd) override final {
osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size());
}
@@ -148,4 +149,4 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_INDEX_MULTIMAP_VECTOR_HPP
+#endif // OSMIUM_INDEX_DETAIL_VECTOR_MULTIMAP_HPP
diff --git a/third_party/osmium/index/index.hpp b/third_party/libosmium/include/osmium/index/index.hpp
similarity index 98%
rename from third_party/osmium/index/index.hpp
rename to third_party/libosmium/include/osmium/index/index.hpp
index ece8ec4..b73b319 100644
--- a/third_party/osmium/index/index.hpp
+++ b/third_party/libosmium/include/osmium/index/index.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/index/map.hpp b/third_party/libosmium/include/osmium/index/map.hpp
similarity index 61%
rename from third_party/osmium/index/map.hpp
rename to third_party/libosmium/include/osmium/index/map.hpp
index 92b880f..7b44b8e 100644
--- a/third_party/osmium/index/map.hpp
+++ b/third_party/libosmium/include/osmium/index/map.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,10 +33,18 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <algorithm>
#include <cstddef>
+#include <functional>
+#include <map>
+#include <memory>
+#include <stdexcept>
+#include <string>
#include <type_traits>
+#include <vector>
-#include <osmium/index/index.hpp> // IWYU pragma: export
+#include <osmium/util/compatibility.hpp>
+#include <osmium/util/string.hpp>
namespace osmium {
@@ -76,8 +84,7 @@ namespace osmium {
template <typename TId, typename TValue>
class Map {
- static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value,
- "TId template parameter for class Map must be unsigned integral type");
+ static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value, "TId template parameter for class Map must be unsigned integral type");
Map(const Map&) = delete;
Map& operator=(const Map&) = delete;
@@ -140,7 +147,7 @@ namespace osmium {
// default implementation is empty
}
- virtual void dump_as_list(int /*fd*/) const {
+ virtual void dump_as_list(const int /*fd*/) {
std::runtime_error("can't dump as list");
}
@@ -148,6 +155,98 @@ namespace osmium {
} // namespace map
+ template <typename TId, typename TValue>
+ class MapFactory {
+
+ public:
+
+ typedef TId id_type;
+ typedef TValue value_type;
+ typedef osmium::index::map::Map<id_type, value_type> map_type;
+ typedef std::function<map_type*(const std::vector<std::string>&)> create_map_func;
+
+ private:
+
+ std::map<const std::string, create_map_func> m_callbacks;
+
+ MapFactory() = default;
+
+ MapFactory(const MapFactory&) = delete;
+ MapFactory& operator=(const MapFactory&) = delete;
+
+ MapFactory(MapFactory&&) = delete;
+ MapFactory& operator=(MapFactory&&) = delete;
+
+ OSMIUM_NORETURN static void error(const std::string& map_type_name) {
+ std::string error_message {"Support for map type '"};
+ error_message += map_type_name;
+ error_message += "' not compiled into this binary.";
+ throw std::runtime_error(error_message);
+ }
+
+ public:
+
+ static MapFactory<id_type, value_type>& instance() {
+ static MapFactory<id_type, value_type> factory;
+ return factory;
+ }
+
+ bool register_map(const std::string& map_type_name, create_map_func func) {
+ return m_callbacks.emplace(map_type_name, func).second;
+ }
+
+ std::vector<std::string> map_types() const {
+ std::vector<std::string> result;
+
+ for (const auto& cb : m_callbacks) {
+ result.push_back(cb.first);
+ }
+
+ std::sort(result.begin(), result.end());
+
+ return result;
+ }
+
+ std::unique_ptr<map_type> create_map(const std::string& config_string) const {
+ std::vector<std::string> config = osmium::split_string(config_string, ',');
+
+ if (config.empty()) {
+ throw std::runtime_error("Need non-empty map type name.");
+ }
+
+ auto it = m_callbacks.find(config[0]);
+ if (it != m_callbacks.end()) {
+ return std::unique_ptr<map_type>((it->second)(config));
+ }
+
+ error(config[0]);
+ }
+
+ }; // class MapFactory
+
+ namespace map {
+
+ template <typename TId, typename TValue, template<typename, typename> class TMap>
+ struct create_map {
+ TMap<TId, TValue>* operator()(const std::vector<std::string>&) {
+ return new TMap<TId, TValue>();
+ }
+ };
+
+ } // namespace map
+
+ template <typename TId, typename TValue, template<typename, typename> class TMap>
+ inline bool register_map(const std::string& name) {
+ return osmium::index::MapFactory<TId, TValue>::instance().register_map(name, [](const std::vector<std::string>& config) {
+ return map::create_map<TId, TValue, TMap>()(config);
+ });
+ }
+
+#define REGISTER_MAP(id, value, klass, name) \
+namespace { \
+ const bool registered_index_map_##name = osmium::index::register_map<id, value, klass>(#name); \
+}
+
} // namespace index
} // namespace osmium
diff --git a/third_party/osmium/config/constexpr.hpp b/third_party/libosmium/include/osmium/index/map/all.hpp
similarity index 63%
copy from third_party/osmium/config/constexpr.hpp
copy to third_party/libosmium/include/osmium/index/map/all.hpp
index 3eddc84..9ffadc0 100644
--- a/third_party/osmium/config/constexpr.hpp
+++ b/third_party/libosmium/include/osmium/index/map/all.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_CONFIG_CONSTEXPR_HPP
-#define OSMIUM_CONFIG_CONSTEXPR_HPP
+#ifndef OSMIUM_INDEX_MAP_ALL_HPP
+#define OSMIUM_INDEX_MAP_ALL_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,11 +33,14 @@ DEALINGS IN THE SOFTWARE.
*/
-// Workaround for MSVC which doesn't support constexpr in all cases yet
-#ifdef _MSC_VER
-# define OSMIUM_CONSTEXPR
-#else
-# define OSMIUM_CONSTEXPR constexpr
-#endif
-
-#endif // OSMIUM_CONFIG_CONSTEXPR_HPP
+#include <osmium/index/map/dense_file_array.hpp> // IWYU pragma: keep
+#include <osmium/index/map/dense_mem_array.hpp> // IWYU pragma: keep
+#include <osmium/index/map/dense_mmap_array.hpp> // IWYU pragma: keep
+#include <osmium/index/map/dummy.hpp> // IWYU pragma: keep
+#include <osmium/index/map/sparse_file_array.hpp> // IWYU pragma: keep
+#include <osmium/index/map/sparse_mem_array.hpp> // IWYU pragma: keep
+#include <osmium/index/map/sparse_mem_map.hpp> // IWYU pragma: keep
+#include <osmium/index/map/sparse_mem_table.hpp> // IWYU pragma: keep
+#include <osmium/index/map/sparse_mmap_array.hpp> // IWYU pragma: keep
+
+#endif // OSMIUM_INDEX_MAP_ALL_HPP
diff --git a/third_party/osmium/index/map/mmap_vector_file.hpp b/third_party/libosmium/include/osmium/index/map/dense_file_array.hpp
similarity index 68%
copy from third_party/osmium/index/map/mmap_vector_file.hpp
copy to third_party/libosmium/include/osmium/index/map/dense_file_array.hpp
index 7ea76fa..d209a87 100644
--- a/third_party/osmium/index/map/mmap_vector_file.hpp
+++ b/third_party/libosmium/include/osmium/index/map/dense_file_array.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MAP_MMAP_VECTOR_FILE_HPP
-#define OSMIUM_INDEX_MAP_MMAP_VECTOR_FILE_HPP
+#ifndef OSMIUM_INDEX_MAP_DENSE_FILE_ARRAY_HPP
+#define OSMIUM_INDEX_MAP_DENSE_FILE_ARRAY_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,8 +33,14 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <osmium/index/map/vector.hpp>
+#include <string>
+#include <vector>
+
#include <osmium/index/detail/mmap_vector_file.hpp>
+#include <osmium/index/detail/vector_map.hpp>
+#include <osmium/index/detail/create_map_with_fd.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_DENSE_FILE_ARRAY
namespace osmium {
@@ -43,10 +49,14 @@ namespace osmium {
namespace map {
template <typename TId, typename TValue>
- using DenseMapFile = VectorBasedDenseMap<osmium::detail::mmap_vector_file<TValue>, TId, TValue>;
+ using DenseFileArray = VectorBasedDenseMap<osmium::detail::mmap_vector_file<TValue>, TId, TValue>;
template <typename TId, typename TValue>
- using SparseMapFile = VectorBasedSparseMap<TId, TValue, osmium::detail::mmap_vector_file>;
+ struct create_map<TId, TValue, DenseFileArray> {
+ DenseFileArray<TId, TValue>* operator()(const std::vector<std::string>& config) {
+ return osmium::index::detail::create_map_with_fd<DenseFileArray<TId, TValue>>(config);
+ }
+ };
} // namespace map
@@ -54,4 +64,4 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_INDEX_MAP_MMAP_VECTOR_FILE_HPP
+#endif // OSMIUM_INDEX_MAP_DENSE_FILE_ARRAY_HPP
diff --git a/third_party/osmium/index/multimap/stl_vector.hpp b/third_party/libosmium/include/osmium/index/map/dense_mem_array.hpp
similarity index 76%
copy from third_party/osmium/index/multimap/stl_vector.hpp
copy to third_party/libosmium/include/osmium/index/map/dense_mem_array.hpp
index 2102824..b45eec4 100644
--- a/third_party/osmium/index/multimap/stl_vector.hpp
+++ b/third_party/libosmium/include/osmium/index/map/dense_mem_array.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MULTIMAP_STL_VECTOR_HPP
-#define OSMIUM_INDEX_MULTIMAP_STL_VECTOR_HPP
+#ifndef OSMIUM_INDEX_MAP_DENSE_MEM_ARRAY_HPP
+#define OSMIUM_INDEX_MAP_DENSE_MEM_ARRAY_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -35,24 +35,23 @@ DEALINGS IN THE SOFTWARE.
#include <vector>
-#include <osmium/index/multimap/vector.hpp>
+#include <osmium/index/detail/vector_map.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_DENSE_MEM_ARRAY
namespace osmium {
namespace index {
- namespace multimap {
-
- template <typename T>
- using StdVectorWrap = std::vector<T>;
+ namespace map {
template <typename TId, typename TValue>
- using SparseMultimapMem = VectorBasedSparseMultimap<TId, TValue, StdVectorWrap>;
+ using DenseMemArray = VectorBasedDenseMap<std::vector<TValue>, TId, TValue>;
- } // namespace multimap
+ } // namespace map
} // namespace index
} // namespace osmium
-#endif // OSMIUM_INDEX_MULTIMAP_STL_VECTOR_HPP
+#endif // OSMIUM_INDEX_MAP_DENSE_MEM_ARRAY_HPP
diff --git a/third_party/osmium/index/map/mmap_vector_anon.hpp b/third_party/libosmium/include/osmium/index/map/dense_mmap_array.hpp
similarity index 77%
rename from third_party/osmium/index/map/mmap_vector_anon.hpp
rename to third_party/libosmium/include/osmium/index/map/dense_mmap_array.hpp
index a62e99a..fc60a1e 100644
--- a/third_party/osmium/index/map/mmap_vector_anon.hpp
+++ b/third_party/libosmium/include/osmium/index/map/dense_mmap_array.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MAP_MMAP_VECTOR_ANON_HPP
-#define OSMIUM_INDEX_MAP_MMAP_VECTOR_ANON_HPP
+#ifndef OSMIUM_INDEX_MAP_DENSE_MMAP_ARRAY_HPP
+#define OSMIUM_INDEX_MAP_DENSE_MMAP_ARRAY_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -35,8 +35,10 @@ DEALINGS IN THE SOFTWARE.
#ifdef __linux__
-#include <osmium/index/map/vector.hpp>
#include <osmium/index/detail/mmap_vector_anon.hpp>
+#include <osmium/index/detail/vector_map.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_DENSE_MMAP_ARRAY
namespace osmium {
@@ -45,10 +47,7 @@ namespace osmium {
namespace map {
template <typename TId, typename TValue>
- using DenseMapMmap = VectorBasedDenseMap<osmium::detail::mmap_vector_anon<TValue>, TId, TValue>;
-
- template <typename TId, typename TValue>
- using SparseMapMmap = VectorBasedSparseMap<TId, TValue, osmium::detail::mmap_vector_anon>;
+ using DenseMmapArray = VectorBasedDenseMap<osmium::detail::mmap_vector_anon<TValue>, TId, TValue>;
} // namespace map
@@ -58,4 +57,4 @@ namespace osmium {
#endif // __linux__
-#endif // OSMIUM_INDEX_MAP_MMAP_VECTOR_ANON_HPP
+#endif // OSMIUM_INDEX_MAP_DENSE_MMAP_ARRAY_HPP
diff --git a/third_party/osmium/index/map/dummy.hpp b/third_party/libosmium/include/osmium/index/map/dummy.hpp
similarity index 96%
rename from third_party/osmium/index/map/dummy.hpp
rename to third_party/libosmium/include/osmium/index/map/dummy.hpp
index bafb810..de05d1d 100644
--- a/third_party/osmium/index/map/dummy.hpp
+++ b/third_party/libosmium/include/osmium/index/map/dummy.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -35,6 +35,7 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
+#include <osmium/index/index.hpp>
#include <osmium/index/map.hpp>
namespace osmium {
diff --git a/third_party/osmium/index/map/mmap_vector_file.hpp b/third_party/libosmium/include/osmium/index/map/sparse_file_array.hpp
similarity index 68%
copy from third_party/osmium/index/map/mmap_vector_file.hpp
copy to third_party/libosmium/include/osmium/index/map/sparse_file_array.hpp
index 7ea76fa..2ba9315 100644
--- a/third_party/osmium/index/map/mmap_vector_file.hpp
+++ b/third_party/libosmium/include/osmium/index/map/sparse_file_array.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MAP_MMAP_VECTOR_FILE_HPP
-#define OSMIUM_INDEX_MAP_MMAP_VECTOR_FILE_HPP
+#ifndef OSMIUM_INDEX_MAP_SPARSE_FILE_ARRAY_HPP
+#define OSMIUM_INDEX_MAP_SPARSE_FILE_ARRAY_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,8 +33,14 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <osmium/index/map/vector.hpp>
+#include <string>
+#include <vector>
+
#include <osmium/index/detail/mmap_vector_file.hpp>
+#include <osmium/index/detail/vector_map.hpp>
+#include <osmium/index/detail/create_map_with_fd.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_SPARSE_FILE_ARRAY
namespace osmium {
@@ -43,10 +49,14 @@ namespace osmium {
namespace map {
template <typename TId, typename TValue>
- using DenseMapFile = VectorBasedDenseMap<osmium::detail::mmap_vector_file<TValue>, TId, TValue>;
+ using SparseFileArray = VectorBasedSparseMap<TId, TValue, osmium::detail::mmap_vector_file>;
template <typename TId, typename TValue>
- using SparseMapFile = VectorBasedSparseMap<TId, TValue, osmium::detail::mmap_vector_file>;
+ struct create_map<TId, TValue, SparseFileArray> {
+ SparseFileArray<TId, TValue>* operator()(const std::vector<std::string>& config) {
+ return osmium::index::detail::create_map_with_fd<SparseFileArray<TId, TValue>>(config);
+ }
+ };
} // namespace map
@@ -54,4 +64,4 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_INDEX_MAP_MMAP_VECTOR_FILE_HPP
+#endif // OSMIUM_INDEX_MAP_SPARSE_FILE_ARRAY_HPP
diff --git a/third_party/osmium/index/map/stl_vector.hpp b/third_party/libosmium/include/osmium/index/map/sparse_mem_array.hpp
similarity index 79%
rename from third_party/osmium/index/map/stl_vector.hpp
rename to third_party/libosmium/include/osmium/index/map/sparse_mem_array.hpp
index 238e9af..9adf41f 100644
--- a/third_party/osmium/index/map/stl_vector.hpp
+++ b/third_party/libosmium/include/osmium/index/map/sparse_mem_array.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MAP_STL_VECTOR_HPP
-#define OSMIUM_INDEX_MAP_STL_VECTOR_HPP
+#ifndef OSMIUM_INDEX_MAP_SPARSE_MEM_ARRAY_HPP
+#define OSMIUM_INDEX_MAP_SPARSE_MEM_ARRAY_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -35,7 +35,9 @@ DEALINGS IN THE SOFTWARE.
#include <vector>
-#include <osmium/index/map/vector.hpp>
+#include <osmium/index/detail/vector_map.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_SPARSE_MEM_ARRAY
namespace osmium {
@@ -43,14 +45,11 @@ namespace osmium {
namespace map {
- template <typename TId, typename TValue>
- using DenseMapMem = VectorBasedDenseMap<std::vector<TValue>, TId, TValue>;
-
template <typename T>
using StdVectorWrap = std::vector<T>;
template <typename TId, typename TValue>
- using SparseMapMem = VectorBasedSparseMap<TId, TValue, StdVectorWrap>;
+ using SparseMemArray = VectorBasedSparseMap<TId, TValue, StdVectorWrap>;
} // namespace map
@@ -58,4 +57,4 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_INDEX_MAP_STL_VECTOR_HPP
+#endif // OSMIUM_INDEX_MAP_SPARSE_MEM_ARRAY_HPP
diff --git a/third_party/osmium/index/map/stl_map.hpp b/third_party/libosmium/include/osmium/index/map/sparse_mem_map.hpp
similarity index 86%
rename from third_party/osmium/index/map/stl_map.hpp
rename to third_party/libosmium/include/osmium/index/map/sparse_mem_map.hpp
index d2781a7..d053155 100644
--- a/third_party/osmium/index/map/stl_map.hpp
+++ b/third_party/libosmium/include/osmium/index/map/sparse_mem_map.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MAP_STL_MAP_HPP
-#define OSMIUM_INDEX_MAP_STL_MAP_HPP
+#ifndef OSMIUM_INDEX_MAP_SPARSE_MEM_MAP_HPP
+#define OSMIUM_INDEX_MAP_SPARSE_MEM_MAP_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -41,8 +41,11 @@ DEALINGS IN THE SOFTWARE.
#include <vector>
#include <osmium/index/map.hpp>
+#include <osmium/index/index.hpp>
#include <osmium/io/detail/read_write.hpp>
+#define OSMIUM_HAS_INDEX_MAP_SPARSE_MEM_MAP
+
namespace osmium {
namespace index {
@@ -54,7 +57,7 @@ namespace osmium {
* lot of memory, but might make sense for small maps.
*/
template <typename TId, typename TValue>
- class StlMap : public osmium::index::map::Map<TId, TValue> {
+ class SparseMemMap : public osmium::index::map::Map<TId, TValue> {
// This is a rough estimate for the memory needed for each
// element in the map (id + value + pointers to left, right,
@@ -66,9 +69,9 @@ namespace osmium {
public:
- StlMap() = default;
+ SparseMemMap() = default;
- ~StlMap() override final = default;
+ ~SparseMemMap() override final = default;
void set(const TId id, const TValue value) override final {
m_elements[id] = value;
@@ -94,14 +97,14 @@ namespace osmium {
m_elements.clear();
}
- void dump_as_list(const int fd) const override final {
+ void dump_as_list(const int fd) override final {
typedef typename std::map<TId, TValue>::value_type t;
std::vector<t> v;
std::copy(m_elements.begin(), m_elements.end(), std::back_inserter(v));
osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(t) * v.size());
}
- }; // class StlMap
+ }; // class SparseMemMap
} // namespace map
@@ -109,4 +112,4 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_INDEX_MAP_STL_MAP_HPP
+#endif // OSMIUM_INDEX_MAP_SPARSE_MEM_MAP_HPP
diff --git a/third_party/osmium/index/map/sparse_table.hpp b/third_party/libosmium/include/osmium/index/map/sparse_mem_table.hpp
similarity index 84%
rename from third_party/osmium/index/map/sparse_table.hpp
rename to third_party/libosmium/include/osmium/index/map/sparse_mem_table.hpp
index 704e33e..09ee81b 100644
--- a/third_party/osmium/index/map/sparse_table.hpp
+++ b/third_party/libosmium/include/osmium/index/map/sparse_mem_table.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MAP_SPARSE_TABLE_HPP
-#define OSMIUM_INDEX_MAP_SPARSE_TABLE_HPP
+#ifndef OSMIUM_INDEX_MAP_SPARSE_MEM_TABLE_HPP
+#define OSMIUM_INDEX_MAP_SPARSE_MEM_TABLE_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,16 +33,20 @@ DEALINGS IN THE SOFTWARE.
*/
+#ifdef OSMIUM_WITH_SPARSEHASH
+
#include <cstddef>
-#include <stdexcept>
#include <utility>
#include <vector>
#include <google/sparsetable>
+#include <osmium/index/index.hpp>
#include <osmium/index/map.hpp>
#include <osmium/io/detail/read_write.hpp>
+#define OSMIUM_HAS_INDEX_MAP_SPARSE_MEM_TABLE
+
namespace osmium {
namespace index {
@@ -50,9 +54,9 @@ namespace osmium {
namespace map {
/**
- * The SparseTable index stores elements in a Google sparsetable,
+ * The SparseMemTable index stores elements in a Google sparsetable,
* a data structure that can hold sparsly filled tables in a
- * very space efficient way. It will resize automatically.
+ * space efficient way. It will resize automatically.
*
* Use this index if the ID space is only sparsly
* populated, such as when working with smaller OSM files (like
@@ -61,7 +65,7 @@ namespace osmium {
* This will only work on 64 bit machines.
*/
template <typename TId, typename TValue>
- class SparseTable : public osmium::index::map::Map<TId, TValue> {
+ class SparseMemTable : public osmium::index::map::Map<TId, TValue> {
TId m_grow_size;
@@ -79,12 +83,12 @@ namespace osmium {
* The storage will grow by at least this size
* every time it runs out of space.
*/
- explicit SparseTable(const TId grow_size=10000) :
+ explicit SparseMemTable(const TId grow_size = 10000) :
m_grow_size(grow_size),
m_elements(grow_size) {
}
- ~SparseTable() override final = default;
+ ~SparseMemTable() override final = default;
void set(const TId id, const TValue value) override final {
if (id >= m_elements.size()) {
@@ -117,9 +121,9 @@ namespace osmium {
m_elements.clear();
}
- void dump_as_list(const int fd) const override final {
+ void dump_as_list(const int fd) override final {
std::vector<std::pair<TId, TValue>> v;
- int n=0;
+ int n = 0;
for (const TValue value : m_elements) {
if (value != osmium::index::empty_value<TValue>()) {
v.emplace_back(n, value);
@@ -129,7 +133,7 @@ namespace osmium {
osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(std::pair<TId, TValue>) * v.size());
}
- }; // class SparseTable
+ }; // class SparseMemTable
} // namespace map
@@ -137,4 +141,6 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_INDEX_BYID_SPARSE_TABLE_HPP
+#endif // OSMIUM_WITH_SPARSEHASH
+
+#endif // OSMIUM_INDEX_BYID_SPARSE_MEM_TABLE_HPP
diff --git a/third_party/osmium/index/map/mmap_vector_file.hpp b/third_party/libosmium/include/osmium/index/map/sparse_mmap_array.hpp
similarity index 74%
rename from third_party/osmium/index/map/mmap_vector_file.hpp
rename to third_party/libosmium/include/osmium/index/map/sparse_mmap_array.hpp
index 7ea76fa..c85e2c9 100644
--- a/third_party/osmium/index/map/mmap_vector_file.hpp
+++ b/third_party/libosmium/include/osmium/index/map/sparse_mmap_array.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MAP_MMAP_VECTOR_FILE_HPP
-#define OSMIUM_INDEX_MAP_MMAP_VECTOR_FILE_HPP
+#ifndef OSMIUM_INDEX_MAP_SPARSE_MMAP_ARRAY_HPP
+#define OSMIUM_INDEX_MAP_SPARSE_MMAP_ARRAY_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,8 +33,12 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <osmium/index/map/vector.hpp>
-#include <osmium/index/detail/mmap_vector_file.hpp>
+#ifdef __linux__
+
+#include <osmium/index/detail/mmap_vector_anon.hpp>
+#include <osmium/index/detail/vector_map.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_SPARSE_MMAP_ARRAY
namespace osmium {
@@ -43,10 +47,7 @@ namespace osmium {
namespace map {
template <typename TId, typename TValue>
- using DenseMapFile = VectorBasedDenseMap<osmium::detail::mmap_vector_file<TValue>, TId, TValue>;
-
- template <typename TId, typename TValue>
- using SparseMapFile = VectorBasedSparseMap<TId, TValue, osmium::detail::mmap_vector_file>;
+ using SparseMmapArray = VectorBasedSparseMap<TId, TValue, osmium::detail::mmap_vector_anon>;
} // namespace map
@@ -54,4 +55,6 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_INDEX_MAP_MMAP_VECTOR_FILE_HPP
+#endif // __linux__
+
+#endif // OSMIUM_INDEX_MAP_SPARSE_MMAP_ARRAY_HPP
diff --git a/third_party/osmium/index/multimap.hpp b/third_party/libosmium/include/osmium/index/multimap.hpp
similarity index 93%
rename from third_party/osmium/index/multimap.hpp
rename to third_party/libosmium/include/osmium/index/multimap.hpp
index f76c65d..c817b6f 100644
--- a/third_party/osmium/index/multimap.hpp
+++ b/third_party/libosmium/include/osmium/index/multimap.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -34,11 +34,10 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstddef>
+#include <stdexcept>
#include <type_traits>
#include <utility>
-#include <osmium/index/index.hpp> // IWYU pragma: export
-
namespace osmium {
namespace index {
@@ -51,8 +50,7 @@ namespace osmium {
template <typename TId, typename TValue>
class Multimap {
- static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value,
- "TId template parameter for class Multimap must be unsigned integral type");
+ static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value, "TId template parameter for class Multimap must be unsigned integral type");
typedef typename std::pair<TId, TValue> element_type;
@@ -114,7 +112,7 @@ namespace osmium {
// default implementation is empty
}
- virtual void dump_as_list(int /*fd*/) const {
+ virtual void dump_as_list(const int /*fd*/) {
std::runtime_error("can't dump as list");
}
diff --git a/third_party/osmium/config/constexpr.hpp b/third_party/libosmium/include/osmium/index/multimap/all.hpp
similarity index 74%
rename from third_party/osmium/config/constexpr.hpp
rename to third_party/libosmium/include/osmium/index/multimap/all.hpp
index 3eddc84..8b0ae99 100644
--- a/third_party/osmium/config/constexpr.hpp
+++ b/third_party/libosmium/include/osmium/index/multimap/all.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_CONFIG_CONSTEXPR_HPP
-#define OSMIUM_CONFIG_CONSTEXPR_HPP
+#ifndef OSMIUM_INDEX_MULTIMAP_ALL_HPP
+#define OSMIUM_INDEX_MULTIMAP_ALL_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,11 +33,9 @@ DEALINGS IN THE SOFTWARE.
*/
-// Workaround for MSVC which doesn't support constexpr in all cases yet
-#ifdef _MSC_VER
-# define OSMIUM_CONSTEXPR
-#else
-# define OSMIUM_CONSTEXPR constexpr
-#endif
+#include <osmium/index/multimap/sparse_file_array.hpp> // IWYU pragma: keep
+#include <osmium/index/multimap/sparse_mem_array.hpp> // IWYU pragma: keep
+#include <osmium/index/multimap/sparse_mem_multimap.hpp> // IWYU pragma: keep
+#include <osmium/index/multimap/sparse_mmap_array.hpp> // IWYU pragma: keep
-#endif // OSMIUM_CONFIG_CONSTEXPR_HPP
+#endif // OSMIUM_INDEX_MULTIMAP_ALL_HPP
diff --git a/third_party/osmium/index/multimap/hybrid.hpp b/third_party/libosmium/include/osmium/index/multimap/hybrid.hpp
similarity index 92%
rename from third_party/osmium/index/multimap/hybrid.hpp
rename to third_party/libosmium/include/osmium/index/multimap/hybrid.hpp
index abaf31e..ac2d964 100644
--- a/third_party/osmium/index/multimap/hybrid.hpp
+++ b/third_party/libosmium/include/osmium/index/multimap/hybrid.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -36,9 +36,10 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <utility>
+#include <osmium/index/index.hpp>
#include <osmium/index/multimap.hpp>
-#include <osmium/index/multimap/stl_vector.hpp>
-#include <osmium/index/multimap/stl_multimap.hpp>
+#include <osmium/index/multimap/sparse_mem_array.hpp>
+#include <osmium/index/multimap/sparse_mem_multimap.hpp>
namespace osmium {
@@ -49,8 +50,8 @@ namespace osmium {
template <typename TId, typename TValue>
class HybridIterator {
- typedef SparseMultimapMem<TId, TValue> main_map_type;
- typedef StlMultimap<TId, TValue> extra_map_type;
+ typedef SparseMemArray<TId, TValue> main_map_type;
+ typedef SparseMemMultimap<TId, TValue> extra_map_type;
typedef typename std::pair<TId, TValue> element_type;
@@ -117,8 +118,8 @@ namespace osmium {
template <typename TId, typename TValue>
class Hybrid : public Multimap<TId, TValue> {
- typedef SparseMultimapMem<TId, TValue> main_map_type;
- typedef StlMultimap<TId, TValue> extra_map_type;
+ typedef SparseMemArray<TId, TValue> main_map_type;
+ typedef SparseMemMultimap<TId, TValue> extra_map_type;
main_map_type m_main;
extra_map_type m_extra;
@@ -174,7 +175,7 @@ namespace osmium {
m_main.sort();
}
- void dump_as_list(int fd) override final {
+ void dump_as_list(const int fd) override final {
consolidate();
m_main.dump_as_list(fd);
}
diff --git a/third_party/osmium/index/multimap/mmap_vector_file.hpp b/third_party/libosmium/include/osmium/index/multimap/sparse_file_array.hpp
similarity index 81%
rename from third_party/osmium/index/multimap/mmap_vector_file.hpp
rename to third_party/libosmium/include/osmium/index/multimap/sparse_file_array.hpp
index 0a925b4..0b9ae92 100644
--- a/third_party/osmium/index/multimap/mmap_vector_file.hpp
+++ b/third_party/libosmium/include/osmium/index/multimap/sparse_file_array.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_FILE_HPP
-#define OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_FILE_HPP
+#ifndef OSMIUM_INDEX_MULTIMAP_SPARSE_FILE_ARRAY_HPP
+#define OSMIUM_INDEX_MULTIMAP_SPARSE_FILE_ARRAY_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,8 +33,8 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <osmium/index/multimap/vector.hpp>
#include <osmium/index/detail/mmap_vector_file.hpp>
+#include <osmium/index/detail/vector_multimap.hpp>
namespace osmium {
@@ -43,7 +43,7 @@ namespace osmium {
namespace multimap {
template <typename TId, typename TValue>
- using SparseMultimapFile = VectorBasedSparseMultimap<TId, TValue, osmium::detail::mmap_vector_file>;
+ using SparseFileArray = VectorBasedSparseMultimap<TId, TValue, osmium::detail::mmap_vector_file>;
} // namespace multimap
@@ -51,4 +51,4 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_FILE_HPP
+#endif // OSMIUM_INDEX_MULTIMAP_SPARSE_FILE_ARRAY_HPP
diff --git a/third_party/osmium/index/multimap/stl_vector.hpp b/third_party/libosmium/include/osmium/index/multimap/sparse_mem_array.hpp
similarity index 82%
rename from third_party/osmium/index/multimap/stl_vector.hpp
rename to third_party/libosmium/include/osmium/index/multimap/sparse_mem_array.hpp
index 2102824..c4140cb 100644
--- a/third_party/osmium/index/multimap/stl_vector.hpp
+++ b/third_party/libosmium/include/osmium/index/multimap/sparse_mem_array.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MULTIMAP_STL_VECTOR_HPP
-#define OSMIUM_INDEX_MULTIMAP_STL_VECTOR_HPP
+#ifndef OSMIUM_INDEX_MULTIMAP_SPARSE_MEM_ARRAY_HPP
+#define OSMIUM_INDEX_MULTIMAP_SPARSE_MEM_ARRAY_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -35,7 +35,7 @@ DEALINGS IN THE SOFTWARE.
#include <vector>
-#include <osmium/index/multimap/vector.hpp>
+#include <osmium/index/detail/vector_multimap.hpp>
namespace osmium {
@@ -47,7 +47,7 @@ namespace osmium {
using StdVectorWrap = std::vector<T>;
template <typename TId, typename TValue>
- using SparseMultimapMem = VectorBasedSparseMultimap<TId, TValue, StdVectorWrap>;
+ using SparseMemArray = VectorBasedSparseMultimap<TId, TValue, StdVectorWrap>;
} // namespace multimap
@@ -55,4 +55,4 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_INDEX_MULTIMAP_STL_VECTOR_HPP
+#endif // OSMIUM_INDEX_MULTIMAP_SPARSE_MEM_ARRAY_HPP
diff --git a/third_party/osmium/index/multimap/stl_multimap.hpp b/third_party/libosmium/include/osmium/index/multimap/sparse_mem_multimap.hpp
similarity index 90%
rename from third_party/osmium/index/multimap/stl_multimap.hpp
rename to third_party/libosmium/include/osmium/index/multimap/sparse_mem_multimap.hpp
index 3df07ab..5b47152 100644
--- a/third_party/osmium/index/multimap/stl_multimap.hpp
+++ b/third_party/libosmium/include/osmium/index/multimap/sparse_mem_multimap.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MULTIMAP_STL_MULTIMAP_HPP
-#define OSMIUM_INDEX_MULTIMAP_STL_MULTIMAP_HPP
+#ifndef OSMIUM_INDEX_MULTIMAP_SPARSE_MEM_MULTIMAP_HPP
+#define OSMIUM_INDEX_MULTIMAP_SPARSE_MEM_MULTIMAP_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -53,7 +53,7 @@ namespace osmium {
* lot of memory, but might make sense for small maps.
*/
template <typename TId, typename TValue>
- class StlMultimap : public osmium::index::multimap::Multimap<TId, TValue> {
+ class SparseMemMultimap : public osmium::index::multimap::Multimap<TId, TValue> {
// This is a rough estimate for the memory needed for each
// element in the map (id + value + pointers to left, right,
@@ -76,9 +76,9 @@ namespace osmium {
public:
- StlMultimap() = default;
+ SparseMemMultimap() = default;
- ~StlMultimap() noexcept override final = default;
+ ~SparseMemMultimap() noexcept override final = default;
void unsorted_set(const TId id, const TValue value) {
m_elements.emplace(id, value);
@@ -130,7 +130,7 @@ namespace osmium {
// intentionally left blank
}
- void dump_as_list(const int fd) const override final {
+ void dump_as_list(const int fd) override final {
std::vector<element_type> v;
for (const auto& element : m_elements) {
v.emplace_back(element.first, element.second);
@@ -140,7 +140,7 @@ namespace osmium {
osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(element_type) * v.size());
}
- }; // class StlMultimap
+ }; // class SparseMemMultimap
} // namespace multimap
@@ -148,4 +148,4 @@ namespace osmium {
} // namespace osmium
-#endif // OSMIUM_INDEX_MULTIMAP_STL_MULTIMAP_HPP
+#endif // OSMIUM_INDEX_MULTIMAP_SPARSE_MEM_MULTIMAP_HPP
diff --git a/third_party/osmium/index/multimap/mmap_vector_anon.hpp b/third_party/libosmium/include/osmium/index/multimap/sparse_mmap_array.hpp
similarity index 81%
rename from third_party/osmium/index/multimap/mmap_vector_anon.hpp
rename to third_party/libosmium/include/osmium/index/multimap/sparse_mmap_array.hpp
index b9de34a..9f92555 100644
--- a/third_party/osmium/index/multimap/mmap_vector_anon.hpp
+++ b/third_party/libosmium/include/osmium/index/multimap/sparse_mmap_array.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_ANON_HPP
-#define OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_ANON_HPP
+#ifndef OSMIUM_INDEX_MULTIMAP_SPARSE_MMAP_ARRAY_HPP
+#define OSMIUM_INDEX_MULTIMAP_SPARSE_MMAP_ARRAY_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -35,8 +35,8 @@ DEALINGS IN THE SOFTWARE.
#ifdef __linux__
-#include <osmium/index/multimap/vector.hpp>
#include <osmium/index/detail/mmap_vector_anon.hpp>
+#include <osmium/index/detail/vector_multimap.hpp>
namespace osmium {
@@ -45,7 +45,7 @@ namespace osmium {
namespace multimap {
template <typename TId, typename TValue>
- using SparseMultimapMmap = VectorBasedSparseMultimap<TId, TValue, osmium::detail::mmap_vector_anon>;
+ using SparseMmapArray = VectorBasedSparseMultimap<TId, TValue, osmium::detail::mmap_vector_anon>;
} // namespace multimap
@@ -55,4 +55,4 @@ namespace osmium {
#endif // __linux__
-#endif // OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_ANON_HPP
+#endif // OSMIUM_INDEX_MULTIMAP_SPARSE_MMAP_ARRAY_HPP
diff --git a/third_party/libosmium/include/osmium/index/node_locations_map.hpp b/third_party/libosmium/include/osmium/index/node_locations_map.hpp
new file mode 100644
index 0000000..ca4b136
--- /dev/null
+++ b/third_party/libosmium/include/osmium/index/node_locations_map.hpp
@@ -0,0 +1,70 @@
+#ifndef OSMIUM_INDEX_NODE_LOCATIONS_MAP_HPP
+#define OSMIUM_INDEX_NODE_LOCATIONS_MAP_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+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.
+
+*/
+
+#include <osmium/index/map.hpp> // IWYU pragma: keep
+
+#ifdef OSMIUM_HAS_INDEX_MAP_DENSE_FILE_ARRAY
+ REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::DenseFileArray, dense_file_array)
+#endif
+
+#ifdef OSMIUM_HAS_INDEX_MAP_DENSE_MEM_ARRAY
+ REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::DenseMemArray, dense_mem_array)
+#endif
+
+#ifdef OSMIUM_HAS_INDEX_MAP_DENSE_MMAP_ARRAY
+ REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::DenseMmapArray, dense_mmap_array)
+#endif
+
+#ifdef OSMIUM_HAS_INDEX_MAP_SPARSE_FILE_ARRAY
+ REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseFileArray, sparse_file_array)
+#endif
+
+#ifdef OSMIUM_HAS_INDEX_MAP_SPARSE_MEM_ARRAY
+ REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMemArray, sparse_mem_array)
+#endif
+
+#ifdef OSMIUM_HAS_INDEX_MAP_SPARSE_MEM_MAP
+ REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMemMap, sparse_mem_map)
+#endif
+
+#ifdef OSMIUM_HAS_INDEX_MAP_SPARSE_MEM_TABLE
+ REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMemTable, sparse_mem_table)
+#endif
+
+#ifdef OSMIUM_HAS_INDEX_MAP_SPARSE_MMAP_ARRAY
+ REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMmapArray, sparse_mmap_array)
+#endif
+
+#endif // OSMIUM_INDEX_NODE_LOCATIONS_MAP_HPP
diff --git a/third_party/osmium/io/any_compression.hpp b/third_party/libosmium/include/osmium/io/any_compression.hpp
similarity index 86%
rename from third_party/osmium/io/any_compression.hpp
rename to third_party/libosmium/include/osmium/io/any_compression.hpp
index 03ad5ce..00e8ee2 100644
--- a/third_party/osmium/io/any_compression.hpp
+++ b/third_party/libosmium/include/osmium/io/any_compression.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,6 +33,15 @@ DEALINGS IN THE SOFTWARE.
*/
+/**
+ * @file
+ *
+ * Include this file if you want to read or write compressed OSM XML files.
+ *
+ * @attention If you include this file, you'll need to link with `libz`
+ * and `libbz2`.
+ */
+
#include <osmium/io/bzip2_compression.hpp> // IWYU pragma: export
#include <osmium/io/gzip_compression.hpp> // IWYU pragma: export
diff --git a/third_party/osmium/io/any_input.hpp b/third_party/libosmium/include/osmium/io/any_input.hpp
similarity index 82%
rename from third_party/osmium/io/any_input.hpp
rename to third_party/libosmium/include/osmium/io/any_input.hpp
index f60ff14..633fab3 100644
--- a/third_party/osmium/io/any_input.hpp
+++ b/third_party/libosmium/include/osmium/io/any_input.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,6 +33,16 @@ DEALINGS IN THE SOFTWARE.
*/
+/**
+ * @file
+ *
+ * Include this file if you want to read all kinds of OSM files.
+ *
+ * @attention If you include this file, you'll need to link with
+ * `libprotobuf-lite`, `libosmpbf`, `ws2_32` (Windows only),
+ * `libexpat`, `libz`, `libbz2`, and enable multithreading.
+ */
+
#include <osmium/io/any_compression.hpp> // IWYU pragma: export
#include <osmium/io/pbf_input.hpp> // IWYU pragma: export
diff --git a/third_party/osmium/io/any_output.hpp b/third_party/libosmium/include/osmium/io/any_output.hpp
similarity index 83%
rename from third_party/osmium/io/any_output.hpp
rename to third_party/libosmium/include/osmium/io/any_output.hpp
index 9d97d7d..63de3ff 100644
--- a/third_party/osmium/io/any_output.hpp
+++ b/third_party/libosmium/include/osmium/io/any_output.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,6 +33,16 @@ DEALINGS IN THE SOFTWARE.
*/
+/**
+ * @file
+ *
+ * Include this file if you want to write all kinds of OSM files.
+ *
+ * @attention If you include this file, you'll need to link with
+ * `libprotobuf-lite`, `libosmpbf`, `ws2_32` (Windows only),
+ * `libz`, `libbz2`, and enable multithreading.
+ */
+
#include <osmium/io/any_compression.hpp> // IWYU pragma: export
#include <osmium/io/opl_output.hpp> // IWYU pragma: export
diff --git a/third_party/osmium/io/bzip2_compression.hpp b/third_party/libosmium/include/osmium/io/bzip2_compression.hpp
similarity index 71%
rename from third_party/osmium/io/bzip2_compression.hpp
rename to third_party/libosmium/include/osmium/io/bzip2_compression.hpp
index cbfaf9a..7e86c15 100644
--- a/third_party/osmium/io/bzip2_compression.hpp
+++ b/third_party/libosmium/include/osmium/io/bzip2_compression.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,8 +33,17 @@ DEALINGS IN THE SOFTWARE.
*/
-#define OSMIUM_LINK_WITH_LIBS_BZ2LIB -lbz2
-
+/**
+ * @file
+ *
+ * Include this file if you want to read or write bzip2-compressed OSM XML
+ * files.
+ *
+ * @attention If you include this file, you'll need to link with `libbz2`.
+ */
+
+#include <cerrno>
+#include <cstddef>
#include <cstdio>
#include <stdexcept>
#include <string>
@@ -73,7 +82,7 @@ namespace osmium {
namespace detail {
- OSMIUM_NORETURN inline void throw_bzip2_error(BZFILE* bzfile, const char* msg, int bzlib_error=0) {
+ OSMIUM_NORETURN inline void throw_bzip2_error(BZFILE* bzfile, const char* msg, int bzlib_error = 0) {
std::string error("bzip2 error: ");
error += msg;
error += ": ";
@@ -158,37 +167,39 @@ namespace osmium {
}
std::string read() override final {
- if (m_stream_end) {
- return std::string();
- }
- std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
- int error;
- int nread = ::BZ2_bzRead(&error, m_bzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<int>(buffer.size()));
- if (error != BZ_OK && error != BZ_STREAM_END) {
- detail::throw_bzip2_error(m_bzfile, "read failed", error);
- }
- if (error == BZ_STREAM_END) {
- void* unused;
- int nunused;
- if (! feof(m_file)) {
- ::BZ2_bzReadGetUnused(&error, m_bzfile, &unused, &nunused);
- if (error != BZ_OK) {
- detail::throw_bzip2_error(m_bzfile, "get unused failed", error);
- }
- std::string unused_data(static_cast<const char*>(unused), static_cast<std::string::size_type>(nunused));
- ::BZ2_bzReadClose(&error, m_bzfile);
- if (error != BZ_OK) {
- detail::throw_bzip2_error(m_bzfile, "read close failed", error);
- }
- m_bzfile = ::BZ2_bzReadOpen(&error, m_file, 0, 0, const_cast<void*>(static_cast<const void*>(unused_data.data())), static_cast_with_assert<int>(unused_data.size()));
- if (error != BZ_OK) {
- detail::throw_bzip2_error(m_bzfile, "read open failed", error);
+ std::string buffer;
+
+ if (!m_stream_end) {
+ buffer.resize(osmium::io::Decompressor::input_buffer_size);
+ int error;
+ int nread = ::BZ2_bzRead(&error, m_bzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<int>(buffer.size()));
+ if (error != BZ_OK && error != BZ_STREAM_END) {
+ detail::throw_bzip2_error(m_bzfile, "read failed", error);
+ }
+ if (error == BZ_STREAM_END) {
+ void* unused;
+ int nunused;
+ if (! feof(m_file)) {
+ ::BZ2_bzReadGetUnused(&error, m_bzfile, &unused, &nunused);
+ if (error != BZ_OK) {
+ detail::throw_bzip2_error(m_bzfile, "get unused failed", error);
+ }
+ std::string unused_data(static_cast<const char*>(unused), static_cast<std::string::size_type>(nunused));
+ ::BZ2_bzReadClose(&error, m_bzfile);
+ if (error != BZ_OK) {
+ detail::throw_bzip2_error(m_bzfile, "read close failed", error);
+ }
+ m_bzfile = ::BZ2_bzReadOpen(&error, m_file, 0, 0, const_cast<void*>(static_cast<const void*>(unused_data.data())), static_cast_with_assert<int>(unused_data.size()));
+ if (error != BZ_OK) {
+ detail::throw_bzip2_error(m_bzfile, "read open failed", error);
+ }
+ } else {
+ m_stream_end = true;
}
- } else {
- m_stream_end = true;
}
+ buffer.resize(static_cast<std::string::size_type>(nread));
}
- buffer.resize(static_cast<std::string::size_type>(nread));
+
return buffer;
}
@@ -234,27 +245,28 @@ namespace osmium {
}
std::string read() override final {
- if (!m_buffer) {
- return std::string();
- }
-
- const size_t buffer_size = 10240;
- std::string output(buffer_size, '\0');
- m_bzstream.next_out = const_cast<char*>(output.data());
- m_bzstream.avail_out = buffer_size;
- int result = BZ2_bzDecompress(&m_bzstream);
+ std::string output;
+
+ if (m_buffer) {
+ const size_t buffer_size = 10240;
+ output.resize(buffer_size);
+ m_bzstream.next_out = const_cast<char*>(output.data());
+ m_bzstream.avail_out = buffer_size;
+ int result = BZ2_bzDecompress(&m_bzstream);
+
+ if (result != BZ_OK) {
+ m_buffer = nullptr;
+ m_buffer_size = 0;
+ }
- if (result != BZ_OK) {
- m_buffer = nullptr;
- m_buffer_size = 0;
- }
+ if (result != BZ_OK && result != BZ_STREAM_END) {
+ std::string message("bzip2 error: decompress failed: ");
+ throw bzip2_error(message, result);
+ }
- if (result != BZ_OK && result != BZ_STREAM_END) {
- std::string message("bzip2 error: decompress failed: ");
- throw bzip2_error(message, result);
+ output.resize(static_cast<unsigned long>(m_bzstream.next_out - output.data()));
}
- output.resize(static_cast<unsigned long>(m_bzstream.next_out - output.data()));
return output;
}
diff --git a/third_party/osmium/io/compression.hpp b/third_party/libosmium/include/osmium/io/compression.hpp
similarity index 92%
rename from third_party/osmium/io/compression.hpp
rename to third_party/libosmium/include/osmium/io/compression.hpp
index 5977640..c1f8de2 100644
--- a/third_party/osmium/io/compression.hpp
+++ b/third_party/libosmium/include/osmium/io/compression.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -75,7 +75,7 @@ namespace osmium {
public:
- static constexpr size_t input_buffer_size = 256 * 1024;
+ static constexpr unsigned int input_buffer_size = 1024 * 1024;
Decompressor() = default;
@@ -235,22 +235,24 @@ namespace osmium {
}
std::string read() override final {
+ std::string buffer;
+
if (m_buffer) {
- if (m_buffer_size == 0) {
- return std::string();
+ if (m_buffer_size != 0) {
+ size_t size = m_buffer_size;
+ m_buffer_size = 0;
+ buffer.append(m_buffer, size);
}
- size_t size = m_buffer_size;
- m_buffer_size = 0;
- return std::string(m_buffer, size);
} else {
- std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
- ssize_t nread = ::read(m_fd, const_cast<char*>(buffer.data()), buffer.size());
+ buffer.resize(osmium::io::Decompressor::input_buffer_size);
+ auto nread = ::read(m_fd, const_cast<char*>(buffer.data()), osmium::io::Decompressor::input_buffer_size);
if (nread < 0) {
throw std::system_error(errno, std::system_category(), "Read failed");
}
- buffer.resize(static_cast<size_t>(nread));
- return buffer;
+ buffer.resize(nread);
}
+
+ return buffer;
}
void close() override final {
diff --git a/third_party/osmium/io/detail/input_format.hpp b/third_party/libosmium/include/osmium/io/detail/input_format.hpp
similarity index 93%
rename from third_party/osmium/io/detail/input_format.hpp
rename to third_party/libosmium/include/osmium/io/detail/input_format.hpp
index f88561b..03e1190 100644
--- a/third_party/osmium/io/detail/input_format.hpp
+++ b/third_party/libosmium/include/osmium/io/detail/input_format.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -69,13 +69,11 @@ namespace osmium {
osmium::io::File m_file;
osmium::osm_entity_bits::type m_read_which_entities;
- osmium::thread::Queue<std::string>& m_input_queue;
osmium::io::Header m_header;
- explicit InputFormat(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) :
+ explicit InputFormat(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities) :
m_file(file),
- m_read_which_entities(read_which_entities),
- m_input_queue(input_queue) {
+ m_read_which_entities(read_which_entities) {
m_header.set_has_multiple_object_versions(m_file.has_multiple_object_versions());
}
diff --git a/third_party/osmium/io/detail/opl_output_format.hpp b/third_party/libosmium/include/osmium/io/detail/opl_output_format.hpp
similarity index 84%
rename from third_party/osmium/io/detail/opl_output_format.hpp
rename to third_party/libosmium/include/osmium/io/detail/opl_output_format.hpp
index b21d118..cf92e13 100644
--- a/third_party/osmium/io/detail/opl_output_format.hpp
+++ b/third_party/libosmium/include/osmium/io/detail/opl_output_format.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -97,9 +97,9 @@ namespace osmium {
static constexpr size_t tmp_buffer_size = 100;
- osmium::memory::Buffer m_input_buffer;
+ std::shared_ptr<osmium::memory::Buffer> m_input_buffer;
- std::string m_out;
+ std::shared_ptr<std::string> m_out;
char m_tmp_buffer[tmp_buffer_size+1];
@@ -114,13 +114,13 @@ namespace osmium {
_snprintf(m_tmp_buffer, tmp_buffer_size, format, std::forward<TArgs>(args)...);
#endif
assert(len > 0 && static_cast<size_t>(len) < tmp_buffer_size);
- m_out += m_tmp_buffer;
+ *m_out += m_tmp_buffer;
}
void append_encoded_string(const std::string& data) {
boost::u8_to_u32_iterator<std::string::const_iterator> it(data.cbegin(), data.cbegin(), data.cend());
boost::u8_to_u32_iterator<std::string::const_iterator> end(data.cend(), data.cend(), data.cend());
- boost::utf8_output_iterator<std::back_insert_iterator<std::string>> oit(std::back_inserter(m_out));
+ boost::utf8_output_iterator<std::back_insert_iterator<std::string>> oit(std::back_inserter(*m_out));
for (; it != end; ++it) {
uint32_t c = *it;
@@ -140,7 +140,7 @@ namespace osmium {
(0x00ae <= c && c <= 0x05ff)) {
*oit = c;
} else {
- m_out += '%';
+ *m_out += '%';
output_formatted("%04x", c);
}
}
@@ -148,21 +148,21 @@ namespace osmium {
void write_meta(const osmium::OSMObject& object) {
output_formatted("%" PRId64 " v%d d", object.id(), object.version());
- m_out += (object.visible() ? 'V' : 'D');
+ *m_out += (object.visible() ? 'V' : 'D');
output_formatted(" c%d t", object.changeset());
- m_out += object.timestamp().to_iso();
+ *m_out += object.timestamp().to_iso();
output_formatted(" i%d u", object.uid());
append_encoded_string(object.user());
- m_out += " T";
+ *m_out += " T";
bool first = true;
for (const auto& tag : object.tags()) {
if (first) {
first = false;
} else {
- m_out += ',';
+ *m_out += ',';
}
append_encoded_string(tag.key());
- m_out += '=';
+ *m_out += '=';
append_encoded_string(tag.value());
}
}
@@ -171,101 +171,103 @@ namespace osmium {
if (location) {
output_formatted(" %c%.7f %c%.7f", x, location.lon_without_check(), y, location.lat_without_check());
} else {
- m_out += ' ';
- m_out += x;
- m_out += ' ';
- m_out += y;
+ *m_out += ' ';
+ *m_out += x;
+ *m_out += ' ';
+ *m_out += y;
}
}
public:
explicit OPLOutputBlock(osmium::memory::Buffer&& buffer) :
- m_input_buffer(std::move(buffer)),
- m_out(),
+ m_input_buffer(std::make_shared<osmium::memory::Buffer>(std::move(buffer))),
+ m_out(std::make_shared<std::string>()),
m_tmp_buffer() {
}
- OPLOutputBlock(const OPLOutputBlock&) = delete;
- OPLOutputBlock& operator=(const OPLOutputBlock&) = delete;
+ OPLOutputBlock(const OPLOutputBlock&) = default;
+ OPLOutputBlock& operator=(const OPLOutputBlock&) = default;
OPLOutputBlock(OPLOutputBlock&&) = default;
OPLOutputBlock& operator=(OPLOutputBlock&&) = default;
+ ~OPLOutputBlock() = default;
+
std::string operator()() {
- osmium::apply(m_input_buffer.cbegin(), m_input_buffer.cend(), *this);
+ osmium::apply(m_input_buffer->cbegin(), m_input_buffer->cend(), *this);
std::string out;
- std::swap(out, m_out);
+ std::swap(out, *m_out);
return out;
}
void node(const osmium::Node& node) {
- m_out += 'n';
+ *m_out += 'n';
write_meta(node);
write_location(node.location(), 'x', 'y');
- m_out += '\n';
+ *m_out += '\n';
}
void way(const osmium::Way& way) {
- m_out += 'w';
+ *m_out += 'w';
write_meta(way);
- m_out += " N";
+ *m_out += " N";
bool first = true;
for (const auto& node_ref : way.nodes()) {
if (first) {
first = false;
} else {
- m_out += ',';
+ *m_out += ',';
}
output_formatted("n%" PRId64, node_ref.ref());
}
- m_out += '\n';
+ *m_out += '\n';
}
void relation(const osmium::Relation& relation) {
- m_out += 'r';
+ *m_out += 'r';
write_meta(relation);
- m_out += " M";
+ *m_out += " M";
bool first = true;
for (const auto& member : relation.members()) {
if (first) {
first = false;
} else {
- m_out += ',';
+ *m_out += ',';
}
- m_out += item_type_to_char(member.type());
+ *m_out += item_type_to_char(member.type());
output_formatted("%" PRId64 "@", member.ref());
- m_out += member.role();
+ *m_out += member.role();
}
- m_out += '\n';
+ *m_out += '\n';
}
void changeset(const osmium::Changeset& changeset) {
output_formatted("c%d k%d s", changeset.id(), changeset.num_changes());
- m_out += changeset.created_at().to_iso();
- m_out += " e";
- m_out += changeset.closed_at().to_iso();
+ *m_out += changeset.created_at().to_iso();
+ *m_out += " e";
+ *m_out += changeset.closed_at().to_iso();
output_formatted(" i%d u", changeset.uid());
append_encoded_string(changeset.user());
write_location(changeset.bounds().bottom_left(), 'x', 'y');
write_location(changeset.bounds().top_right(), 'X', 'Y');
- m_out += " T";
+ *m_out += " T";
bool first = true;
for (const auto& tag : changeset.tags()) {
if (first) {
first = false;
} else {
- m_out += ',';
+ *m_out += ',';
}
append_encoded_string(tag.key());
- m_out += '=';
+ *m_out += '=';
append_encoded_string(tag.value());
}
- m_out += '\n';
+ *m_out += '\n';
}
}; // OPLOutputBlock
diff --git a/third_party/osmium/io/detail/output_format.hpp b/third_party/libosmium/include/osmium/io/detail/output_format.hpp
similarity index 98%
rename from third_party/osmium/io/detail/output_format.hpp
rename to third_party/libosmium/include/osmium/io/detail/output_format.hpp
index ad9e702..529a189 100644
--- a/third_party/osmium/io/detail/output_format.hpp
+++ b/third_party/libosmium/include/osmium/io/detail/output_format.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/io/detail/pbf.hpp b/third_party/libosmium/include/osmium/io/detail/pbf.hpp
similarity index 95%
rename from third_party/osmium/io/detail/pbf.hpp
rename to third_party/libosmium/include/osmium/io/detail/pbf.hpp
index 9814bd4..e64e51a 100644
--- a/third_party/osmium/io/detail/pbf.hpp
+++ b/third_party/libosmium/include/osmium/io/detail/pbf.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,8 +33,6 @@ DEALINGS IN THE SOFTWARE.
*/
-#define OSMIUM_LINK_WITH_LIBS_PBF -pthread -lz -lprotobuf-lite -losmpbf
-
#include <stdexcept>
#include <osmpbf/osmpbf.h>
diff --git a/third_party/osmium/io/detail/pbf_input_format.hpp b/third_party/libosmium/include/osmium/io/detail/pbf_input_format.hpp
similarity index 85%
rename from third_party/osmium/io/detail/pbf_input_format.hpp
rename to third_party/libosmium/include/osmium/io/detail/pbf_input_format.hpp
index 3491bed..ba8fb42 100644
--- a/third_party/osmium/io/detail/pbf_input_format.hpp
+++ b/third_party/libosmium/include/osmium/io/detail/pbf_input_format.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -84,8 +84,9 @@ namespace osmium {
class PBFInputFormat : public osmium::io::detail::InputFormat {
bool m_use_thread_pool;
+ bool m_eof { false };
queue_type m_queue;
- std::atomic<bool> m_done;
+ std::atomic<bool> m_quit_input_thread;
std::thread m_reader;
osmium::thread::Queue<std::string>& m_input_queue;
std::string m_input_buffer;
@@ -151,7 +152,7 @@ namespace osmium {
void parse_osm_data(osmium::osm_entity_bits::type read_types) {
osmium::thread::set_thread_name("_osmium_pbf_in");
- int n=0;
+ int n = 0;
while (auto size = read_blob_header("OSMData")) {
if (m_use_thread_pool) {
@@ -164,11 +165,20 @@ namespace osmium {
}
++n;
- if (m_done) {
+ if (m_quit_input_thread) {
return;
}
}
- m_done = true;
+
+ // Send an empty buffer to signal the reader that we are
+ // done.
+ std::promise<osmium::memory::Buffer> promise;
+ m_queue.push(promise.get_future());
+ promise.set_value(osmium::memory::Buffer{});
+ }
+
+ void signal_input_thread_to_quit() {
+ m_quit_input_thread = true;
}
public:
@@ -181,10 +191,10 @@ namespace osmium {
* @param input_queue String queue where data is read from.
*/
PBFInputFormat(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) :
- osmium::io::detail::InputFormat(file, read_which_entities, input_queue),
+ osmium::io::detail::InputFormat(file, read_which_entities),
m_use_thread_pool(osmium::config::use_pool_threads_for_pbf_parsing()),
m_queue(20, "pbf_parser_results"), // XXX
- m_done(false),
+ m_quit_input_thread(false),
m_input_queue(input_queue),
m_input_buffer() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
@@ -199,25 +209,37 @@ namespace osmium {
}
~PBFInputFormat() {
- m_done = true;
+ signal_input_thread_to_quit();
if (m_reader.joinable()) {
m_reader.join();
}
}
/**
- * Returns the next buffer with OSM data read from the PBF file.
- * Blocks if data is not available yet.
+ * Returns the next buffer with OSM data read from the PBF
+ * file. Blocks if data is not available yet.
* Returns an empty buffer at end of input.
*/
osmium::memory::Buffer read() override {
- if (!m_done || !m_queue.empty()) {
- std::future<osmium::memory::Buffer> buffer_future;
- m_queue.wait_and_pop(buffer_future);
- return std::move(buffer_future.get());
+ osmium::memory::Buffer buffer;
+ if (m_eof) {
+ return buffer;
}
- return osmium::memory::Buffer();
+ std::future<osmium::memory::Buffer> buffer_future;
+ m_queue.wait_and_pop(buffer_future);
+
+ try {
+ buffer = std::move(buffer_future.get());
+ if (!buffer) {
+ m_eof = true;
+ }
+ return buffer;
+ } catch (...) {
+ m_eof = true;
+ signal_input_thread_to_quit();
+ throw;
+ }
}
}; // class PBFInputFormat
diff --git a/third_party/osmium/io/detail/pbf_output_format.hpp b/third_party/libosmium/include/osmium/io/detail/pbf_output_format.hpp
similarity index 95%
rename from third_party/osmium/io/detail/pbf_output_format.hpp
rename to third_party/libosmium/include/osmium/io/detail/pbf_output_format.hpp
index 44f8ffb..288008f 100644
--- a/third_party/osmium/io/detail/pbf_output_format.hpp
+++ b/third_party/libosmium/include/osmium/io/detail/pbf_output_format.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -295,6 +295,14 @@ namespace osmium {
bool m_use_compression {true};
/**
+ * Should the string tables in the data blocks be sorted?
+ *
+ * Not sorting the string tables makes writing PBF files
+ * slightly faster.
+ */
+ bool m_sort_stringtables { true };
+
+ /**
* While the .osm.pbf-format is able to carry all meta information, it is
* also able to omit this information to reduce size.
*/
@@ -340,6 +348,21 @@ namespace osmium {
///// Blob writing /////
+ void delta_encode_string_ids() {
+ if (pbf_nodes && pbf_nodes->has_dense()) {
+ OSMPBF::DenseNodes* dense = pbf_nodes->mutable_dense();
+
+ if (dense->has_denseinfo()) {
+ OSMPBF::DenseInfo* denseinfo = dense->mutable_denseinfo();
+
+ for (int i = 0, l=denseinfo->user_sid_size(); i<l; ++i) {
+ auto user_sid = denseinfo->user_sid(i);
+ denseinfo->set_user_sid(i, m_delta_user_sid.update(user_sid));
+ }
+ }
+ }
+ }
+
/**
* Before a PrimitiveBlock gets serialized, all interim StringTable-ids needs to be
* mapped to the associated real StringTable ids. This is done in this function.
@@ -351,7 +374,7 @@ namespace osmium {
// test, if the node-block has been allocated
if (pbf_nodes) {
// iterate over all nodes, passing them to the map_common_string_ids function
- for (int i=0, l=pbf_nodes->nodes_size(); i<l; ++i) {
+ for (int i = 0, l=pbf_nodes->nodes_size(); i<l; ++i) {
map_common_string_ids(pbf_nodes->mutable_nodes(i));
}
@@ -363,7 +386,7 @@ namespace osmium {
// in the densenodes structure keys and vals are encoded in an intermixed
// array, individual nodes are seperated by a value of 0 (0 in the StringTable
// is always unused). String-ids of 0 are thus kept alone.
- for (int i=0, l=dense->keys_vals_size(); i<l; ++i) {
+ for (int i = 0, l=dense->keys_vals_size(); i<l; ++i) {
// map interim string-ids > 0 to real string ids
auto sid = dense->keys_vals(i);
if (sid > 0) {
@@ -377,7 +400,7 @@ namespace osmium {
OSMPBF::DenseInfo* denseinfo = dense->mutable_denseinfo();
// iterate over all username string-ids
- for (int i=0, l=denseinfo->user_sid_size(); i<l; ++i) {
+ for (int i = 0, l=denseinfo->user_sid_size(); i<l; ++i) {
// map interim string-ids > 0 to real string ids
auto user_sid = string_table.map_string_id(denseinfo->user_sid(i));
@@ -391,7 +414,7 @@ namespace osmium {
// test, if the ways-block has been allocated
if (pbf_ways) {
// iterate over all ways, passing them to the map_common_string_ids function
- for (int i=0, l=pbf_ways->ways_size(); i<l; ++i) {
+ for (int i = 0, l=pbf_ways->ways_size(); i<l; ++i) {
map_common_string_ids(pbf_ways->mutable_ways(i));
}
}
@@ -399,7 +422,7 @@ namespace osmium {
// test, if the relations-block has been allocated
if (pbf_relations) {
// iterate over all relations
- for (int i=0, l=pbf_relations->relations_size(); i<l; ++i) {
+ for (int i = 0, l=pbf_relations->relations_size(); i<l; ++i) {
// get a pointer to the relation
OSMPBF::Relation* relation = pbf_relations->mutable_relations(i);
@@ -408,7 +431,7 @@ namespace osmium {
// iterate over all relation members, mapping the interim string-ids
// of the role to real string ids
- for (int mi=0; mi < relation->roles_sid_size(); ++mi) {
+ for (int mi = 0; mi < relation->roles_sid_size(); ++mi) {
relation->set_roles_sid(mi, string_table.map_string_id(relation->roles_sid(mi)));
}
}
@@ -431,7 +454,7 @@ namespace osmium {
}
// iterate over all tags and map the interim-ids of the key and the value to real ids
- for (int i=0, l=in->keys_size(); i<l; ++i) {
+ for (int i = 0, l=in->keys_size(); i<l; ++i) {
in->set_keys(i, string_table.map_string_id(in->keys(i)));
in->set_vals(i, string_table.map_string_id(in->vals(i)));
}
@@ -518,11 +541,13 @@ namespace osmium {
pbf_primitive_block.set_granularity(location_granularity());
pbf_primitive_block.set_date_granularity(date_granularity());
- // store the interim StringTable into the protobuf object
- string_table.store_stringtable(pbf_primitive_block.mutable_stringtable());
+ string_table.store_stringtable(pbf_primitive_block.mutable_stringtable(), m_sort_stringtables);
- // map all interim string ids to real ids
- map_string_ids();
+ if (m_sort_stringtables) {
+ map_string_ids();
+ } else {
+ delta_encode_string_ids();
+ }
std::promise<std::string> promise;
m_output_queue.push(promise.get_future());
@@ -743,6 +768,9 @@ namespace osmium {
if (file.get("pbf_compression") == "none" || file.get("pbf_compression") == "false") {
m_use_compression = false;
}
+ if (file.get("pbf_sort_stringtables") == "false") {
+ m_sort_stringtables = false;
+ }
if (file.get("pbf_add_metadata") == "false") {
m_should_add_metadata = false;
}
diff --git a/third_party/osmium/io/detail/pbf_parser.hpp b/third_party/libosmium/include/osmium/io/detail/pbf_parser.hpp
similarity index 92%
rename from third_party/osmium/io/detail/pbf_parser.hpp
rename to third_party/libosmium/include/osmium/io/detail/pbf_parser.hpp
index 201c57c..65a11e1 100644
--- a/third_party/osmium/io/detail/pbf_parser.hpp
+++ b/third_party/libosmium/include/osmium/io/detail/pbf_parser.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -106,7 +106,7 @@ namespace osmium {
m_date_factor = pbf_primitive_block.date_granularity() / 1000;
m_granularity = pbf_primitive_block.granularity();
- for (int i=0; i < pbf_primitive_block.primitivegroup_size(); ++i) {
+ for (int i = 0; i < pbf_primitive_block.primitivegroup_size(); ++i) {
const OSMPBF::PrimitiveGroup& group = pbf_primitive_block.primitivegroup(i);
if (group.has_dense()) {
@@ -148,7 +148,7 @@ namespace osmium {
}
void parse_node_group(const OSMPBF::PrimitiveGroup& group) {
- for (int i=0; i < group.nodes_size(); ++i) {
+ for (int i = 0; i < group.nodes_size(); ++i) {
osmium::builder::NodeBuilder builder(m_buffer);
const OSMPBF::Node& pbf_node = group.nodes(i);
parse_attributes(builder, pbf_node);
@@ -161,7 +161,7 @@ namespace osmium {
if (pbf_node.keys_size() > 0) {
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
- for (int tag=0; tag < pbf_node.keys_size(); ++tag) {
+ for (int tag = 0; tag < pbf_node.keys_size(); ++tag) {
tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_node.keys(tag))),
m_stringtable->s(static_cast<int>(pbf_node.vals(tag))));
}
@@ -172,7 +172,7 @@ namespace osmium {
}
void parse_way_group(const OSMPBF::PrimitiveGroup& group) {
- for (int i=0; i < group.ways_size(); ++i) {
+ for (int i = 0; i < group.ways_size(); ++i) {
osmium::builder::WayBuilder builder(m_buffer);
const OSMPBF::Way& pbf_way = group.ways(i);
parse_attributes(builder, pbf_way);
@@ -180,7 +180,7 @@ namespace osmium {
if (pbf_way.refs_size() > 0) {
osmium::builder::WayNodeListBuilder wnl_builder(m_buffer, &builder);
int64_t ref = 0;
- for (int n=0; n < pbf_way.refs_size(); ++n) {
+ for (int n = 0; n < pbf_way.refs_size(); ++n) {
ref += pbf_way.refs(n);
wnl_builder.add_node_ref(ref);
}
@@ -188,7 +188,7 @@ namespace osmium {
if (pbf_way.keys_size() > 0) {
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
- for (int tag=0; tag < pbf_way.keys_size(); ++tag) {
+ for (int tag = 0; tag < pbf_way.keys_size(); ++tag) {
tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_way.keys(tag))),
m_stringtable->s(static_cast<int>(pbf_way.vals(tag))));
}
@@ -199,7 +199,7 @@ namespace osmium {
}
void parse_relation_group(const OSMPBF::PrimitiveGroup& group) {
- for (int i=0; i < group.relations_size(); ++i) {
+ for (int i = 0; i < group.relations_size(); ++i) {
osmium::builder::RelationBuilder builder(m_buffer);
const OSMPBF::Relation& pbf_relation = group.relations(i);
parse_attributes(builder, pbf_relation);
@@ -207,7 +207,7 @@ namespace osmium {
if (pbf_relation.types_size() > 0) {
osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder);
int64_t ref = 0;
- for (int n=0; n < pbf_relation.types_size(); ++n) {
+ for (int n = 0; n < pbf_relation.types_size(); ++n) {
ref += pbf_relation.memids(n);
rml_builder.add_member(osmpbf_membertype_to_item_type(pbf_relation.types(n)), ref, m_stringtable->s(pbf_relation.roles_sid(n)));
}
@@ -215,7 +215,7 @@ namespace osmium {
if (pbf_relation.keys_size() > 0) {
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
- for (int tag=0; tag < pbf_relation.keys_size(); ++tag) {
+ for (int tag = 0; tag < pbf_relation.keys_size(); ++tag) {
tl_builder.add_tag(m_stringtable->s(static_cast<int>(pbf_relation.keys(tag))),
m_stringtable->s(static_cast<int>(pbf_relation.vals(tag))));
}
@@ -264,7 +264,7 @@ namespace osmium {
const OSMPBF::DenseNodes& dense = group.dense();
- for (int i=0; i < dense.id_size(); ++i) {
+ for (int i = 0; i < dense.id_size(); ++i) {
bool visible = true;
last_dense_id += dense.id(i);
@@ -361,7 +361,7 @@ namespace osmium {
}
osmium::io::Header header;
- for (int i=0; i < pbf_header_block.required_features_size(); ++i) {
+ for (int i = 0; i < pbf_header_block.required_features_size(); ++i) {
const std::string& feature = pbf_header_block.required_features(i);
if (feature == "OsmSchema-V0.6") continue;
@@ -377,7 +377,7 @@ namespace osmium {
throw osmium::pbf_error(std::string("required feature not supported: ") + feature);
}
- for (int i=0; i < pbf_header_block.optional_features_size(); ++i) {
+ for (int i = 0; i < pbf_header_block.optional_features_size(); ++i) {
const std::string& feature = pbf_header_block.optional_features(i);
header.set("pbf_optional_feature_" + std::to_string(i), feature);
}
@@ -412,30 +412,36 @@ namespace osmium {
class DataBlobParser {
- std::string m_input_buffer;
+ std::shared_ptr<std::string> m_input_buffer;
osmium::osm_entity_bits::type m_read_types;
public:
DataBlobParser(std::string&& input_buffer, osmium::osm_entity_bits::type read_types) :
- m_input_buffer(std::move(input_buffer)),
+ m_input_buffer(std::make_shared<std::string>(std::move(input_buffer))),
m_read_types(read_types) {
if (input_buffer.size() > OSMPBF::max_uncompressed_blob_size) {
throw osmium::pbf_error(std::string("invalid blob size: " + std::to_string(input_buffer.size())));
}
}
-
+/*
DataBlobParser(const DataBlobParser& other) :
m_input_buffer(std::move(other.m_input_buffer)),
m_read_types(other.m_read_types) {
- }
+ }*/
+
+ DataBlobParser(const DataBlobParser&) = default;
+ DataBlobParser& operator=(const DataBlobParser&) = default;
+
+ DataBlobParser(DataBlobParser&&) = default;
+ DataBlobParser& operator=(DataBlobParser&&) = default;
- DataBlobParser& operator=(const DataBlobParser&) = delete;
+ ~DataBlobParser() = default;
osmium::memory::Buffer operator()() {
- const std::unique_ptr<const std::string> data = unpack_blob(m_input_buffer);
+ const std::unique_ptr<const std::string> data = unpack_blob(*m_input_buffer);
PBFPrimitiveBlockParser parser(*data, m_read_types);
- return std::move(parser());
+ return parser();
}
}; // class DataBlobParser
diff --git a/third_party/osmium/io/detail/pbf_stringtable.hpp b/third_party/libosmium/include/osmium/io/detail/pbf_stringtable.hpp
similarity index 80%
rename from third_party/osmium/io/detail/pbf_stringtable.hpp
rename to third_party/libosmium/include/osmium/io/detail/pbf_stringtable.hpp
index 6f6c54c..5f540f1 100644
--- a/third_party/osmium/io/detail/pbf_stringtable.hpp
+++ b/third_party/libosmium/include/osmium/io/detail/pbf_stringtable.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -145,30 +145,44 @@ namespace osmium {
* implementation) is that the string table is sorted first by reverse count (ie descending)
* and then by reverse lexicographic order.
*/
- void store_stringtable(OSMPBF::StringTable* st) {
+ void store_stringtable(OSMPBF::StringTable* st, bool sort) {
// add empty StringTable entry at index 0
// StringTable index 0 is reserved as delimiter in the densenodes key/value list
// this line also ensures that there's always a valid StringTable
st->add_s("");
- std::multimap<string_info, std::string> sortedbycount;
+ if (sort) {
+ std::multimap<string_info, std::string> sortedbycount;
- m_id2id_map.resize(m_size+1);
+ m_id2id_map.resize(m_size+1);
- std::transform(m_strings.begin(), m_strings.end(),
- std::inserter(sortedbycount, sortedbycount.begin()),
- [](const std::pair<std::string, string_info>& p) {
- return std::pair<string_info, std::string>(p.second, p.first);
- });
+ std::transform(m_strings.begin(), m_strings.end(),
+ std::inserter(sortedbycount, sortedbycount.begin()),
+ [](const std::pair<std::string, string_info>& p) {
+ return std::pair<string_info, std::string>(p.second, p.first);
+ });
- string_id_type n=0;
+ string_id_type n = 0;
- for (const auto& mapping : sortedbycount) {
- // add the string of the current item to the pbf StringTable
- st->add_s(mapping.second);
+ for (const auto& mapping : sortedbycount) {
+ // add the string of the current item to the pbf StringTable
+ st->add_s(mapping.second);
- // store the mapping from the interim-id to the real id
- m_id2id_map[mapping.first.interim_id] = ++n;
+ // store the mapping from the interim-id to the real id
+ m_id2id_map[mapping.first.interim_id] = ++n;
+ }
+ } else {
+ std::vector<std::pair<string_id_type, const char*>> sortedbyid;
+ sortedbyid.reserve(m_strings.size());
+
+ for (const auto& p : m_strings) {
+ sortedbyid.emplace_back(p.second.interim_id, p.first.c_str());
+ }
+
+ std::sort(sortedbyid.begin(), sortedbyid.end());
+ for (const auto& mapping : sortedbyid) {
+ st->add_s(mapping.second);
+ }
}
}
diff --git a/third_party/osmium/io/detail/read_thread.hpp b/third_party/libosmium/include/osmium/io/detail/read_thread.hpp
similarity index 98%
rename from third_party/osmium/io/detail/read_thread.hpp
rename to third_party/libosmium/include/osmium/io/detail/read_thread.hpp
index 7c37139..bce4f55 100644
--- a/third_party/osmium/io/detail/read_thread.hpp
+++ b/third_party/libosmium/include/osmium/io/detail/read_thread.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/io/detail/read_write.hpp b/third_party/libosmium/include/osmium/io/detail/read_write.hpp
similarity index 93%
rename from third_party/osmium/io/detail/read_write.hpp
rename to third_party/libosmium/include/osmium/io/detail/read_write.hpp
index a949296..6651cce 100644
--- a/third_party/osmium/io/detail/read_write.hpp
+++ b/third_party/libosmium/include/osmium/io/detail/read_write.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -43,7 +43,6 @@ DEALINGS IN THE SOFTWARE.
# include <unistd.h>
#else
# include <io.h>
-typedef int ssize_t;
#endif
#include <osmium/io/overwrite.hpp>
@@ -123,9 +122,14 @@ namespace osmium {
* @throws std::system_error On error.
*/
inline void reliable_write(const int fd, const unsigned char* output_buffer, const size_t size) {
+ constexpr size_t max_write = 100 * 1024 * 1024; // Max 100 MByte per write
size_t offset = 0;
do {
- ssize_t length = ::write(fd, output_buffer + offset, size - offset);
+ auto write_count = size - offset;
+ if (write_count > max_write) {
+ write_count = max_write;
+ }
+ auto length = ::write(fd, output_buffer + offset, static_cast<unsigned int>(write_count));
if (length < 0) {
throw std::system_error(errno, std::system_category(), "Write failed");
}
diff --git a/third_party/osmium/io/detail/write_thread.hpp b/third_party/libosmium/include/osmium/io/detail/write_thread.hpp
similarity index 97%
rename from third_party/osmium/io/detail/write_thread.hpp
rename to third_party/libosmium/include/osmium/io/detail/write_thread.hpp
index 49b7b5d..fad22ed 100644
--- a/third_party/osmium/io/detail/write_thread.hpp
+++ b/third_party/libosmium/include/osmium/io/detail/write_thread.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/io/detail/xml_input_format.hpp b/third_party/libosmium/include/osmium/io/detail/xml_input_format.hpp
similarity index 97%
rename from third_party/osmium/io/detail/xml_input_format.hpp
rename to third_party/libosmium/include/osmium/io/detail/xml_input_format.hpp
index 1564b78..c03f84d 100644
--- a/third_party/osmium/io/detail/xml_input_format.hpp
+++ b/third_party/libosmium/include/osmium/io/detail/xml_input_format.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,8 +33,6 @@ DEALINGS IN THE SOFTWARE.
*/
-#define OSMIUM_LINK_WITH_LIBS_EXPAT -lexpat
-
#include <atomic>
#include <cassert>
#include <chrono>
@@ -76,8 +74,8 @@ namespace osmium {
/**
* Exception thrown when the XML parser failed. The exception contains
- * information about the place where the error happened and the type of
- * error.
+ * (if available) information about the place where the error happened
+ * and the type of error.
*/
struct xml_error : public io_error {
@@ -86,7 +84,7 @@ namespace osmium {
XML_Error error_code;
std::string error_string;
- xml_error(XML_Parser parser) :
+ explicit xml_error(XML_Parser parser) :
io_error(std::string("XML parsing error at line ")
+ std::to_string(XML_GetCurrentLineNumber(parser))
+ ", column "
@@ -99,8 +97,20 @@ namespace osmium {
error_string(XML_ErrorString(error_code)) {
}
+ explicit xml_error(const std::string& message) :
+ io_error(message),
+ line(0),
+ column(0),
+ error_code(),
+ error_string(message) {
+ }
+
}; // struct xml_error
+ /**
+ * Exception thrown when an OSM XML files contains no version attribute
+ * on the 'osm' element or if the version is unknown.
+ */
struct format_version_error : public io_error {
std::string version;
@@ -436,6 +446,8 @@ namespace osmium {
if (m_header.get("version") == "") {
throw osmium::format_version_error();
}
+ } else {
+ throw osmium::xml_error(std::string("Unknown top-level element: ") + element);
}
m_context = context::top;
break;
@@ -671,7 +683,7 @@ namespace osmium {
* @param input_queue String queue where data is read from.
*/
explicit XMLInputFormat(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) :
- osmium::io::detail::InputFormat(file, read_which_entities, input_queue),
+ osmium::io::detail::InputFormat(file, read_which_entities),
m_queue(max_queue_size, "xml_parser_results"),
m_done(false),
m_header_promise(),
@@ -701,7 +713,7 @@ namespace osmium {
return buffer;
}
- void close() {
+ void close() override {
m_done = true;
osmium::thread::wait_until_done(m_parser_future);
}
diff --git a/third_party/osmium/io/detail/xml_output_format.hpp b/third_party/libosmium/include/osmium/io/detail/xml_output_format.hpp
similarity index 75%
rename from third_party/osmium/io/detail/xml_output_format.hpp
rename to third_party/libosmium/include/osmium/io/detail/xml_output_format.hpp
index c8c7a38..65ba171 100644
--- a/third_party/osmium/io/detail/xml_output_format.hpp
+++ b/third_party/libosmium/include/osmium/io/detail/xml_output_format.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -120,9 +120,9 @@ namespace osmium {
op_delete = 3
}; // enum class operation
- osmium::memory::Buffer m_input_buffer;
+ std::shared_ptr<osmium::memory::Buffer> m_input_buffer;
- std::string m_out;
+ std::shared_ptr<std::string> m_out;
operation m_last_op {operation::op_none};
@@ -130,8 +130,8 @@ namespace osmium {
const bool m_write_change_ops;
void write_spaces(int num) {
- for (; num!=0; --num) {
- m_out += ' ';
+ for (; num != 0; --num) {
+ *m_out += ' ';
}
}
@@ -144,33 +144,33 @@ namespace osmium {
}
void write_meta(const osmium::OSMObject& object) {
- oprintf(m_out, " id=\"%" PRId64 "\"", object.id());
+ oprintf(*m_out, " id=\"%" PRId64 "\"", object.id());
if (object.version()) {
- oprintf(m_out, " version=\"%d\"", object.version());
+ oprintf(*m_out, " version=\"%d\"", object.version());
}
if (object.timestamp()) {
- m_out += " timestamp=\"";
- m_out += object.timestamp().to_iso();
- m_out += "\"";
+ *m_out += " timestamp=\"";
+ *m_out += object.timestamp().to_iso();
+ *m_out += "\"";
}
if (!object.user_is_anonymous()) {
- oprintf(m_out, " uid=\"%d\" user=\"", object.uid());
- xml_string(m_out, object.user());
- m_out += "\"";
+ oprintf(*m_out, " uid=\"%d\" user=\"", object.uid());
+ xml_string(*m_out, object.user());
+ *m_out += "\"";
}
if (object.changeset()) {
- oprintf(m_out, " changeset=\"%d\"", object.changeset());
+ oprintf(*m_out, " changeset=\"%d\"", object.changeset());
}
if (m_write_visible_flag) {
if (object.visible()) {
- m_out += " visible=\"true\"";
+ *m_out += " visible=\"true\"";
} else {
- m_out += " visible=\"false\"";
+ *m_out += " visible=\"false\"";
}
}
}
@@ -178,11 +178,11 @@ namespace osmium {
void write_tags(const osmium::TagList& tags) {
for (const auto& tag : tags) {
write_prefix();
- m_out += " <tag k=\"";
- xml_string(m_out, tag.key());
- m_out += "\" v=\"";
- xml_string(m_out, tag.value());
- m_out += "\"/>\n";
+ *m_out += " <tag k=\"";
+ xml_string(*m_out, tag.key());
+ *m_out += "\" v=\"";
+ xml_string(*m_out, tag.value());
+ *m_out += "\"/>\n";
}
}
@@ -195,13 +195,13 @@ namespace osmium {
case operation::op_none:
break;
case operation::op_create:
- m_out += " </create>\n";
+ *m_out += " </create>\n";
break;
case operation::op_modify:
- m_out += " </modify>\n";
+ *m_out += " </modify>\n";
break;
case operation::op_delete:
- m_out += " </delete>\n";
+ *m_out += " </delete>\n";
break;
}
@@ -209,13 +209,13 @@ namespace osmium {
case operation::op_none:
break;
case operation::op_create:
- m_out += " <create>\n";
+ *m_out += " <create>\n";
break;
case operation::op_modify:
- m_out += " <modify>\n";
+ *m_out += " <modify>\n";
break;
case operation::op_delete:
- m_out += " <delete>\n";
+ *m_out += " <delete>\n";
break;
}
@@ -225,26 +225,29 @@ namespace osmium {
public:
explicit XMLOutputBlock(osmium::memory::Buffer&& buffer, bool write_visible_flag, bool write_change_ops) :
- m_input_buffer(std::move(buffer)),
+ m_input_buffer(std::make_shared<osmium::memory::Buffer>(std::move(buffer))),
+ m_out(std::make_shared<std::string>()),
m_write_visible_flag(write_visible_flag && !write_change_ops),
m_write_change_ops(write_change_ops) {
}
- XMLOutputBlock(const XMLOutputBlock&) = delete;
- XMLOutputBlock& operator=(const XMLOutputBlock&) = delete;
+ XMLOutputBlock(const XMLOutputBlock&) = default;
+ XMLOutputBlock& operator=(const XMLOutputBlock&) = default;
XMLOutputBlock(XMLOutputBlock&&) = default;
XMLOutputBlock& operator=(XMLOutputBlock&&) = default;
+ ~XMLOutputBlock() = default;
+
std::string operator()() {
- osmium::apply(m_input_buffer.cbegin(), m_input_buffer.cend(), *this);
+ osmium::apply(m_input_buffer->cbegin(), m_input_buffer->cend(), *this);
if (m_write_change_ops) {
open_close_op_tag();
}
std::string out;
- std::swap(out, m_out);
+ std::swap(out, *m_out);
return out;
}
@@ -254,29 +257,29 @@ namespace osmium {
}
write_prefix();
- m_out += "<node";
+ *m_out += "<node";
write_meta(node);
if (node.location()) {
- m_out += " lat=\"";
- osmium::util::double2string(std::back_inserter(m_out), node.location().lat_without_check(), 7);
- m_out += "\" lon=\"";
- osmium::util::double2string(std::back_inserter(m_out), node.location().lon_without_check(), 7);
- m_out += "\"";
+ *m_out += " lat=\"";
+ osmium::util::double2string(std::back_inserter(*m_out), node.location().lat_without_check(), 7);
+ *m_out += "\" lon=\"";
+ osmium::util::double2string(std::back_inserter(*m_out), node.location().lon_without_check(), 7);
+ *m_out += "\"";
}
if (node.tags().empty()) {
- m_out += "/>\n";
+ *m_out += "/>\n";
return;
}
- m_out += ">\n";
+ *m_out += ">\n";
write_tags(node.tags());
write_prefix();
- m_out += "</node>\n";
+ *m_out += "</node>\n";
}
void way(const osmium::Way& way) {
@@ -285,25 +288,25 @@ namespace osmium {
}
write_prefix();
- m_out += "<way";
+ *m_out += "<way";
write_meta(way);
if (way.tags().empty() && way.nodes().empty()) {
- m_out += "/>\n";
+ *m_out += "/>\n";
return;
}
- m_out += ">\n";
+ *m_out += ">\n";
for (const auto& node_ref : way.nodes()) {
write_prefix();
- oprintf(m_out, " <nd ref=\"%" PRId64 "\"/>\n", node_ref.ref());
+ oprintf(*m_out, " <nd ref=\"%" PRId64 "\"/>\n", node_ref.ref());
}
write_tags(way.tags());
write_prefix();
- m_out += "</way>\n";
+ *m_out += "</way>\n";
}
void relation(const osmium::Relation& relation) {
@@ -312,77 +315,77 @@ namespace osmium {
}
write_prefix();
- m_out += "<relation";
+ *m_out += "<relation";
write_meta(relation);
if (relation.tags().empty() && relation.members().empty()) {
- m_out += "/>\n";
+ *m_out += "/>\n";
return;
}
- m_out += ">\n";
+ *m_out += ">\n";
for (const auto& member : relation.members()) {
write_prefix();
- m_out += " <member type=\"";
- m_out += item_type_to_name(member.type());
- oprintf(m_out, "\" ref=\"%" PRId64 "\" role=\"", member.ref());
- xml_string(m_out, member.role());
- m_out += "\"/>\n";
+ *m_out += " <member type=\"";
+ *m_out += item_type_to_name(member.type());
+ oprintf(*m_out, "\" ref=\"%" PRId64 "\" role=\"", member.ref());
+ xml_string(*m_out, member.role());
+ *m_out += "\"/>\n";
}
write_tags(relation.tags());
write_prefix();
- m_out += "</relation>\n";
+ *m_out += "</relation>\n";
}
void changeset(const osmium::Changeset& changeset) {
write_prefix();
- m_out += "<changeset";
+ *m_out += "<changeset";
- oprintf(m_out, " id=\"%" PRId32 "\"", changeset.id());
+ oprintf(*m_out, " id=\"%" PRId32 "\"", changeset.id());
if (changeset.created_at()) {
- m_out += " created_at=\"";
- m_out += changeset.created_at().to_iso();
- m_out += "\"";
+ *m_out += " created_at=\"";
+ *m_out += changeset.created_at().to_iso();
+ *m_out += "\"";
}
- oprintf(m_out, " num_changes=\"%" PRId32 "\"", changeset.num_changes());
+ oprintf(*m_out, " num_changes=\"%" PRId32 "\"", changeset.num_changes());
if (changeset.closed_at()) {
- m_out += " closed_at=\"";
- m_out += changeset.closed_at().to_iso();
- m_out += "\" open=\"false\"";
+ *m_out += " closed_at=\"";
+ *m_out += changeset.closed_at().to_iso();
+ *m_out += "\" open=\"false\"";
} else {
- m_out += " open=\"true\"";
+ *m_out += " open=\"true\"";
}
if (changeset.bounds()) {
- oprintf(m_out, " min_lon=\"%.7f\"", changeset.bounds().bottom_left().lon_without_check());
- oprintf(m_out, " min_lat=\"%.7f\"", changeset.bounds().bottom_left().lat_without_check());
- oprintf(m_out, " max_lon=\"%.7f\"", changeset.bounds().top_right().lon_without_check());
- oprintf(m_out, " max_lat=\"%.7f\"", changeset.bounds().top_right().lat_without_check());
+ oprintf(*m_out, " min_lon=\"%.7f\"", changeset.bounds().bottom_left().lon_without_check());
+ oprintf(*m_out, " min_lat=\"%.7f\"", changeset.bounds().bottom_left().lat_without_check());
+ oprintf(*m_out, " max_lon=\"%.7f\"", changeset.bounds().top_right().lon_without_check());
+ oprintf(*m_out, " max_lat=\"%.7f\"", changeset.bounds().top_right().lat_without_check());
}
if (!changeset.user_is_anonymous()) {
- m_out += " user=\"";
- xml_string(m_out, changeset.user());
- oprintf(m_out, "\" uid=\"%d\"", changeset.uid());
+ *m_out += " user=\"";
+ xml_string(*m_out, changeset.user());
+ oprintf(*m_out, "\" uid=\"%d\"", changeset.uid());
}
if (changeset.tags().empty()) {
- m_out += "/>\n";
+ *m_out += "/>\n";
return;
}
- m_out += ">\n";
+ *m_out += ">\n";
write_tags(changeset.tags());
write_prefix();
- m_out += "</changeset>\n";
+ *m_out += "</changeset>\n";
}
}; // class XMLOutputBlock
diff --git a/third_party/osmium/io/detail/zlib.hpp b/third_party/libosmium/include/osmium/io/detail/zlib.hpp
similarity index 63%
rename from third_party/osmium/io/detail/zlib.hpp
rename to third_party/libosmium/include/osmium/io/detail/zlib.hpp
index 84ab86c..a402bf7 100644
--- a/third_party/osmium/io/detail/zlib.hpp
+++ b/third_party/libosmium/include/osmium/io/detail/zlib.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,14 +33,14 @@ DEALINGS IN THE SOFTWARE.
*/
-#define OSMIUM_LINK_WITH_LIBS_ZLIB -lz
-
#include <memory>
#include <stdexcept>
#include <string>
#include <zlib.h>
+#include <osmium/util/cast.hpp>
+
namespace osmium {
namespace io {
@@ -50,19 +50,26 @@ namespace osmium {
/**
* Compress data using zlib.
*
+ * Note that this function can not compress data larger than
+ * what fits in an unsigned long, on Windows this is usually 32bit.
+ *
* @param input Data to compress.
* @returns Compressed data.
*/
inline std::string zlib_compress(const std::string& input) {
- unsigned long output_size = ::compressBound(input.size());
+ unsigned long output_size = ::compressBound(osmium::static_cast_with_assert<unsigned long>(input.size()));
std::string output(output_size, '\0');
- if (::compress(reinterpret_cast<unsigned char*>(const_cast<char *>(output.data())),
- &output_size,
- reinterpret_cast<const unsigned char*>(input.data()),
- input.size()) != Z_OK) {
- throw std::runtime_error("failed to compress data");
+ auto result = ::compress(
+ reinterpret_cast<unsigned char*>(const_cast<char *>(output.data())),
+ &output_size,
+ reinterpret_cast<const unsigned char*>(input.data()),
+ osmium::static_cast_with_assert<unsigned long>(input.size())
+ );
+
+ if (result != Z_OK) {
+ throw std::runtime_error(std::string("failed to compress data: ") + zError(result));
}
output.resize(output_size);
@@ -73,6 +80,9 @@ namespace osmium {
/**
* Uncompress data using zlib.
*
+ * Note that this function can not uncompress data larger than
+ * what fits in an unsigned long, on Windows this is usually 32bit.
+ *
* @param input Compressed input data.
* @param raw_size Size of uncompressed data.
* @returns Uncompressed data.
@@ -80,11 +90,15 @@ namespace osmium {
inline std::unique_ptr<std::string> zlib_uncompress(const std::string& input, unsigned long raw_size) {
auto output = std::unique_ptr<std::string>(new std::string(raw_size, '\0'));
- if (::uncompress(reinterpret_cast<unsigned char*>(const_cast<char *>(output->data())),
- &raw_size,
- reinterpret_cast<const unsigned char*>(input.data()),
- input.size()) != Z_OK) {
- throw std::runtime_error("failed to uncompress data");
+ auto result = ::uncompress(
+ reinterpret_cast<unsigned char*>(const_cast<char *>(output->data())),
+ &raw_size,
+ reinterpret_cast<const unsigned char*>(input.data()),
+ osmium::static_cast_with_assert<unsigned long>(input.size())
+ );
+
+ if (result != Z_OK) {
+ throw std::runtime_error(std::string("failed to uncompress data: ") + zError(result));
}
return output;
diff --git a/third_party/osmium/io/error.hpp b/third_party/libosmium/include/osmium/io/error.hpp
similarity index 95%
rename from third_party/osmium/io/error.hpp
rename to third_party/libosmium/include/osmium/io/error.hpp
index 8fb9f05..07652bc 100644
--- a/third_party/osmium/io/error.hpp
+++ b/third_party/libosmium/include/osmium/io/error.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -34,6 +34,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <stdexcept>
+#include <string>
namespace osmium {
diff --git a/third_party/osmium/io/file.hpp b/third_party/libosmium/include/osmium/io/file.hpp
similarity index 99%
rename from third_party/osmium/io/file.hpp
rename to third_party/libosmium/include/osmium/io/file.hpp
index 21469b8..5b6c02f 100644
--- a/third_party/osmium/io/file.hpp
+++ b/third_party/libosmium/include/osmium/io/file.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -42,6 +42,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/file_format.hpp>
#include <osmium/io/file_compression.hpp>
#include <osmium/util/options.hpp>
+#include <osmium/util/compatibility.hpp>
namespace osmium {
diff --git a/third_party/osmium/io/file_compression.hpp b/third_party/libosmium/include/osmium/io/file_compression.hpp
similarity index 97%
rename from third_party/osmium/io/file_compression.hpp
rename to third_party/libosmium/include/osmium/io/file_compression.hpp
index c718715..292ddcf 100644
--- a/third_party/osmium/io/file_compression.hpp
+++ b/third_party/libosmium/include/osmium/io/file_compression.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/io/file_format.hpp b/third_party/libosmium/include/osmium/io/file_format.hpp
similarity index 97%
rename from third_party/osmium/io/file_format.hpp
rename to third_party/libosmium/include/osmium/io/file_format.hpp
index 5a4aa5c..1a63a5e 100644
--- a/third_party/osmium/io/file_format.hpp
+++ b/third_party/libosmium/include/osmium/io/file_format.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/io/gzip_compression.hpp b/third_party/libosmium/include/osmium/io/gzip_compression.hpp
similarity index 84%
rename from third_party/osmium/io/gzip_compression.hpp
rename to third_party/libosmium/include/osmium/io/gzip_compression.hpp
index db99acb..2723977 100644
--- a/third_party/osmium/io/gzip_compression.hpp
+++ b/third_party/libosmium/include/osmium/io/gzip_compression.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,7 +33,14 @@ DEALINGS IN THE SOFTWARE.
*/
-#define OSMIUM_LINK_WITH_LIBS_ZLIB -lz
+/**
+ * @file
+ *
+ * Include this file if you want to read or write gzip-compressed OSM XML
+ * files.
+ *
+ * @attention If you include this file, you'll need to link with `libz`.
+ */
#include <stdexcept>
#include <string>
@@ -69,7 +76,7 @@ namespace osmium {
namespace detail {
- OSMIUM_NORETURN inline void throw_gzip_error(gzFile gzfile, const char* msg, int zlib_error=0) {
+ OSMIUM_NORETURN inline void throw_gzip_error(gzFile gzfile, const char* msg, int zlib_error = 0) {
std::string error("gzip error: ");
error += msg;
error += ": ";
@@ -192,30 +199,31 @@ namespace osmium {
}
std::string read() override final {
- if (!m_buffer) {
- return std::string();
- }
+ std::string output;
- const size_t buffer_size = 10240;
- std::string output(buffer_size, '\0');
- m_zstream.next_out = reinterpret_cast<unsigned char*>(const_cast<char*>(output.data()));
- m_zstream.avail_out = buffer_size;
- int result = inflate(&m_zstream, Z_SYNC_FLUSH);
+ if (m_buffer) {
+ const size_t buffer_size = 10240;
+ output.append(buffer_size, '\0');
+ m_zstream.next_out = reinterpret_cast<unsigned char*>(const_cast<char*>(output.data()));
+ m_zstream.avail_out = buffer_size;
+ int result = inflate(&m_zstream, Z_SYNC_FLUSH);
- if (result != Z_OK) {
- m_buffer = nullptr;
- m_buffer_size = 0;
- }
+ if (result != Z_OK) {
+ m_buffer = nullptr;
+ m_buffer_size = 0;
+ }
- if (result != Z_OK && result != Z_STREAM_END) {
- std::string message("gzip error: inflate failed: ");
- if (m_zstream.msg) {
- message.append(m_zstream.msg);
+ if (result != Z_OK && result != Z_STREAM_END) {
+ std::string message("gzip error: inflate failed: ");
+ if (m_zstream.msg) {
+ message.append(m_zstream.msg);
+ }
+ throw osmium::gzip_error(message, result);
}
- throw osmium::gzip_error(message, result);
+
+ output.resize(static_cast<unsigned long>(m_zstream.next_out - reinterpret_cast<const unsigned char*>(output.data())));
}
- output.resize(static_cast<unsigned long>(m_zstream.next_out - reinterpret_cast<const unsigned char*>(output.data())));
return output;
}
diff --git a/third_party/osmium/io/header.hpp b/third_party/libosmium/include/osmium/io/header.hpp
similarity index 98%
rename from third_party/osmium/io/header.hpp
rename to third_party/libosmium/include/osmium/io/header.hpp
index 0fdbf77..4b0830a 100644
--- a/third_party/osmium/io/header.hpp
+++ b/third_party/libosmium/include/osmium/io/header.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/io/input_iterator.hpp b/third_party/libosmium/include/osmium/io/input_iterator.hpp
similarity index 97%
rename from third_party/osmium/io/input_iterator.hpp
rename to third_party/libosmium/include/osmium/io/input_iterator.hpp
index a2e3b83..f619729 100644
--- a/third_party/osmium/io/input_iterator.hpp
+++ b/third_party/libosmium/include/osmium/io/input_iterator.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -41,6 +41,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/memory/buffer.hpp>
#include <osmium/memory/item.hpp>
+#include <osmium/util/compatibility.hpp>
namespace osmium {
diff --git a/third_party/osmium/io/opl_output.hpp b/third_party/libosmium/include/osmium/io/opl_output.hpp
similarity index 96%
rename from third_party/osmium/io/opl_output.hpp
rename to third_party/libosmium/include/osmium/io/opl_output.hpp
index 46a1224..04385d9 100644
--- a/third_party/osmium/io/opl_output.hpp
+++ b/third_party/libosmium/include/osmium/io/opl_output.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/io/output_iterator.hpp b/third_party/libosmium/include/osmium/io/output_iterator.hpp
similarity index 91%
rename from third_party/osmium/io/output_iterator.hpp
rename to third_party/libosmium/include/osmium/io/output_iterator.hpp
index e6a9cc0..608852f 100644
--- a/third_party/osmium/io/output_iterator.hpp
+++ b/third_party/libosmium/include/osmium/io/output_iterator.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -75,6 +75,14 @@ namespace osmium {
m_buffer_wrapper(std::make_shared<buffer_wrapper>(buffer_size)) {
}
+ OutputIterator(const OutputIterator&) = default;
+ OutputIterator(OutputIterator&&) = default;
+
+ OutputIterator& operator=(const OutputIterator&) = default;
+ OutputIterator& operator=(OutputIterator&&) = default;
+
+ ~OutputIterator() = default;
+
void flush() {
osmium::memory::Buffer buffer(m_buffer_wrapper->buffer.capacity(), osmium::memory::Buffer::auto_grow::no);
std::swap(m_buffer_wrapper->buffer, buffer);
diff --git a/third_party/osmium/io/overwrite.hpp b/third_party/libosmium/include/osmium/io/overwrite.hpp
similarity index 95%
rename from third_party/osmium/io/overwrite.hpp
rename to third_party/libosmium/include/osmium/io/overwrite.hpp
index f29a932..e33894b 100644
--- a/third_party/osmium/io/overwrite.hpp
+++ b/third_party/libosmium/include/osmium/io/overwrite.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/io/pbf_input.hpp b/third_party/libosmium/include/osmium/io/pbf_input.hpp
similarity index 83%
rename from third_party/osmium/io/pbf_input.hpp
rename to third_party/libosmium/include/osmium/io/pbf_input.hpp
index 8426f6c..766153e 100644
--- a/third_party/osmium/io/pbf_input.hpp
+++ b/third_party/libosmium/include/osmium/io/pbf_input.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,6 +33,16 @@ DEALINGS IN THE SOFTWARE.
*/
+/**
+ * @file
+ *
+ * Include this file if you want to read OSM PBF files.
+ *
+ * @attention If you include this file, you'll need to link with
+ * `libprotobuf-lite`, `libosmpbf`, `ws2_32` (Windows only),
+ * `libz`, and enable multithreading.
+ */
+
#include <osmium/io/reader.hpp> // IWYU pragma: export
#include <osmium/io/detail/pbf_input_format.hpp> // IWYU pragma: export
diff --git a/third_party/osmium/io/pbf_output.hpp b/third_party/libosmium/include/osmium/io/pbf_output.hpp
similarity index 83%
rename from third_party/osmium/io/pbf_output.hpp
rename to third_party/libosmium/include/osmium/io/pbf_output.hpp
index 9fd0396..5f46ede 100644
--- a/third_party/osmium/io/pbf_output.hpp
+++ b/third_party/libosmium/include/osmium/io/pbf_output.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,6 +33,16 @@ DEALINGS IN THE SOFTWARE.
*/
+/**
+ * @file
+ *
+ * Include this file if you want to write OSM PBF files.
+ *
+ * @attention If you include this file, you'll need to link with
+ * `libprotobuf-lite`, `libosmpbf`, `ws2_32` (Windows only),
+ * `libz`, and enable multithreading.
+ */
+
#include <osmium/io/writer.hpp> // IWYU pragma: export
#include <osmium/io/detail/pbf_output_format.hpp> // IWYU pragma: export
diff --git a/third_party/osmium/io/reader.hpp b/third_party/libosmium/include/osmium/io/reader.hpp
similarity index 93%
rename from third_party/osmium/io/reader.hpp
rename to third_party/libosmium/include/osmium/io/reader.hpp
index a9b8b95..c68a8e1 100644
--- a/third_party/osmium/io/reader.hpp
+++ b/third_party/libosmium/include/osmium/io/reader.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -109,7 +109,7 @@ namespace osmium {
}
if (pid == 0) { // child
// close all file descriptors except one end of the pipe
- for (int i=0; i < 32; ++i) {
+ for (int i = 0; i < 32; ++i) {
if (i != pipefd[1]) {
::close(i);
}
@@ -258,11 +258,20 @@ namespace osmium {
return osmium::memory::Buffer();
}
- osmium::memory::Buffer buffer = m_input->read();
- if (!buffer) {
- m_input_done = true;
+ // m_input->read() can return an invalid buffer to signal EOF,
+ // or a valid buffer with or without data. A valid buffer
+ // without data is not an error, it just means we have to
+ // keep getting the next buffer until there is one with data.
+ while (true) {
+ osmium::memory::Buffer buffer = m_input->read();
+ if (!buffer) {
+ m_input_done = true;
+ return buffer;
+ }
+ if (buffer.committed() > 0) {
+ return buffer;
+ }
}
- return buffer;
}
/**
diff --git a/third_party/osmium/io/reader_iterator.hpp b/third_party/libosmium/include/osmium/io/reader_iterator.hpp
similarity index 96%
rename from third_party/osmium/io/reader_iterator.hpp
rename to third_party/libosmium/include/osmium/io/reader_iterator.hpp
index 8d71418..8620789 100644
--- a/third_party/osmium/io/reader_iterator.hpp
+++ b/third_party/libosmium/include/osmium/io/reader_iterator.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/io/writer.hpp b/third_party/libosmium/include/osmium/io/writer.hpp
similarity index 98%
rename from third_party/osmium/io/writer.hpp
rename to third_party/libosmium/include/osmium/io/writer.hpp
index 7e9bd13..64afe20 100644
--- a/third_party/osmium/io/writer.hpp
+++ b/third_party/libosmium/include/osmium/io/writer.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -80,7 +80,7 @@ namespace osmium {
* defaults will be used. See the default constructor
* of osmium::io::Header for details.
* @param allow_overwrite Allow overwriting of existing file? Can be
- * osmium::io::overwrite::allow or osmium::io::overwrite::no+
+ * osmium::io::overwrite::allow or osmium::io::overwrite::no
* (default).
*
* @throws std::runtime_error If the file could not be opened.
diff --git a/third_party/osmium/io/xml_input.hpp b/third_party/libosmium/include/osmium/io/xml_input.hpp
similarity index 86%
rename from third_party/osmium/io/xml_input.hpp
rename to third_party/libosmium/include/osmium/io/xml_input.hpp
index f33d37e..dfcd0a9 100644
--- a/third_party/osmium/io/xml_input.hpp
+++ b/third_party/libosmium/include/osmium/io/xml_input.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,6 +33,15 @@ DEALINGS IN THE SOFTWARE.
*/
+/**
+ * @file
+ *
+ * Include this file if you want to read OSM XML files.
+ *
+ * @attention If you include this file, you'll need to link with
+ * `libexpat`, and enable multithreading.
+ */
+
#include <osmium/io/reader.hpp> // IWYU pragma: export
#include <osmium/io/detail/xml_input_format.hpp> // IWYU pragma: export
diff --git a/third_party/osmium/io/xml_output.hpp b/third_party/libosmium/include/osmium/io/xml_output.hpp
similarity index 88%
rename from third_party/osmium/io/xml_output.hpp
rename to third_party/libosmium/include/osmium/io/xml_output.hpp
index d5b839f..18a1386 100644
--- a/third_party/osmium/io/xml_output.hpp
+++ b/third_party/libosmium/include/osmium/io/xml_output.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,6 +33,14 @@ DEALINGS IN THE SOFTWARE.
*/
+/**
+ * @file
+ *
+ * Include this file if you want to write OSM XML files.
+ *
+ * @attention If you include this file, you'll need to enable multithreading.
+ */
+
#include <osmium/io/writer.hpp> // IWYU pragma: export
#include <osmium/io/detail/xml_output_format.hpp> // IWYU pragma: export
diff --git a/third_party/osmium/memory/buffer.hpp b/third_party/libosmium/include/osmium/memory/buffer.hpp
similarity index 97%
rename from third_party/osmium/memory/buffer.hpp
rename to third_party/libosmium/include/osmium/memory/buffer.hpp
index fe040ca..85a3a46 100644
--- a/third_party/osmium/memory/buffer.hpp
+++ b/third_party/libosmium/include/osmium/memory/buffer.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
@@ -365,9 +366,9 @@ namespace osmium {
*/
template <class T>
T& add_item(const T& item) {
- unsigned char* ptr = reserve_space(item.padded_size());
- std::memcpy(ptr, &item, item.padded_size());
- return *reinterpret_cast<T*>(ptr);
+ unsigned char* target = reserve_space(item.padded_size());
+ std::copy_n(reinterpret_cast<const unsigned char*>(&item), item.padded_size(), target);
+ return *reinterpret_cast<T*>(target);
}
/**
@@ -377,8 +378,8 @@ namespace osmium {
* commit this data.
*/
void add_buffer(const Buffer& buffer) {
- unsigned char* ptr = reserve_space(buffer.committed());
- std::memcpy(ptr, buffer.data(), buffer.committed());
+ unsigned char* target = reserve_space(buffer.committed());
+ std::copy_n(reinterpret_cast<const unsigned char*>(buffer.data()), buffer.committed(), target);
}
/**
diff --git a/third_party/osmium/memory/collection.hpp b/third_party/libosmium/include/osmium/memory/collection.hpp
similarity index 98%
rename from third_party/osmium/memory/collection.hpp
rename to third_party/libosmium/include/osmium/memory/collection.hpp
index b25dd64..7deb88b 100644
--- a/third_party/osmium/memory/collection.hpp
+++ b/third_party/libosmium/include/osmium/memory/collection.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -38,6 +38,7 @@ DEALINGS IN THE SOFTWARE.
#include <type_traits>
#include <osmium/memory/item.hpp>
+#include <osmium/util/compatibility.hpp>
namespace osmium {
diff --git a/third_party/osmium/memory/item.hpp b/third_party/libosmium/include/osmium/memory/item.hpp
similarity index 95%
rename from third_party/osmium/memory/item.hpp
rename to third_party/libosmium/include/osmium/memory/item.hpp
index 2d22f94..2679ca6 100644
--- a/third_party/osmium/memory/item.hpp
+++ b/third_party/libosmium/include/osmium/memory/item.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -55,8 +55,7 @@ namespace osmium {
template <typename T>
inline T padded_length(T length) noexcept {
- static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
- "Template parameter must be unsigned integral type");
+ static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, "Template parameter must be unsigned integral type");
return (length + align_bytes - 1) & ~(align_bytes - 1);
}
@@ -119,7 +118,7 @@ namespace osmium {
protected:
- explicit Item(item_size_type size=0, item_type type=item_type()) noexcept :
+ explicit Item(item_size_type size = 0, item_type type = item_type()) noexcept :
m_size(size),
m_type(type),
m_removed(false),
diff --git a/third_party/osmium/memory/item_iterator.hpp b/third_party/libosmium/include/osmium/memory/item_iterator.hpp
similarity index 99%
rename from third_party/osmium/memory/item_iterator.hpp
rename to third_party/libosmium/include/osmium/memory/item_iterator.hpp
index 34ed600..3e5b5fa 100644
--- a/third_party/osmium/memory/item_iterator.hpp
+++ b/third_party/libosmium/include/osmium/memory/item_iterator.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/object_pointer_collection.hpp b/third_party/libosmium/include/osmium/object_pointer_collection.hpp
similarity index 98%
rename from third_party/osmium/object_pointer_collection.hpp
rename to third_party/libosmium/include/osmium/object_pointer_collection.hpp
index 22029a1..7524703 100644
--- a/third_party/osmium/object_pointer_collection.hpp
+++ b/third_party/libosmium/include/osmium/object_pointer_collection.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/osm.hpp b/third_party/libosmium/include/osmium/osm.hpp
similarity index 96%
rename from third_party/osmium/osm.hpp
rename to third_party/libosmium/include/osmium/osm.hpp
index bf21c19..e92d9b8 100644
--- a/third_party/osmium/osm.hpp
+++ b/third_party/libosmium/include/osmium/osm.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/osm/area.hpp b/third_party/libosmium/include/osmium/osm/area.hpp
similarity index 82%
rename from third_party/osmium/osm/area.hpp
rename to third_party/libosmium/include/osmium/osm/area.hpp
index a388de2..3e129d0 100644
--- a/third_party/osmium/osm/area.hpp
+++ b/third_party/libosmium/include/osmium/osm/area.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -53,12 +53,14 @@ namespace osmium {
/**
* An outer ring of an Area.
*/
- class OuterRing : public NodeRefList<osmium::item_type::outer_ring> {
+ class OuterRing : public NodeRefList {
public:
+ static constexpr osmium::item_type itemtype = osmium::item_type::outer_ring;
+
OuterRing():
- NodeRefList<osmium::item_type::outer_ring>() {
+ NodeRefList(itemtype) {
}
}; // class OuterRing
@@ -68,12 +70,14 @@ namespace osmium {
/**
* An inner ring of an Area.
*/
- class InnerRing : public NodeRefList<osmium::item_type::inner_ring> {
+ class InnerRing : public NodeRefList {
public:
+ static constexpr osmium::item_type itemtype = osmium::item_type::inner_ring;
+
InnerRing():
- NodeRefList<osmium::item_type::inner_ring>() {
+ NodeRefList(itemtype) {
}
}; // class InnerRing
@@ -87,7 +91,7 @@ namespace osmium {
* @param type Type of object (way or relation)
* @returns Area id
*/
- inline osmium::object_id_type object_id_to_area_id(osmium::object_id_type id, osmium::item_type type) {
+ inline osmium::object_id_type object_id_to_area_id(osmium::object_id_type id, osmium::item_type type) noexcept {
osmium::object_id_type area_id = std::abs(id) * 2;
if (type == osmium::item_type::relation) {
++area_id;
@@ -101,7 +105,7 @@ namespace osmium {
* @param id Area id
* @returns Way or Relation id.
*/
- inline osmium::object_id_type area_id_to_object_id(osmium::object_id_type id) {
+ inline osmium::object_id_type area_id_to_object_id(osmium::object_id_type id) noexcept {
return id / 2;
}
@@ -131,15 +135,17 @@ namespace osmium {
/**
* Return the Id of the way or relation this area was created from.
*/
- osmium::object_id_type orig_id() const {
+ osmium::object_id_type orig_id() const noexcept {
return osmium::area_id_to_object_id(id());
}
/**
* Count the number of outer and inner rings of this area.
+ *
+ * @returns Pair (number outer rings, number inner rings)
*/
std::pair<int, int> num_rings() const {
- std::pair<int, int> counter;
+ std::pair<int, int> counter { 0, 0 };
for (auto it = cbegin(); it != cend(); ++it) {
switch (it->type()) {
@@ -170,16 +176,31 @@ namespace osmium {
}
/**
- * Is this area a multipolygon, ie. has it more than one outer ring?
+ * Check whether this area is a multipolygon, ie. whether it has more
+ * than one outer ring?
*/
bool is_multipolygon() const {
return num_rings().first > 1;
}
+ /**
+ * Get iterator for iterating over all inner rings in a specified outer
+ * ring.
+ *
+ * @param it Iterator specifying outer ring.
+ * @returns Iterator to first inner ring in specified outer ring.
+ */
osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cbegin(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
return it.cast<const osmium::InnerRing>();
}
+ /**
+ * Get iterator for iterating over all inner rings in a specified outer
+ * ring.
+ *
+ * @param it Iterator specifying outer ring.
+ * @returns Iterator one past last inner ring in specified outer ring.
+ */
osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cend(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
return std::next(it).cast<const osmium::InnerRing>();
}
diff --git a/third_party/osmium/osm/box.hpp b/third_party/libosmium/include/osmium/osm/box.hpp
similarity index 67%
rename from third_party/osmium/osm/box.hpp
rename to third_party/libosmium/include/osmium/osm/box.hpp
index 2b761fe..631f919 100644
--- a/third_party/osmium/osm/box.hpp
+++ b/third_party/libosmium/include/osmium/osm/box.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <cassert>
#include <iosfwd>
#include <osmium/util/compatibility.hpp>
@@ -41,7 +42,10 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
/**
- * Bounding box.
+ * Bounding box. A box is defined by two locations (bottom left location
+ * and top right location) or, alternatively by four coordinates (minx,
+ * miny, maxx, and maxy). If both locations are undefined, the box is
+ * undefined, too.
*/
class Box {
@@ -59,14 +63,33 @@ namespace osmium {
m_top_right() {
}
+ /**
+ * Create box from minimum and maximum coordinates.
+ *
+ * @pre @code minx <= maxx && miny <= maxy @endcode
+ */
Box(double minx, double miny, double maxx, double maxy) :
m_bottom_left(minx, miny),
m_top_right(maxx, maxy) {
+ assert(minx <= maxx && miny <= maxy);
}
+ /**
+ * Create box from bottom left and top right locations.
+ *
+ * @pre Either both locations must be defined or neither.
+ * @pre If both locations are defined, the
+ * bottom left location must actually be to the left and below
+ * the top right location. Same coordinates for bottom/top or
+ * left/right are also okay.
+ */
Box(const osmium::Location& bottom_left, const osmium::Location& top_right) :
m_bottom_left(bottom_left),
m_top_right(top_right) {
+ assert(
+ (!!bottom_left && !!top_right) ||
+ (bottom_left.x() <= top_right.x() && bottom_left.y() <= top_right.y())
+ );
}
Box(const Box&) = default;
@@ -76,8 +99,13 @@ namespace osmium {
~Box() = default;
/**
- * Extend this bounding box by the given location. If the
- * location is undefined, the bounding box is unchanged.
+ * Extend this bounding box by the specified location. If the
+ * location is undefined, the bounding box is unchanged. If
+ * the box is undefined it will only contain the location after
+ * this call.
+ *
+ * @param location The location we want to extend the box by.
+ * @returns A reference to this box.
*/
Box& extend(const Location& location) noexcept {
if (location) {
@@ -103,8 +131,11 @@ namespace osmium {
}
/**
- * Extend this bounding box by the given box. If the
- * box is undefined, the bounding box is unchanged.
+ * Extend this bounding box by the specified box. If the
+ * specified box is undefined, the bounding box is unchanged.
+ *
+ * @param box The box to extend by.
+ * @returns A reference to this box.
*/
Box& extend(const Box& box) noexcept {
extend(box.bottom_left());
@@ -113,52 +144,58 @@ namespace osmium {
}
/**
- * Box are defined, ie. contains defined coordinates.
+ * Box is defined, ie. contains defined locations.
*/
explicit constexpr operator bool() const noexcept {
return static_cast<bool>(m_bottom_left);
}
/**
- * Box are valid, ie. defined and inside usual bounds
+ * Box is valid, ie. defined and inside usual bounds
* (-180<=lon<=180, -90<=lat<=90).
*/
- constexpr bool valid() const noexcept {
+ OSMIUM_CONSTEXPR bool valid() const noexcept {
return bottom_left().valid() && top_right().valid();
}
/**
- * Bottom-left location.
+ * Access bottom-left location.
*/
OSMIUM_CONSTEXPR Location bottom_left() const noexcept {
return m_bottom_left;
}
/**
- * Bottom-left location.
+ * Access bottom-left location.
*/
Location& bottom_left() noexcept {
return m_bottom_left;
}
/**
- * Top-right location.
+ * Access top-right location.
*/
OSMIUM_CONSTEXPR Location top_right() const noexcept {
return m_top_right;
}
/**
- * Top-right location.
+ * Access top-right location.
*/
Location& top_right() noexcept {
return m_top_right;
}
/**
- * Is the location inside the box?
+ * Check whether the location is inside the box.
+ *
+ * @pre Location must be defined.
+ * @pre Box must be defined.
*/
- bool contains(const osmium::Location& location) const {
+ bool contains(const osmium::Location& location) const noexcept {
+ assert(bottom_left());
+ assert(top_right());
+ assert(location);
return location.x() >= bottom_left().x() && location.y() >= bottom_left().y() &&
location.x() <= top_right().x() && location.y() <= top_right().y();
}
@@ -166,7 +203,7 @@ namespace osmium {
/**
* Calculate size of the box in square degrees.
*
- * @throws osmium::invalid_location unless all coordinates are valid
+ * @throws osmium::invalid_location unless all coordinates are valid.
*/
double size() const {
return (m_top_right.lon() - m_bottom_left.lon()) *
@@ -176,14 +213,19 @@ namespace osmium {
}; // class Box
/**
- * Boxes are equal if both locations are equal.
+ * Boxes are equal if both locations are equal. Undefined boxes will
+ * compare equal.
*/
inline OSMIUM_CONSTEXPR bool operator==(const Box& lhs, const Box& rhs) noexcept {
- return lhs.bottom_left() == rhs.bottom_left() && lhs.top_right() == rhs.top_right();
+ return lhs.bottom_left() == rhs.bottom_left() &&
+ lhs.top_right() == rhs.top_right();
}
/**
- * Output a box to a stream.
+ * Output a box to a stream. The format is "(LON, LAT, LON, LAT)" or
+ * "(undefined)" if the box is undefined.
+ *
+ * @returns Reference to basic_ostream given as first parameter.
*/
template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Box& box) {
@@ -202,6 +244,7 @@ namespace osmium {
}
return out;
}
+
} // namespace osmium
#endif // OSMIUM_OSM_BOX_HPP
diff --git a/third_party/osmium/osm/changeset.hpp b/third_party/libosmium/include/osmium/osm/changeset.hpp
similarity index 98%
rename from third_party/osmium/osm/changeset.hpp
rename to third_party/libosmium/include/osmium/osm/changeset.hpp
index 2b79fb5..0ab4e9b 100644
--- a/third_party/osmium/osm/changeset.hpp
+++ b/third_party/libosmium/include/osmium/osm/changeset.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -298,8 +298,7 @@ namespace osmium {
}; // class Changeset
- static_assert(sizeof(Changeset) % osmium::memory::align_bytes == 0,
- "Class osmium::Changeset has wrong size to be aligned properly!");
+ static_assert(sizeof(Changeset) % osmium::memory::align_bytes == 0, "Class osmium::Changeset has wrong size to be aligned properly!");
/**
* Changesets are equal if their IDs are equal.
diff --git a/third_party/osmium/osm/diff_object.hpp b/third_party/libosmium/include/osmium/osm/diff_object.hpp
similarity index 98%
rename from third_party/osmium/osm/diff_object.hpp
rename to third_party/libosmium/include/osmium/osm/diff_object.hpp
index a8f91ec..55a5cef 100644
--- a/third_party/osmium/osm/diff_object.hpp
+++ b/third_party/libosmium/include/osmium/osm/diff_object.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/osm/entity.hpp b/third_party/libosmium/include/osmium/osm/entity.hpp
similarity index 90%
rename from third_party/osmium/osm/entity.hpp
rename to third_party/libosmium/include/osmium/osm/entity.hpp
index e37ed4c..14861a2 100644
--- a/third_party/osmium/osm/entity.hpp
+++ b/third_party/libosmium/include/osmium/osm/entity.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -34,6 +34,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <osmium/memory/item.hpp>
+#include <osmium/osm/entity_bits.hpp>
namespace osmium {
@@ -67,6 +68,10 @@ namespace osmium {
Item(size, type) {
}
+ bool type_is_in(osmium::osm_entity_bits::type entity_bits) const {
+ return (osm_entity_bits::from_item_type(type()) & entity_bits) != 0;
+ }
+
}; // class OSMEntity
} // namespace osmium
diff --git a/third_party/osmium/osm/entity_bits.hpp b/third_party/libosmium/include/osmium/osm/entity_bits.hpp
similarity index 92%
rename from third_party/osmium/osm/entity_bits.hpp
rename to third_party/libosmium/include/osmium/osm/entity_bits.hpp
index 2a4d964..1c1cb80 100644
--- a/third_party/osmium/osm/entity_bits.hpp
+++ b/third_party/libosmium/include/osmium/osm/entity_bits.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,6 +33,8 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <osmium/osm/item_type.hpp>
+
namespace osmium {
/**
@@ -92,6 +94,10 @@ namespace osmium {
return lhs;
}
+ inline type from_item_type(osmium::item_type item_type) noexcept {
+ return static_cast<osmium::osm_entity_bits::type>(0x1 << (static_cast<uint16_t>(item_type) - 1));
+ }
+
} // namespace osm_entity_bits
} // namespace osmium
diff --git a/third_party/osmium/osm/item_type.hpp b/third_party/libosmium/include/osmium/osm/item_type.hpp
similarity index 98%
rename from third_party/osmium/osm/item_type.hpp
rename to third_party/libosmium/include/osmium/osm/item_type.hpp
index d277e06..c2187a3 100644
--- a/third_party/osmium/osm/item_type.hpp
+++ b/third_party/libosmium/include/osmium/osm/item_type.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/osm/location.hpp b/third_party/libosmium/include/osmium/osm/location.hpp
similarity index 99%
rename from third_party/osmium/osm/location.hpp
rename to third_party/libosmium/include/osmium/osm/location.hpp
index cabecd5..0d4fdc1 100644
--- a/third_party/osmium/osm/location.hpp
+++ b/third_party/libosmium/include/osmium/osm/location.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/osm/node.hpp b/third_party/libosmium/include/osmium/osm/node.hpp
similarity index 97%
rename from third_party/osmium/osm/node.hpp
rename to third_party/libosmium/include/osmium/osm/node.hpp
index 50146c5..123bfc4 100644
--- a/third_party/osmium/osm/node.hpp
+++ b/third_party/libosmium/include/osmium/osm/node.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/osm/node_ref.hpp b/third_party/libosmium/include/osmium/osm/node_ref.hpp
similarity index 96%
rename from third_party/osmium/osm/node_ref.hpp
rename to third_party/libosmium/include/osmium/osm/node_ref.hpp
index ed50b9e..76afa75 100644
--- a/third_party/osmium/osm/node_ref.hpp
+++ b/third_party/libosmium/include/osmium/osm/node_ref.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -54,7 +54,7 @@ namespace osmium {
public:
- NodeRef(const osmium::object_id_type ref=0, const osmium::Location& location=Location()) noexcept :
+ NodeRef(const osmium::object_id_type ref = 0, const osmium::Location& location = Location()) noexcept :
m_ref(ref),
m_location(location) {
}
diff --git a/third_party/osmium/osm/node_ref_list.hpp b/third_party/libosmium/include/osmium/osm/node_ref_list.hpp
similarity index 53%
rename from third_party/osmium/osm/node_ref_list.hpp
rename to third_party/libosmium/include/osmium/osm/node_ref_list.hpp
index 321c952..f0dfedb 100644
--- a/third_party/osmium/osm/node_ref_list.hpp
+++ b/third_party/libosmium/include/osmium/osm/node_ref_list.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -44,51 +44,92 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
/**
- * A vector of NodeRef objects. Usually this is not instatiated directly,
+ * A vector of NodeRef objects. Usually this is not instantiated directly,
* but one of its subclasses are used.
*/
- template <osmium::item_type TItemType>
class NodeRefList : public osmium::memory::Item {
public:
- static constexpr osmium::item_type itemtype = TItemType;
-
- NodeRefList() noexcept :
- osmium::memory::Item(sizeof(NodeRefList), TItemType) {
+ NodeRefList(osmium::item_type itemtype) noexcept :
+ osmium::memory::Item(sizeof(NodeRefList), itemtype) {
}
+ /**
+ * Checks whether the node list is empty.
+ */
bool empty() const noexcept {
return sizeof(NodeRefList) == byte_size();
}
+ /**
+ * Returns the number of nodes in the list.
+ */
size_t size() const noexcept {
- assert((osmium::memory::Item::byte_size() - sizeof(NodeRefList)) % sizeof(NodeRef) == 0);
- return (osmium::memory::Item::byte_size() - sizeof(NodeRefList)) / sizeof(NodeRef);
- }
-
- const NodeRef& operator[](size_t n) const {
+ auto size_node_refs = osmium::memory::Item::byte_size() - sizeof(NodeRefList);
+ assert(size_node_refs % sizeof(NodeRef) == 0);
+ return size_node_refs / sizeof(NodeRef);
+ }
+
+ /**
+ * Access specified element.
+ *
+ * @param n Get this element of the list.
+ * @pre @code n < size() @endcode
+ */
+ const NodeRef& operator[](size_t n) const noexcept {
+ assert(n < size());
const NodeRef* node_ref = &*(cbegin());
return node_ref[n];
}
- const NodeRef& front() const {
+ /**
+ * Access the first element.
+ *
+ * @pre @code !empty() @endcode
+ */
+ const NodeRef& front() const noexcept {
+ assert(!empty());
return operator[](0);
}
- const NodeRef& back() const {
+ /**
+ * Access the last element.
+ *
+ * @pre @code !empty() @endcode
+ */
+ const NodeRef& back() const noexcept {
+ assert(!empty());
return operator[](size()-1);
}
- bool is_closed() const {
+ /**
+ * Checks whether the first and last node in the list have the same ID.
+ *
+ * @pre @code !empty() @endcode
+ */
+ bool is_closed() const noexcept {
return front().ref() == back().ref();
}
- bool ends_have_same_id() const {
+ /**
+ * Checks whether the first and last node in the list have the same ID.
+ *
+ * @pre @code !empty() @endcode
+ */
+ bool ends_have_same_id() const noexcept {
return front().ref() == back().ref();
}
+ /**
+ * Checks whether the first and last node in the list have the same
+ * location. The ID is not checked.
+ *
+ * @pre @code !empty() @endcode
+ * @pre @code front().location() && back().location() @endcode
+ */
bool ends_have_same_location() const {
+ assert(front().location() && back().location());
return front().location() == back().location();
}
@@ -96,35 +137,43 @@ namespace osmium {
typedef const NodeRef* const_iterator;
typedef std::reverse_iterator<const NodeRef*> const_reverse_iterator;
- iterator begin() {
+ /// Returns an iterator to the beginning.
+ iterator begin() noexcept {
return iterator(data() + sizeof(NodeRefList));
}
- iterator end() {
+ /// Returns an iterator to the end.
+ iterator end() noexcept {
return iterator(data() + byte_size());
}
- const_iterator cbegin() const {
+ /// Returns an iterator to the beginning.
+ const_iterator cbegin() const noexcept {
return const_iterator(data() + sizeof(NodeRefList));
}
- const_iterator cend() const {
+ /// Returns an iterator to the end.
+ const_iterator cend() const noexcept {
return const_iterator(data() + byte_size());
}
- const_iterator begin() const {
+ /// Returns an iterator to the beginning.
+ const_iterator begin() const noexcept {
return cbegin();
}
- const_iterator end() const {
+ /// Returns an iterator to the end.
+ const_iterator end() const noexcept {
return cend();
}
- const_reverse_iterator crbegin() const {
+ /// Returns a reverse_iterator to the beginning.
+ const_reverse_iterator crbegin() const noexcept {
return const_reverse_iterator(cend());
}
- const_reverse_iterator crend() const {
+ /// Returns a reverse_iterator to the end.
+ const_reverse_iterator crend() const noexcept {
return const_reverse_iterator(cbegin());
}
diff --git a/third_party/osmium/osm/object.hpp b/third_party/libosmium/include/osmium/osm/object.hpp
similarity index 99%
rename from third_party/osmium/osm/object.hpp
rename to third_party/libosmium/include/osmium/osm/object.hpp
index 9c4d603..d5ae48a 100644
--- a/third_party/osmium/osm/object.hpp
+++ b/third_party/libosmium/include/osmium/osm/object.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/osm/object_comparisons.hpp b/third_party/libosmium/include/osmium/osm/object_comparisons.hpp
similarity index 98%
rename from third_party/osmium/osm/object_comparisons.hpp
rename to third_party/libosmium/include/osmium/osm/object_comparisons.hpp
index db11b0d..bdf99e1 100644
--- a/third_party/osmium/osm/object_comparisons.hpp
+++ b/third_party/libosmium/include/osmium/osm/object_comparisons.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/osm/relation.hpp b/third_party/libosmium/include/osmium/osm/relation.hpp
similarity index 96%
rename from third_party/osmium/osm/relation.hpp
rename to third_party/libosmium/include/osmium/osm/relation.hpp
index f5d0401..e5b42fe 100644
--- a/third_party/osmium/osm/relation.hpp
+++ b/third_party/libosmium/include/osmium/osm/relation.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -101,7 +101,7 @@ namespace osmium {
static constexpr item_type collection_type = item_type::relation_member_list;
- RelationMember(const object_id_type ref=0, const item_type type=item_type(), const bool full=false) noexcept :
+ RelationMember(const object_id_type ref = 0, const item_type type = item_type(), const bool full = false) noexcept :
m_ref(ref),
m_type(type),
m_flags(full ? 1 : 0) {
diff --git a/third_party/osmium/osm/segment.hpp b/third_party/libosmium/include/osmium/osm/segment.hpp
similarity index 98%
rename from third_party/osmium/osm/segment.hpp
rename to third_party/libosmium/include/osmium/osm/segment.hpp
index 205036e..f3a82c9 100644
--- a/third_party/osmium/osm/segment.hpp
+++ b/third_party/libosmium/include/osmium/osm/segment.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/osm/tag.hpp b/third_party/libosmium/include/osmium/osm/tag.hpp
similarity index 98%
rename from third_party/osmium/osm/tag.hpp
rename to third_party/libosmium/include/osmium/osm/tag.hpp
index fe80de3..2e93ede 100644
--- a/third_party/osmium/osm/tag.hpp
+++ b/third_party/libosmium/include/osmium/osm/tag.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/osm/timestamp.hpp b/third_party/libosmium/include/osmium/osm/timestamp.hpp
similarity index 83%
rename from third_party/osmium/osm/timestamp.hpp
rename to third_party/libosmium/include/osmium/osm/timestamp.hpp
index 662b61f..6b6a6e1 100644
--- a/third_party/osmium/osm/timestamp.hpp
+++ b/third_party/libosmium/include/osmium/osm/timestamp.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -101,7 +101,7 @@ namespace osmium {
tm.tm_wday = 0;
tm.tm_yday = 0;
tm.tm_isdst = 0;
- m_timestamp = _mkgmtime(&tm);
+ m_timestamp = static_cast<uint32_t>(_mkgmtime(&tm));
#endif
}
@@ -113,6 +113,10 @@ namespace osmium {
return static_cast<time_t>(m_timestamp);
}
+ explicit constexpr operator uint32_t() const noexcept {
+ return m_timestamp;
+ }
+
template <typename T>
void operator+=(T time_difference) noexcept {
m_timestamp += time_difference;
@@ -127,24 +131,26 @@ namespace osmium {
* Return UTC Unix time as string in ISO date/time format.
*/
std::string to_iso() const {
- if (m_timestamp == 0) {
- return std::string("");
- }
- struct tm tm;
- time_t sse = seconds_since_epoch();
+ std::string s;
+
+ if (m_timestamp != 0) {
+ struct tm tm;
+ time_t sse = seconds_since_epoch();
#ifndef _MSC_VER
- gmtime_r(&sse, &tm);
+ gmtime_r(&sse, &tm);
#else
- gmtime_s(&tm, &sse);
+ gmtime_s(&tm, &sse);
#endif
- std::string s(timestamp_length, '\0');
- /* This const_cast is ok, because we know we have enough space
- in the string for the format we are using (well at least until
- the year will have 5 digits). And by setting the size
- afterwards from the result of strftime we make sure thats set
- right, too. */
- s.resize(strftime(const_cast<char*>(s.c_str()), timestamp_length, timestamp_format(), &tm));
+ s.resize(timestamp_length);
+ /* This const_cast is ok, because we know we have enough space
+ in the string for the format we are using (well at least until
+ the year will have 5 digits). And by setting the size
+ afterwards from the result of strftime we make sure thats set
+ right, too. */
+ s.resize(strftime(const_cast<char*>(s.c_str()), timestamp_length, timestamp_format(), &tm));
+ }
+
return s;
}
diff --git a/third_party/osmium/osm/types.hpp b/third_party/libosmium/include/osmium/osm/types.hpp
similarity index 98%
rename from third_party/osmium/osm/types.hpp
rename to third_party/libosmium/include/osmium/osm/types.hpp
index 532b549..aea61bd 100644
--- a/third_party/osmium/osm/types.hpp
+++ b/third_party/libosmium/include/osmium/osm/types.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/osm/undirected_segment.hpp b/third_party/libosmium/include/osmium/osm/undirected_segment.hpp
similarity index 98%
rename from third_party/osmium/osm/undirected_segment.hpp
rename to third_party/libosmium/include/osmium/osm/undirected_segment.hpp
index 487e7bf..654ef7d 100644
--- a/third_party/osmium/osm/undirected_segment.hpp
+++ b/third_party/libosmium/include/osmium/osm/undirected_segment.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/osm/way.hpp b/third_party/libosmium/include/osmium/osm/way.hpp
similarity index 93%
rename from third_party/osmium/osm/way.hpp
rename to third_party/libosmium/include/osmium/osm/way.hpp
index a30cf91..3c5f1f6 100644
--- a/third_party/osmium/osm/way.hpp
+++ b/third_party/libosmium/include/osmium/osm/way.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -49,12 +49,14 @@ namespace osmium {
/**
* List of node references (id and location) in a way.
*/
- class WayNodeList : public NodeRefList<osmium::item_type::way_node_list> {
+ class WayNodeList : public NodeRefList {
public:
+ static constexpr osmium::item_type itemtype = osmium::item_type::way_node_list;
+
WayNodeList():
- NodeRefList<osmium::item_type::way_node_list>() {
+ NodeRefList(itemtype) {
}
}; // class WayNodeList
diff --git a/third_party/osmium/relations/collector.hpp b/third_party/libosmium/include/osmium/relations/collector.hpp
similarity index 99%
rename from third_party/osmium/relations/collector.hpp
rename to third_party/libosmium/include/osmium/relations/collector.hpp
index 60864d3..e3c4980 100644
--- a/third_party/osmium/relations/collector.hpp
+++ b/third_party/libosmium/include/osmium/relations/collector.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -389,7 +389,7 @@ namespace osmium {
RelationMeta relation_meta(offset);
- int n=0;
+ int n = 0;
for (auto& member : m_relations_buffer.get<osmium::Relation>(offset).members()) {
if (static_cast<TCollector*>(this)->keep_member(relation_meta, member)) {
member_meta(member.type()).emplace_back(member.ref(), m_relations.size(), n);
@@ -509,7 +509,7 @@ namespace osmium {
const size_t size_before = m_members_buffer.committed();
m_members_buffer.purge_removed(this);
const size_t size_after = m_members_buffer.committed();
- double percent = size_before - size_after;
+ double percent = static_cast<double>(size_before - size_after);
percent /= size_before;
percent *= 100;
std::cerr << "PURGE (size before=" << size_before << " after=" << size_after << " purged=" << (size_before - size_after) << " / " << static_cast<int>(percent) << "%)\n";
diff --git a/third_party/osmium/relations/detail/member_meta.hpp b/third_party/libosmium/include/osmium/relations/detail/member_meta.hpp
similarity index 98%
rename from third_party/osmium/relations/detail/member_meta.hpp
rename to third_party/libosmium/include/osmium/relations/detail/member_meta.hpp
index 5463a1c..a45088e 100644
--- a/third_party/osmium/relations/detail/member_meta.hpp
+++ b/third_party/libosmium/include/osmium/relations/detail/member_meta.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/relations/detail/relation_meta.hpp b/third_party/libosmium/include/osmium/relations/detail/relation_meta.hpp
similarity index 98%
rename from third_party/osmium/relations/detail/relation_meta.hpp
rename to third_party/libosmium/include/osmium/relations/detail/relation_meta.hpp
index 77ca0c1..a48c50a 100644
--- a/third_party/osmium/relations/detail/relation_meta.hpp
+++ b/third_party/libosmium/include/osmium/relations/detail/relation_meta.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/tags/filter.hpp b/third_party/libosmium/include/osmium/tags/filter.hpp
similarity index 92%
rename from third_party/osmium/tags/filter.hpp
rename to third_party/libosmium/include/osmium/tags/filter.hpp
index 0a0fd3b..3c1946c 100644
--- a/third_party/osmium/tags/filter.hpp
+++ b/third_party/libosmium/include/osmium/tags/filter.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -135,6 +135,20 @@ namespace osmium {
return m_default_result;
}
+ /**
+ * Return the number of rules in this filter.
+ */
+ size_t count() const {
+ return m_rules.count();
+ }
+
+ /**
+ * Is this filter empty, ie are there no rules defined?
+ */
+ bool empty() const {
+ return m_rules.empty();
+ }
+
}; // class Filter
typedef Filter<std::string, std::string> KeyValueFilter;
diff --git a/third_party/osmium/tags/regex_filter.hpp b/third_party/libosmium/include/osmium/tags/regex_filter.hpp
similarity index 96%
rename from third_party/osmium/tags/regex_filter.hpp
rename to third_party/libosmium/include/osmium/tags/regex_filter.hpp
index ae2703a..725c423 100644
--- a/third_party/osmium/tags/regex_filter.hpp
+++ b/third_party/libosmium/include/osmium/tags/regex_filter.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/tags/taglist.hpp b/third_party/libosmium/include/osmium/tags/taglist.hpp
similarity index 85%
rename from third_party/osmium/tags/taglist.hpp
rename to third_party/libosmium/include/osmium/tags/taglist.hpp
index 41ef993..d7c78dc 100644
--- a/third_party/osmium/tags/taglist.hpp
+++ b/third_party/libosmium/include/osmium/tags/taglist.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -47,17 +47,17 @@ namespace osmium {
template <class TFilter>
inline bool match_any_of(const osmium::TagList& tag_list, TFilter&& filter) {
- return std::any_of(tag_list.begin(), tag_list.end(), std::forward<TFilter>(filter));
+ return std::any_of(tag_list.cbegin(), tag_list.cend(), std::forward<TFilter>(filter));
}
template <class TFilter>
inline bool match_all_of(const osmium::TagList& tag_list, TFilter&& filter) {
- return std::all_of(tag_list.begin(), tag_list.end(), std::forward<TFilter>(filter));
+ return std::all_of(tag_list.cbegin(), tag_list.cend(), std::forward<TFilter>(filter));
}
template <class TFilter>
inline bool match_none_of(const osmium::TagList& tag_list, TFilter&& filter) {
- return std::none_of(tag_list.begin(), tag_list.end(), std::forward<TFilter>(filter));
+ return std::none_of(tag_list.cbegin(), tag_list.cend(), std::forward<TFilter>(filter));
}
} // namespace tags
diff --git a/third_party/osmium/thread/function_wrapper.hpp b/third_party/libosmium/include/osmium/thread/function_wrapper.hpp
similarity index 96%
rename from third_party/osmium/thread/function_wrapper.hpp
rename to third_party/libosmium/include/osmium/thread/function_wrapper.hpp
index dbb47ff..fe0a492 100644
--- a/third_party/osmium/thread/function_wrapper.hpp
+++ b/third_party/libosmium/include/osmium/thread/function_wrapper.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -94,9 +94,10 @@ namespace osmium {
}
function_wrapper(const function_wrapper&) = delete;
- function_wrapper(function_wrapper&) = delete;
function_wrapper& operator=(const function_wrapper&) = delete;
+ ~function_wrapper() = default;
+
explicit operator bool() const {
return static_cast<bool>(impl);
}
diff --git a/third_party/osmium/thread/pool.hpp b/third_party/libosmium/include/osmium/thread/pool.hpp
similarity index 95%
rename from third_party/osmium/thread/pool.hpp
rename to third_party/libosmium/include/osmium/thread/pool.hpp
index 702be66..87dd1fb 100644
--- a/third_party/osmium/thread/pool.hpp
+++ b/third_party/libosmium/include/osmium/thread/pool.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -128,7 +128,7 @@ namespace osmium {
}
try {
- for (int i=0; i < m_num_threads; ++i) {
+ for (int i = 0; i < m_num_threads; ++i) {
m_threads.push_back(std::thread(&Pool::worker_thread, this));
}
} catch (...) {
@@ -160,11 +160,11 @@ namespace osmium {
}
template <typename TFunction>
- std::future<typename std::result_of<TFunction()>::type> submit(TFunction f) {
+ std::future<typename std::result_of<TFunction()>::type> submit(TFunction&& func) {
typedef typename std::result_of<TFunction()>::type result_type;
- std::packaged_task<result_type()> task(std::move(f));
+ std::packaged_task<result_type()> task(std::forward<TFunction>(func));
std::future<result_type> future_result(task.get_future());
m_work_queue.push(std::move(task));
diff --git a/third_party/osmium/thread/queue.hpp b/third_party/libosmium/include/osmium/thread/queue.hpp
similarity index 93%
rename from third_party/osmium/thread/queue.hpp
rename to third_party/libosmium/include/osmium/thread/queue.hpp
index b01dd39..baaf2dc 100644
--- a/third_party/osmium/thread/queue.hpp
+++ b/third_party/libosmium/include/osmium/thread/queue.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -39,14 +39,17 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <mutex>
#include <queue>
+#include <string>
#include <thread>
#include <utility>
+#include <osmium/util/compatibility.hpp>
+
namespace osmium {
namespace thread {
- constexpr std::chrono::milliseconds full_queue_sleep_duration { 10 }; // XXX
+ static const std::chrono::milliseconds full_queue_sleep_duration { 10 }; // XXX
/**
* A thread-safe queue.
@@ -134,7 +137,7 @@ namespace osmium {
m_data_available.wait(lock, [this] {
return !m_queue.empty();
});
- value=std::move(m_queue.front());
+ value = std::move(m_queue.front());
m_queue.pop();
}
@@ -145,7 +148,7 @@ namespace osmium {
})) {
return;
}
- value=std::move(m_queue.front());
+ value = std::move(m_queue.front());
m_queue.pop();
}
@@ -154,7 +157,7 @@ namespace osmium {
if (m_queue.empty()) {
return false;
}
- value=std::move(m_queue.front());
+ value = std::move(m_queue.front());
m_queue.pop();
return true;
}
diff --git a/third_party/osmium/thread/sorted_queue.hpp b/third_party/libosmium/include/osmium/thread/sorted_queue.hpp
similarity index 96%
rename from third_party/osmium/thread/sorted_queue.hpp
rename to third_party/libosmium/include/osmium/thread/sorted_queue.hpp
index e33dfe6..e76ade1 100644
--- a/third_party/osmium/thread/sorted_queue.hpp
+++ b/third_party/libosmium/include/osmium/thread/sorted_queue.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -107,7 +107,7 @@ namespace osmium {
m_data_available.wait(lock, [this] {
return !empty_intern();
});
- value=std::move(m_queue.front());
+ value = std::move(m_queue.front());
m_queue.pop_front();
++m_offset;
}
@@ -122,7 +122,7 @@ namespace osmium {
if (empty_intern()) {
return false;
}
- value=std::move(m_queue.front());
+ value = std::move(m_queue.front());
m_queue.pop_front();
++m_offset;
return true;
diff --git a/third_party/osmium/thread/util.hpp b/third_party/libosmium/include/osmium/thread/util.hpp
similarity index 97%
rename from third_party/osmium/thread/util.hpp
rename to third_party/libosmium/include/osmium/thread/util.hpp
index 286ea5e..62bb82a 100644
--- a/third_party/osmium/thread/util.hpp
+++ b/third_party/libosmium/include/osmium/thread/util.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/libosmium/include/osmium/util/cast.hpp b/third_party/libosmium/include/osmium/util/cast.hpp
new file mode 100644
index 0000000..4866fde
--- /dev/null
+++ b/third_party/libosmium/include/osmium/util/cast.hpp
@@ -0,0 +1,103 @@
+#ifndef OSMIUM_UTIL_CAST_HPP
+#define OSMIUM_UTIL_CAST_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
+
+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.
+
+*/
+
+#ifndef assert
+# include <cassert>
+#endif
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+namespace osmium {
+
+ // These functions are wrappers around static_cast<>() that call assert()
+ // to check that there is no integer overflow happening before doing the
+ // cast. There are several versions of this templated function here
+ // depending on the types of the input and output. In any case, both input
+ // and output have to be integral types. If the cast can't overflow, no
+ // check is done.
+
+ template <typename A, typename B>
+ struct are_real_integers :
+ std::integral_constant<bool,
+ std::is_integral<A>::value &&
+ std::is_integral<B>::value &&
+ !std::is_same<A, bool>::value &&
+ !std::is_same<B, bool>::value> {
+ };
+
+ template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && std::is_same<T, F>::value, int>::type = 0>
+ inline T static_cast_with_assert(const F value) {
+ return value;
+ }
+
+ template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && (sizeof(T) > sizeof(F)), int>::type = 0>
+ inline T static_cast_with_assert(const F value) {
+ return static_cast<T>(value);
+ }
+
+ template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && std::is_signed<T>::value == std::is_signed<F>::value && (sizeof(T) == sizeof(F)), int>::type = 0>
+ inline T static_cast_with_assert(const F value) {
+ return static_cast<T>(value);
+ }
+
+ template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && (sizeof(T) < sizeof(F)) && std::is_signed<T>::value && std::is_signed<F>::value, int>::type = 0>
+ inline T static_cast_with_assert(const F value) {
+ assert(value >= std::numeric_limits<T>::min() && value <= std::numeric_limits<T>::max());
+ return static_cast<T>(value);
+ }
+
+ template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && (sizeof(T) <= sizeof(F)) && std::is_unsigned<T>::value && std::is_signed<F>::value, int>::type = 0>
+ inline T static_cast_with_assert(const F value) {
+ assert(value >= 0 && static_cast<typename std::make_unsigned<F>::type>(value) <= std::numeric_limits<T>::max());
+ return static_cast<T>(value);
+ }
+
+ template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && (sizeof(T) < sizeof(F)) && std::is_unsigned<T>::value && std::is_unsigned<F>::value, int>::type = 0>
+ inline T static_cast_with_assert(const F value) {
+ assert(value <= std::numeric_limits<T>::max());
+ return static_cast<T>(value);
+ }
+
+ template <typename T, typename F, typename std::enable_if<are_real_integers<T, F>::value && !std::is_same<T, F>::value && (sizeof(T) <= sizeof(F)) && std::is_signed<T>::value && std::is_unsigned<F>::value, int>::type = 0>
+ inline T static_cast_with_assert(const F value) {
+ assert(static_cast<int64_t>(value) <= static_cast<int64_t>(std::numeric_limits<T>::max()));
+ return static_cast<T>(value);
+ }
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_CAST_HPP
diff --git a/third_party/osmium/util/compatibility.hpp b/third_party/libosmium/include/osmium/util/compatibility.hpp
similarity index 96%
rename from third_party/osmium/util/compatibility.hpp
rename to third_party/libosmium/include/osmium/util/compatibility.hpp
index 48a6db0..90d85c5 100644
--- a/third_party/osmium/util/compatibility.hpp
+++ b/third_party/libosmium/include/osmium/util/compatibility.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/util/config.hpp b/third_party/libosmium/include/osmium/util/config.hpp
similarity index 94%
rename from third_party/osmium/util/config.hpp
rename to third_party/libosmium/include/osmium/util/config.hpp
index 6c86d68..3285eed 100644
--- a/third_party/osmium/util/config.hpp
+++ b/third_party/libosmium/include/osmium/util/config.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -36,9 +36,8 @@ DEALINGS IN THE SOFTWARE.
#include <cstdlib>
#include <cstring>
-#ifdef _MSC_VER
-#define strncasecmp _strnicmp
-#define strcasecmp _stricmp
+#ifdef _MSC_VER
+# define strcasecmp _stricmp
#endif
namespace osmium {
diff --git a/third_party/osmium/util/double.hpp b/third_party/libosmium/include/osmium/util/double.hpp
similarity index 96%
rename from third_party/osmium/util/double.hpp
rename to third_party/libosmium/include/osmium/util/double.hpp
index 91f4ac7..85a2508 100644
--- a/third_party/osmium/util/double.hpp
+++ b/third_party/libosmium/include/osmium/util/double.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -37,6 +37,8 @@ DEALINGS IN THE SOFTWARE.
#include <cassert>
#include <cmath>
#include <cstdio>
+#include <iterator>
+#include <string>
namespace osmium {
diff --git a/third_party/osmium/util/options.hpp b/third_party/libosmium/include/osmium/util/options.hpp
similarity index 98%
rename from third_party/osmium/util/options.hpp
rename to third_party/libosmium/include/osmium/util/options.hpp
index fc74980..fea0752 100644
--- a/third_party/osmium/util/options.hpp
+++ b/third_party/libosmium/include/osmium/util/options.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/osmium/diff_handler.hpp b/third_party/libosmium/include/osmium/util/string.hpp
similarity index 61%
rename from third_party/osmium/diff_handler.hpp
rename to third_party/libosmium/include/osmium/util/string.hpp
index 9864df5..54eb361 100644
--- a/third_party/osmium/diff_handler.hpp
+++ b/third_party/libosmium/include/osmium/util/string.hpp
@@ -1,11 +1,11 @@
-#ifndef OSMIUM_DIFF_HANDLER_HPP
-#define OSMIUM_DIFF_HANDLER_HPP
+#ifndef OSMIUM_UTIL_STRING_HPP
+#define OSMIUM_UTIL_STRING_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -33,35 +33,36 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <osmium/osm/diff_object.hpp>
+#include <string>
+#include <vector>
+#include <iostream>
namespace osmium {
/**
- * @brief Osmium diff handlers provide access to differences between OSM object versions
+ * Split string on the separator character.
+ *
+ * @param str The string to be split.
+ * @param sep The separastor character.
+ * @returns Vector with the parts of the string split up.
*/
- namespace diff_handler {
-
- class DiffHandler {
-
- public:
-
- DiffHandler() {
- }
-
- void node(const osmium::DiffNode&) const {
+ inline std::vector<std::string> split_string(const std::string& str, const char sep) {
+ std::vector<std::string> tokens;
+
+ if (!str.empty()) {
+ size_t pos = 0;
+ size_t nextpos = str.find_first_of(sep);
+ while (nextpos != std::string::npos) {
+ tokens.push_back(str.substr(pos, nextpos-pos));
+ pos = nextpos + 1;
+ nextpos = str.find_first_of(sep, pos);
}
+ tokens.push_back(str.substr(pos));
+ }
- void way(const osmium::DiffWay&) const {
- }
-
- void relation(const osmium::DiffRelation&) const {
- }
-
- }; // class DiffHandler
-
- } // namespace diff_handler
+ return tokens;
+ }
} // namespace osmium
-#endif // OSMIUM_DIFF_HANDLER_HPP
+#endif // OSMIUM_UTIL_STRING_HPP
diff --git a/third_party/osmium/util/verbose_output.hpp b/third_party/libosmium/include/osmium/util/verbose_output.hpp
similarity index 97%
rename from third_party/osmium/util/verbose_output.hpp
rename to third_party/libosmium/include/osmium/util/verbose_output.hpp
index 8709441..249d67f 100644
--- a/third_party/osmium/util/verbose_output.hpp
+++ b/third_party/libosmium/include/osmium/util/verbose_output.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
@@ -87,7 +87,7 @@ namespace osmium {
public:
- explicit VerboseOutput(bool verbose=false) noexcept :
+ explicit VerboseOutput(bool verbose = false) noexcept :
m_start(time(NULL)),
m_verbose(verbose),
m_newline(true) {
diff --git a/third_party/osmium/visitor.hpp b/third_party/libosmium/include/osmium/visitor.hpp
similarity index 99%
rename from third_party/osmium/visitor.hpp
rename to third_party/libosmium/include/osmium/visitor.hpp
index d71a2e0..0250f11 100644
--- a/third_party/osmium/visitor.hpp
+++ b/third_party/libosmium/include/osmium/visitor.hpp
@@ -5,7 +5,7 @@
This file is part of Osmium (http://osmcode.org/libosmium).
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
+Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
diff --git a/third_party/libosmium/osmium.imp b/third_party/libosmium/osmium.imp
new file mode 100644
index 0000000..c45794d
--- /dev/null
+++ b/third_party/libosmium/osmium.imp
@@ -0,0 +1,11 @@
+#-----------------------------------------------------------------------------
+#
+# Configuration for Include-What-You-Use tool
+#
+# https://code.google.com/p/include-what-you-use/
+#
+#-----------------------------------------------------------------------------
+[
+ { "include": ["<bits/fcntl-linux.h>", "private", "<fcntl.h>", "public"] },
+ { "include": ["<sys/types.h>", "public", "<cstdint>", "public"] }
+]
diff --git a/third_party/libosmium/test/CMakeLists.txt b/third_party/libosmium/test/CMakeLists.txt
new file mode 100644
index 0000000..7ba455b
--- /dev/null
+++ b/third_party/libosmium/test/CMakeLists.txt
@@ -0,0 +1,165 @@
+#-----------------------------------------------------------------------------
+#
+# CMake Config
+#
+# Libosmium unit tests
+#
+#-----------------------------------------------------------------------------
+
+message(STATUS "Configuring unit tests")
+
+include(CMakeParseArguments)
+include_directories(include)
+
+add_library(testlib STATIC test_main.cpp)
+
+set(ALL_TESTS "")
+
+
+#-----------------------------------------------------------------------------
+#
+# Define function for adding tests
+#
+# add_unit_tests(group name [ENABLE_IF bool] [LIBS libs] [LABELS labels])
+#
+# group - test group (directory)
+# name - name of test
+# bool - boolean variable telling whether the test should be run (optional)
+# libs - lib or libs that should be used when compiling test (optional)
+# labels - additional labels this test should get (optional)
+#
+#-----------------------------------------------------------------------------
+function(add_unit_test _tgroup _tname)
+ set(_testid "${_tgroup}_${_tname}")
+ set(_tpath "${_tgroup}/${_tname}")
+
+ set(ALL_TESTS "${ALL_TESTS};${_tpath}" PARENT_SCOPE)
+
+ cmake_parse_arguments(_param "" "ENABLE_IF" "LIBS;LABELS" ${ARGN})
+
+ if(Osmium_DEBUG)
+ message("${_testid} ENABLE_IF=[${_param_ENABLE_IF}] LIBS=[${_param_LIBS}] LABELS=[${_param_LABELS}]")
+ endif()
+
+ if((NOT(DEFINED _param_ENABLE_IF)) OR (_param_ENABLE_IF))
+ if(Osmium_DEBUG)
+ message("Adding test: ${_tpath}")
+ endif()
+ add_executable(${_testid} t/${_tpath}.cpp)
+ target_link_libraries(${_testid} testlib)
+
+ if(DEFINED _param_LIBS)
+ if(Osmium_DEBUG)
+ message(" Adding libs: ${_param_LIBS}")
+ endif()
+ target_link_libraries(${_testid} ${_param_LIBS})
+ endif()
+
+ add_test(NAME ${_testid}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${_testid}
+ )
+
+ set(_labels "unit;fast;${_tgroup}")
+ if(DEFINED _param_LABELS)
+ if(Osmium_DEBUG)
+ message(" Adding labels: ${_param_LABELS}")
+ endif()
+ set(_labels "${_labels};${_param_LABELS}")
+ endif()
+
+ set_tests_properties(${_testid} PROPERTIES
+ LABELS "${_labels}"
+ ENVIRONMENT "OSMIUM_TEST_DATA_DIR=${CMAKE_CURRENT_SOURCE_DIR}"
+ )
+ else()
+ message("Skipped test ${_tpath} because a dependency was not found")
+ set(OSMIUM_SKIPPED_TESTS
+ "${OSMIUM_SKIPPED_TESTS} ${_tpath}"
+ CACHE STRING "Tests that were skipped because of missing dependecies")
+ endif()
+endfunction()
+
+#-----------------------------------------------------------------------------
+#
+# Add all tests.
+#
+#-----------------------------------------------------------------------------
+add_unit_test(area test_area_id)
+add_unit_test(area test_node_ref_segment)
+
+add_unit_test(basic test_box)
+add_unit_test(basic test_changeset)
+add_unit_test(basic test_entity_bits)
+add_unit_test(basic test_location)
+add_unit_test(basic test_node)
+add_unit_test(basic test_node_ref)
+add_unit_test(basic test_object_comparisons)
+add_unit_test(basic test_relation)
+add_unit_test(basic test_timestamp)
+add_unit_test(basic test_way)
+
+add_unit_test(buffer test_buffer_node)
+add_unit_test(buffer test_buffer_purge)
+
+if(GEOS_FOUND AND PROJ_FOUND)
+ set(GEOS_AND_PROJ_FOUND TRUE)
+else()
+ set(GEOS_AND_PROJ_FOUND FALSE)
+endif()
+add_unit_test(geom test_factory_with_projection
+ ENABLE_IF ${GEOS_AND_PROJ_FOUND}
+ LIBS ${GEOS_LIBRARY} ${PROJ_LIBRARY})
+
+add_unit_test(geom test_geojson)
+add_unit_test(geom test_geos ENABLE_IF ${GEOS_FOUND} LIBS ${GEOS_LIBRARY})
+add_unit_test(geom test_geos_wkb ENABLE_IF ${GEOS_FOUND} LIBS ${GEOS_LIBRARY})
+add_unit_test(geom test_mercator)
+add_unit_test(geom test_ogr ENABLE_IF ${GDAL_FOUND} LIBS ${GDAL_LIBRARY})
+add_unit_test(geom test_projection ENABLE_IF ${PROJ_FOUND} LIBS ${PROJ_LIBRARY})
+add_unit_test(geom test_wkb)
+add_unit_test(geom test_wkt)
+
+add_unit_test(index test_id_to_location ENABLE_IF ${SPARSEHASH_FOUND})
+add_unit_test(index test_typed_mmap)
+add_unit_test(index test_typed_mmap_grow LABELS "fails_on_windows")
+
+add_unit_test(io test_bzip2 ENABLE_IF ${BZIP2_FOUND} LIBS ${BZIP2_LIBRARIES})
+add_unit_test(io test_file_formats)
+add_unit_test(io test_reader LIBS "${OSMIUM_XML_LIBRARIES}")
+add_unit_test(io test_output_iterator ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT})
+
+add_unit_test(tags test_filter)
+add_unit_test(tags test_operators)
+add_unit_test(tags test_tag_list)
+
+add_unit_test(thread test_pool ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT})
+
+add_unit_test(util test_cast_with_assert)
+add_unit_test(util test_double)
+add_unit_test(util test_options)
+add_unit_test(util test_string)
+
+
+#-----------------------------------------------------------------------------
+#
+# Check that all tests available in test/t/*/test_*.cpp are run.
+#
+#-----------------------------------------------------------------------------
+file(GLOB TESTS_IN_DIR RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/t" t/*/test_*.cpp)
+
+foreach(file ${TESTS_IN_DIR})
+ string(REPLACE ".cpp" "" out1 ${file})
+ string(REPLACE "//" "/" tname ${out1})
+ list(FIND ALL_TESTS ${tname} found)
+ if(${found} EQUAL -1)
+ message(WARNING "Test '${tname}' not found in cmake config. It will not be run!")
+ endif()
+endforeach()
+
+
+#-----------------------------------------------------------------------------
+message(STATUS "Configuring unit tests - done")
+
+
+#-----------------------------------------------------------------------------
diff --git a/third_party/libosmium/test/README b/third_party/libosmium/test/README
new file mode 100644
index 0000000..8195824
--- /dev/null
+++ b/third_party/libosmium/test/README
@@ -0,0 +1,13 @@
+Osmium uses Catch (https://github.com/philsquared/Catch/) for its unit tests.
+
+Only one header file is needed (catch.hpp) which can be downloaded from
+http://builds.catch-lib.net/ and put into the include directory.
+
+Osmium needs a few changes to catch.hpp, they were patched in. To be able to
+compare with the original version, it is stored in include/catch_orig.hpp.
+
+Changes are:
+* Disable more warnings in GCC
+* CATCH_CONFIG_CPP11_NULLPTR must be set for MSVC
+* Problem with test running in loop: https://github.com/philsquared/Catch/issues/271
+
diff --git a/third_party/libosmium/test/data-tests/.gitignore b/third_party/libosmium/test/data-tests/.gitignore
new file mode 100644
index 0000000..98df22e
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/.gitignore
@@ -0,0 +1 @@
+multipolygon.qgs~
diff --git a/third_party/libosmium/test/data-tests/CMakeLists.txt b/third_party/libosmium/test/data-tests/CMakeLists.txt
new file mode 100644
index 0000000..89aead9
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/CMakeLists.txt
@@ -0,0 +1,118 @@
+#-----------------------------------------------------------------------------
+#
+# CMake Config
+#
+# Libosmium data tests
+#
+#-----------------------------------------------------------------------------
+
+message(STATUS "Configuring data tests")
+
+if(NOT GDAL_FOUND OR NOT EXPAT_FOUND)
+ message(STATUS "Sorry, building data tests needs GDAL and Expat")
+ message(STATUS "Configuring data tests - failed")
+ return()
+endif()
+
+message(STATUS "Looking for osm-testdata")
+find_path(OSM_TESTDATA grid/data/all.osm HINT ../../../osm-testdata)
+if(OSM_TESTDATA STREQUAL "OSM_TESTDATA-NOTFOUND")
+ message(STATUS "Looking for osm-testdata - not found (data tests disabled)")
+ message(STATUS "Configuring data tests - failed")
+ return()
+endif()
+message(STATUS "Looking for osm-testdata - found")
+
+
+#-----------------------------------------------------------------------------
+
+include_directories("include")
+include_directories("../include")
+
+
+#-----------------------------------------------------------------------------
+#
+# testcases
+#
+#-----------------------------------------------------------------------------
+file(GLOB TESTCASE_CPPS testcases/*.cpp)
+add_executable(testdata-testcases testdata-testcases.cpp ${TESTCASE_CPPS})
+target_link_libraries(testdata-testcases
+ ${OSMIUM_XML_LIBRARIES}
+)
+add_test(NAME testdata-testcases
+ COMMAND testdata-testcases
+)
+set_tests_properties(testdata-testcases PROPERTIES
+ ENVIRONMENT "TESTCASES_DIR=${OSM_TESTDATA}/grid/data"
+ LABELS "data;fast")
+
+
+#-----------------------------------------------------------------------------
+#
+# xml
+#
+#-----------------------------------------------------------------------------
+add_executable(testdata-xml testdata-xml.cpp)
+target_link_libraries(testdata-xml
+ ${OSMIUM_XML_LIBRARIES}
+)
+add_test(NAME testdata-xml
+ COMMAND testdata-xml
+)
+set_tests_properties(testdata-xml PROPERTIES
+ ENVIRONMENT "TESTDIR=${OSM_TESTDATA}/xml/data"
+ LABELS "data;fast")
+
+
+#-----------------------------------------------------------------------------
+#
+# overview
+#
+#-----------------------------------------------------------------------------
+add_executable(testdata-overview testdata-overview.cpp)
+target_link_libraries(testdata-overview
+ ${OSMIUM_XML_LIBRARIES}
+ ${GDAL_LIBRARIES}
+)
+add_test(NAME testdata-overview
+ COMMAND testdata-overview ${OSM_TESTDATA}/grid/data/all.osm
+)
+set_tests_properties(testdata-overview PROPERTIES
+ LABELS "data;slow")
+
+
+#-----------------------------------------------------------------------------
+#
+# multipolygon
+#
+#-----------------------------------------------------------------------------
+
+find_package(Ruby 1.9)
+find_package(Gem COMPONENTS json)
+find_program(SPATIALITE spatialite)
+
+if(RUBY_FOUND AND GEM_json_FOUND AND SPATIALITE)
+ add_executable(testdata-multipolygon testdata-multipolygon.cpp)
+ target_link_libraries(testdata-multipolygon
+ ${OSMIUM_XML_LIBRARIES}
+ ${GDAL_LIBRARIES}
+ )
+
+ add_test(NAME testdata-multipolygon
+ COMMAND ${CMAKE_COMMAND}
+ -D OSM_TESTDATA=${OSM_TESTDATA}
+ -D RUBY=${RUBY_EXECUTABLE}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/run-testdata-multipolygon.cmake)
+
+ set_tests_properties(testdata-multipolygon PROPERTIES LABELS "data;slow")
+else()
+ message(WARNING "Disabled testdata-multipolygon test because 'ruby' and/or 'json' ruby gem and/or 'spatialite' was not found")
+endif()
+
+
+#-----------------------------------------------------------------------------
+message(STATUS "Configuring data tests - done")
+
+
+#-----------------------------------------------------------------------------
diff --git a/third_party/libosmium/test/data-tests/README.md b/third_party/libosmium/test/data-tests/README.md
new file mode 100644
index 0000000..5138bf8
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/README.md
@@ -0,0 +1,10 @@
+# OSM Testdata
+
+This directory contains software that can be used with the osm-testdata
+repository at https://github.com/osmcode/osm-testdata . To use it, clone
+the `osm-testdata` repository in the same directory where you cloned the
+`libosmium` repository.
+
+Tests will be built if the CMake option `BUILD_DATA_TESTS` is set and run as
+part of the `ctest` run.
+
diff --git a/third_party/libosmium/test/data-tests/include/check_basics_handler.hpp b/third_party/libosmium/test/data-tests/include/check_basics_handler.hpp
new file mode 100644
index 0000000..757ab4d
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/include/check_basics_handler.hpp
@@ -0,0 +1,92 @@
+#ifndef CHECK_BASICS_HANDLER_HPP
+#define CHECK_BASICS_HANDLER_HPP
+
+#include <iostream>
+#include <unordered_set>
+
+#include <osmium/handler.hpp>
+#include <osmium/osm.hpp>
+
+/**
+ * Check some basics of the input data:
+ *
+ * 1. Correct number of nodes, ways, and relations
+ * 2. Correct ID space used by nodes, ways, and relations
+ * 3. No ID used more than once
+ */
+class CheckBasicsHandler : public osmium::handler::Handler {
+
+ // Lower bound for the id range allowed in this test.
+ int m_id_range;
+
+ // In the beginning these contains the number of nodes, ways, and relations
+ // supposedly in the data.osm file. They will be decremented on each object
+ // and have to be 0 at the end.
+ int m_num_nodes;
+ int m_num_ways;
+ int m_num_relations;
+
+ // All IDs encountered in the data.osm file will be stored in this set and
+ // checked for duplicates.
+ std::unordered_set<osmium::object_id_type> m_ids;
+
+ // Check id is in range [min, max] and that it isn't more than once in input.
+ void id_check(osmium::object_id_type id, osmium::object_id_type min, osmium::object_id_type max) {
+ if (id < m_id_range + min || id > m_id_range + max) {
+ std::cerr << " id " << id << " out of range for this test case\n";
+ exit(1);
+ }
+
+ auto r = m_ids.insert(id);
+ if (!r.second) {
+ std::cerr << " id " << id << " contained twice in data.osm\n";
+ exit(1);
+ }
+ }
+
+public:
+
+ static const int ids_per_testcase = 1000;
+
+ CheckBasicsHandler(int testcase, int nodes, int ways, int relations) :
+ osmium::handler::Handler(),
+ m_id_range(testcase * ids_per_testcase),
+ m_num_nodes(nodes),
+ m_num_ways(ways),
+ m_num_relations(relations) {
+ }
+
+ ~CheckBasicsHandler() {
+ if (m_num_nodes != 0) {
+ std::cerr << " wrong number of nodes in data.osm\n";
+ exit(1);
+ }
+ if (m_num_ways != 0) {
+ std::cerr << " wrong number of ways in data.osm\n";
+ exit(1);
+ }
+ if (m_num_relations != 0) {
+ std::cerr << " wrong number of relations in data.osm\n";
+ exit(1);
+ }
+ }
+
+ void node(const osmium::Node& node) {
+ id_check(node.id(), 0, 799);
+ --m_num_nodes;
+ }
+
+ void way(const osmium::Way& way) {
+ id_check(way.id(), 800, 899);
+ --m_num_ways;
+ }
+
+ void relations(const osmium::Relation& relation) {
+ id_check(relation.id(), 900, 999);
+ --m_num_relations;
+ }
+
+}; // CheckBasicsHandler
+
+
+#endif // CHECK_BASICS_HANDLER_HPP
diff --git a/third_party/libosmium/test/data-tests/include/check_wkt_handler.hpp b/third_party/libosmium/test/data-tests/include/check_wkt_handler.hpp
new file mode 100644
index 0000000..fe0199e
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/include/check_wkt_handler.hpp
@@ -0,0 +1,86 @@
+#ifndef CHECK_WKT_HANDLER_HPP
+#define CHECK_WKT_HANDLER_HPP
+
+#include <cassert>
+#include <fstream>
+#include <map>
+#include <sstream>
+#include <string>
+
+#include <osmium/handler.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/types.hpp>
+
+class CheckWKTHandler : public osmium::handler::Handler {
+
+ std::map<osmium::object_id_type, std::string> m_geometries;
+ osmium::geom::WKTFactory<> m_factory;
+
+ void read_wkt_file(const std::string& filename) {
+ std::ifstream in(filename, std::ifstream::in);
+ if (in) {
+ osmium::object_id_type id;
+ std::string line;
+ while (std::getline(in, line)) {
+ size_t pos = line.find_first_of(' ');
+
+ if (pos == std::string::npos) {
+ std::cerr << filename << " not formatted correctly\n";
+ exit(1);
+ }
+
+ std::string id_str = line.substr(0, pos);
+ std::istringstream iss(id_str);
+ iss >> id;
+
+ if (m_geometries.find(id) != m_geometries.end()) {
+ std::cerr << filename + " contains id " << id << "twice\n";
+ exit(1);
+ }
+
+ m_geometries[id] = line.substr(pos+1);
+ }
+ }
+ }
+
+public:
+
+ CheckWKTHandler(const std::string& dirname, int test_id) :
+ osmium::handler::Handler() {
+
+ std::string filename = dirname + "/" + std::to_string(test_id / 100) + "/" + std::to_string(test_id) + "/";
+ read_wkt_file(filename + "nodes.wkt");
+ read_wkt_file(filename + "ways.wkt");
+ }
+
+ ~CheckWKTHandler() {
+ if (!m_geometries.empty()) {
+ for (const auto& geom : m_geometries) {
+ std::cerr << "geometry id " << geom.first << " not in data.osm.\n";
+ }
+ exit(1);
+ }
+ }
+
+ void node(const osmium::Node& node) {
+ const std::string wkt = m_geometries[node.id()];
+ assert(wkt != "" && "Missing geometry for node in nodes.wkt");
+
+ std::string this_wkt = m_factory.create_point(node.location());
+ assert(wkt == this_wkt && "wkt geometries don't match");
+ m_geometries.erase(node.id());
+ }
+
+ void way(const osmium::Way& way) {
+ const std::string wkt = m_geometries[way.id()];
+ assert(wkt != "" && "Missing geometry for way in ways.wkt");
+
+ std::string this_wkt = m_factory.create_linestring(way);
+ assert(wkt == this_wkt && "wkt geometries don't match");
+ m_geometries.erase(way.id());
+ }
+
+}; // CheckWKTHandler
+
+
+#endif // CHECK_WKT_HANDLER_HPP
diff --git a/third_party/libosmium/test/data-tests/include/common.hpp b/third_party/libosmium/test/data-tests/include/common.hpp
new file mode 100644
index 0000000..a6fd3df
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/include/common.hpp
@@ -0,0 +1,22 @@
+#ifndef COMMON_HPP
+#define COMMON_HPP
+
+#include <osmium/index/map/dummy.hpp>
+#include <osmium/index/map/sparse_mem_array.hpp>
+
+#include <osmium/geom/wkt.hpp>
+#include <osmium/handler.hpp>
+#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/io/xml_input.hpp>
+#include <osmium/visitor.hpp>
+
+typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
+typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
+typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
+
+#include "check_basics_handler.hpp"
+#include "check_wkt_handler.hpp"
+
+#include "testdata-testcases.hpp"
+
+#endif // COMMON_HPP
diff --git a/third_party/libosmium/test/data-tests/include/testdata-testcases.hpp b/third_party/libosmium/test/data-tests/include/testdata-testcases.hpp
new file mode 100644
index 0000000..d7d0c01
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/include/testdata-testcases.hpp
@@ -0,0 +1,10 @@
+#ifndef TESTDATA_TESTCASES_HPP
+#define TESTDATA_TESTCASES_HPP
+
+#include <catch.hpp>
+
+#include <string>
+
+extern std::string dirname;
+
+#endif // TESTDATA_TESTCASES_HPP
diff --git a/third_party/libosmium/test/data-tests/multipolygon.qgs b/third_party/libosmium/test/data-tests/multipolygon.qgs
new file mode 100644
index 0000000..5553670
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/multipolygon.qgs
@@ -0,0 +1,880 @@
+<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
+<qgis projectname="" version="2.2.0-Valmiera">
+ <title></title>
+ <relations/>
+ <mapcanvas>
+ <units>degrees</units>
+ <extent>
+ <xmin>0.77500024999999972</xmin>
+ <ymin>-0.84791712574962541</ymin>
+ <xmax>10.22498975000000065</xmax>
+ <ymax>3.94791712574962572</ymax>
+ </extent>
+ <projections>0</projections>
+ <destinationsrs>
+ <spatialrefsys>
+ <proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
+ <srsid>3452</srsid>
+ <srid>4326</srid>
+ <authid>EPSG:4326</authid>
+ <description>WGS 84</description>
+ <projectionacronym>longlat</projectionacronym>
+ <ellipsoidacronym>WGS84</ellipsoidacronym>
+ <geographicflag>true</geographicflag>
+ </spatialrefsys>
+ </destinationsrs>
+ <layer_coordinate_transform_info/>
+ </mapcanvas>
+ <legend updateDrawingOrder="true">
+ <legendlayer drawingOrder="-1" open="true" checked="Qt::Checked" name="Error Points" showFeatureCount="0">
+ <filegroup open="true" hidden="false">
+ <legendlayerfile isInOverview="0" layerid="perrors20140228163658956" visible="1"/>
+ </filegroup>
+ </legendlayer>
+ <legendlayer drawingOrder="-1" open="true" checked="Qt::Checked" name="Error Lines" showFeatureCount="0">
+ <filegroup open="true" hidden="false">
+ <legendlayerfile isInOverview="0" layerid="lerrors20140228172357933" visible="1"/>
+ </filegroup>
+ </legendlayer>
+ <legendlayer drawingOrder="-1" open="true" checked="Qt::Checked" name="multipolygons" showFeatureCount="0">
+ <filegroup open="true" hidden="false">
+ <legendlayerfile isInOverview="0" layerid="multipolygons20140221151811742" visible="1"/>
+ </filegroup>
+ </legendlayer>
+ <legendgroup embedded="1" drawingOrder="-1" open="true" checked="Qt::Checked" name="Overview" project="../../../osm-testdata/grid/tests.qgs"/>
+ <legendgroup embedded="1" drawingOrder="-1" open="true" checked="Qt::Checked" name="Test Framework" project="../../../osm-testdata/grid/tests.qgs"/>
+ </legend>
+ <projectlayers layercount="9">
+ <maplayer minimumScale="-4.65661e-10" maximumScale="1e+08" simplifyDrawingHints="1" minLabelScale="0" maxLabelScale="1e+08" simplifyDrawingTol="1" geometry="Line" simplifyMaxScale="1" type="vector" hasScaleBasedVisibilityFlag="0" simplifyLocal="1" scaleBasedLabelVisibilityFlag="0">
+ <id>lerrors20140228172357933</id>
+ <datasource>dbname='./multipolygon.db' table="lerrors" (GEOMETRY) sql=</datasource>
+ <title></title>
+ <abstract></abstract>
+ <keywordList>
+ <value></value>
+ </keywordList>
+ <layername>Error Lines</layername>
+ <srs>
+ <spatialrefsys>
+ <proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
+ <srsid>3452</srsid>
+ <srid>4326</srid>
+ <authid>EPSG:4326</authid>
+ <description>WGS 84</description>
+ <projectionacronym>longlat</projectionacronym>
+ <ellipsoidacronym>WGS84</ellipsoidacronym>
+ <geographicflag>true</geographicflag>
+ </spatialrefsys>
+ </srs>
+ <provider encoding="System">spatialite</provider>
+ <previewExpression>COALESCE( "OGC_FID", '<NULL>' )</previewExpression>
+ <vectorjoins/>
+ <renderer-v2 attr="problem_type" symbollevels="0" type="categorizedSymbol">
+ <categories>
+ <category symbol="0" value="intersection" label="intersection"/>
+ <category symbol="1" value="role_should_be_outer" label="role_should_be_outer"/>
+ <category symbol="2" value="role_should_be_inner" label="role_should_be_inner"/>
+ <category symbol="3" value="" label=""/>
+ </categories>
+ <symbols>
+ <symbol alpha="1" type="line" name="0">
+ <layer pass="0" class="SimpleLine" locked="0">
+ <prop k="capstyle" v="square"/>
+ <prop k="color" v="255,0,0,255"/>
+ <prop k="customdash" v="5;2"/>
+ <prop k="customdash_unit" v="MM"/>
+ <prop k="draw_inside_polygon" v="0"/>
+ <prop k="joinstyle" v="bevel"/>
+ <prop k="offset" v="0"/>
+ <prop k="offset_unit" v="MM"/>
+ <prop k="penstyle" v="solid"/>
+ <prop k="use_custom_dash" v="0"/>
+ <prop k="width" v="0.5"/>
+ <prop k="width_unit" v="MM"/>
+ </layer>
+ </symbol>
+ <symbol alpha="1" type="line" name="1">
+ <layer pass="0" class="SimpleLine" locked="0">
+ <prop k="capstyle" v="square"/>
+ <prop k="color" v="255,122,33,255"/>
+ <prop k="customdash" v="5;2"/>
+ <prop k="customdash_unit" v="MM"/>
+ <prop k="draw_inside_polygon" v="0"/>
+ <prop k="joinstyle" v="bevel"/>
+ <prop k="offset" v="0"/>
+ <prop k="offset_unit" v="MM"/>
+ <prop k="penstyle" v="solid"/>
+ <prop k="use_custom_dash" v="0"/>
+ <prop k="width" v="0.5"/>
+ <prop k="width_unit" v="MM"/>
+ </layer>
+ </symbol>
+ <symbol alpha="1" type="line" name="2">
+ <layer pass="0" class="SimpleLine" locked="0">
+ <prop k="capstyle" v="square"/>
+ <prop k="color" v="255,122,33,255"/>
+ <prop k="customdash" v="5;2"/>
+ <prop k="customdash_unit" v="MM"/>
+ <prop k="draw_inside_polygon" v="0"/>
+ <prop k="joinstyle" v="bevel"/>
+ <prop k="offset" v="0"/>
+ <prop k="offset_unit" v="MM"/>
+ <prop k="penstyle" v="dash"/>
+ <prop k="use_custom_dash" v="0"/>
+ <prop k="width" v="0.5"/>
+ <prop k="width_unit" v="MM"/>
+ </layer>
+ </symbol>
+ <symbol alpha="1" type="line" name="3">
+ <layer pass="0" class="SimpleLine" locked="0">
+ <prop k="capstyle" v="square"/>
+ <prop k="color" v="255,0,0,255"/>
+ <prop k="customdash" v="5;2"/>
+ <prop k="customdash_unit" v="MM"/>
+ <prop k="draw_inside_polygon" v="0"/>
+ <prop k="joinstyle" v="bevel"/>
+ <prop k="offset" v="0"/>
+ <prop k="offset_unit" v="MM"/>
+ <prop k="penstyle" v="solid"/>
+ <prop k="use_custom_dash" v="0"/>
+ <prop k="width" v="0.5"/>
+ <prop k="width_unit" v="MM"/>
+ </layer>
+ </symbol>
+ </symbols>
+ <source-symbol>
+ <symbol alpha="1" type="line" name="0">
+ <layer pass="0" class="SimpleLine" locked="0">
+ <prop k="capstyle" v="square"/>
+ <prop k="color" v="77,243,51,255"/>
+ <prop k="customdash" v="5;2"/>
+ <prop k="customdash_unit" v="MM"/>
+ <prop k="draw_inside_polygon" v="0"/>
+ <prop k="joinstyle" v="bevel"/>
+ <prop k="offset" v="0"/>
+ <prop k="offset_unit" v="MM"/>
+ <prop k="penstyle" v="solid"/>
+ <prop k="use_custom_dash" v="0"/>
+ <prop k="width" v="0.26"/>
+ <prop k="width_unit" v="MM"/>
+ </layer>
+ </symbol>
+ </source-symbol>
+ <rotation/>
+ <sizescale scalemethod="area"/>
+ </renderer-v2>
+ <customproperties>
+ <property key="labeling" value="pal"/>
+ <property key="labeling/addDirectionSymbol" value="false"/>
+ <property key="labeling/angleOffset" value="0"/>
+ <property key="labeling/blendMode" value="0"/>
+ <property key="labeling/bufferBlendMode" value="0"/>
+ <property key="labeling/bufferColorA" value="255"/>
+ <property key="labeling/bufferColorB" value="255"/>
+ <property key="labeling/bufferColorG" value="255"/>
+ <property key="labeling/bufferColorR" value="255"/>
+ <property key="labeling/bufferDraw" value="false"/>
+ <property key="labeling/bufferJoinStyle" value="64"/>
+ <property key="labeling/bufferNoFill" value="false"/>
+ <property key="labeling/bufferSize" value="1"/>
+ <property key="labeling/bufferSizeInMapUnits" value="false"/>
+ <property key="labeling/bufferTransp" value="0"/>
+ <property key="labeling/centroidWhole" value="false"/>
+ <property key="labeling/decimals" value="3"/>
+ <property key="labeling/displayAll" value="false"/>
+ <property key="labeling/dist" value="0"/>
+ <property key="labeling/distInMapUnits" value="false"/>
+ <property key="labeling/enabled" value="false"/>
+ <property key="labeling/fieldName" value=""/>
+ <property key="labeling/fontBold" value="false"/>
+ <property key="labeling/fontCapitals" value="0"/>
+ <property key="labeling/fontFamily" value="Sans"/>
+ <property key="labeling/fontItalic" value="false"/>
+ <property key="labeling/fontLetterSpacing" value="0"/>
+ <property key="labeling/fontLimitPixelSize" value="false"/>
+ <property key="labeling/fontMaxPixelSize" value="10000"/>
+ <property key="labeling/fontMinPixelSize" value="3"/>
+ <property key="labeling/fontSize" value="10"/>
+ <property key="labeling/fontSizeInMapUnits" value="false"/>
+ <property key="labeling/fontStrikeout" value="false"/>
+ <property key="labeling/fontUnderline" value="false"/>
+ <property key="labeling/fontWeight" value="50"/>
+ <property key="labeling/fontWordSpacing" value="0"/>
+ <property key="labeling/formatNumbers" value="false"/>
+ <property key="labeling/isExpression" value="false"/>
+ <property key="labeling/labelOffsetInMapUnits" value="true"/>
+ <property key="labeling/labelPerPart" value="false"/>
+ <property key="labeling/leftDirectionSymbol" value="<"/>
+ <property key="labeling/limitNumLabels" value="false"/>
+ <property key="labeling/maxCurvedCharAngleIn" value="20"/>
+ <property key="labeling/maxCurvedCharAngleOut" value="-20"/>
+ <property key="labeling/maxNumLabels" value="2000"/>
+ <property key="labeling/mergeLines" value="false"/>
+ <property key="labeling/minFeatureSize" value="0"/>
+ <property key="labeling/multilineAlign" value="0"/>
+ <property key="labeling/multilineHeight" value="1"/>
+ <property key="labeling/namedStyle" value=""/>
+ <property key="labeling/obstacle" value="true"/>
+ <property key="labeling/placeDirectionSymbol" value="0"/>
+ <property key="labeling/placement" value="2"/>
+ <property key="labeling/placementFlags" value="10"/>
+ <property key="labeling/plussign" value="false"/>
+ <property key="labeling/preserveRotation" value="true"/>
+ <property key="labeling/previewBkgrdColor" value="#ffffff"/>
+ <property key="labeling/priority" value="5"/>
+ <property key="labeling/quadOffset" value="4"/>
+ <property key="labeling/reverseDirectionSymbol" value="false"/>
+ <property key="labeling/rightDirectionSymbol" value=">"/>
+ <property key="labeling/scaleMax" value="10000000"/>
+ <property key="labeling/scaleMin" value="1"/>
+ <property key="labeling/scaleVisibility" value="false"/>
+ <property key="labeling/shadowBlendMode" value="6"/>
+ <property key="labeling/shadowColorB" value="0"/>
+ <property key="labeling/shadowColorG" value="0"/>
+ <property key="labeling/shadowColorR" value="0"/>
+ <property key="labeling/shadowDraw" value="false"/>
+ <property key="labeling/shadowOffsetAngle" value="135"/>
+ <property key="labeling/shadowOffsetDist" value="1"/>
+ <property key="labeling/shadowOffsetGlobal" value="true"/>
+ <property key="labeling/shadowOffsetUnits" value="1"/>
+ <property key="labeling/shadowRadius" value="1.5"/>
+ <property key="labeling/shadowRadiusAlphaOnly" value="false"/>
+ <property key="labeling/shadowRadiusUnits" value="1"/>
+ <property key="labeling/shadowScale" value="100"/>
+ <property key="labeling/shadowTransparency" value="30"/>
+ <property key="labeling/shadowUnder" value="0"/>
+ <property key="labeling/shapeBlendMode" value="0"/>
+ <property key="labeling/shapeBorderColorA" value="255"/>
+ <property key="labeling/shapeBorderColorB" value="128"/>
+ <property key="labeling/shapeBorderColorG" value="128"/>
+ <property key="labeling/shapeBorderColorR" value="128"/>
+ <property key="labeling/shapeBorderWidth" value="0"/>
+ <property key="labeling/shapeBorderWidthUnits" value="1"/>
+ <property key="labeling/shapeDraw" value="false"/>
+ <property key="labeling/shapeFillColorA" value="255"/>
+ <property key="labeling/shapeFillColorB" value="255"/>
+ <property key="labeling/shapeFillColorG" value="255"/>
+ <property key="labeling/shapeFillColorR" value="255"/>
+ <property key="labeling/shapeJoinStyle" value="64"/>
+ <property key="labeling/shapeOffsetUnits" value="1"/>
+ <property key="labeling/shapeOffsetX" value="0"/>
+ <property key="labeling/shapeOffsetY" value="0"/>
+ <property key="labeling/shapeRadiiUnits" value="1"/>
+ <property key="labeling/shapeRadiiX" value="0"/>
+ <property key="labeling/shapeRadiiY" value="0"/>
+ <property key="labeling/shapeRotation" value="0"/>
+ <property key="labeling/shapeRotationType" value="0"/>
+ <property key="labeling/shapeSVGFile" value=""/>
+ <property key="labeling/shapeSizeType" value="0"/>
+ <property key="labeling/shapeSizeUnits" value="1"/>
+ <property key="labeling/shapeSizeX" value="0"/>
+ <property key="labeling/shapeSizeY" value="0"/>
+ <property key="labeling/shapeTransparency" value="0"/>
+ <property key="labeling/shapeType" value="0"/>
+ <property key="labeling/textColorA" value="255"/>
+ <property key="labeling/textColorB" value="0"/>
+ <property key="labeling/textColorG" value="0"/>
+ <property key="labeling/textColorR" value="0"/>
+ <property key="labeling/textTransp" value="0"/>
+ <property key="labeling/upsidedownLabels" value="0"/>
+ <property key="labeling/wrapChar" value=""/>
+ <property key="labeling/xOffset" value="0"/>
+ <property key="labeling/yOffset" value="0"/>
+ </customproperties>
+ <blendMode>0</blendMode>
+ <featureBlendMode>0</featureBlendMode>
+ <layerTransparency>0</layerTransparency>
+ <displayfield>OGC_FID</displayfield>
+ <label>0</label>
+ <labelattributes>
+ <label fieldname="" text="Label"/>
+ <family fieldname="" name="Sans"/>
+ <size fieldname="" units="pt" value="12"/>
+ <bold fieldname="" on="0"/>
+ <italic fieldname="" on="0"/>
+ <underline fieldname="" on="0"/>
+ <strikeout fieldname="" on="0"/>
+ <color fieldname="" red="0" blue="0" green="0"/>
+ <x fieldname=""/>
+ <y fieldname=""/>
+ <offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
+ <angle fieldname="" value="0" auto="0"/>
+ <alignment fieldname="" value="center"/>
+ <buffercolor fieldname="" red="255" blue="255" green="255"/>
+ <buffersize fieldname="" units="pt" value="1"/>
+ <bufferenabled fieldname="" on=""/>
+ <multilineenabled fieldname="" on=""/>
+ <selectedonly on=""/>
+ </labelattributes>
+ <edittypes>
+ <edittype labelontop="0" editable="1" type="0" name="OGC_FID"/>
+ <edittype labelontop="0" editable="1" type="0" name="id"/>
+ <edittype labelontop="0" editable="1" type="0" name="object_id"/>
+ <edittype labelontop="0" editable="1" type="0" name="problem_type"/>
+ <edittype labelontop="0" editable="1" type="0" name="type"/>
+ <edittype labelontop="0" editable="1" type="0" name="way_id"/>
+ </edittypes>
+ <editform>.</editform>
+ <editforminit></editforminit>
+ <featformsuppress>0</featformsuppress>
+ <annotationform>.</annotationform>
+ <editorlayout>generatedlayout</editorlayout>
+ <excludeAttributesWMS/>
+ <excludeAttributesWFS/>
+ <attributeactions/>
+ </maplayer>
+ <maplayer minimumScale="-4.65661e-10" maximumScale="1e+08" simplifyDrawingHints="1" minLabelScale="0" maxLabelScale="1e+08" simplifyDrawingTol="1" geometry="Polygon" simplifyMaxScale="1" type="vector" hasScaleBasedVisibilityFlag="0" simplifyLocal="1" scaleBasedLabelVisibilityFlag="0">
+ <id>multipolygons20140221151811742</id>
+ <datasource>dbname='./multipolygon.db' table="multipolygons" (GEOMETRY) sql=</datasource>
+ <title></title>
+ <abstract></abstract>
+ <keywordList>
+ <value></value>
+ </keywordList>
+ <layername>multipolygons</layername>
+ <srs>
+ <spatialrefsys>
+ <proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
+ <srsid>3452</srsid>
+ <srid>4326</srid>
+ <authid>EPSG:4326</authid>
+ <description>WGS 84</description>
+ <projectionacronym>longlat</projectionacronym>
+ <ellipsoidacronym>WGS84</ellipsoidacronym>
+ <geographicflag>true</geographicflag>
+ </spatialrefsys>
+ </srs>
+ <provider encoding="System">spatialite</provider>
+ <previewExpression></previewExpression>
+ <vectorjoins/>
+ <renderer-v2 symbollevels="0" type="singleSymbol">
+ <symbols>
+ <symbol alpha="0.494118" type="fill" name="0">
+ <layer pass="0" class="SimpleFill" locked="0">
+ <prop k="border_width_unit" v="MM"/>
+ <prop k="color" v="0,170,255,255"/>
+ <prop k="color_border" v="0,0,0,255"/>
+ <prop k="offset" v="0,0"/>
+ <prop k="offset_unit" v="MM"/>
+ <prop k="style" v="solid"/>
+ <prop k="style_border" v="solid"/>
+ <prop k="width_border" v="0.26"/>
+ </layer>
+ </symbol>
+ </symbols>
+ <rotation/>
+ <sizescale scalemethod="area"/>
+ </renderer-v2>
+ <customproperties>
+ <property key="labeling" value="pal"/>
+ <property key="labeling/addDirectionSymbol" value="false"/>
+ <property key="labeling/angleOffset" value="0"/>
+ <property key="labeling/blendMode" value="0"/>
+ <property key="labeling/bufferBlendMode" value="0"/>
+ <property key="labeling/bufferColorA" value="255"/>
+ <property key="labeling/bufferColorB" value="255"/>
+ <property key="labeling/bufferColorG" value="255"/>
+ <property key="labeling/bufferColorR" value="255"/>
+ <property key="labeling/bufferDraw" value="false"/>
+ <property key="labeling/bufferJoinStyle" value="64"/>
+ <property key="labeling/bufferNoFill" value="false"/>
+ <property key="labeling/bufferSize" value="1"/>
+ <property key="labeling/bufferSizeInMapUnits" value="false"/>
+ <property key="labeling/bufferTransp" value="0"/>
+ <property key="labeling/centroidWhole" value="false"/>
+ <property key="labeling/decimals" value="3"/>
+ <property key="labeling/displayAll" value="false"/>
+ <property key="labeling/dist" value="0"/>
+ <property key="labeling/distInMapUnits" value="false"/>
+ <property key="labeling/enabled" value="false"/>
+ <property key="labeling/fieldName" value=""/>
+ <property key="labeling/fontBold" value="false"/>
+ <property key="labeling/fontCapitals" value="0"/>
+ <property key="labeling/fontFamily" value="Sans"/>
+ <property key="labeling/fontItalic" value="false"/>
+ <property key="labeling/fontLetterSpacing" value="0"/>
+ <property key="labeling/fontLimitPixelSize" value="false"/>
+ <property key="labeling/fontMaxPixelSize" value="10000"/>
+ <property key="labeling/fontMinPixelSize" value="3"/>
+ <property key="labeling/fontSize" value="10"/>
+ <property key="labeling/fontSizeInMapUnits" value="false"/>
+ <property key="labeling/fontStrikeout" value="false"/>
+ <property key="labeling/fontUnderline" value="false"/>
+ <property key="labeling/fontWeight" value="50"/>
+ <property key="labeling/fontWordSpacing" value="0"/>
+ <property key="labeling/formatNumbers" value="false"/>
+ <property key="labeling/isExpression" value="false"/>
+ <property key="labeling/labelOffsetInMapUnits" value="true"/>
+ <property key="labeling/labelPerPart" value="false"/>
+ <property key="labeling/leftDirectionSymbol" value="<"/>
+ <property key="labeling/limitNumLabels" value="false"/>
+ <property key="labeling/maxCurvedCharAngleIn" value="20"/>
+ <property key="labeling/maxCurvedCharAngleOut" value="-20"/>
+ <property key="labeling/maxNumLabels" value="2000"/>
+ <property key="labeling/mergeLines" value="false"/>
+ <property key="labeling/minFeatureSize" value="0"/>
+ <property key="labeling/multilineAlign" value="0"/>
+ <property key="labeling/multilineHeight" value="1"/>
+ <property key="labeling/namedStyle" value=""/>
+ <property key="labeling/obstacle" value="true"/>
+ <property key="labeling/placeDirectionSymbol" value="0"/>
+ <property key="labeling/placement" value="0"/>
+ <property key="labeling/placementFlags" value="0"/>
+ <property key="labeling/plussign" value="false"/>
+ <property key="labeling/preserveRotation" value="true"/>
+ <property key="labeling/previewBkgrdColor" value="#ffffff"/>
+ <property key="labeling/priority" value="5"/>
+ <property key="labeling/quadOffset" value="4"/>
+ <property key="labeling/reverseDirectionSymbol" value="false"/>
+ <property key="labeling/rightDirectionSymbol" value=">"/>
+ <property key="labeling/scaleMax" value="10000000"/>
+ <property key="labeling/scaleMin" value="1"/>
+ <property key="labeling/scaleVisibility" value="false"/>
+ <property key="labeling/shadowBlendMode" value="6"/>
+ <property key="labeling/shadowColorB" value="0"/>
+ <property key="labeling/shadowColorG" value="0"/>
+ <property key="labeling/shadowColorR" value="0"/>
+ <property key="labeling/shadowDraw" value="false"/>
+ <property key="labeling/shadowOffsetAngle" value="135"/>
+ <property key="labeling/shadowOffsetDist" value="1"/>
+ <property key="labeling/shadowOffsetGlobal" value="true"/>
+ <property key="labeling/shadowOffsetUnits" value="1"/>
+ <property key="labeling/shadowRadius" value="1.5"/>
+ <property key="labeling/shadowRadiusAlphaOnly" value="false"/>
+ <property key="labeling/shadowRadiusUnits" value="1"/>
+ <property key="labeling/shadowScale" value="100"/>
+ <property key="labeling/shadowTransparency" value="30"/>
+ <property key="labeling/shadowUnder" value="0"/>
+ <property key="labeling/shapeBlendMode" value="0"/>
+ <property key="labeling/shapeBorderColorA" value="255"/>
+ <property key="labeling/shapeBorderColorB" value="128"/>
+ <property key="labeling/shapeBorderColorG" value="128"/>
+ <property key="labeling/shapeBorderColorR" value="128"/>
+ <property key="labeling/shapeBorderWidth" value="0"/>
+ <property key="labeling/shapeBorderWidthUnits" value="1"/>
+ <property key="labeling/shapeDraw" value="false"/>
+ <property key="labeling/shapeFillColorA" value="255"/>
+ <property key="labeling/shapeFillColorB" value="255"/>
+ <property key="labeling/shapeFillColorG" value="255"/>
+ <property key="labeling/shapeFillColorR" value="255"/>
+ <property key="labeling/shapeJoinStyle" value="64"/>
+ <property key="labeling/shapeOffsetUnits" value="1"/>
+ <property key="labeling/shapeOffsetX" value="0"/>
+ <property key="labeling/shapeOffsetY" value="0"/>
+ <property key="labeling/shapeRadiiUnits" value="1"/>
+ <property key="labeling/shapeRadiiX" value="0"/>
+ <property key="labeling/shapeRadiiY" value="0"/>
+ <property key="labeling/shapeRotation" value="0"/>
+ <property key="labeling/shapeRotationType" value="0"/>
+ <property key="labeling/shapeSVGFile" value=""/>
+ <property key="labeling/shapeSizeType" value="0"/>
+ <property key="labeling/shapeSizeUnits" value="1"/>
+ <property key="labeling/shapeSizeX" value="0"/>
+ <property key="labeling/shapeSizeY" value="0"/>
+ <property key="labeling/shapeTransparency" value="0"/>
+ <property key="labeling/shapeType" value="0"/>
+ <property key="labeling/textColorA" value="255"/>
+ <property key="labeling/textColorB" value="0"/>
+ <property key="labeling/textColorG" value="0"/>
+ <property key="labeling/textColorR" value="0"/>
+ <property key="labeling/textTransp" value="0"/>
+ <property key="labeling/upsidedownLabels" value="0"/>
+ <property key="labeling/wrapChar" value=""/>
+ <property key="labeling/xOffset" value="0"/>
+ <property key="labeling/yOffset" value="0"/>
+ </customproperties>
+ <blendMode>0</blendMode>
+ <featureBlendMode>0</featureBlendMode>
+ <layerTransparency>0</layerTransparency>
+ <displayfield>OGC_FID</displayfield>
+ <label>0</label>
+ <labelattributes>
+ <label fieldname="" text="Label"/>
+ <family fieldname="" name="Sans"/>
+ <size fieldname="" units="pt" value="12"/>
+ <bold fieldname="" on="0"/>
+ <italic fieldname="" on="0"/>
+ <underline fieldname="" on="0"/>
+ <strikeout fieldname="" on="0"/>
+ <color fieldname="" red="0" blue="0" green="0"/>
+ <x fieldname=""/>
+ <y fieldname=""/>
+ <offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
+ <angle fieldname="" value="0" auto="0"/>
+ <alignment fieldname="" value="center"/>
+ <buffercolor fieldname="" red="255" blue="255" green="255"/>
+ <buffersize fieldname="" units="pt" value="1"/>
+ <bufferenabled fieldname="" on=""/>
+ <multilineenabled fieldname="" on=""/>
+ <selectedonly on=""/>
+ </labelattributes>
+ <edittypes>
+ <edittype labelontop="0" editable="1" type="0" name="OGC_FID"/>
+ <edittype labelontop="0" editable="1" type="0" name="id"/>
+ <edittype labelontop="0" editable="1" type="0" name="type"/>
+ </edittypes>
+ <editform>.</editform>
+ <editforminit></editforminit>
+ <featformsuppress>0</featformsuppress>
+ <annotationform>.</annotationform>
+ <editorlayout>generatedlayout</editorlayout>
+ <excludeAttributesWMS/>
+ <excludeAttributesWFS/>
+ <attributeactions/>
+ </maplayer>
+ <maplayer minimumScale="0" maximumScale="1e+08" simplifyDrawingHints="0" minLabelScale="0" maxLabelScale="1e+08" simplifyDrawingTol="1" geometry="Point" simplifyMaxScale="1" type="vector" hasScaleBasedVisibilityFlag="0" simplifyLocal="1" scaleBasedLabelVisibilityFlag="0">
+ <id>perrors20140228163658956</id>
+ <datasource>dbname='./multipolygon.db' table="perrors" (GEOMETRY) sql=</datasource>
+ <title></title>
+ <abstract></abstract>
+ <keywordList>
+ <value></value>
+ </keywordList>
+ <layername>Error Points</layername>
+ <srs>
+ <spatialrefsys>
+ <proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
+ <srsid>3452</srsid>
+ <srid>4326</srid>
+ <authid>EPSG:4326</authid>
+ <description>WGS 84</description>
+ <projectionacronym>longlat</projectionacronym>
+ <ellipsoidacronym>WGS84</ellipsoidacronym>
+ <geographicflag>true</geographicflag>
+ </spatialrefsys>
+ </srs>
+ <provider encoding="System">spatialite</provider>
+ <previewExpression>COALESCE( "OGC_FID", '<NULL>' )</previewExpression>
+ <vectorjoins/>
+ <renderer-v2 attr="problem_type" symbollevels="0" type="categorizedSymbol">
+ <categories>
+ <category symbol="0" value="intersection" label="intersection"/>
+ <category symbol="1" value="ring_not_closed" label="ring_not_closed"/>
+ <category symbol="2" value="duplicate_node" label="duplicate_node"/>
+ </categories>
+ <symbols>
+ <symbol alpha="1" type="marker" name="0">
+ <layer pass="0" class="SimpleMarker" locked="0">
+ <prop k="angle" v="0"/>
+ <prop k="color" v="255,0,0,255"/>
+ <prop k="color_border" v="255,255,255,255"/>
+ <prop k="horizontal_anchor_point" v="1"/>
+ <prop k="name" v="diamond"/>
+ <prop k="offset" v="0,0"/>
+ <prop k="offset_unit" v="MM"/>
+ <prop k="outline_style" v="solid"/>
+ <prop k="outline_width" v="0.4"/>
+ <prop k="outline_width_unit" v="MM"/>
+ <prop k="scale_method" v="area"/>
+ <prop k="size" v="2.8"/>
+ <prop k="size_unit" v="MM"/>
+ <prop k="vertical_anchor_point" v="1"/>
+ </layer>
+ </symbol>
+ <symbol alpha="1" type="marker" name="1">
+ <layer pass="0" class="SimpleMarker" locked="0">
+ <prop k="angle" v="0"/>
+ <prop k="color" v="255,0,0,255"/>
+ <prop k="color_border" v="255,255,255,255"/>
+ <prop k="horizontal_anchor_point" v="1"/>
+ <prop k="name" v="triangle"/>
+ <prop k="offset" v="0,0"/>
+ <prop k="offset_unit" v="MM"/>
+ <prop k="outline_style" v="solid"/>
+ <prop k="outline_width" v="0.4"/>
+ <prop k="outline_width_unit" v="MM"/>
+ <prop k="scale_method" v="area"/>
+ <prop k="size" v="2.8"/>
+ <prop k="size_unit" v="MM"/>
+ <prop k="vertical_anchor_point" v="1"/>
+ </layer>
+ </symbol>
+ <symbol alpha="1" type="marker" name="2">
+ <layer pass="0" class="SimpleMarker" locked="0">
+ <prop k="angle" v="0"/>
+ <prop k="color" v="255,255,255,255"/>
+ <prop k="color_border" v="255,0,0,255"/>
+ <prop k="horizontal_anchor_point" v="1"/>
+ <prop k="name" v="circle"/>
+ <prop k="offset" v="0,0"/>
+ <prop k="offset_unit" v="MM"/>
+ <prop k="outline_style" v="solid"/>
+ <prop k="outline_width" v="0.4"/>
+ <prop k="outline_width_unit" v="MM"/>
+ <prop k="scale_method" v="area"/>
+ <prop k="size" v="2.4"/>
+ <prop k="size_unit" v="MM"/>
+ <prop k="vertical_anchor_point" v="1"/>
+ </layer>
+ <layer pass="0" class="SimpleMarker" locked="0">
+ <prop k="angle" v="0"/>
+ <prop k="color" v="255,0,0,255"/>
+ <prop k="color_border" v="255,0,0,255"/>
+ <prop k="horizontal_anchor_point" v="1"/>
+ <prop k="name" v="circle"/>
+ <prop k="offset" v="0,0"/>
+ <prop k="offset_unit" v="MM"/>
+ <prop k="outline_style" v="solid"/>
+ <prop k="outline_width" v="0.8"/>
+ <prop k="outline_width_unit" v="MM"/>
+ <prop k="scale_method" v="area"/>
+ <prop k="size" v="0.5"/>
+ <prop k="size_unit" v="MM"/>
+ <prop k="vertical_anchor_point" v="1"/>
+ </layer>
+ </symbol>
+ </symbols>
+ <source-symbol>
+ <symbol alpha="1" type="marker" name="0">
+ <layer pass="0" class="SimpleMarker" locked="0">
+ <prop k="angle" v="0"/>
+ <prop k="color" v="139,168,110,255"/>
+ <prop k="color_border" v="0,0,0,255"/>
+ <prop k="horizontal_anchor_point" v="1"/>
+ <prop k="name" v="circle"/>
+ <prop k="offset" v="0,0"/>
+ <prop k="offset_unit" v="MM"/>
+ <prop k="outline_style" v="solid"/>
+ <prop k="outline_width" v="0"/>
+ <prop k="outline_width_unit" v="MM"/>
+ <prop k="scale_method" v="area"/>
+ <prop k="size" v="2"/>
+ <prop k="size_unit" v="MM"/>
+ <prop k="vertical_anchor_point" v="1"/>
+ </layer>
+ </symbol>
+ </source-symbol>
+ <rotation/>
+ <sizescale scalemethod="area"/>
+ </renderer-v2>
+ <customproperties>
+ <property key="labeling" value="pal"/>
+ <property key="labeling/addDirectionSymbol" value="false"/>
+ <property key="labeling/angleOffset" value="0"/>
+ <property key="labeling/blendMode" value="0"/>
+ <property key="labeling/bufferBlendMode" value="0"/>
+ <property key="labeling/bufferColorA" value="255"/>
+ <property key="labeling/bufferColorB" value="255"/>
+ <property key="labeling/bufferColorG" value="255"/>
+ <property key="labeling/bufferColorR" value="255"/>
+ <property key="labeling/bufferDraw" value="false"/>
+ <property key="labeling/bufferJoinStyle" value="64"/>
+ <property key="labeling/bufferNoFill" value="false"/>
+ <property key="labeling/bufferSize" value="1"/>
+ <property key="labeling/bufferSizeInMapUnits" value="false"/>
+ <property key="labeling/bufferTransp" value="0"/>
+ <property key="labeling/centroidWhole" value="false"/>
+ <property key="labeling/decimals" value="3"/>
+ <property key="labeling/displayAll" value="false"/>
+ <property key="labeling/dist" value="0"/>
+ <property key="labeling/distInMapUnits" value="false"/>
+ <property key="labeling/enabled" value="false"/>
+ <property key="labeling/fieldName" value=""/>
+ <property key="labeling/fontBold" value="false"/>
+ <property key="labeling/fontCapitals" value="0"/>
+ <property key="labeling/fontFamily" value="Sans"/>
+ <property key="labeling/fontItalic" value="false"/>
+ <property key="labeling/fontLetterSpacing" value="0"/>
+ <property key="labeling/fontLimitPixelSize" value="false"/>
+ <property key="labeling/fontMaxPixelSize" value="10000"/>
+ <property key="labeling/fontMinPixelSize" value="3"/>
+ <property key="labeling/fontSize" value="10"/>
+ <property key="labeling/fontSizeInMapUnits" value="false"/>
+ <property key="labeling/fontStrikeout" value="false"/>
+ <property key="labeling/fontUnderline" value="false"/>
+ <property key="labeling/fontWeight" value="50"/>
+ <property key="labeling/fontWordSpacing" value="0"/>
+ <property key="labeling/formatNumbers" value="false"/>
+ <property key="labeling/isExpression" value="false"/>
+ <property key="labeling/labelOffsetInMapUnits" value="true"/>
+ <property key="labeling/labelPerPart" value="false"/>
+ <property key="labeling/leftDirectionSymbol" value="<"/>
+ <property key="labeling/limitNumLabels" value="false"/>
+ <property key="labeling/maxCurvedCharAngleIn" value="20"/>
+ <property key="labeling/maxCurvedCharAngleOut" value="-20"/>
+ <property key="labeling/maxNumLabels" value="2000"/>
+ <property key="labeling/mergeLines" value="false"/>
+ <property key="labeling/minFeatureSize" value="0"/>
+ <property key="labeling/multilineAlign" value="0"/>
+ <property key="labeling/multilineHeight" value="1"/>
+ <property key="labeling/namedStyle" value=""/>
+ <property key="labeling/obstacle" value="true"/>
+ <property key="labeling/placeDirectionSymbol" value="0"/>
+ <property key="labeling/placement" value="0"/>
+ <property key="labeling/placementFlags" value="0"/>
+ <property key="labeling/plussign" value="false"/>
+ <property key="labeling/preserveRotation" value="true"/>
+ <property key="labeling/previewBkgrdColor" value="#ffffff"/>
+ <property key="labeling/priority" value="5"/>
+ <property key="labeling/quadOffset" value="4"/>
+ <property key="labeling/reverseDirectionSymbol" value="false"/>
+ <property key="labeling/rightDirectionSymbol" value=">"/>
+ <property key="labeling/scaleMax" value="10000000"/>
+ <property key="labeling/scaleMin" value="1"/>
+ <property key="labeling/scaleVisibility" value="false"/>
+ <property key="labeling/shadowBlendMode" value="6"/>
+ <property key="labeling/shadowColorB" value="0"/>
+ <property key="labeling/shadowColorG" value="0"/>
+ <property key="labeling/shadowColorR" value="0"/>
+ <property key="labeling/shadowDraw" value="false"/>
+ <property key="labeling/shadowOffsetAngle" value="135"/>
+ <property key="labeling/shadowOffsetDist" value="1"/>
+ <property key="labeling/shadowOffsetGlobal" value="true"/>
+ <property key="labeling/shadowOffsetUnits" value="1"/>
+ <property key="labeling/shadowRadius" value="1.5"/>
+ <property key="labeling/shadowRadiusAlphaOnly" value="false"/>
+ <property key="labeling/shadowRadiusUnits" value="1"/>
+ <property key="labeling/shadowScale" value="100"/>
+ <property key="labeling/shadowTransparency" value="30"/>
+ <property key="labeling/shadowUnder" value="0"/>
+ <property key="labeling/shapeBlendMode" value="0"/>
+ <property key="labeling/shapeBorderColorA" value="255"/>
+ <property key="labeling/shapeBorderColorB" value="128"/>
+ <property key="labeling/shapeBorderColorG" value="128"/>
+ <property key="labeling/shapeBorderColorR" value="128"/>
+ <property key="labeling/shapeBorderWidth" value="0"/>
+ <property key="labeling/shapeBorderWidthUnits" value="1"/>
+ <property key="labeling/shapeDraw" value="false"/>
+ <property key="labeling/shapeFillColorA" value="255"/>
+ <property key="labeling/shapeFillColorB" value="255"/>
+ <property key="labeling/shapeFillColorG" value="255"/>
+ <property key="labeling/shapeFillColorR" value="255"/>
+ <property key="labeling/shapeJoinStyle" value="64"/>
+ <property key="labeling/shapeOffsetUnits" value="1"/>
+ <property key="labeling/shapeOffsetX" value="0"/>
+ <property key="labeling/shapeOffsetY" value="0"/>
+ <property key="labeling/shapeRadiiUnits" value="1"/>
+ <property key="labeling/shapeRadiiX" value="0"/>
+ <property key="labeling/shapeRadiiY" value="0"/>
+ <property key="labeling/shapeRotation" value="0"/>
+ <property key="labeling/shapeRotationType" value="0"/>
+ <property key="labeling/shapeSVGFile" value=""/>
+ <property key="labeling/shapeSizeType" value="0"/>
+ <property key="labeling/shapeSizeUnits" value="1"/>
+ <property key="labeling/shapeSizeX" value="0"/>
+ <property key="labeling/shapeSizeY" value="0"/>
+ <property key="labeling/shapeTransparency" value="0"/>
+ <property key="labeling/shapeType" value="0"/>
+ <property key="labeling/textColorA" value="255"/>
+ <property key="labeling/textColorB" value="0"/>
+ <property key="labeling/textColorG" value="0"/>
+ <property key="labeling/textColorR" value="0"/>
+ <property key="labeling/textTransp" value="0"/>
+ <property key="labeling/upsidedownLabels" value="0"/>
+ <property key="labeling/wrapChar" value=""/>
+ <property key="labeling/xOffset" value="0"/>
+ <property key="labeling/yOffset" value="0"/>
+ </customproperties>
+ <blendMode>0</blendMode>
+ <featureBlendMode>0</featureBlendMode>
+ <layerTransparency>0</layerTransparency>
+ <displayfield>OGC_FID</displayfield>
+ <label>0</label>
+ <labelattributes>
+ <label fieldname="" text="Label"/>
+ <family fieldname="" name="Sans"/>
+ <size fieldname="" units="pt" value="12"/>
+ <bold fieldname="" on="0"/>
+ <italic fieldname="" on="0"/>
+ <underline fieldname="" on="0"/>
+ <strikeout fieldname="" on="0"/>
+ <color fieldname="" red="0" blue="0" green="0"/>
+ <x fieldname=""/>
+ <y fieldname=""/>
+ <offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
+ <angle fieldname="" value="0" auto="0"/>
+ <alignment fieldname="" value="center"/>
+ <buffercolor fieldname="" red="255" blue="255" green="255"/>
+ <buffersize fieldname="" units="pt" value="1"/>
+ <bufferenabled fieldname="" on=""/>
+ <multilineenabled fieldname="" on=""/>
+ <selectedonly on=""/>
+ </labelattributes>
+ <edittypes>
+ <edittype labelontop="0" editable="1" type="0" name="OGC_FID"/>
+ <edittype labelontop="0" editable="1" type="0" name="id"/>
+ <edittype labelontop="0" editable="1" type="0" name="node_id"/>
+ <edittype labelontop="0" editable="1" type="0" name="object_id"/>
+ <edittype labelontop="0" editable="1" type="0" name="problem_type"/>
+ <edittype labelontop="0" editable="1" type="0" name="type"/>
+ </edittypes>
+ <editform>.</editform>
+ <editforminit></editforminit>
+ <featformsuppress>0</featformsuppress>
+ <annotationform>.</annotationform>
+ <editorlayout>generatedlayout</editorlayout>
+ <excludeAttributesWMS/>
+ <excludeAttributesWFS/>
+ <attributeactions/>
+ </maplayer>
+ </projectlayers>
+ <properties>
+ <WMSContactPerson type="QString"></WMSContactPerson>
+ <WMSOnlineResource type="QString"></WMSOnlineResource>
+ <WMSContactOrganization type="QString"></WMSContactOrganization>
+ <WMSExtent type="QStringList">
+ <value>0.82500024999999999</value>
+ <value>-0.35415386986094277</value>
+ <value>8.17498974999999994</value>
+ <value>3.45415386986094308</value>
+ </WMSExtent>
+ <WMSKeywordList type="QStringList">
+ <value></value>
+ </WMSKeywordList>
+ <WFSUrl type="QString"></WFSUrl>
+ <Paths>
+ <Absolute type="bool">false</Absolute>
+ </Paths>
+ <WMSServiceTitle type="QString">mp test</WMSServiceTitle>
+ <WFSLayers type="QStringList"/>
+ <WMSContactMail type="QString"></WMSContactMail>
+ <PositionPrecision>
+ <DecimalPlaces type="int">2</DecimalPlaces>
+ <Automatic type="bool">true</Automatic>
+ <DegreeFormat type="QString">D</DegreeFormat>
+ </PositionPrecision>
+ <WCSUrl type="QString"></WCSUrl>
+ <WMSContactPhone type="QString"></WMSContactPhone>
+ <WMSServiceCapabilities type="bool">true</WMSServiceCapabilities>
+ <WMSServiceAbstract type="QString"></WMSServiceAbstract>
+ <WMSAddWktGeometry type="bool">false</WMSAddWktGeometry>
+ <Measure>
+ <Ellipsoid type="QString">NONE</Ellipsoid>
+ </Measure>
+ <WFSTLayers>
+ <Insert type="QStringList"/>
+ <Update type="QStringList"/>
+ <Delete type="QStringList"/>
+ </WFSTLayers>
+ <Gui>
+ <SelectionColorBluePart type="int">0</SelectionColorBluePart>
+ <CanvasColorGreenPart type="int">255</CanvasColorGreenPart>
+ <CanvasColorRedPart type="int">255</CanvasColorRedPart>
+ <SelectionColorRedPart type="int">255</SelectionColorRedPart>
+ <SelectionColorAlphaPart type="int">255</SelectionColorAlphaPart>
+ <SelectionColorGreenPart type="int">255</SelectionColorGreenPart>
+ <CanvasColorBluePart type="int">255</CanvasColorBluePart>
+ </Gui>
+ <Identify>
+ <disabledLayers type="QStringList"/>
+ </Identify>
+ <Macros>
+ <pythonCode type="QString"></pythonCode>
+ </Macros>
+ <WMSAccessConstraints type="QString"></WMSAccessConstraints>
+ <WCSLayers type="QStringList"/>
+ <SpatialRefSys>
+ <ProjectCrs type="QString">EPSG:4326</ProjectCrs>
+ </SpatialRefSys>
+ <DefaultStyles>
+ <Fill type="QString"></Fill>
+ <Line type="QString"></Line>
+ <Marker type="QString"></Marker>
+ <RandomColors type="bool">true</RandomColors>
+ <AlphaInt type="int">255</AlphaInt>
+ <ColorRamp type="QString"></ColorRamp>
+ </DefaultStyles>
+ <WMSFees type="QString"></WMSFees>
+ <WMSUrl type="QString"></WMSUrl>
+ </properties>
+</qgis>
diff --git a/third_party/libosmium/test/data-tests/run-testdata-multipolygon.cmake b/third_party/libosmium/test/data-tests/run-testdata-multipolygon.cmake
new file mode 100644
index 0000000..0d08f5a
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/run-testdata-multipolygon.cmake
@@ -0,0 +1,46 @@
+#-----------------------------------------------------------------------------
+#
+# Helper script that runs the 'multipolygon' test.
+#
+#-----------------------------------------------------------------------------
+
+# Remove files that might be left over from previous run
+file(REMOVE multipolygon.db multipolygon-tests.json)
+
+
+#-----------------------------------------------------------------------------
+#
+# Create multipolygons from test data.
+#
+#-----------------------------------------------------------------------------
+execute_process(
+ COMMAND ${CMAKE_CURRENT_BINARY_DIR}/testdata-multipolygon
+ ${OSM_TESTDATA}/grid/data/all.osm
+ RESULT_VARIABLE _result
+ OUTPUT_FILE multipolygon.log
+ ERROR_FILE multipolygon.log
+)
+
+if(_result)
+ message(FATAL_ERROR "Error running testdata-multipolygon command")
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+# Compare created multipolygons with reference data.
+#
+#-----------------------------------------------------------------------------
+execute_process(
+ COMMAND ${RUBY} ${OSM_TESTDATA}/bin/compare-areas.rb
+ ${OSM_TESTDATA}/grid/data/tests.json
+ multipolygon-tests.json
+ RESULT_VARIABLE _result
+)
+
+if(_result)
+ message(FATAL_ERROR "Error running compare-areas command")
+endif()
+
+
+#-----------------------------------------------------------------------------
diff --git a/third_party/libosmium/test/data-tests/testcases/test-100.cpp b/third_party/libosmium/test/data-tests/testcases/test-100.cpp
new file mode 100644
index 0000000..feafe77
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/testcases/test-100.cpp
@@ -0,0 +1,41 @@
+
+#include "common.hpp"
+
+class TestHandler100 : public osmium::handler::Handler {
+
+public:
+
+ TestHandler100() :
+ osmium::handler::Handler() {
+ }
+
+ void node(osmium::Node& node) {
+ if (node.id() == 100000) {
+ REQUIRE(node.version() == 1);
+ REQUIRE(node.timestamp() == osmium::Timestamp("2014-01-01T00:00:00Z"));
+ REQUIRE(node.uid() == 1);
+ REQUIRE(!strcmp(node.user(), "test"));
+ REQUIRE(node.changeset() == 1);
+ REQUIRE(node.location().lon() == 1.02);
+ REQUIRE(node.location().lat() == 1.02);
+ } else {
+ throw std::runtime_error("Unknown ID");
+ }
+ }
+
+}; // class TestHandler100
+
+TEST_CASE("100") {
+
+ SECTION("test 100") {
+ osmium::io::Reader reader(dirname + "/1/100/data.osm");
+
+ CheckBasicsHandler check_basics_handler(100, 1, 0, 0);
+ CheckWKTHandler check_wkt_handler(dirname, 100);
+ TestHandler100 test_handler;
+
+ osmium::apply(reader, check_basics_handler, check_wkt_handler, test_handler);
+ }
+
+}
+
diff --git a/third_party/libosmium/test/data-tests/testcases/test-101.cpp b/third_party/libosmium/test/data-tests/testcases/test-101.cpp
new file mode 100644
index 0000000..de2a5fd
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/testcases/test-101.cpp
@@ -0,0 +1,43 @@
+
+#include "common.hpp"
+
+class TestHandler101 : public osmium::handler::Handler {
+
+public:
+
+ TestHandler101() :
+ osmium::handler::Handler() {
+ }
+
+ void node(osmium::Node& node) {
+ if (node.id() == 101000) {
+ REQUIRE(node.version() == 1);
+ REQUIRE(node.location().lon() == 1.12);
+ REQUIRE(node.location().lat() == 1.02);
+ } else if (node.id() == 101001) {
+ REQUIRE(node.version() == 1);
+ REQUIRE(node.location().lon() == 1.12);
+ REQUIRE(node.location().lat() == 1.03);
+ } else if (node.id() == 101002) {
+ } else if (node.id() == 101003) {
+ } else {
+ throw std::runtime_error("Unknown ID");
+ }
+ }
+
+}; // class TestHandler101
+
+TEST_CASE("101") {
+
+ SECTION("test 101") {
+ osmium::io::Reader reader(dirname + "/1/101/data.osm");
+
+ CheckBasicsHandler check_basics_handler(101, 4, 0, 0);
+ CheckWKTHandler check_wkt_handler(dirname, 101);
+ TestHandler101 test_handler;
+
+ osmium::apply(reader, check_basics_handler, check_wkt_handler, test_handler);
+ }
+
+}
+
diff --git a/third_party/libosmium/test/data-tests/testcases/test-110.cpp b/third_party/libosmium/test/data-tests/testcases/test-110.cpp
new file mode 100644
index 0000000..16b039b
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/testcases/test-110.cpp
@@ -0,0 +1,58 @@
+
+#include "common.hpp"
+
+class TestHandler110 : public osmium::handler::Handler {
+
+public:
+
+ TestHandler110() :
+ osmium::handler::Handler() {
+ }
+
+ void node(const osmium::Node& node) {
+ if (node.id() == 110000) {
+ REQUIRE(node.location().lon() == 1.02);
+ REQUIRE(node.location().lat() == 1.12);
+ } else if (node.id() == 110001) {
+ REQUIRE(node.location().lon() == 1.07);
+ REQUIRE(node.location().lat() == 1.13);
+ } else {
+ throw std::runtime_error("Unknown ID");
+ }
+ }
+
+ void way(const osmium::Way& way) {
+ if (way.id() == 110800) {
+ REQUIRE(way.version() == 1);
+ REQUIRE(way.nodes().size() == 2);
+ REQUIRE(!way.is_closed());
+
+ const char *test_id = way.tags().get_value_by_key("test:id");
+ REQUIRE(test_id);
+ REQUIRE(!strcmp(test_id, "110"));
+ } else {
+ throw std::runtime_error("Unknown ID");
+ }
+ }
+
+}; // class TestHandler110
+
+TEST_CASE("110") {
+
+ SECTION("test 110") {
+ osmium::io::Reader reader(dirname + "/1/110/data.osm");
+
+ index_pos_type index_pos;
+ index_neg_type index_neg;
+ location_handler_type location_handler(index_pos, index_neg);
+ location_handler.ignore_errors();
+
+ CheckBasicsHandler check_basics_handler(110, 2, 1, 0);
+ CheckWKTHandler check_wkt_handler(dirname, 110);
+ TestHandler110 test_handler;
+
+ osmium::apply(reader, location_handler, check_basics_handler, check_wkt_handler, test_handler);
+ }
+
+}
+
diff --git a/third_party/libosmium/test/data-tests/testdata-multipolygon.cpp b/third_party/libosmium/test/data-tests/testdata-multipolygon.cpp
new file mode 100644
index 0000000..0fd0d98
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/testdata-multipolygon.cpp
@@ -0,0 +1,291 @@
+
+#include <iostream>
+#include <fstream>
+#include <map>
+
+#include <osmium/index/map/sparse_mem_array.hpp>
+
+#include <osmium/area/assembler.hpp>
+#include <osmium/area/multipolygon_collector.hpp>
+#include <osmium/area/problem_reporter_ogr.hpp>
+#include <osmium/geom/ogr.hpp>
+#include <osmium/geom/wkt.hpp>
+#include <osmium/handler.hpp>
+#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/io/xml_input.hpp>
+#include <osmium/visitor.hpp>
+
+typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
+
+typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type;
+
+struct less_charptr {
+
+ bool operator()(const char* a, const char* b) const {
+ return std::strcmp(a, b) < 0;
+ }
+
+}; // less_charptr
+
+typedef std::map<const char*, const char*, less_charptr> tagmap_type;
+
+inline tagmap_type create_map(const osmium::TagList& taglist) {
+ tagmap_type map;
+
+ for (auto& tag : taglist) {
+ map[tag.key()] = tag.value();
+ }
+
+ return map;
+}
+
+class TestHandler : public osmium::handler::Handler {
+
+ OGRDataSource* m_data_source;
+ OGRLayer* m_layer_point;
+ OGRLayer* m_layer_linestring;
+ OGRLayer* m_layer_polygon;
+
+ osmium::geom::OGRFactory<> m_ogr_factory;
+ osmium::geom::WKTFactory<> m_wkt_factory;
+
+ std::ofstream m_out;
+
+ bool m_first_out {true};
+
+public:
+
+ TestHandler(OGRDataSource* data_source) :
+ m_data_source(data_source),
+ m_out("multipolygon-tests.json") {
+
+ OGRSpatialReference sparef;
+ sparef.SetWellKnownGeogCS("WGS84");
+
+ /**************/
+
+ m_layer_point = m_data_source->CreateLayer("points", &sparef, wkbPoint, nullptr);
+ if (!m_layer_point) {
+ std::cerr << "Layer creation failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_point_field_id("id", OFTReal);
+ layer_point_field_id.SetWidth(10);
+
+ if (m_layer_point->CreateField(&layer_point_field_id) != OGRERR_NONE) {
+ std::cerr << "Creating id field failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_point_field_type("type", OFTString);
+ layer_point_field_type.SetWidth(30);
+
+ if (m_layer_point->CreateField(&layer_point_field_type) != OGRERR_NONE) {
+ std::cerr << "Creating type field failed.\n";
+ exit(1);
+ }
+
+ /**************/
+
+ m_layer_linestring = m_data_source->CreateLayer("lines", &sparef, wkbLineString, nullptr);
+ if (!m_layer_linestring) {
+ std::cerr << "Layer creation failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_linestring_field_id("id", OFTReal);
+ layer_linestring_field_id.SetWidth(10);
+
+ if (m_layer_linestring->CreateField(&layer_linestring_field_id) != OGRERR_NONE) {
+ std::cerr << "Creating id field failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_linestring_field_type("type", OFTString);
+ layer_linestring_field_type.SetWidth(30);
+
+ if (m_layer_linestring->CreateField(&layer_linestring_field_type) != OGRERR_NONE) {
+ std::cerr << "Creating type field failed.\n";
+ exit(1);
+ }
+
+ /**************/
+
+ m_layer_polygon = m_data_source->CreateLayer("multipolygons", &sparef, wkbMultiPolygon, nullptr);
+ if (!m_layer_polygon) {
+ std::cerr << "Layer creation failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_polygon_field_id("id", OFTInteger);
+ layer_polygon_field_id.SetWidth(10);
+
+ if (m_layer_polygon->CreateField(&layer_polygon_field_id) != OGRERR_NONE) {
+ std::cerr << "Creating id field failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_polygon_field_from_type("from_type", OFTString);
+ layer_polygon_field_from_type.SetWidth(1);
+
+ if (m_layer_polygon->CreateField(&layer_polygon_field_from_type) != OGRERR_NONE) {
+ std::cerr << "Creating from_type field failed.\n";
+ exit(1);
+ }
+ }
+
+ ~TestHandler() {
+ m_out << "\n]\n";
+ }
+
+ void node(const osmium::Node& node) {
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_point->GetLayerDefn());
+ std::unique_ptr<OGRPoint> ogr_point = m_ogr_factory.create_point(node);
+ feature->SetGeometry(ogr_point.get());
+ feature->SetField("id", static_cast<double>(node.id()));
+ feature->SetField("type", node.tags().get_value_by_key("type"));
+
+ if (m_layer_point->CreateFeature(feature) != OGRERR_NONE) {
+ std::cerr << "Failed to create feature.\n";
+ exit(1);
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ }
+
+ void way(const osmium::Way& way) {
+ try {
+ std::unique_ptr<OGRLineString> ogr_linestring = m_ogr_factory.create_linestring(way);
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_linestring->GetLayerDefn());
+ feature->SetGeometry(ogr_linestring.get());
+ feature->SetField("id", static_cast<double>(way.id()));
+ feature->SetField("type", way.tags().get_value_by_key("type"));
+
+ if (m_layer_linestring->CreateFeature(feature) != OGRERR_NONE) {
+ std::cerr << "Failed to create feature.\n";
+ exit(1);
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ } catch (osmium::geometry_error&) {
+ std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
+ }
+ }
+
+ void area(const osmium::Area& area) {
+ if (m_first_out) {
+ m_out << "[\n";
+ m_first_out = false;
+ } else {
+ m_out << ",\n";
+ }
+ m_out << "{\n \"test_id\": " << (area.orig_id() / 1000) << ",\n \"area_id\": " << area.id() << ",\n \"from_id\": " << area.orig_id() << ",\n \"from_type\": \"" << (area.from_way() ? "way" : "relation") << "\",\n \"wkt\": \"";
+ try {
+ std::string wkt = m_wkt_factory.create_multipolygon(area);
+ m_out << wkt << "\",\n \"tags\": {";
+
+ auto tagmap = create_map(area.tags());
+ bool first = true;
+ for (auto& tag : tagmap) {
+ if (first) {
+ first = false;
+ } else {
+ m_out << ", ";
+ }
+ m_out << '"' << tag.first << "\": \"" << tag.second << '"';
+ }
+ m_out << "}\n}";
+ } catch (osmium::geometry_error&) {
+ m_out << "INVALID\"\n}";
+ }
+ try {
+ std::unique_ptr<OGRMultiPolygon> ogr_polygon = m_ogr_factory.create_multipolygon(area);
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_polygon->GetLayerDefn());
+ feature->SetGeometry(ogr_polygon.get());
+ feature->SetField("id", static_cast<int>(area.orig_id()));
+
+ std::string from_type;
+ if (area.from_way()) {
+ from_type = "w";
+ } else {
+ from_type = "r";
+ }
+ feature->SetField("from_type", from_type.c_str());
+
+ if (m_layer_polygon->CreateFeature(feature) != OGRERR_NONE) {
+ std::cerr << "Failed to create feature.\n";
+ exit(1);
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ } catch (osmium::geometry_error&) {
+ std::cerr << "Ignoring illegal geometry for area " << area.id() << " created from " << (area.from_way() ? "way" : "relation") << " with id=" << area.orig_id() << ".\n";
+ }
+ }
+
+}; // class TestHandler
+
+/* ================================================== */
+
+OGRDataSource* initialize_database(const std::string& output_format, const std::string& output_filename) {
+ OGRRegisterAll();
+
+ OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(output_format.c_str());
+ if (!driver) {
+ std::cerr << output_format << " driver not available.\n";
+ exit(1);
+ }
+
+ CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
+ const char* options[] = { "SPATIALITE=TRUE", nullptr };
+ OGRDataSource* data_source = driver->CreateDataSource(output_filename.c_str(), const_cast<char**>(options));
+ if (!data_source) {
+ std::cerr << "Creation of output file failed.\n";
+ exit(1);
+ }
+
+ return data_source;
+}
+
+int main(int argc, char* argv[]) {
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " INFILE\n";
+ exit(1);
+ }
+
+ std::string output_format("SQLite");
+ std::string input_filename(argv[1]);
+ std::string output_filename("multipolygon.db");
+
+ OGRDataSource* data_source = initialize_database(output_format, output_filename);
+
+ osmium::area::ProblemReporterOGR problem_reporter(data_source);
+ osmium::area::Assembler::config_type assembler_config(&problem_reporter);
+ assembler_config.enable_debug_output();
+ osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config);
+
+ std::cerr << "Pass 1...\n";
+ osmium::io::Reader reader1(input_filename);
+ collector.read_relations(reader1);
+ reader1.close();
+ std::cerr << "Pass 1 done\n";
+
+ index_type index;
+ location_handler_type location_handler(index);
+ location_handler.ignore_errors();
+
+ TestHandler test_handler(data_source);
+
+ std::cerr << "Pass 2...\n";
+ osmium::io::Reader reader2(input_filename);
+ osmium::apply(reader2, location_handler, test_handler, collector.handler([&test_handler](const osmium::memory::Buffer& area_buffer) {
+ osmium::apply(area_buffer, test_handler);
+ }));
+ reader2.close();
+ std::cerr << "Pass 2 done\n";
+
+ OGRDataSource::DestroyDataSource(data_source);
+ OGRCleanupAll();
+}
+
diff --git a/third_party/libosmium/test/data-tests/testdata-overview.cpp b/third_party/libosmium/test/data-tests/testdata-overview.cpp
new file mode 100644
index 0000000..2d63dc6
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/testdata-overview.cpp
@@ -0,0 +1,197 @@
+/* The code in this file is released into the Public Domain. */
+
+#include <iostream>
+
+#include <osmium/index/map/sparse_mem_array.hpp>
+
+#include <osmium/geom/ogr.hpp>
+#include <osmium/handler.hpp>
+#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/io/xml_input.hpp>
+#include <osmium/visitor.hpp>
+
+typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
+typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type;
+
+class TestOverviewHandler : public osmium::handler::Handler {
+
+ OGRDataSource* m_data_source;
+
+ OGRLayer* m_layer_nodes;
+ OGRLayer* m_layer_labels;
+ OGRLayer* m_layer_ways;
+
+ osmium::geom::OGRFactory<> m_factory;
+
+public:
+
+ TestOverviewHandler(const std::string& driver_name, const std::string& filename) {
+
+ OGRRegisterAll();
+
+ OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str());
+ if (!driver) {
+ std::cerr << driver_name << " driver not available.\n";
+ exit(1);
+ }
+
+ CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
+ const char* options[] = { "SPATIALITE=TRUE", nullptr };
+ m_data_source = driver->CreateDataSource(filename.c_str(), const_cast<char**>(options));
+ if (!m_data_source) {
+ std::cerr << "Creation of output file failed.\n";
+ exit(1);
+ }
+
+ OGRSpatialReference sparef;
+ sparef.SetWellKnownGeogCS("WGS84");
+
+ // nodes layer
+
+ m_layer_nodes = m_data_source->CreateLayer("nodes", &sparef, wkbPoint, nullptr);
+ if (!m_layer_nodes) {
+ std::cerr << "Layer creation failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_nodes_field_id("id", OFTReal);
+ layer_nodes_field_id.SetWidth(10);
+
+ if (m_layer_nodes->CreateField(&layer_nodes_field_id) != OGRERR_NONE) {
+ std::cerr << "Creating id field failed.\n";
+ exit(1);
+ }
+
+ // labels layer
+
+ m_layer_labels = m_data_source->CreateLayer("labels", &sparef, wkbPoint, nullptr);
+ if (!m_layer_labels) {
+ std::cerr << "Layer creation failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_labels_field_id("id", OFTReal);
+ layer_labels_field_id.SetWidth(10);
+
+ if (m_layer_labels->CreateField(&layer_labels_field_id) != OGRERR_NONE) {
+ std::cerr << "Creating id field failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_labels_field_label("label", OFTString);
+ layer_labels_field_label.SetWidth(30);
+
+ if (m_layer_labels->CreateField(&layer_labels_field_label) != OGRERR_NONE) {
+ std::cerr << "Creating label field failed.\n";
+ exit(1);
+ }
+
+ // ways layer
+
+ m_layer_ways = m_data_source->CreateLayer("ways", &sparef, wkbLineString, nullptr);
+ if (!m_layer_ways) {
+ std::cerr << "Layer creation failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_way_field_id("id", OFTReal);
+ layer_way_field_id.SetWidth(10);
+
+ if (m_layer_ways->CreateField(&layer_way_field_id) != OGRERR_NONE) {
+ std::cerr << "Creating id field failed.\n";
+ exit(1);
+ }
+
+ OGRFieldDefn layer_way_field_test("test", OFTInteger);
+ layer_way_field_test.SetWidth(3);
+
+ if (m_layer_ways->CreateField(&layer_way_field_test) != OGRERR_NONE) {
+ std::cerr << "Creating test field failed.\n";
+ exit(1);
+ }
+ }
+
+ ~TestOverviewHandler() {
+ OGRDataSource::DestroyDataSource(m_data_source);
+ OGRCleanupAll();
+ }
+
+ void node(const osmium::Node& node) {
+ const char* label = node.tags().get_value_by_key("label");
+ if (label) {
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_labels->GetLayerDefn());
+ std::unique_ptr<OGRPoint> ogr_point = m_factory.create_point(node);
+ feature->SetGeometry(ogr_point.get());
+ feature->SetField("id", static_cast<double>(node.id()));
+ feature->SetField("label", label);
+
+ if (m_layer_labels->CreateFeature(feature) != OGRERR_NONE) {
+ std::cerr << "Failed to create feature.\n";
+ exit(1);
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ } else {
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_nodes->GetLayerDefn());
+ std::unique_ptr<OGRPoint> ogr_point = m_factory.create_point(node);
+ feature->SetGeometry(ogr_point.get());
+ feature->SetField("id", static_cast<double>(node.id()));
+
+ if (m_layer_nodes->CreateFeature(feature) != OGRERR_NONE) {
+ std::cerr << "Failed to create feature.\n";
+ exit(1);
+ }
+ OGRFeature::DestroyFeature(feature);
+ }
+ }
+
+ void way(const osmium::Way& way) {
+ try {
+ std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way);
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_ways->GetLayerDefn());
+ feature->SetGeometry(ogr_linestring.get());
+ feature->SetField("id", static_cast<double>(way.id()));
+
+ const char* test = way.tags().get_value_by_key("test");
+ if (test) {
+ feature->SetField("test", test);
+ }
+
+ if (m_layer_ways->CreateFeature(feature) != OGRERR_NONE) {
+ std::cerr << "Failed to create feature.\n";
+ exit(1);
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ } catch (osmium::geometry_error&) {
+ std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
+ }
+ }
+
+};
+
+/* ================================================== */
+
+int main(int argc, char* argv[]) {
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " INFILE\n";
+ exit(1);
+ }
+
+ std::string output_format("SQLite");
+ std::string input_filename(argv[1]);
+ std::string output_filename("testdata-overview.db");
+ ::unlink(output_filename.c_str());
+
+ osmium::io::Reader reader(input_filename);
+
+ index_type index;
+ location_handler_type location_handler(index);
+ location_handler.ignore_errors();
+
+ TestOverviewHandler handler(output_format, output_filename);
+
+ osmium::apply(reader, location_handler, handler);
+ reader.close();
+}
+
diff --git a/third_party/libosmium/test/data-tests/testdata-testcases.cpp b/third_party/libosmium/test/data-tests/testdata-testcases.cpp
new file mode 100644
index 0000000..6ed6ae9
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/testdata-testcases.cpp
@@ -0,0 +1,27 @@
+
+#include <iostream>
+#include <string>
+
+#define CATCH_CONFIG_RUNNER
+
+#include "testdata-testcases.hpp"
+
+#include <osmpbf/osmpbf.h>
+
+std::string dirname;
+
+int main(int argc, char* argv[]) {
+ const char* testcases_dir = getenv("TESTCASES_DIR");
+ if (testcases_dir) {
+ dirname = testcases_dir;
+ std::cerr << "Running tests from '" << dirname << "' (from TESTCASES_DIR environment variable)\n";
+ } else {
+ std::cerr << "Please set TESTCASES_DIR environment variable.\n";
+ exit(1);
+ }
+
+ int result = Catch::Session().run(argc, argv);
+
+ return result;
+}
+
diff --git a/third_party/libosmium/test/data-tests/testdata-xml.cpp b/third_party/libosmium/test/data-tests/testdata-xml.cpp
new file mode 100644
index 0000000..5af4c4f
--- /dev/null
+++ b/third_party/libosmium/test/data-tests/testdata-xml.cpp
@@ -0,0 +1,462 @@
+/* The code in this file is released into the Public Domain. */
+
+#define CATCH_CONFIG_MAIN
+#include "catch.hpp"
+
+#include <cassert>
+#include <cstdlib>
+#include <iostream>
+#include <string>
+
+#include <osmium/io/xml_input.hpp>
+#include <osmium/io/gzip_compression.hpp>
+#include <osmium/visitor.hpp>
+
+std::string filename(const char* test_id, const char* suffix = "osm") {
+ const char* testdir = getenv("TESTDIR");
+ if (!testdir) {
+ std::cerr << "You have to set TESTDIR environment variable before running testdata-xml\n";
+ exit(2);
+ }
+
+ std::string f;
+ f += testdir;
+ f += "/";
+ f += test_id;
+ f += "/data.";
+ f += suffix;
+ return f;
+}
+
+struct header_buffer_type {
+ osmium::io::Header header;
+ osmium::memory::Buffer buffer;
+};
+
+// =============================================
+
+// The following helper functions are used to call different parts of the
+// Osmium internals used to read and parse XML files. This way those parts
+// can be tested individually. These function can not be used in normal
+// operations, because they make certain assumptions, for instance that
+// file contents fit into small buffers.
+
+std::string read_file(const char* test_id) {
+ int fd = osmium::io::detail::open_for_reading(filename(test_id));
+ assert(fd >= 0);
+
+ std::string input(10000, '\0');
+ auto n = ::read(fd, reinterpret_cast<unsigned char*>(const_cast<char*>(input.data())), 10000);
+ assert(n >= 0);
+ input.resize(static_cast<std::string::size_type>(n));
+
+ close(fd);
+
+ return input;
+}
+
+std::string read_gz_file(const char* test_id, const char* suffix) {
+ int fd = osmium::io::detail::open_for_reading(filename(test_id, suffix));
+ assert(fd >= 0);
+
+ osmium::io::GzipDecompressor gzip_decompressor(fd);
+ std::string input = gzip_decompressor.read();
+ gzip_decompressor.close();
+
+ return input;
+}
+
+
+header_buffer_type parse_xml(std::string input) {
+ osmium::thread::Queue<std::string> input_queue;
+ osmium::thread::Queue<osmium::memory::Buffer> output_queue;
+ std::promise<osmium::io::Header> header_promise;
+ std::atomic<bool> done {false};
+ input_queue.push(input);
+ input_queue.push(std::string()); // EOF marker
+
+ osmium::io::detail::XMLParser parser(input_queue, output_queue, header_promise, osmium::osm_entity_bits::all, done);
+ parser();
+
+ header_buffer_type result;
+ result.header = header_promise.get_future().get();
+ output_queue.wait_and_pop(result.buffer);
+
+ if (result.buffer) {
+ osmium::memory::Buffer buffer;
+ output_queue.wait_and_pop(buffer);
+ assert(!buffer);
+ }
+
+ return result;
+}
+
+header_buffer_type read_xml(const char* test_id) {
+ std::string input = read_file(test_id);
+ return parse_xml(input);
+}
+
+// =============================================
+
+TEST_CASE("Reading OSM XML 100") {
+
+ SECTION("Direct") {
+ header_buffer_type r = read_xml("100-correct_but_no_data");
+
+ REQUIRE(r.header.get("generator") == "testdata");
+ REQUIRE(0 == r.buffer.committed());
+ REQUIRE(! r.buffer);
+ }
+
+ SECTION("Using Reader") {
+ osmium::io::Reader reader(filename("100-correct_but_no_data"));
+
+ osmium::io::Header header = reader.header();
+ REQUIRE(header.get("generator") == "testdata");
+
+ osmium::memory::Buffer buffer = reader.read();
+ REQUIRE(0 == buffer.committed());
+ REQUIRE(! buffer);
+ reader.close();
+ }
+
+ SECTION("Using Reader asking for header only") {
+ osmium::io::Reader reader(filename("100-correct_but_no_data"), osmium::osm_entity_bits::nothing);
+
+ osmium::io::Header header = reader.header();
+ REQUIRE(header.get("generator") == "testdata");
+ reader.close();
+ }
+
+}
+
+// =============================================
+
+TEST_CASE("Reading OSM XML 101") {
+
+ SECTION("Direct") {
+ REQUIRE_THROWS_AS(read_xml("101-missing_version"), osmium::format_version_error);
+ try {
+ read_xml("101-missing_version");
+ } catch (osmium::format_version_error& e) {
+ REQUIRE(e.version.empty());
+ }
+ }
+
+ SECTION("Using Reader") {
+ REQUIRE_THROWS_AS({
+ osmium::io::Reader reader(filename("101-missing_version"));
+ osmium::io::Header header = reader.header();
+ osmium::memory::Buffer buffer = reader.read();
+ reader.close();
+ }, osmium::format_version_error);
+ }
+
+}
+
+// =============================================
+
+TEST_CASE("Reading OSM XML 102") {
+
+ SECTION("Direct") {
+ REQUIRE_THROWS_AS(read_xml("102-wrong_version"), osmium::format_version_error);
+ try {
+ read_xml("102-wrong_version");
+ } catch (osmium::format_version_error& e) {
+ REQUIRE(e.version == "0.1");
+ }
+ }
+
+ SECTION("Using Reader") {
+ REQUIRE_THROWS_AS({
+ osmium::io::Reader reader(filename("102-wrong_version"));
+
+ osmium::io::Header header = reader.header();
+ osmium::memory::Buffer buffer = reader.read();
+ reader.close();
+ }, osmium::format_version_error);
+ }
+
+}
+
+// =============================================
+
+TEST_CASE("Reading OSM XML 103") {
+
+ SECTION("Direct") {
+ REQUIRE_THROWS_AS(read_xml("103-old_version"), osmium::format_version_error);
+ try {
+ read_xml("103-old_version");
+ } catch (osmium::format_version_error& e) {
+ REQUIRE(e.version == "0.5");
+ }
+ }
+
+ SECTION("Using Reader") {
+ REQUIRE_THROWS_AS({
+ osmium::io::Reader reader(filename("103-old_version"));
+ osmium::io::Header header = reader.header();
+ osmium::memory::Buffer buffer = reader.read();
+ reader.close();
+ }, osmium::format_version_error);
+ }
+
+}
+
+// =============================================
+
+TEST_CASE("Reading OSM XML 104") {
+
+ SECTION("Direct") {
+ REQUIRE_THROWS_AS(read_xml("104-empty_file"), osmium::xml_error);
+ try {
+ read_xml("104-empty_file");
+ } catch (osmium::xml_error& e) {
+ REQUIRE(e.line == 1);
+ REQUIRE(e.column == 0);
+ }
+ }
+
+ SECTION("Using Reader") {
+ REQUIRE_THROWS_AS({
+ osmium::io::Reader reader(filename("104-empty_file"));
+ osmium::io::Header header = reader.header();
+ osmium::memory::Buffer buffer = reader.read();
+ reader.close();
+ }, osmium::xml_error);
+ }
+}
+
+// =============================================
+
+TEST_CASE("Reading OSM XML 105") {
+
+ SECTION("Direct") {
+ REQUIRE_THROWS_AS(read_xml("105-incomplete_xml_file"), osmium::xml_error);
+ }
+
+ SECTION("Using Reader") {
+ REQUIRE_THROWS_AS({
+ osmium::io::Reader reader(filename("105-incomplete_xml_file"));
+ osmium::io::Header header = reader.header();
+ osmium::memory::Buffer buffer = reader.read();
+ reader.close();
+ }, osmium::xml_error);
+ }
+
+}
+
+// =============================================
+
+TEST_CASE("Reading OSM XML 120") {
+
+ SECTION("Direct") {
+ std::string data = read_gz_file("120-correct_gzip_file_without_data", "osm.gz");
+
+ REQUIRE(data.size() == 102);
+
+ header_buffer_type r = parse_xml(data);
+ REQUIRE(r.header.get("generator") == "testdata");
+ REQUIRE(0 == r.buffer.committed());
+ REQUIRE(! r.buffer);
+ }
+
+ SECTION("Using Reader") {
+ osmium::io::Reader reader(filename("120-correct_gzip_file_without_data", "osm.gz"));
+
+ osmium::io::Header header = reader.header();
+ REQUIRE(header.get("generator") == "testdata");
+
+ osmium::memory::Buffer buffer = reader.read();
+ REQUIRE(0 == buffer.committed());
+ REQUIRE(! buffer);
+ reader.close();
+ }
+
+}
+
+// =============================================
+
+TEST_CASE("Reading OSM XML 121") {
+
+ SECTION("Direct") {
+ REQUIRE_THROWS_AS( {
+ read_gz_file("121-truncated_gzip_file", "osm.gz");
+ }, osmium::gzip_error);
+ }
+
+ SECTION("Using Reader") {
+ REQUIRE_THROWS_AS({
+ osmium::io::Reader reader(filename("121-truncated_gzip_file", "osm.gz"));
+ osmium::io::Header header = reader.header();
+ osmium::memory::Buffer buffer = reader.read();
+ reader.close();
+ }, osmium::gzip_error);
+ }
+
+}
+
+// =============================================
+
+TEST_CASE("Reading OSM XML 122") {
+
+ SECTION("Direct") {
+ REQUIRE_THROWS_AS( {
+ read_xml("122-no_osm_element");
+ }, osmium::xml_error);
+ }
+
+ SECTION("Using Reader") {
+ REQUIRE_THROWS_AS({
+ osmium::io::Reader reader(filename("122-no_osm_element"));
+ osmium::io::Header header = reader.header();
+ osmium::memory::Buffer buffer = reader.read();
+ reader.close();
+ }, osmium::xml_error);
+ }
+
+}
+
+// =============================================
+
+TEST_CASE("Reading OSM XML 140") {
+
+ SECTION("Using Reader") {
+ osmium::io::Reader reader(filename("140-unicode"));
+ osmium::memory::Buffer buffer = reader.read();
+ reader.close();
+
+ int count = 0;
+ for (auto it = buffer.begin<osmium::Node>(); it != buffer.end<osmium::Node>(); ++it) {
+ ++count;
+ REQUIRE(it->id() == count);
+ const osmium::TagList& t = it->tags();
+
+ const char* uc = t["unicode_char"];
+
+ auto len = atoi(t["unicode_utf8_length"]);
+ REQUIRE(len == strlen(uc));
+
+ REQUIRE(!strcmp(uc, t["unicode_xml"]));
+
+// workaround for missing support for u8 string literals on Windows
+#if !defined(_MSC_VER)
+ switch (count) {
+ case 1:
+ REQUIRE(!strcmp(uc, u8"a"));
+ break;
+ case 2:
+ REQUIRE(!strcmp(uc, u8"\u00e4"));
+ break;
+ case 3:
+ REQUIRE(!strcmp(uc, u8"\u30dc"));
+ break;
+ case 4:
+ REQUIRE(!strcmp(uc, u8"\U0001d11e"));
+ break;
+ case 5:
+ REQUIRE(!strcmp(uc, u8"\U0001f6eb"));
+ break;
+ default:
+ REQUIRE(false); // should not be here
+ }
+#endif
+ }
+ REQUIRE(count == 5);
+ }
+
+}
+
+
+// =============================================
+
+TEST_CASE("Reading OSM XML 141") {
+
+ SECTION("Using Reader") {
+ osmium::io::Reader reader(filename("141-entities"));
+ osmium::memory::Buffer buffer = reader.read();
+ reader.close();
+ REQUIRE(buffer.committed() > 0);
+ REQUIRE(buffer.get<osmium::memory::Item>(0).type() == osmium::item_type::node);
+
+ const osmium::Node& node = buffer.get<osmium::Node>(0);
+ const osmium::TagList& tags = node.tags();
+
+ REQUIRE(!strcmp(tags["less-than"], "<"));
+ REQUIRE(!strcmp(tags["greater-than"], ">"));
+ REQUIRE(!strcmp(tags["apostrophe"], "'"));
+ REQUIRE(!strcmp(tags["ampersand"], "&"));
+ REQUIRE(!strcmp(tags["quote"], "\""));
+ }
+
+}
+
+
+// =============================================
+
+TEST_CASE("Reading OSM XML 200") {
+
+ SECTION("Direct") {
+ header_buffer_type r = read_xml("200-nodes");
+
+ REQUIRE(r.header.get("generator") == "testdata");
+ REQUIRE(r.buffer.committed() > 0);
+ REQUIRE(r.buffer.get<osmium::memory::Item>(0).type() == osmium::item_type::node);
+ REQUIRE(r.buffer.get<osmium::Node>(0).id() == 36966060);
+ REQUIRE(std::distance(r.buffer.begin(), r.buffer.end()) == 3);
+ }
+
+ SECTION("Using Reader") {
+ osmium::io::Reader reader(filename("200-nodes"));
+
+ osmium::io::Header header = reader.header();
+ REQUIRE(header.get("generator") == "testdata");
+
+ osmium::memory::Buffer buffer = reader.read();
+ REQUIRE(buffer.committed() > 0);
+ REQUIRE(buffer.get<osmium::memory::Item>(0).type() == osmium::item_type::node);
+ REQUIRE(buffer.get<osmium::Node>(0).id() == 36966060);
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 3);
+ reader.close();
+ }
+
+ SECTION("Using Reader asking for nodes") {
+ osmium::io::Reader reader(filename("200-nodes"), osmium::osm_entity_bits::node);
+
+ osmium::io::Header header = reader.header();
+ REQUIRE(header.get("generator") == "testdata");
+
+ osmium::memory::Buffer buffer = reader.read();
+ REQUIRE(buffer.committed() > 0);
+ REQUIRE(buffer.get<osmium::memory::Item>(0).type() == osmium::item_type::node);
+ REQUIRE(buffer.get<osmium::Node>(0).id() == 36966060);
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 3);
+ reader.close();
+ }
+
+ SECTION("Using Reader asking for header only") {
+ osmium::io::Reader reader(filename("200-nodes"), osmium::osm_entity_bits::nothing);
+
+ osmium::io::Header header = reader.header();
+ REQUIRE(header.get("generator") == "testdata");
+
+ osmium::memory::Buffer buffer = reader.read();
+ REQUIRE(0 == buffer.committed());
+ REQUIRE(! buffer);
+ reader.close();
+ }
+
+ SECTION("Using Reader asking for ways") {
+ osmium::io::Reader reader(filename("200-nodes"), osmium::osm_entity_bits::way);
+
+ osmium::io::Header header = reader.header();
+ REQUIRE(header.get("generator") == "testdata");
+
+ osmium::memory::Buffer buffer = reader.read();
+ REQUIRE(0 == buffer.committed());
+ REQUIRE(! buffer);
+ reader.close();
+ }
+
+}
+
diff --git a/third_party/libosmium/test/include/catch.hpp b/third_party/libosmium/test/include/catch.hpp
new file mode 100644
index 0000000..bb87af2
--- /dev/null
+++ b/third_party/libosmium/test/include/catch.hpp
@@ -0,0 +1,9003 @@
+
+// This is needed for Windows
+#define CATCH_CONFIG_CPP11_NULLPTR
+
+/*
+ * CATCH v1.0 build 53 (master branch)
+ * Generated: 2014-08-20 08:08:19.533804
+ * ----------------------------------------------------------
+ * 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
+
+// #included from: internal/catch_suppress_warnings.h
+
+#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+#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"
+#elif defined __GNUC__
+#pragma GCC diagnostic ignored "-Wvariadic-macros"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpadded"
+#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
+#pragma GCC diagnostic ignored "-Wsign-promo"
+#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; }
+ inline bool alwaysTrue() { return true; }
+ inline bool alwaysFalse() { return false; }
+
+ 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 );
+ 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( 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_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
+
+ }; };
+
+ 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 = 0x00,
+
+ ContinueOnFailure = 0x01, // Failures fail test, but execution continues
+ FalseTest = 0x02, // Prefix expression 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 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_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
+
+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 );
+
+ 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 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_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
+
+// #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();
+ }
+ };
+
+ 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>
+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( 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_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
+
+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_CPP11_OR_GREATER
+ ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
+# endif
+
+public:
+ ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {}
+# ifdef CATCH_CPP11_OR_GREATER
+ 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 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 std::string getCurrentTestName() const = 0;
+ virtual const AssertionResult* getLastResult() const = 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, macroName ) \
+ do { \
+ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+ if( __catchResult.allowThrows() ) \
+ try { \
+ expr; \
+ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
+ } \
+ catch( ... ) { \
+ __catchResult.captureResult( Catch::ResultWas::Ok ); \
+ } \
+ 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 = ::Catch::Matchers::matcher.toString(); \
+ __catchResult \
+ .setLhs( Catch::toString( arg ) ) \
+ .setRhs( matcherAsString == "{?}" ? #matcher : matcherAsString ) \
+ .setOp( "matches" ) \
+ .setResultType( ::Catch::Matchers::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
+
+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;
+ };
+
+} // 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 ), 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;
+ }
+
+ 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;
+ };
+}
+
+// #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( SectionInfo const& info );
+ ~Section();
+
+ // This indicates whether the section should be executed or not
+ operator bool() const;
+
+ private:
+#ifdef CATCH_CPP11_OR_GREATER
+ Section( Section const& ) = delete;
+ Section( Section && ) = delete;
+ Section& operator = ( Section const& ) = delete;
+ Section& operator = ( Section && ) = delete;
+#else
+ Section( Section const& info );
+ Section& operator = ( Section const& );
+#endif
+ 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 <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>
+// #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();
+
+}
+
+
+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
+
+// #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( 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
+
+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 <string>
+#include <set>
+
+#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 );
+
+ 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( 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 = static_cast<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.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
+ }; };
+
+ 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;
+ };
+}
+
+// #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( ITagAliasRegistry::get() );
+ 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 = static_cast<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 = 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( &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,
+ 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:
+ static Detail::IColourImpl* impl();
+ 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 <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( ITagAliasRegistry::get() ).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( ITagAliasRegistry::get() ).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;
+ }
+
+ 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() )
+ std::cout << "Tags for matching test cases:\n";
+ else {
+ std::cout << "All available tags:\n";
+ testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+ }
+
+ std::map<std::string, TagInfo> 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::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 ) );
+ 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 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;
+
+ 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() ) { // XXX Hack that makes Catch not run in loop in certain situations
+ 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 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:
+
+ 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 );
+ 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(...) {
+ ResultBuilder exResult( m_lastAssertionInfo.macroName.c_str(),
+ m_lastAssertionInfo.lineInfo,
+ m_lastAssertionInfo.capturedExpression.c_str(),
+ m_lastAssertionInfo.resultDisposition );
+ exResult.useActiveException();
+ }
+ // 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 );
+
+ 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 );
+ }
+
+ 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;
+ };
+
+ 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 _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( ITagAliasRegistry::get() ).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( TestFailureException& ) {
+ throw;
+ }
+ 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 ) : 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 ) {
+ 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( 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( 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 );
+ 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 == "." )
+ isHidden = true;
+ else
+ tags.insert( tag );
+ tag.clear();
+ }
+ else
+ tag += c;
+ }
+ }
+ if( isHidden ) {
+ tags.insert( "hide" );
+ tags.insert( "." );
+ }
+
+ TestCaseInfo info( _name, _className, desc, tags, _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,
+ SourceLineInfo const& _lineInfo )
+ : name( _name ),
+ className( _className ),
+ description( _description ),
+ tags( _tags ),
+ lineInfo( _lineInfo ),
+ properties( None )
+ {
+ 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 );
+ properties = static_cast<SpecialProperties>( properties | parseSpecialTag( lcaseTag ) );
+ lcaseTags.insert( lcaseTag );
+ }
+ tagsAsString = oss.str();
+ }
+
+ 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 {
+
+ // These numbers are maintained by a script
+ Version libraryVersion( 1, 0, 53, "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( 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 );
+
+ 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 );
+ }
+}
+
+// #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 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::getElapsedNanoseconds() const {
+ return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
+ }
+ unsigned int Timer::getElapsedMilliseconds() const {
+ return static_cast<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( 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 )
+ getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
+ }
+
+ // 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/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 {
+
+namespace Detail {
+
+ namespace {
+ 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 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;
+ 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 ) );
+}
+
+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_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 {
+
+ ResultBuilder::ResultBuilder( char const* macroName,
+ SourceLineInfo const& lineInfo,
+ char const* capturedExpression,
+ ResultDisposition::Flags resultDisposition )
+ : m_assertionInfo( macroName, lineInfo, capturedExpression, 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::captureExpression() {
+ AssertionResult result = build();
+ 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 <map>
+#include <iostream>
+
+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 );
+ std::cerr << ex.what() << std::endl;
+ exit(1);
+ }
+ }
+
+} // 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 ) {}
+ 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() )
+ {}
+ ~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;
+ }
+
+ 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;
+ }
+ }
+
+ 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.setStream( 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 )
+ .writeAttribute( "expectedFailures", totals.assertions.failedButOk );
+ 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 )
+ .writeAttribute( "expectedFailures", totals.assertions.failedButOk );
+ 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 )
+ .writeAttribute( "expectedFailures", assertions.failedButOk );
+ 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 )
+ {}
+
+ 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 ) {
+ 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::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.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";
+ }
+
+ 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";
+ }
+ 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;
+ };
+
+ 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::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 {
+ 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::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_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_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__ )
+#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( "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::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_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_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__ )
+#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( " 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;
+
+// #included from: internal/catch_reenable_warnings.h
+
+#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#elif defined __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
diff --git a/third_party/libosmium/test/include/catch_orig.hpp b/third_party/libosmium/test/include/catch_orig.hpp
new file mode 100644
index 0000000..6b8dfb5
--- /dev/null
+++ b/third_party/libosmium/test/include/catch_orig.hpp
@@ -0,0 +1,8997 @@
+/*
+ * CATCH v1.0 build 53 (master branch)
+ * Generated: 2014-08-20 08:08:19.533804
+ * ----------------------------------------------------------
+ * 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
+
+// #included from: internal/catch_suppress_warnings.h
+
+#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+#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"
+#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
+
+#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; }
+ inline bool alwaysTrue() { return true; }
+ inline bool alwaysFalse() { return false; }
+
+ 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 );
+ 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( 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_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
+
+ }; };
+
+ 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 = 0x00,
+
+ ContinueOnFailure = 0x01, // Failures fail test, but execution continues
+ FalseTest = 0x02, // Prefix expression 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 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_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
+
+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 );
+
+ 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 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_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
+
+// #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();
+ }
+ };
+
+ 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>
+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( 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_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
+
+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_CPP11_OR_GREATER
+ ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
+# endif
+
+public:
+ ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {}
+# ifdef CATCH_CPP11_OR_GREATER
+ 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 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 std::string getCurrentTestName() const = 0;
+ virtual const AssertionResult* getLastResult() const = 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, macroName ) \
+ do { \
+ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+ if( __catchResult.allowThrows() ) \
+ try { \
+ expr; \
+ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
+ } \
+ catch( ... ) { \
+ __catchResult.captureResult( Catch::ResultWas::Ok ); \
+ } \
+ 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 = ::Catch::Matchers::matcher.toString(); \
+ __catchResult \
+ .setLhs( Catch::toString( arg ) ) \
+ .setRhs( matcherAsString == "{?}" ? #matcher : matcherAsString ) \
+ .setOp( "matches" ) \
+ .setResultType( ::Catch::Matchers::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
+
+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;
+ };
+
+} // 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 ), 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;
+ }
+
+ 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;
+ };
+}
+
+// #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( SectionInfo const& info );
+ ~Section();
+
+ // This indicates whether the section should be executed or not
+ operator bool() const;
+
+ private:
+#ifdef CATCH_CPP11_OR_GREATER
+ Section( Section const& ) = delete;
+ Section( Section && ) = delete;
+ Section& operator = ( Section const& ) = delete;
+ Section& operator = ( Section && ) = delete;
+#else
+ Section( Section const& info );
+ Section& operator = ( Section const& );
+#endif
+ 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 <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>
+// #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();
+
+}
+
+
+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
+
+// #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( 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
+
+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 <string>
+#include <set>
+
+#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 );
+
+ 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( 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 = static_cast<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.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
+ }; };
+
+ 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;
+ };
+}
+
+// #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( ITagAliasRegistry::get() );
+ 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 = static_cast<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 = 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( &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,
+ 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:
+ static Detail::IColourImpl* impl();
+ 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 <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( ITagAliasRegistry::get() ).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( ITagAliasRegistry::get() ).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;
+ }
+
+ 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() )
+ std::cout << "Tags for matching test cases:\n";
+ else {
+ std::cout << "All available tags:\n";
+ testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+ }
+
+ std::map<std::string, TagInfo> 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::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 ) );
+ 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 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;
+
+ 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 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:
+
+ 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 );
+ 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(...) {
+ ResultBuilder exResult( m_lastAssertionInfo.macroName.c_str(),
+ m_lastAssertionInfo.lineInfo,
+ m_lastAssertionInfo.capturedExpression.c_str(),
+ m_lastAssertionInfo.resultDisposition );
+ exResult.useActiveException();
+ }
+ // 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 );
+
+ 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 );
+ }
+
+ 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;
+ };
+
+ 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 _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( ITagAliasRegistry::get() ).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( TestFailureException& ) {
+ throw;
+ }
+ 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 ) : 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 ) {
+ 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( 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( 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 );
+ 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 == "." )
+ isHidden = true;
+ else
+ tags.insert( tag );
+ tag.clear();
+ }
+ else
+ tag += c;
+ }
+ }
+ if( isHidden ) {
+ tags.insert( "hide" );
+ tags.insert( "." );
+ }
+
+ TestCaseInfo info( _name, _className, desc, tags, _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,
+ SourceLineInfo const& _lineInfo )
+ : name( _name ),
+ className( _className ),
+ description( _description ),
+ tags( _tags ),
+ lineInfo( _lineInfo ),
+ properties( None )
+ {
+ 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 );
+ properties = static_cast<SpecialProperties>( properties | parseSpecialTag( lcaseTag ) );
+ lcaseTags.insert( lcaseTag );
+ }
+ tagsAsString = oss.str();
+ }
+
+ 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 {
+
+ // These numbers are maintained by a script
+ Version libraryVersion( 1, 0, 53, "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( 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 );
+
+ 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 );
+ }
+}
+
+// #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 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::getElapsedNanoseconds() const {
+ return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
+ }
+ unsigned int Timer::getElapsedMilliseconds() const {
+ return static_cast<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( 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 )
+ getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
+ }
+
+ // 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/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 {
+
+namespace Detail {
+
+ namespace {
+ 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 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;
+ 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 ) );
+}
+
+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_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 {
+
+ ResultBuilder::ResultBuilder( char const* macroName,
+ SourceLineInfo const& lineInfo,
+ char const* capturedExpression,
+ ResultDisposition::Flags resultDisposition )
+ : m_assertionInfo( macroName, lineInfo, capturedExpression, 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::captureExpression() {
+ AssertionResult result = build();
+ 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 <map>
+#include <iostream>
+
+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 );
+ std::cerr << ex.what() << std::endl;
+ exit(1);
+ }
+ }
+
+} // 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 ) {}
+ 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() )
+ {}
+ ~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;
+ }
+
+ 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;
+ }
+ }
+
+ 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.setStream( 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 )
+ .writeAttribute( "expectedFailures", totals.assertions.failedButOk );
+ 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 )
+ .writeAttribute( "expectedFailures", totals.assertions.failedButOk );
+ 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 )
+ .writeAttribute( "expectedFailures", assertions.failedButOk );
+ 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 )
+ {}
+
+ 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 ) {
+ 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::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.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";
+ }
+
+ 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";
+ }
+ 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;
+ };
+
+ 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::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 {
+ 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::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_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_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__ )
+#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( "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::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_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_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__ )
+#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( " 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;
+
+// #included from: internal/catch_reenable_warnings.h
+
+#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#elif defined __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
diff --git a/third_party/libosmium/test/include/utils.hpp b/third_party/libosmium/test/include/utils.hpp
new file mode 100644
index 0000000..662155a
--- /dev/null
+++ b/third_party/libosmium/test/include/utils.hpp
@@ -0,0 +1,18 @@
+
+#include <cstdlib>
+#include <string>
+
+inline std::string with_data_dir(const char* filename) {
+ const char* data_dir = getenv("OSMIUM_TEST_DATA_DIR");
+
+ std::string result;
+ if (data_dir) {
+ result = data_dir;
+ result += '/';
+ }
+
+ result += filename;
+
+ return result;
+}
+
diff --git a/third_party/libosmium/test/include/win_mkstemp.hpp b/third_party/libosmium/test/include/win_mkstemp.hpp
new file mode 100644
index 0000000..693c266
--- /dev/null
+++ b/third_party/libosmium/test/include/win_mkstemp.hpp
@@ -0,0 +1,42 @@
+/*
+ * mkstemp.c
+ *
+ * Provides a trivial replacement for the POSIX `mkstemp()' function,
+ * suitable for use in MinGW (Win32) applications.
+ *
+ * This file is part of the MinGW32 package set.
+ *
+ * Contributed by Keith Marshall <keithmarshall at users.sourceforge.net>
+ * Patched to VS2013 by alex85k
+ * THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ * This source code is offered for use in the public domain. You may
+ * use, modify or distribute it freely.
+ *
+ * This code is distributed in the hope that it will be useful but
+ * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ * DISCLAIMED. This includes but is not limited to warranties of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef WIN_MKSTEMP_H
+#define WIN_MKSTEMP_H
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <share.h>
+
+inline int mkstemp( char *templ )
+{
+ int maxtry = 26, rtn = -1;
+
+ while( maxtry-- && (rtn < 0) )
+ {
+ char *r = _mktemp( templ );
+ if( r == NULL )
+ return -1;
+ rtn = sopen( r, O_RDWR | O_CREAT | O_EXCL | O_BINARY, SH_DENYRW, 0600 );
+ }
+ return rtn;
+}
+#endif
diff --git a/third_party/libosmium/test/t/area/test_area_id.cpp b/third_party/libosmium/test/t/area/test_area_id.cpp
new file mode 100644
index 0000000..fbd8d78
--- /dev/null
+++ b/third_party/libosmium/test/t/area/test_area_id.cpp
@@ -0,0 +1,25 @@
+#include "catch.hpp"
+
+#include <osmium/osm/area.hpp>
+
+TEST_CASE("area_id") {
+
+ SECTION("object_id_to_area_id_conversion") {
+ REQUIRE( 46 == osmium::object_id_to_area_id( 23, osmium::item_type::way));
+ REQUIRE( 47 == osmium::object_id_to_area_id( 23, osmium::item_type::relation));
+ REQUIRE( 0 == osmium::object_id_to_area_id( 0, osmium::item_type::way));
+ REQUIRE( 1 == osmium::object_id_to_area_id( 0, osmium::item_type::relation));
+ REQUIRE(-24 == osmium::object_id_to_area_id(-12, osmium::item_type::way));
+ REQUIRE(-25 == osmium::object_id_to_area_id(-12, osmium::item_type::relation));
+ }
+
+ SECTION("area_id_to_object_id_conversion") {
+ REQUIRE( 23 == osmium::area_id_to_object_id( 46));
+ REQUIRE( 23 == osmium::area_id_to_object_id( 47));
+ REQUIRE( 0 == osmium::area_id_to_object_id( 0));
+ REQUIRE( 0 == osmium::area_id_to_object_id( 1));
+ REQUIRE(-12 == osmium::area_id_to_object_id(-24));
+ REQUIRE(-12 == osmium::area_id_to_object_id(-25));
+ }
+
+}
diff --git a/third_party/libosmium/test/t/area/test_node_ref_segment.cpp b/third_party/libosmium/test/t/area/test_node_ref_segment.cpp
new file mode 100644
index 0000000..3097687
--- /dev/null
+++ b/third_party/libosmium/test/t/area/test_node_ref_segment.cpp
@@ -0,0 +1,115 @@
+#include "catch.hpp"
+
+#include <osmium/area/detail/node_ref_segment.hpp>
+
+using osmium::area::detail::NodeRefSegment;
+
+TEST_CASE("NodeRefSegmentClass") {
+
+ SECTION("instantiation_with_default_parameters") {
+ NodeRefSegment s;
+ REQUIRE(s.first().ref() == 0);
+ REQUIRE(s.first().location() == osmium::Location());
+ REQUIRE(s.second().ref() == 0);
+ REQUIRE(s.second().location() == osmium::Location());
+ }
+
+ SECTION("instantiation") {
+ osmium::NodeRef nr1(1, { 1.2, 3.4 });
+ osmium::NodeRef nr2(2, { 1.4, 3.1 });
+ osmium::NodeRef nr3(3, { 1.2, 3.6 });
+ osmium::NodeRef nr4(4, { 1.2, 3.7 });
+
+ NodeRefSegment s1(nr1, nr2, nullptr, nullptr);
+ REQUIRE(s1.first().ref() == 1);
+ REQUIRE(s1.second().ref() == 2);
+
+ NodeRefSegment s2(nr2, nr3, nullptr, nullptr);
+ REQUIRE(s2.first().ref() == 3);
+ REQUIRE(s2.second().ref() == 2);
+
+ NodeRefSegment s3(nr3, nr4, nullptr, nullptr);
+ REQUIRE(s3.first().ref() == 3);
+ REQUIRE(s3.second().ref() == 4);
+ }
+
+ SECTION("intersection") {
+ NodeRefSegment s1({ 1, {0.0, 0.0}}, { 2, {2.0, 2.0}}, nullptr, nullptr);
+ NodeRefSegment s2({ 3, {0.0, 2.0}}, { 4, {2.0, 0.0}}, nullptr, nullptr);
+ NodeRefSegment s3({ 5, {2.0, 0.0}}, { 6, {4.0, 2.0}}, nullptr, nullptr);
+ NodeRefSegment s4({ 7, {1.0, 0.0}}, { 8, {3.0, 2.0}}, nullptr, nullptr);
+ NodeRefSegment s5({ 9, {0.0, 4.0}}, {10, {4.0, 0.0}}, nullptr, nullptr);
+ NodeRefSegment s6({11, {0.0, 0.0}}, {12, {1.0, 1.0}}, nullptr, nullptr);
+ NodeRefSegment s7({13, {1.0, 1.0}}, {14, {3.0, 3.0}}, nullptr, nullptr);
+
+ REQUIRE(calculate_intersection(s1, s2) == osmium::Location(1.0, 1.0));
+ REQUIRE(calculate_intersection(s1, s3) == osmium::Location());
+ REQUIRE(calculate_intersection(s2, s3) == osmium::Location());
+ REQUIRE(calculate_intersection(s1, s4) == osmium::Location());
+ REQUIRE(calculate_intersection(s1, s5) == osmium::Location(2.0, 2.0));
+ REQUIRE(calculate_intersection(s1, s1) == osmium::Location());
+ REQUIRE(calculate_intersection(s1, s6) == osmium::Location());
+ REQUIRE(calculate_intersection(s1, s7) == osmium::Location());
+ }
+
+ SECTION("to_left_of") {
+ osmium::Location loc { 2.0, 2.0 };
+
+ REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {0.0, 4.0}}, nullptr, nullptr).to_left_of(loc));
+ REQUIRE(NodeRefSegment({0, {4.0, 0.0}}, {1, {4.0, 4.0}}, nullptr, nullptr).to_left_of(loc) == false);
+ REQUIRE(NodeRefSegment({0, {1.0, 0.0}}, {1, {1.0, 4.0}}, nullptr, nullptr).to_left_of(loc));
+
+ REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {1.0, 4.0}}, nullptr, nullptr).to_left_of(loc));
+ REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {2.0, 4.0}}, nullptr, nullptr).to_left_of(loc));
+ REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {3.0, 4.0}}, nullptr, nullptr).to_left_of(loc));
+ REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {4.0, 4.0}}, nullptr, nullptr).to_left_of(loc));
+ REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {4.0, 3.0}}, nullptr, nullptr).to_left_of(loc) == false);
+
+ REQUIRE(NodeRefSegment({0, {1.0, 3.0}}, {1, {2.0, 0.0}}, nullptr, nullptr).to_left_of(loc));
+ REQUIRE(NodeRefSegment({0, {1.0, 3.0}}, {1, {3.0, 1.0}}, nullptr, nullptr).to_left_of(loc));
+ REQUIRE(NodeRefSegment({0, {1.0, 3.0}}, {1, {3.0, 2.0}}, nullptr, nullptr).to_left_of(loc) == false);
+
+ REQUIRE(NodeRefSegment({0, {0.0, 2.0}}, {1, {2.0, 2.0}}, nullptr, nullptr).to_left_of(loc) == false);
+
+ REQUIRE(NodeRefSegment({0, {2.0, 0.0}}, {1, {2.0, 4.0}}, nullptr, nullptr).to_left_of(loc));
+ REQUIRE(NodeRefSegment({0, {2.0, 0.0}}, {1, {2.0, 2.0}}, nullptr, nullptr).to_left_of(loc) == false);
+ REQUIRE(NodeRefSegment({0, {2.0, 2.0}}, {1, {2.0, 4.0}}, nullptr, nullptr).to_left_of(loc) == false);
+
+ REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {0.0, 1.0}}, nullptr, nullptr).to_left_of(loc) == false);
+ REQUIRE(NodeRefSegment({0, {1.0, 0.0}}, {1, {0.0, 1.0}}, nullptr, nullptr).to_left_of(loc) == false);
+
+ REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {1.0, 3.0}}, nullptr, nullptr).to_left_of(loc));
+ REQUIRE(NodeRefSegment({0, {0.0, 2.0}}, {1, {2.0, 0.0}}, nullptr, nullptr).to_left_of(loc));
+ REQUIRE(NodeRefSegment({0, {0.0, 2.0}}, {1, {3.0, 4.0}}, nullptr, nullptr).to_left_of(loc) == false);
+
+ REQUIRE(NodeRefSegment({0, {1.0, 0.0}}, {1, {1.0, 2.0}}, nullptr, nullptr).to_left_of(loc));
+ REQUIRE(NodeRefSegment({0, {0.0, 2.0}}, {1, {1.0, 2.0}}, nullptr, nullptr).to_left_of(loc) == false);
+ REQUIRE(NodeRefSegment({0, {0.0, 2.0}}, {1, {1.0, 4.0}}, nullptr, nullptr).to_left_of(loc) == false);
+
+ REQUIRE(NodeRefSegment({0, {0.0, 0.0}}, {1, {0.0, 2.0}}, nullptr, nullptr).to_left_of(loc));
+ REQUIRE(NodeRefSegment({0, {0.0, 2.0}}, {1, {4.0, 4.0}}, nullptr, nullptr).to_left_of(loc) == false);
+
+ REQUIRE(NodeRefSegment({0, {0.0, 1.0}}, {1, {2.0, 2.0}}, nullptr, nullptr).to_left_of(loc) == false);
+ REQUIRE(NodeRefSegment({0, {2.0, 2.0}}, {1, {4.0, 0.0}}, nullptr, nullptr).to_left_of(loc) == false);
+ }
+
+ SECTION("ordering") {
+ osmium::NodeRef node_ref1(1, { 1.0, 3.0 });
+ osmium::NodeRef node_ref2(2, { 1.4, 2.9 });
+ osmium::NodeRef node_ref3(3, { 1.2, 3.0 });
+ osmium::NodeRef node_ref4(4, { 1.2, 3.3 });
+
+ REQUIRE(node_ref1 < node_ref2);
+ REQUIRE(node_ref2 < node_ref3);
+ REQUIRE(node_ref1 < node_ref3);
+ REQUIRE(node_ref1 >= node_ref1);
+
+ REQUIRE( osmium::location_less()(node_ref1, node_ref2));
+ REQUIRE(!osmium::location_less()(node_ref2, node_ref3));
+ REQUIRE( osmium::location_less()(node_ref1, node_ref3));
+ REQUIRE( osmium::location_less()(node_ref3, node_ref4));
+ REQUIRE(!osmium::location_less()(node_ref1, node_ref1));
+ }
+
+}
+
diff --git a/third_party/libosmium/test/t/basic/helper.hpp b/third_party/libosmium/test/t/basic/helper.hpp
new file mode 100644
index 0000000..61e0769
--- /dev/null
+++ b/third_party/libosmium/test/t/basic/helper.hpp
@@ -0,0 +1,97 @@
+#ifndef TEST_BASIC_HELPER_HPP
+#define TEST_BASIC_HELPER_HPP
+
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include <osmium/builder/osm_object_builder.hpp>
+
+inline void add_tags(osmium::memory::Buffer& buffer, osmium::builder::Builder& builder, const std::vector<std::pair<const char*, const char*>>& tags) {
+ osmium::builder::TagListBuilder tl_builder(buffer, &builder);
+ for (auto& tag : tags) {
+ tl_builder.add_tag(tag.first, tag.second);
+ }
+}
+
+inline osmium::Node& buffer_add_node(osmium::memory::Buffer& buffer, const char* user, const std::vector<std::pair<const char*, const char*>>& tags, const osmium::Location& location) {
+ osmium::builder::NodeBuilder builder(buffer);
+ builder.add_user(user);
+ add_tags(buffer, builder, tags);
+ buffer.commit();
+ return builder.object().set_location(location);
+}
+
+inline osmium::Way& buffer_add_way(osmium::memory::Buffer& buffer, const char* user, const std::vector<std::pair<const char*, const char*>>& tags, const std::vector<osmium::object_id_type>& nodes) {
+ osmium::builder::WayBuilder builder(buffer);
+ builder.add_user(user);
+ add_tags(buffer, builder, tags);
+ osmium::builder::WayNodeListBuilder wnl_builder(buffer, &builder);
+ for (const osmium::object_id_type ref : nodes) {
+ wnl_builder.add_node_ref(ref);
+ }
+ buffer.commit();
+ return builder.object();
+}
+
+inline osmium::Way& buffer_add_way(osmium::memory::Buffer& buffer, const char* user, const std::vector<std::pair<const char*, const char*>>& tags, const std::vector<std::pair<osmium::object_id_type, osmium::Location>>& nodes) {
+ osmium::builder::WayBuilder builder(buffer);
+ builder.add_user(user);
+ add_tags(buffer, builder, tags);
+ osmium::builder::WayNodeListBuilder wnl_builder(buffer, &builder);
+ for (auto& p : nodes) {
+ wnl_builder.add_node_ref(p.first, p.second);
+ }
+ buffer.commit();
+ return builder.object();
+}
+
+inline osmium::Relation& buffer_add_relation(
+ osmium::memory::Buffer& buffer,
+ const char* user,
+ const std::vector<std::pair<const char*, const char*>>& tags, const std::vector<std::tuple<char, osmium::object_id_type, const char*>>& members) {
+ osmium::builder::RelationBuilder builder(buffer);
+ builder.add_user(user);
+ add_tags(buffer, builder, tags);
+ osmium::builder::RelationMemberListBuilder rml_builder(buffer, &builder);
+ for (const auto& member : members) {
+ rml_builder.add_member(osmium::char_to_item_type(std::get<0>(member)), std::get<1>(member), std::get<2>(member));
+ }
+ buffer.commit();
+ return builder.object();
+}
+
+inline osmium::Area& buffer_add_area(osmium::memory::Buffer& buffer, const char* user,
+ const std::vector<std::pair<const char*, const char*>>& tags,
+ const std::vector<std::pair<bool,
+ std::vector<std::pair<osmium::object_id_type, osmium::Location>>>>& rings) {
+ osmium::builder::AreaBuilder builder(buffer);
+ builder.add_user(user);
+ add_tags(buffer, builder, tags);
+
+ for (auto& ring : rings) {
+ if (ring.first) {
+ osmium::builder::OuterRingBuilder ring_builder(buffer, &builder);
+ for (auto& p : ring.second) {
+ ring_builder.add_node_ref(p.first, p.second);
+ }
+ } else {
+ osmium::builder::InnerRingBuilder ring_builder(buffer, &builder);
+ for (auto& p : ring.second) {
+ ring_builder.add_node_ref(p.first, p.second);
+ }
+ }
+ }
+ buffer.commit();
+ return builder.object();
+}
+
+inline osmium::Changeset& buffer_add_changeset(osmium::memory::Buffer& buffer, const char* user, const std::vector<std::pair<const char*, const char*>>& tags) {
+ osmium::builder::ChangesetBuilder builder(buffer);
+ builder.add_user(user);
+ add_tags(buffer, builder, tags);
+ buffer.commit();
+ return builder.object();
+}
+
+#endif // TEST_BASIC_HELPER_HPP
diff --git a/third_party/libosmium/test/t/basic/test_box.cpp b/third_party/libosmium/test/t/basic/test_box.cpp
new file mode 100644
index 0000000..8182fbf
--- /dev/null
+++ b/third_party/libosmium/test/t/basic/test_box.cpp
@@ -0,0 +1,91 @@
+#include "catch.hpp"
+
+#include <sstream>
+
+#include <osmium/osm/box.hpp>
+#include <osmium/geom/relations.hpp>
+
+TEST_CASE("Box") {
+
+ SECTION("instantiation") {
+ osmium::Box b;
+ REQUIRE(!b);
+ REQUIRE(!b.bottom_left());
+ REQUIRE(!b.top_right());
+ REQUIRE_THROWS_AS(b.size(), osmium::invalid_location);
+ }
+
+ SECTION("instantiation_and_extend_with_undefined") {
+ osmium::Box b;
+ REQUIRE(!b);
+ b.extend(osmium::Location());
+ REQUIRE(!b.bottom_left());
+ REQUIRE(!b.top_right());
+ }
+
+ SECTION("instantiation_and_extend") {
+ osmium::Box b;
+ osmium::Location loc1 { 1.2, 3.4 };
+ b.extend(loc1);
+ REQUIRE(!!b);
+ REQUIRE(!!b.bottom_left());
+ REQUIRE(!!b.top_right());
+ REQUIRE(b.contains(loc1));
+
+ osmium::Location loc2 { 3.4, 4.5 };
+ osmium::Location loc3 { 5.6, 7.8 };
+
+ b.extend(loc2);
+ b.extend(loc3);
+ REQUIRE(b.bottom_left() == osmium::Location(1.2, 3.4));
+ REQUIRE(b.top_right() == osmium::Location(5.6, 7.8));
+
+ // extend with undefined doesn't change anything
+ b.extend(osmium::Location());
+ REQUIRE(b.bottom_left() == osmium::Location(1.2, 3.4));
+ REQUIRE(b.top_right() == osmium::Location(5.6, 7.8));
+
+ REQUIRE(b.contains(loc1));
+ REQUIRE(b.contains(loc2));
+ REQUIRE(b.contains(loc3));
+ }
+
+ SECTION("output_defined") {
+ osmium::Box b;
+ b.extend(osmium::Location(1.2, 3.4));
+ b.extend(osmium::Location(5.6, 7.8));
+ std::stringstream out;
+ out << b;
+ REQUIRE(out.str() == "(1.2,3.4,5.6,7.8)");
+ REQUIRE(b.size() == Approx(19.36).epsilon(0.000001));
+ }
+
+ SECTION("output_undefined") {
+ osmium::Box b;
+ std::stringstream out;
+ out << b;
+ REQUIRE(out.str() == "(undefined)");
+ }
+
+ SECTION("box_inside_box") {
+ osmium::Box outer;
+ outer.extend(osmium::Location(1, 1));
+ outer.extend(osmium::Location(10, 10));
+
+ osmium::Box inner;
+ inner.extend(osmium::Location(2, 2));
+ inner.extend(osmium::Location(4, 4));
+
+ osmium::Box overlap;
+ overlap.extend(osmium::Location(3, 3));
+ overlap.extend(osmium::Location(5, 5));
+
+ REQUIRE( osmium::geom::contains(inner, outer));
+ REQUIRE(!osmium::geom::contains(outer, inner));
+
+ REQUIRE(!osmium::geom::contains(overlap, inner));
+ REQUIRE(!osmium::geom::contains(inner, overlap));
+ }
+
+}
+
diff --git a/third_party/libosmium/test/t/basic/test_changeset.cpp b/third_party/libosmium/test/t/basic/test_changeset.cpp
new file mode 100644
index 0000000..2549c1e
--- /dev/null
+++ b/third_party/libosmium/test/t/basic/test_changeset.cpp
@@ -0,0 +1,57 @@
+#include "catch.hpp"
+
+#include <osmium/osm/changeset.hpp>
+
+#include "helper.hpp"
+
+TEST_CASE("Basic_Changeset") {
+
+SECTION("changeset_builder") {
+ osmium::memory::Buffer buffer(10 * 1000);
+
+ osmium::Changeset& cs1 = buffer_add_changeset(buffer,
+ "user",
+ {{"comment", "foo"}});
+
+ cs1.set_id(42)
+ .set_created_at(100)
+ .set_closed_at(200)
+ .set_num_changes(7)
+ .set_uid(9);
+
+ REQUIRE(42 == cs1.id());
+ REQUIRE(9 == cs1.uid());
+ REQUIRE(7 == cs1.num_changes());
+ REQUIRE(true == cs1.closed());
+ REQUIRE(osmium::Timestamp(100) == cs1.created_at());
+ REQUIRE(osmium::Timestamp(200) == cs1.closed_at());
+ REQUIRE(1 == cs1.tags().size());
+ REQUIRE(std::string("user") == cs1.user());
+
+ osmium::Changeset& cs2 = buffer_add_changeset(buffer,
+ "user",
+ {{"comment", "foo"}, {"foo", "bar"}});
+
+ cs2.set_id(43)
+ .set_created_at(120)
+ .set_num_changes(21)
+ .set_uid(9);
+
+ REQUIRE(43 == cs2.id());
+ REQUIRE(9 == cs2.uid());
+ REQUIRE(21 == cs2.num_changes());
+ REQUIRE(false == cs2.closed());
+ REQUIRE(osmium::Timestamp(120) == cs2.created_at());
+ REQUIRE(osmium::Timestamp() == cs2.closed_at());
+ REQUIRE(2 == cs2.tags().size());
+ REQUIRE(std::string("user") == cs2.user());
+
+ REQUIRE(cs1 != cs2);
+
+ REQUIRE(cs1 < cs2);
+ REQUIRE(cs1 <= cs2);
+ REQUIRE(false == (cs1 > cs2));
+ REQUIRE(false == (cs1 >= cs2));
+}
+
+}
diff --git a/third_party/libosmium/test/t/basic/test_entity_bits.cpp b/third_party/libosmium/test/t/basic/test_entity_bits.cpp
new file mode 100644
index 0000000..f15068b
--- /dev/null
+++ b/third_party/libosmium/test/t/basic/test_entity_bits.cpp
@@ -0,0 +1,31 @@
+#include "catch.hpp"
+
+#include <osmium/osm/entity_bits.hpp>
+
+TEST_CASE("entity_bits") {
+
+ SECTION("can_be_set_and_checked") {
+ osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::node | osmium::osm_entity_bits::way;
+ REQUIRE(entities == (osmium::osm_entity_bits::node | osmium::osm_entity_bits::way));
+
+ entities |= osmium::osm_entity_bits::relation;
+ REQUIRE((entities & osmium::osm_entity_bits::object));
+
+ entities |= osmium::osm_entity_bits::area;
+ REQUIRE(entities == osmium::osm_entity_bits::object);
+
+ REQUIRE(! (entities & osmium::osm_entity_bits::changeset));
+
+ entities &= osmium::osm_entity_bits::node;
+ REQUIRE((entities & osmium::osm_entity_bits::node));
+ REQUIRE(! (entities & osmium::osm_entity_bits::way));
+ REQUIRE(entities == osmium::osm_entity_bits::node);
+
+ REQUIRE(osmium::osm_entity_bits::node == osmium::osm_entity_bits::from_item_type(osmium::item_type::node));
+ REQUIRE(osmium::osm_entity_bits::way == osmium::osm_entity_bits::from_item_type(osmium::item_type::way));
+ REQUIRE(osmium::osm_entity_bits::relation == osmium::osm_entity_bits::from_item_type(osmium::item_type::relation));
+ REQUIRE(osmium::osm_entity_bits::changeset == osmium::osm_entity_bits::from_item_type(osmium::item_type::changeset));
+ REQUIRE(osmium::osm_entity_bits::area == osmium::osm_entity_bits::from_item_type(osmium::item_type::area));
+ }
+
+}
diff --git a/third_party/libosmium/test/t/basic/test_location.cpp b/third_party/libosmium/test/t/basic/test_location.cpp
new file mode 100644
index 0000000..3fd8d15
--- /dev/null
+++ b/third_party/libosmium/test/t/basic/test_location.cpp
@@ -0,0 +1,154 @@
+#include "catch.hpp"
+
+#include <sstream>
+#include <type_traits>
+
+#include <osmium/osm/location.hpp>
+
+TEST_CASE("Location") {
+
+// fails on MSVC and doesn't really matter
+// static_assert(std::is_literal_type<osmium::Location>::value, "osmium::Location not literal type");
+
+ SECTION("instantiation_with_default_parameters") {
+ osmium::Location loc;
+ REQUIRE(!loc);
+ REQUIRE_THROWS_AS(loc.lon(), osmium::invalid_location);
+ REQUIRE_THROWS_AS(loc.lat(), osmium::invalid_location);
+ }
+
+ SECTION("instantiation_with_double_parameters") {
+ osmium::Location loc1(1.2, 4.5);
+ REQUIRE(!!loc1);
+ REQUIRE(12000000 == loc1.x());
+ REQUIRE(45000000 == loc1.y());
+ REQUIRE(1.2 == loc1.lon());
+ REQUIRE(4.5 == loc1.lat());
+
+ osmium::Location loc2(loc1);
+ REQUIRE(4.5 == loc2.lat());
+
+ osmium::Location loc3 = loc1;
+ REQUIRE(4.5 == loc3.lat());
+ }
+
+ SECTION("instantiation_with_double_parameters_constructor_with_universal_initializer") {
+ osmium::Location loc { 2.2, 3.3 };
+ REQUIRE(2.2 == loc.lon());
+ REQUIRE(3.3 == loc.lat());
+ }
+
+ SECTION("instantiation_with_double_parameters_constructor_with_initializer_list") {
+ osmium::Location loc({ 4.4, 5.5 });
+ REQUIRE(4.4 == loc.lon());
+ REQUIRE(5.5 == loc.lat());
+ }
+
+ SECTION("instantiation_with_double_parameters_operator_equal") {
+ osmium::Location loc = { 5.5, 6.6 };
+ REQUIRE(5.5 == loc.lon());
+ REQUIRE(6.6 == loc.lat());
+ }
+
+ SECTION("equality") {
+ osmium::Location loc1(1.2, 4.5);
+ osmium::Location loc2(1.2, 4.5);
+ osmium::Location loc3(1.5, 1.5);
+ REQUIRE(loc1 == loc2);
+ REQUIRE(loc1 != loc3);
+ }
+
+ SECTION("order") {
+ REQUIRE(osmium::Location(-1.2, 10.0) < osmium::Location(1.2, 10.0));
+ REQUIRE(osmium::Location(1.2, 10.0) > osmium::Location(-1.2, 10.0));
+
+ REQUIRE(osmium::Location(10.2, 20.0) < osmium::Location(11.2, 20.2));
+ REQUIRE(osmium::Location(10.2, 20.2) < osmium::Location(11.2, 20.0));
+ REQUIRE(osmium::Location(11.2, 20.2) > osmium::Location(10.2, 20.0));
+ }
+
+ SECTION("validity") {
+ REQUIRE(osmium::Location(0.0, 0.0).valid());
+ REQUIRE(osmium::Location(1.2, 4.5).valid());
+ REQUIRE(osmium::Location(-1.2, 4.5).valid());
+ REQUIRE(osmium::Location(-180.0, -90.0).valid());
+ REQUIRE(osmium::Location(180.0, -90.0).valid());
+ REQUIRE(osmium::Location(-180.0, 90.0).valid());
+ REQUIRE(osmium::Location(180.0, 90.0).valid());
+
+ REQUIRE(!osmium::Location(200.0, 4.5).valid());
+ REQUIRE(!osmium::Location(-1.2, -100.0).valid());
+ REQUIRE(!osmium::Location(-180.0, 90.005).valid());
+ }
+
+
+ SECTION("output_to_iterator_comma_separator") {
+ char buffer[100];
+ osmium::Location loc(-3.2, 47.3);
+ *loc.as_string(buffer, ',') = 0;
+ REQUIRE(std::string("-3.2,47.3") == buffer);
+ }
+
+ SECTION("output_to_iterator_space_separator") {
+ char buffer[100];
+ osmium::Location loc(0.0, 7.0);
+ *loc.as_string(buffer, ' ') = 0;
+ REQUIRE(std::string("0 7") == buffer);
+ }
+
+ SECTION("output_to_iterator_check_precision") {
+ char buffer[100];
+ osmium::Location loc(-179.9999999, -90.0);
+ *loc.as_string(buffer, ' ') = 0;
+ REQUIRE(std::string("-179.9999999 -90") == buffer);
+ }
+
+ SECTION("output_to_iterator_undefined_location") {
+ char buffer[100];
+ osmium::Location loc;
+ REQUIRE_THROWS_AS(loc.as_string(buffer, ','), osmium::invalid_location);
+ }
+
+ SECTION("output_to_string_comman_separator") {
+ std::string s;
+ osmium::Location loc(-3.2, 47.3);
+ loc.as_string(std::back_inserter(s), ',');
+ REQUIRE(s == "-3.2,47.3");
+ }
+
+ SECTION("output_to_string_space_separator") {
+ std::string s;
+ osmium::Location loc(0.0, 7.0);
+ loc.as_string(std::back_inserter(s), ' ');
+ REQUIRE(s == "0 7");
+ }
+
+ SECTION("output_to_string_check_precision") {
+ std::string s;
+ osmium::Location loc(-179.9999999, -90.0);
+ loc.as_string(std::back_inserter(s), ' ');
+ REQUIRE(s == "-179.9999999 -90");
+ }
+
+ SECTION("output_to_string_undefined_location") {
+ std::string s;
+ osmium::Location loc;
+ REQUIRE_THROWS_AS(loc.as_string(std::back_inserter(s), ','), osmium::invalid_location);
+ }
+
+ SECTION("output_defined") {
+ osmium::Location p(-3.2, 47.3);
+ std::stringstream out;
+ out << p;
+ REQUIRE(out.str() == "(-3.2,47.3)");
+ }
+
+ SECTION("output_undefined") {
+ osmium::Location p;
+ std::stringstream out;
+ out << p;
+ REQUIRE(out.str() == "(undefined,undefined)");
+ }
+
+}
+
diff --git a/third_party/libosmium/test/t/basic/test_node.cpp b/third_party/libosmium/test/t/basic/test_node.cpp
new file mode 100644
index 0000000..6c2c899
--- /dev/null
+++ b/third_party/libosmium/test/t/basic/test_node.cpp
@@ -0,0 +1,117 @@
+#include "catch.hpp"
+
+#include <osmium/osm/node.hpp>
+
+#include "helper.hpp"
+
+TEST_CASE("Basic_Node") {
+
+SECTION("node_builder") {
+ osmium::memory::Buffer buffer(10000);
+
+ osmium::Node& node = buffer_add_node(buffer,
+ "foo",
+ {{"amenity", "pub"}, {"name", "OSM BAR"}},
+ {3.5, 4.7});
+
+ node.set_id(17)
+ .set_version(3)
+ .set_visible(true)
+ .set_changeset(333)
+ .set_uid(21)
+ .set_timestamp(123);
+
+ REQUIRE(osmium::item_type::node == node.type());
+ REQUIRE(node.type_is_in(osmium::osm_entity_bits::node));
+ REQUIRE(node.type_is_in(osmium::osm_entity_bits::nwr));
+ REQUIRE(17l == node.id());
+ REQUIRE(17ul == node.positive_id());
+ REQUIRE(3 == node.version());
+ REQUIRE(true == node.visible());
+ REQUIRE(false == node.deleted());
+ REQUIRE(333 == node.changeset());
+ REQUIRE(21 == node.uid());
+ REQUIRE(std::string("foo") == node.user());
+ REQUIRE(123 == node.timestamp());
+ REQUIRE(osmium::Location(3.5, 4.7) == node.location());
+ REQUIRE(2 == node.tags().size());
+
+ node.set_visible(false);
+ REQUIRE(false == node.visible());
+ REQUIRE(true == node.deleted());
+}
+
+SECTION("node_default_attributes") {
+ osmium::memory::Buffer buffer(10000);
+
+ osmium::Node& node = buffer_add_node(buffer, "", {}, osmium::Location{});
+
+ REQUIRE(0l == node.id());
+ REQUIRE(0ul == node.positive_id());
+ REQUIRE(0 == node.version());
+ REQUIRE(true == node.visible());
+ REQUIRE(0 == node.changeset());
+ REQUIRE(0 == node.uid());
+ REQUIRE(std::string("") == node.user());
+ REQUIRE(0 == node.timestamp());
+ REQUIRE(osmium::Location() == node.location());
+ REQUIRE(0 == node.tags().size());
+}
+
+SECTION("set_node_attributes_from_string") {
+ osmium::memory::Buffer buffer(10000);
+
+ osmium::Node& node = buffer_add_node(buffer,
+ "foo",
+ {{"amenity", "pub"}, {"name", "OSM BAR"}},
+ {3.5, 4.7});
+
+ node.set_id("-17")
+ .set_version("3")
+ .set_visible(true)
+ .set_changeset("333")
+ .set_uid("21");
+
+ REQUIRE(-17l == node.id());
+ REQUIRE(17ul == node.positive_id());
+ REQUIRE(3 == node.version());
+ REQUIRE(true == node.visible());
+ REQUIRE(333 == node.changeset());
+ REQUIRE(21 == node.uid());
+}
+
+SECTION("large_id") {
+ osmium::memory::Buffer buffer(10000);
+
+ osmium::Node& node = buffer_add_node(buffer, "", {}, osmium::Location{});
+
+ int64_t id = 3000000000l;
+ node.set_id(id);
+
+ REQUIRE(id == node.id());
+ REQUIRE(static_cast<osmium::unsigned_object_id_type>(id) == node.positive_id());
+
+ node.set_id(-id);
+ REQUIRE(-id == node.id());
+ REQUIRE(static_cast<osmium::unsigned_object_id_type>(id) == node.positive_id());
+}
+
+SECTION("tags") {
+ osmium::memory::Buffer buffer(10000);
+
+ osmium::Node& node = buffer_add_node(buffer,
+ "foo",
+ {{"amenity", "pub"}, {"name", "OSM BAR"}},
+ {3.5, 4.7});
+
+ REQUIRE(nullptr == node.tags().get_value_by_key("fail"));
+ REQUIRE(std::string("pub") == node.tags().get_value_by_key("amenity"));
+ REQUIRE(std::string("pub") == node.get_value_by_key("amenity"));
+
+ REQUIRE(std::string("default") == node.tags().get_value_by_key("fail", "default"));
+ REQUIRE(std::string("pub") == node.tags().get_value_by_key("amenity", "default"));
+ REQUIRE(std::string("pub") == node.get_value_by_key("amenity", "default"));
+}
+
+
+}
diff --git a/third_party/libosmium/test/t/basic/test_node_ref.cpp b/third_party/libosmium/test/t/basic/test_node_ref.cpp
new file mode 100644
index 0000000..ac7ccbf
--- /dev/null
+++ b/third_party/libosmium/test/t/basic/test_node_ref.cpp
@@ -0,0 +1,57 @@
+#include "catch.hpp"
+
+#include <osmium/osm/node_ref.hpp>
+
+TEST_CASE("NodeRef") {
+
+ SECTION("instantiation_with_default_parameters") {
+ osmium::NodeRef node_ref;
+ REQUIRE(node_ref.ref() == 0);
+// REQUIRE(!node_ref.has_location());
+ }
+
+ SECTION("instantiation_with_id") {
+ osmium::NodeRef node_ref(7);
+ REQUIRE(node_ref.ref() == 7);
+ }
+
+ SECTION("equality") {
+ osmium::NodeRef node_ref1(7, { 1.2, 3.4 });
+ osmium::NodeRef node_ref2(7, { 1.4, 3.1 });
+ osmium::NodeRef node_ref3(9, { 1.2, 3.4 });
+ REQUIRE(node_ref1 == node_ref2);
+ REQUIRE(node_ref1 != node_ref3);
+ REQUIRE(!osmium::location_equal()(node_ref1, node_ref2));
+ REQUIRE(!osmium::location_equal()(node_ref2, node_ref3));
+ REQUIRE(osmium::location_equal()(node_ref1, node_ref3));
+ }
+
+ SECTION("set_location") {
+ osmium::NodeRef node_ref(7);
+ REQUIRE(!node_ref.location().valid());
+ REQUIRE(node_ref.location() == osmium::Location());
+ node_ref.set_location(osmium::Location(13.5, -7.2));
+ REQUIRE(node_ref.location().lon() == 13.5);
+ REQUIRE(node_ref.location().valid());
+ }
+
+ SECTION("ordering") {
+ osmium::NodeRef node_ref1(1, { 1.0, 3.0 });
+ osmium::NodeRef node_ref2(2, { 1.4, 2.9 });
+ osmium::NodeRef node_ref3(3, { 1.2, 3.0 });
+ osmium::NodeRef node_ref4(4, { 1.2, 3.3 });
+
+ REQUIRE(node_ref1 < node_ref2);
+ REQUIRE(node_ref2 < node_ref3);
+ REQUIRE(node_ref1 < node_ref3);
+ REQUIRE(node_ref1 >= node_ref1);
+
+ REQUIRE(osmium::location_less()(node_ref1, node_ref2));
+ REQUIRE(!osmium::location_less()(node_ref2, node_ref3));
+ REQUIRE(osmium::location_less()(node_ref1, node_ref3));
+ REQUIRE(osmium::location_less()(node_ref3, node_ref4));
+ REQUIRE(!osmium::location_less()(node_ref1, node_ref1));
+ }
+
+}
+
diff --git a/third_party/libosmium/test/t/basic/test_object_comparisons.cpp b/third_party/libosmium/test/t/basic/test_object_comparisons.cpp
new file mode 100644
index 0000000..2bfdcad
--- /dev/null
+++ b/third_party/libosmium/test/t/basic/test_object_comparisons.cpp
@@ -0,0 +1,147 @@
+#include "catch.hpp"
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/object_comparisons.hpp>
+
+TEST_CASE("Object_Comparisons") {
+
+ SECTION("order") {
+ osmium::memory::Buffer buffer(10 * 1000);
+
+ {
+ // add node 1
+ osmium::builder::NodeBuilder node_builder(buffer);
+ node_builder.add_user("testuser");
+ buffer.commit();
+ }
+
+ {
+ // add node 2
+ osmium::builder::NodeBuilder node_builder(buffer);
+ node_builder.add_user("testuser");
+ buffer.commit();
+ }
+
+ auto it = buffer.begin();
+ osmium::Node& node1 = static_cast<osmium::Node&>(*it);
+ osmium::Node& node2 = static_cast<osmium::Node&>(*(++it));
+
+ node1.set_id(10);
+ node1.set_version(1);
+ node2.set_id(15);
+ node2.set_version(2);
+ REQUIRE(true == (node1 < node2));
+ REQUIRE(false == (node1 > node2));
+ node1.set_id(20);
+ node1.set_version(1);
+ node2.set_id(20);
+ node2.set_version(2);
+ REQUIRE(true == (node1 < node2));
+ REQUIRE(false == (node1 > node2));
+ node1.set_id(-10);
+ node1.set_version(2);
+ node2.set_id(-15);
+ node2.set_version(1);
+ REQUIRE(true == (node1 < node2));
+ REQUIRE(false == (node1 > node2));
+ }
+
+ SECTION("order_types") {
+ osmium::memory::Buffer buffer(10 * 1000);
+
+ {
+ // add node 1
+ osmium::builder::NodeBuilder node_builder(buffer);
+ osmium::Node& node = node_builder.object();
+ REQUIRE(osmium::item_type::node == node.type());
+
+ node.set_id(3);
+ node.set_version(3);
+ node_builder.add_user("testuser");
+
+ buffer.commit();
+ }
+
+ {
+ // add node 2
+ osmium::builder::NodeBuilder node_builder(buffer);
+ osmium::Node& node = node_builder.object();
+ REQUIRE(osmium::item_type::node == node.type());
+
+ node.set_id(3);
+ node.set_version(4);
+ node_builder.add_user("testuser");
+
+ buffer.commit();
+ }
+
+ {
+ // add node 3
+ osmium::builder::NodeBuilder node_builder(buffer);
+ osmium::Node& node = node_builder.object();
+ REQUIRE(osmium::item_type::node == node.type());
+
+ node.set_id(3);
+ node.set_version(4);
+ node_builder.add_user("testuser");
+
+ buffer.commit();
+ }
+
+ {
+ // add way
+ osmium::builder::WayBuilder way_builder(buffer);
+ osmium::Way& way = way_builder.object();
+ REQUIRE(osmium::item_type::way == way.type());
+
+ way.set_id(2);
+ way.set_version(2);
+ way_builder.add_user("testuser");
+
+ buffer.commit();
+ }
+
+ {
+ // add relation
+ osmium::builder::RelationBuilder relation_builder(buffer);
+ osmium::Relation& relation = relation_builder.object();
+ REQUIRE(osmium::item_type::relation == relation.type());
+
+ relation.set_id(1);
+ relation.set_version(1);
+ relation_builder.add_user("testuser");
+
+ buffer.commit();
+ }
+
+ auto it = buffer.begin();
+ const osmium::Node& node1 = static_cast<const osmium::Node&>(*it);
+ const osmium::Node& node2 = static_cast<const osmium::Node&>(*(++it));
+ const osmium::Node& node3 = static_cast<const osmium::Node&>(*(++it));
+ const osmium::Way& way = static_cast<const osmium::Way&>(*(++it));
+ const osmium::Relation& relation = static_cast<const osmium::Relation&>(*(++it));
+
+ REQUIRE(true == (node1 < node2));
+ REQUIRE(true == (node2 < way));
+ REQUIRE(false == (node2 > way));
+ REQUIRE(true == (way < relation));
+ REQUIRE(true == (node1 < relation));
+
+ REQUIRE(true == osmium::object_order_type_id_version()(node1, node2));
+ REQUIRE(true == osmium::object_order_type_id_reverse_version()(node2, node1));
+ REQUIRE(true == osmium::object_order_type_id_version()(node1, way));
+ REQUIRE(true == osmium::object_order_type_id_reverse_version()(node1, way));
+
+ REQUIRE(false == osmium::object_equal_type_id_version()(node1, node2));
+ REQUIRE(true == osmium::object_equal_type_id_version()(node2, node3));
+
+ REQUIRE(true == osmium::object_equal_type_id()(node1, node2));
+ REQUIRE(true == osmium::object_equal_type_id()(node2, node3));
+
+ REQUIRE(false == osmium::object_equal_type_id_version()(node1, way));
+ REQUIRE(false == osmium::object_equal_type_id_version()(node1, relation));
+ REQUIRE(false == osmium::object_equal_type_id()(node1, relation));
+ }
+
+}
diff --git a/third_party/libosmium/test/t/basic/test_relation.cpp b/third_party/libosmium/test/t/basic/test_relation.cpp
new file mode 100644
index 0000000..4c62a41
--- /dev/null
+++ b/third_party/libosmium/test/t/basic/test_relation.cpp
@@ -0,0 +1,60 @@
+#include "catch.hpp"
+
+#include <osmium/osm/relation.hpp>
+
+#include "helper.hpp"
+
+TEST_CASE("Basic_Relation") {
+
+SECTION("relation_builder") {
+ osmium::memory::Buffer buffer(10000);
+
+ osmium::Relation& relation = buffer_add_relation(buffer,
+ "foo", {
+ {"type", "multipolygon"},
+ {"name", "Sherwood Forest"}
+ }, {
+ std::make_tuple('w', 1, "inner"),
+ std::make_tuple('w', 2, ""),
+ std::make_tuple('w', 3, "outer")
+ });
+
+ relation.set_id(17)
+ .set_version(3)
+ .set_visible(true)
+ .set_changeset(333)
+ .set_uid(21)
+ .set_timestamp(123);
+
+ REQUIRE(17 == relation.id());
+ REQUIRE(3 == relation.version());
+ REQUIRE(true == relation.visible());
+ REQUIRE(333 == relation.changeset());
+ REQUIRE(21 == relation.uid());
+ REQUIRE(std::string("foo") == relation.user());
+ REQUIRE(123 == relation.timestamp());
+ REQUIRE(2 == relation.tags().size());
+ REQUIRE(3 == relation.members().size());
+
+ int n=1;
+ for (auto& member : relation.members()) {
+ REQUIRE(osmium::item_type::way == member.type());
+ REQUIRE(n == member.ref());
+ switch (n) {
+ case 1:
+ REQUIRE(std::string("inner") == member.role());
+ break;
+ case 2:
+ REQUIRE(std::string("") == member.role());
+ break;
+ case 3:
+ REQUIRE(std::string("outer") == member.role());
+ break;
+ default:
+ REQUIRE(false);
+ }
+ ++n;
+ }
+}
+
+}
diff --git a/third_party/libosmium/test/t/basic/test_timestamp.cpp b/third_party/libosmium/test/t/basic/test_timestamp.cpp
new file mode 100644
index 0000000..6a04a4d
--- /dev/null
+++ b/third_party/libosmium/test/t/basic/test_timestamp.cpp
@@ -0,0 +1,58 @@
+#include "catch.hpp"
+
+#include <sstream>
+
+#include <osmium/osm/timestamp.hpp>
+
+TEST_CASE("Timestamp") {
+
+ SECTION("can be default initialized to invalid value") {
+ osmium::Timestamp t;
+ REQUIRE(0 == t);
+ REQUIRE("" == t.to_iso());
+ }
+
+ SECTION("invalid value is zero") {
+ osmium::Timestamp t(static_cast<time_t>(0));
+ REQUIRE(0 == t);
+ REQUIRE("" == t.to_iso());
+ }
+
+ SECTION("can be initialized from time_t") {
+ osmium::Timestamp t(static_cast<time_t>(1));
+ REQUIRE(1 == t);
+ REQUIRE("1970-01-01T00:00:01Z" == t.to_iso());
+ }
+
+ SECTION("can be initialized from string") {
+ osmium::Timestamp t("2000-01-01T00:00:00Z");
+ REQUIRE("2000-01-01T00:00:00Z" == t.to_iso());
+ }
+
+ SECTION("can be implicitly cast to time_t") {
+ osmium::Timestamp t(4242);
+ time_t x = t;
+ REQUIRE(x == 4242);
+ }
+
+ SECTION("uint32_t can be initialized from Timestamp") {
+ osmium::Timestamp t(4242);
+ uint32_t x { t };
+
+ REQUIRE(x == 4242);
+ }
+
+ SECTION("can be compared") {
+ osmium::Timestamp t1(10);
+ osmium::Timestamp t2(50);
+ REQUIRE(t1 < t2);
+ }
+
+ SECTION("can be written to stream") {
+ std::stringstream ss;
+ osmium::Timestamp t(1);
+ ss << t;
+ REQUIRE("1970-01-01T00:00:01Z" == ss.str());
+ }
+
+}
diff --git a/third_party/libosmium/test/t/basic/test_way.cpp b/third_party/libosmium/test/t/basic/test_way.cpp
new file mode 100644
index 0000000..9d2ba06
--- /dev/null
+++ b/third_party/libosmium/test/t/basic/test_way.cpp
@@ -0,0 +1,82 @@
+#include "catch.hpp"
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/osm/way.hpp>
+
+#include "helper.hpp"
+
+TEST_CASE("Basic_Way") {
+
+SECTION("way_builder") {
+ osmium::memory::Buffer buffer(10000);
+
+ osmium::Way& way = buffer_add_way(buffer,
+ "foo",
+ {{"highway", "residential"}, {"name", "High Street"}},
+ {1, 3, 2});
+
+ way.set_id(17)
+ .set_version(3)
+ .set_visible(true)
+ .set_changeset(333)
+ .set_uid(21)
+ .set_timestamp(123);
+
+ REQUIRE(osmium::item_type::way == way.type());
+ REQUIRE(way.type_is_in(osmium::osm_entity_bits::way));
+ REQUIRE(way.type_is_in(osmium::osm_entity_bits::node | osmium::osm_entity_bits::way));
+ REQUIRE(17 == way.id());
+ REQUIRE(3 == way.version());
+ REQUIRE(true == way.visible());
+ REQUIRE(333 == way.changeset());
+ REQUIRE(21 == way.uid());
+ REQUIRE(std::string("foo") == way.user());
+ REQUIRE(123 == way.timestamp());
+ REQUIRE(2 == way.tags().size());
+ REQUIRE(3 == way.nodes().size());
+ REQUIRE(1 == way.nodes()[0].ref());
+ REQUIRE(3 == way.nodes()[1].ref());
+ REQUIRE(2 == way.nodes()[2].ref());
+ REQUIRE(! way.is_closed());
+}
+
+SECTION("closed_way") {
+ osmium::memory::Buffer buffer(10000);
+
+ osmium::Way& way = buffer_add_way(buffer,
+ "foo",
+ {{"highway", "residential"}, {"name", "High Street"}},
+ {1, 3, 1});
+
+ REQUIRE(way.is_closed());
+}
+
+SECTION("way_builder_with_helpers") {
+ osmium::memory::Buffer buffer(10000);
+ {
+ osmium::builder::WayBuilder builder(buffer);
+ builder.add_user("username");
+ builder.add_tags({
+ {"amenity", "restaurant"},
+ {"name", "Zum goldenen Schwanen"}
+ });
+ builder.add_node_refs({
+ {22, {3.5, 4.7}},
+ {67, {4.1, 2.2}}
+ });
+ }
+ buffer.commit();
+ osmium::Way& way = buffer.get<osmium::Way>(0);
+
+ REQUIRE(std::string("username") == way.user());
+
+ REQUIRE(2 == way.tags().size());
+ REQUIRE(std::string("amenity") == way.tags().begin()->key());
+ REQUIRE(std::string("Zum goldenen Schwanen") == way.tags()["name"]);
+
+ REQUIRE(2 == way.nodes().size());
+ REQUIRE(22 == way.nodes()[0].ref());
+ REQUIRE(4.1 == way.nodes()[1].location().lon());
+}
+
+}
diff --git a/third_party/libosmium/test/t/buffer/test_buffer_node.cpp b/third_party/libosmium/test/t/buffer/test_buffer_node.cpp
new file mode 100644
index 0000000..9bc8f70
--- /dev/null
+++ b/third_party/libosmium/test/t/buffer/test_buffer_node.cpp
@@ -0,0 +1,135 @@
+#include "catch.hpp"
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/osm/node.hpp>
+
+void check_node_1(osmium::Node& node) {
+ REQUIRE(1 == node.id());
+ REQUIRE(3 == node.version());
+ REQUIRE(true == node.visible());
+ REQUIRE(333 == node.changeset());
+ REQUIRE(21 == node.uid());
+ REQUIRE(123 == node.timestamp());
+ REQUIRE(osmium::Location(3.5, 4.7) == node.location());
+ REQUIRE(std::string("testuser") == node.user());
+
+ for (osmium::memory::Item& item : node) {
+ REQUIRE(osmium::item_type::tag_list == item.type());
+ }
+
+ REQUIRE(node.tags().begin() == node.tags().end());
+ REQUIRE(node.tags().empty());
+ REQUIRE(0 == std::distance(node.tags().begin(), node.tags().end()));
+}
+
+void check_node_2(osmium::Node& node) {
+ REQUIRE(2 == node.id());
+ REQUIRE(3 == node.version());
+ REQUIRE(true == node.visible());
+ REQUIRE(333 == node.changeset());
+ REQUIRE(21 == node.uid());
+ REQUIRE(123 == node.timestamp());
+ REQUIRE(osmium::Location(3.5, 4.7) == node.location());
+ REQUIRE(std::string("testuser") == node.user());
+
+ for (osmium::memory::Item& item : node) {
+ REQUIRE(osmium::item_type::tag_list == item.type());
+ }
+
+ REQUIRE(!node.tags().empty());
+ REQUIRE(2 == std::distance(node.tags().begin(), node.tags().end()));
+
+ int n = 0;
+ for (const osmium::Tag& tag : node.tags()) {
+ switch (n) {
+ case 0:
+ REQUIRE(std::string("amenity") == tag.key());
+ REQUIRE(std::string("bank") == tag.value());
+ break;
+ case 1:
+ REQUIRE(std::string("name") == tag.key());
+ REQUIRE(std::string("OSM Savings") == tag.value());
+ break;
+ }
+ ++n;
+ }
+ REQUIRE(2 == n);
+}
+
+TEST_CASE("Buffer_Node") {
+
+ SECTION("buffer_node") {
+ constexpr size_t buffer_size = 10000;
+ unsigned char data[buffer_size];
+
+ osmium::memory::Buffer buffer(data, buffer_size, 0);
+
+ {
+ // add node 1
+ osmium::builder::NodeBuilder node_builder(buffer);
+ osmium::Node& node = node_builder.object();
+ REQUIRE(osmium::item_type::node == node.type());
+
+ node.set_id(1);
+ node.set_version(3);
+ node.set_visible(true);
+ node.set_changeset(333);
+ node.set_uid(21);
+ node.set_timestamp(123);
+ node.set_location(osmium::Location(3.5, 4.7));
+
+ node_builder.add_user("testuser");
+
+ buffer.commit();
+ }
+
+ {
+ // add node 2
+ osmium::builder::NodeBuilder node_builder(buffer);
+ osmium::Node& node = node_builder.object();
+ REQUIRE(osmium::item_type::node == node.type());
+
+ node.set_id(2);
+ node.set_version(3);
+ node.set_visible(true);
+ node.set_changeset(333);
+ node.set_uid(21);
+ node.set_timestamp(123);
+ node.set_location(osmium::Location(3.5, 4.7));
+
+ node_builder.add_user("testuser");
+
+ {
+ osmium::builder::TagListBuilder tag_builder(buffer, &node_builder);
+ tag_builder.add_tag("amenity", "bank");
+ tag_builder.add_tag("name", "OSM Savings");
+ }
+
+ buffer.commit();
+ }
+
+ REQUIRE(2 == std::distance(buffer.begin(), buffer.end()));
+ int item_no = 0;
+ for (osmium::memory::Item& item : buffer) {
+ REQUIRE(osmium::item_type::node == item.type());
+
+ osmium::Node& node = static_cast<osmium::Node&>(item);
+
+ switch (item_no) {
+ case 0:
+ check_node_1(node);
+ break;
+ case 1:
+ check_node_2(node);
+ break;
+ default:
+ break;
+ }
+
+ ++item_no;
+
+ }
+
+ }
+
+}
diff --git a/third_party/libosmium/test/t/buffer/test_buffer_purge.cpp b/third_party/libosmium/test/t/buffer/test_buffer_purge.cpp
new file mode 100644
index 0000000..10cdfe7
--- /dev/null
+++ b/third_party/libosmium/test/t/buffer/test_buffer_purge.cpp
@@ -0,0 +1,186 @@
+#include "catch.hpp"
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/osm/node.hpp>
+
+struct CallbackClass {
+
+ int count = 0;
+
+ void moving_in_buffer(size_t old_offset, size_t new_offset) {
+ REQUIRE(old_offset > new_offset);
+ ++count;
+ }
+
+}; // struct CallbackClass
+
+TEST_CASE("Purge data from buffer") {
+
+ constexpr size_t buffer_size = 10000;
+
+ SECTION("purge empty buffer") {
+ osmium::memory::Buffer buffer(buffer_size);
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 0);
+
+ CallbackClass callback;
+ buffer.purge_removed(&callback);
+
+ REQUIRE(callback.count == 0);
+ REQUIRE(buffer.committed() == 0);
+ }
+
+ SECTION("purge buffer with one object but nothing to delete") {
+ osmium::memory::Buffer buffer(buffer_size);
+
+ {
+ osmium::builder::NodeBuilder node_builder(buffer);
+ node_builder.add_user("testuser");
+ }
+ buffer.commit();
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 1);
+ size_t committed = buffer.committed();
+
+ CallbackClass callback;
+ buffer.purge_removed(&callback);
+
+ REQUIRE(callback.count == 0);
+ REQUIRE(committed == buffer.committed());
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 1);
+ }
+
+ SECTION("purge buffer with one object which gets deleted") {
+ osmium::memory::Buffer buffer(buffer_size);
+
+ {
+ osmium::builder::NodeBuilder node_builder(buffer);
+ node_builder.add_user("testuser");
+ node_builder.object().set_removed(true);
+ }
+ buffer.commit();
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 1);
+
+ CallbackClass callback;
+ buffer.purge_removed(&callback);
+
+ REQUIRE(callback.count == 0);
+ REQUIRE(buffer.committed() == 0);
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 0);
+ }
+
+ SECTION("purge buffer with two objects, first gets deleted") {
+ osmium::memory::Buffer buffer(buffer_size);
+
+ {
+ osmium::builder::NodeBuilder node_builder(buffer);
+ node_builder.add_user("testuser");
+ node_builder.object().set_removed(true);
+ }
+ buffer.commit();
+ size_t size1 = buffer.committed();
+ {
+ osmium::builder::NodeBuilder node_builder(buffer);
+ node_builder.add_user("testuser");
+ }
+ buffer.commit();
+ size_t size2 = buffer.committed() - size1;
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 2);
+
+ CallbackClass callback;
+ buffer.purge_removed(&callback);
+
+ REQUIRE(callback.count == 1);
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 1);
+ REQUIRE(buffer.committed() == size2);
+ }
+
+ SECTION("purge buffer with two objects, second gets deleted") {
+ osmium::memory::Buffer buffer(buffer_size);
+
+ {
+ osmium::builder::NodeBuilder node_builder(buffer);
+ node_builder.add_user("testuser_longer_name");
+ }
+ buffer.commit();
+ size_t size1 = buffer.committed();
+ {
+ osmium::builder::NodeBuilder node_builder(buffer);
+ node_builder.add_user("testuser");
+ node_builder.object().set_removed(true);
+ }
+ buffer.commit();
+ size_t size2 = buffer.committed() - size1;
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 2);
+
+ CallbackClass callback;
+ buffer.purge_removed(&callback);
+
+ REQUIRE(callback.count == 0);
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 1);
+ REQUIRE(buffer.committed() == size1);
+ }
+
+ SECTION("purge buffer with three objects, middle one gets deleted") {
+ osmium::memory::Buffer buffer(buffer_size);
+
+ {
+ osmium::builder::NodeBuilder node_builder(buffer);
+ node_builder.add_user("testuser_longer_name");
+ }
+ buffer.commit();
+ size_t size1 = buffer.committed();
+ {
+ osmium::builder::NodeBuilder node_builder(buffer);
+ node_builder.add_user("testuser");
+ node_builder.object().set_removed(true);
+ }
+ buffer.commit();
+ size_t size2 = buffer.committed() - size1;
+ {
+ osmium::builder::NodeBuilder node_builder(buffer);
+ node_builder.add_user("sn");
+ }
+ buffer.commit();
+ size_t size3 = buffer.committed() - (size1 + size2);
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 3);
+
+ CallbackClass callback;
+ buffer.purge_removed(&callback);
+
+ REQUIRE(callback.count == 1);
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 2);
+ }
+
+ SECTION("purge buffer with three objects, all get deleted") {
+ osmium::memory::Buffer buffer(buffer_size);
+
+ {
+ osmium::builder::NodeBuilder node_builder(buffer);
+ node_builder.add_user("testuser_longer_name");
+ node_builder.object().set_removed(true);
+ }
+ buffer.commit();
+ size_t size1 = buffer.committed();
+ {
+ osmium::builder::NodeBuilder node_builder(buffer);
+ node_builder.add_user("testuser");
+ node_builder.object().set_removed(true);
+ }
+ buffer.commit();
+ size_t size2 = buffer.committed() - size1;
+ {
+ osmium::builder::NodeBuilder node_builder(buffer);
+ node_builder.add_user("sn");
+ node_builder.object().set_removed(true);
+ }
+ buffer.commit();
+ size_t size3 = buffer.committed() - (size1 + size2);
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 3);
+
+ CallbackClass callback;
+ buffer.purge_removed(&callback);
+
+ REQUIRE(callback.count == 0);
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 0);
+ }
+
+}
diff --git a/third_party/libosmium/test/t/geom/helper.hpp b/third_party/libosmium/test/t/geom/helper.hpp
new file mode 100644
index 0000000..e0cefe6
--- /dev/null
+++ b/third_party/libosmium/test/t/geom/helper.hpp
@@ -0,0 +1,15 @@
+#ifndef TEST_GEOM_HELPER_HPP
+#define TEST_GEOM_HELPER_HPP
+
+#include <string>
+
+#include <geos/io/WKBWriter.h>
+
+inline std::string geos_to_wkb(const geos::geom::Geometry* geometry) {
+ std::stringstream ss;
+ geos::io::WKBWriter wkb_writer;
+ wkb_writer.writeHEX(*geometry, ss);
+ return ss.str();
+}
+
+#endif // TEST_GEOM_HELPER_HPP
diff --git a/third_party/libosmium/test/t/geom/test_factory_with_projection.cpp b/third_party/libosmium/test/t/geom/test_factory_with_projection.cpp
new file mode 100644
index 0000000..42fc864
--- /dev/null
+++ b/third_party/libosmium/test/t/geom/test_factory_with_projection.cpp
@@ -0,0 +1,41 @@
+#include "catch.hpp"
+
+#include <osmium/geom/geos.hpp>
+#include <osmium/geom/mercator_projection.hpp>
+#include <osmium/geom/projection.hpp>
+#include <osmium/geom/wkb.hpp>
+#include <osmium/geom/wkt.hpp>
+
+#include "helper.hpp"
+
+TEST_CASE("Projection") {
+
+ SECTION("point_mercator") {
+ osmium::geom::WKTFactory<osmium::geom::MercatorProjection> factory(2);
+
+ std::string wkt {factory.create_point(osmium::Location(3.2, 4.2))};
+ REQUIRE(std::string {"POINT(356222.37 467961.14)"} == wkt);
+ }
+
+ SECTION("point_epsg_3857") {
+ osmium::geom::WKTFactory<osmium::geom::Projection> factory(osmium::geom::Projection(3857), 2);
+
+ std::string wkt {factory.create_point(osmium::Location(3.2, 4.2))};
+ REQUIRE(std::string {"POINT(356222.37 467961.14)"} == wkt);
+ }
+
+ SECTION("wkb_with_parameter") {
+ osmium::geom::WKBFactory<osmium::geom::Projection> wkb_factory(osmium::geom::Projection(3857), osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ osmium::geom::GEOSFactory<osmium::geom::Projection> geos_factory(osmium::geom::Projection(3857));
+
+ std::string wkb = wkb_factory.create_point(osmium::Location(3.2, 4.2));
+ std::unique_ptr<geos::geom::Point> geos_point = geos_factory.create_point(osmium::Location(3.2, 4.2));
+ REQUIRE(geos_to_wkb(geos_point.get()) == wkb);
+ }
+
+ SECTION("cleanup") {
+ // trying to make valgrind happy, but there is still a memory leak in proj library
+ pj_deallocate_grids();
+ }
+
+}
diff --git a/third_party/libosmium/test/t/geom/test_geojson.cpp b/third_party/libosmium/test/t/geom/test_geojson.cpp
new file mode 100644
index 0000000..8d7df35
--- /dev/null
+++ b/third_party/libosmium/test/t/geom/test_geojson.cpp
@@ -0,0 +1,236 @@
+#include "catch.hpp"
+
+#include <osmium/builder/builder_helper.hpp>
+#include <osmium/geom/geojson.hpp>
+
+#include "../basic/helper.hpp"
+
+TEST_CASE("GeoJSON_Geometry") {
+
+SECTION("point") {
+ osmium::geom::GeoJSONFactory<> factory;
+
+ std::string json {factory.create_point(osmium::Location(3.2, 4.2))};
+ REQUIRE(std::string{"{\"type\":\"Point\",\"coordinates\":[3.2,4.2]}"} == json);
+}
+
+SECTION("empty_point") {
+ osmium::geom::GeoJSONFactory<> factory;
+
+ REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
+}
+
+SECTION("linestring") {
+ osmium::geom::GeoJSONFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {
+ {1, {3.2, 4.2}},
+ {3, {3.5, 4.7}},
+ {4, {3.5, 4.7}},
+ {2, {3.6, 4.9}}
+ });
+
+ {
+ std::string json {factory.create_linestring(wnl)};
+ REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.2,4.2],[3.5,4.7],[3.6,4.9]]}"} == json);
+ }
+
+ {
+ std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
+ REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.6,4.9],[3.5,4.7],[3.2,4.2]]}"} == json);
+ }
+
+ {
+ std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.2,4.2],[3.5,4.7],[3.5,4.7],[3.6,4.9]]}"} == json);
+ }
+
+ {
+ std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.6,4.9],[3.5,4.7],[3.5,4.7],[3.2,4.2]]}"} == json);
+ }
+}
+
+SECTION("empty_linestring") {
+ osmium::geom::GeoJSONFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {});
+
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
+}
+
+SECTION("linestring_with_two_same_locations") {
+ osmium::geom::GeoJSONFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {
+ {1, {3.5, 4.7}},
+ {2, {3.5, 4.7}}
+ });
+
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+
+ {
+ std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.5,4.7],[3.5,4.7]]}"} == json);
+ }
+
+ {
+ std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.5,4.7],[3.5,4.7]]}"} == json);
+ }
+}
+
+SECTION("linestring_with_undefined_location") {
+ osmium::geom::GeoJSONFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {
+ {1, {3.5, 4.7}},
+ {2, osmium::Location()}
+ });
+
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
+}
+
+SECTION("area_1outer_0inner") {
+ osmium::geom::GeoJSONFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {3.2, 4.2}},
+ {2, {3.5, 4.7}},
+ {3, {3.6, 4.9}},
+ {1, {3.2, 4.2}}
+ }}
+ });
+
+ REQUIRE(!area.is_multipolygon());
+ REQUIRE(std::distance(area.cbegin(), area.cend()) == 2);
+ REQUIRE(std::distance(area.cbegin<osmium::OuterRing>(), area.cend<osmium::OuterRing>()) == area.num_rings().first);
+
+ {
+ std::string json {factory.create_multipolygon(area)};
+ REQUIRE(std::string{"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[3.2,4.2],[3.5,4.7],[3.6,4.9],[3.2,4.2]]]]}"} == json);
+ }
+}
+
+SECTION("area_1outer_1inner") {
+ osmium::geom::GeoJSONFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {0.1, 0.1}},
+ {2, {9.1, 0.1}},
+ {3, {9.1, 9.1}},
+ {4, {0.1, 9.1}},
+ {1, {0.1, 0.1}}
+ }},
+ { false, {
+ {5, {1.0, 1.0}},
+ {6, {8.0, 1.0}},
+ {7, {8.0, 8.0}},
+ {8, {1.0, 8.0}},
+ {5, {1.0, 1.0}}
+ }}
+ });
+
+ REQUIRE(!area.is_multipolygon());
+ REQUIRE(std::distance(area.cbegin(), area.cend()) == 3);
+ REQUIRE(std::distance(area.cbegin<osmium::OuterRing>(), area.cend<osmium::OuterRing>()) == area.num_rings().first);
+ REQUIRE(std::distance(area.cbegin<osmium::InnerRing>(), area.cend<osmium::InnerRing>()) == area.num_rings().second);
+
+ {
+ std::string json {factory.create_multipolygon(area)};
+ REQUIRE(std::string{"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[0.1,0.1],[9.1,0.1],[9.1,9.1],[0.1,9.1],[0.1,0.1]],[[1,1],[8,1],[8,8],[1,8],[1,1]]]]}"} == json);
+ }
+}
+
+SECTION("area_2outer_2inner") {
+ osmium::geom::GeoJSONFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {0.1, 0.1}},
+ {2, {9.1, 0.1}},
+ {3, {9.1, 9.1}},
+ {4, {0.1, 9.1}},
+ {1, {0.1, 0.1}}
+ }},
+ { false, {
+ {5, {1.0, 1.0}},
+ {6, {4.0, 1.0}},
+ {7, {4.0, 4.0}},
+ {8, {1.0, 4.0}},
+ {5, {1.0, 1.0}}
+ }},
+ { false, {
+ {10, {5.0, 5.0}},
+ {11, {5.0, 7.0}},
+ {12, {7.0, 7.0}},
+ {10, {5.0, 5.0}}
+ }},
+ { true, {
+ {100, {10.0, 10.0}},
+ {101, {11.0, 10.0}},
+ {102, {11.0, 11.0}},
+ {103, {10.0, 11.0}},
+ {100, {10.0, 10.0}}
+ }}
+ });
+
+ REQUIRE(area.is_multipolygon());
+ REQUIRE(std::distance(area.cbegin(), area.cend()) == 5);
+ REQUIRE(std::distance(area.cbegin<osmium::OuterRing>(), area.cend<osmium::OuterRing>()) == area.num_rings().first);
+ REQUIRE(std::distance(area.cbegin<osmium::InnerRing>(), area.cend<osmium::InnerRing>()) == area.num_rings().second);
+
+ int outer_ring=0;
+ int inner_ring=0;
+ for (auto it_outer = area.cbegin<osmium::OuterRing>(); it_outer != area.cend<osmium::OuterRing>(); ++it_outer) {
+ if (outer_ring == 0) {
+ REQUIRE(it_outer->front().ref() == 1);
+ } else if (outer_ring == 1) {
+ REQUIRE(it_outer->front().ref() == 100);
+ } else {
+ REQUIRE(false);
+ }
+ for (auto it_inner = area.inner_ring_cbegin(it_outer); it_inner != area.inner_ring_cend(it_outer); ++it_inner) {
+ if (outer_ring == 0 && inner_ring == 0) {
+ REQUIRE(it_inner->front().ref() == 5);
+ } else if (outer_ring == 0 && inner_ring == 1) {
+ REQUIRE(it_inner->front().ref() == 10);
+ } else {
+ REQUIRE(false);
+ }
+ ++inner_ring;
+ }
+ inner_ring = 0;
+ ++outer_ring;
+ }
+
+ {
+ std::string json {factory.create_multipolygon(area)};
+ REQUIRE(std::string{"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[0.1,0.1],[9.1,0.1],[9.1,9.1],[0.1,9.1],[0.1,0.1]],[[1,1],[4,1],[4,4],[1,4],[1,1]],[[5,5],[5,7],[7,7],[5,5]]],[[[10,10],[11,10],[11,11],[10,11],[10,10]]]]}"} == json);
+ }
+}
+
+}
+
diff --git a/third_party/libosmium/test/t/geom/test_geos.cpp b/third_party/libosmium/test/t/geom/test_geos.cpp
new file mode 100644
index 0000000..e93228b
--- /dev/null
+++ b/third_party/libosmium/test/t/geom/test_geos.cpp
@@ -0,0 +1,198 @@
+#include "catch.hpp"
+
+#include <osmium/builder/builder_helper.hpp>
+#include <osmium/geom/geos.hpp>
+
+#include "../basic/helper.hpp"
+
+TEST_CASE("GEOS_Geometry") {
+
+SECTION("point") {
+ osmium::geom::GEOSFactory<> factory;
+
+ std::unique_ptr<geos::geom::Point> point {factory.create_point(osmium::Location(3.2, 4.2))};
+ REQUIRE(3.2 == point->getX());
+ REQUIRE(4.2 == point->getY());
+ REQUIRE(-1 == point->getSRID());
+}
+
+SECTION("non_default_srid") {
+ osmium::geom::GEOSFactory<> factory(4326);
+
+ std::unique_ptr<geos::geom::Point> point {factory.create_point(osmium::Location(3.2, 4.2))};
+ REQUIRE(3.2 == point->getX());
+ REQUIRE(4.2 == point->getY());
+ REQUIRE(4326 == point->getSRID());
+}
+
+SECTION("empty_point") {
+ osmium::geom::GEOSFactory<> factory;
+
+ REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
+}
+
+SECTION("linestring") {
+ osmium::geom::GEOSFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {
+ {1, {3.2, 4.2}},
+ {3, {3.5, 4.7}},
+ {4, {3.5, 4.7}},
+ {2, {3.6, 4.9}}
+ });
+
+ {
+ std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl)};
+ REQUIRE(3 == linestring->getNumPoints());
+
+ std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
+ REQUIRE(3.2 == p0->getX());
+ std::unique_ptr<geos::geom::Point> p2 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(2));
+ REQUIRE(3.6 == p2->getX());
+ }
+
+ {
+ std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
+ REQUIRE(3 == linestring->getNumPoints());
+ std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
+ REQUIRE(3.6 == p0->getX());
+ std::unique_ptr<geos::geom::Point> p2 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(2));
+ REQUIRE(3.2 == p2->getX());
+ }
+
+ {
+ std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ REQUIRE(4 == linestring->getNumPoints());
+ std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
+ REQUIRE(3.2 == p0->getX());
+ }
+
+ {
+ std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ REQUIRE(4 == linestring->getNumPoints());
+ std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
+ REQUIRE(3.6 == p0->getX());
+ }
+}
+
+SECTION("area_1outer_0inner") {
+ osmium::geom::GEOSFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {3.2, 4.2}},
+ {2, {3.5, 4.7}},
+ {3, {3.6, 4.9}},
+ {1, {3.2, 4.2}}
+ }}
+ });
+
+ std::unique_ptr<geos::geom::MultiPolygon> mp {factory.create_multipolygon(area)};
+ REQUIRE(1 == mp->getNumGeometries());
+
+ const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0));
+ REQUIRE(0 == p0->getNumInteriorRing());
+
+ const geos::geom::LineString* l0e = p0->getExteriorRing();
+ REQUIRE(4 == l0e->getNumPoints());
+
+ std::unique_ptr<geos::geom::Point> l0e_p0 = std::unique_ptr<geos::geom::Point>(l0e->getPointN(1));
+ REQUIRE(3.5 == l0e_p0->getX());
+}
+
+SECTION("area_1outer_1inner") {
+ osmium::geom::GEOSFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {0.1, 0.1}},
+ {2, {9.1, 0.1}},
+ {3, {9.1, 9.1}},
+ {4, {0.1, 9.1}},
+ {1, {0.1, 0.1}}
+ }},
+ { false, {
+ {5, {1.0, 1.0}},
+ {6, {8.0, 1.0}},
+ {7, {8.0, 8.0}},
+ {8, {1.0, 8.0}},
+ {5, {1.0, 1.0}}
+ }}
+ });
+
+ std::unique_ptr<geos::geom::MultiPolygon> mp {factory.create_multipolygon(area)};
+ REQUIRE(1 == mp->getNumGeometries());
+
+ const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0));
+ REQUIRE(1 == p0->getNumInteriorRing());
+
+ const geos::geom::LineString* l0e = p0->getExteriorRing();
+ REQUIRE(5 == l0e->getNumPoints());
+
+ const geos::geom::LineString* l0i0 = p0->getInteriorRingN(0);
+ REQUIRE(5 == l0i0->getNumPoints());
+}
+
+SECTION("area_2outer_2inner") {
+ osmium::geom::GEOSFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {0.1, 0.1}},
+ {2, {9.1, 0.1}},
+ {3, {9.1, 9.1}},
+ {4, {0.1, 9.1}},
+ {1, {0.1, 0.1}}
+ }},
+ { false, {
+ {5, {1.0, 1.0}},
+ {6, {4.0, 1.0}},
+ {7, {4.0, 4.0}},
+ {8, {1.0, 4.0}},
+ {5, {1.0, 1.0}}
+ }},
+ { false, {
+ {10, {5.0, 5.0}},
+ {11, {5.0, 7.0}},
+ {12, {7.0, 7.0}},
+ {10, {5.0, 5.0}}
+ }},
+ { true, {
+ {100, {10.0, 10.0}},
+ {101, {11.0, 10.0}},
+ {102, {11.0, 11.0}},
+ {103, {10.0, 11.0}},
+ {100, {10.0, 10.0}}
+ }}
+ });
+
+ std::unique_ptr<geos::geom::MultiPolygon> mp {factory.create_multipolygon(area)};
+ REQUIRE(2 == mp->getNumGeometries());
+
+ const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0));
+ REQUIRE(2 == p0->getNumInteriorRing());
+
+ const geos::geom::LineString* l0e = p0->getExteriorRing();
+ REQUIRE(5 == l0e->getNumPoints());
+
+ const geos::geom::Polygon* p1 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(1));
+ REQUIRE(0 == p1->getNumInteriorRing());
+
+ const geos::geom::LineString* l1e = p1->getExteriorRing();
+ REQUIRE(5 == l1e->getNumPoints());
+}
+
+}
diff --git a/third_party/libosmium/test/t/geom/test_geos_wkb.cpp b/third_party/libosmium/test/t/geom/test_geos_wkb.cpp
new file mode 100644
index 0000000..0f54427
--- /dev/null
+++ b/third_party/libosmium/test/t/geom/test_geos_wkb.cpp
@@ -0,0 +1,156 @@
+#include "catch.hpp"
+
+#include <osmium/builder/builder_helper.hpp>
+#include <osmium/geom/geos.hpp>
+#include <osmium/geom/wkb.hpp>
+
+#include "../basic/helper.hpp"
+#include "helper.hpp"
+
+TEST_CASE("WKB_Geometry_with_GEOS") {
+
+SECTION("point") {
+ osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ osmium::geom::GEOSFactory<> geos_factory;
+
+ std::string wkb {wkb_factory.create_point(osmium::Location(3.2, 4.2))};
+
+ std::unique_ptr<geos::geom::Point> geos_point = geos_factory.create_point(osmium::Location(3.2, 4.2));
+ REQUIRE(geos_to_wkb(geos_point.get()) == wkb);
+}
+
+
+SECTION("linestring") {
+ osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ osmium::geom::GEOSFactory<> geos_factory;
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {
+ {1, {3.2, 4.2}},
+ {3, {3.5, 4.7}},
+ {4, {3.5, 4.7}},
+ {2, {3.6, 4.9}}
+ });
+
+ {
+ std::string wkb = wkb_factory.create_linestring(wnl);
+ std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl);
+ REQUIRE(geos_to_wkb(geos.get()) == wkb);
+ }
+
+ {
+ std::string wkb = wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward);
+ std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward);
+ REQUIRE(geos_to_wkb(geos.get()) == wkb);
+ }
+
+ {
+ std::string wkb = wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::all);
+ std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl, osmium::geom::use_nodes::all);
+ REQUIRE(geos_to_wkb(geos.get()) == wkb);
+ }
+
+ {
+ std::string wkb = wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward);
+ std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward);
+ REQUIRE(geos_to_wkb(geos.get()) == wkb);
+ }
+}
+
+SECTION("area_1outer_0inner") {
+ osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ osmium::geom::GEOSFactory<> geos_factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {3.2, 4.2}},
+ {2, {3.5, 4.7}},
+ {3, {3.6, 4.9}},
+ {1, {3.2, 4.2}}
+ }}
+ });
+
+ std::string wkb = wkb_factory.create_multipolygon(area);
+ std::unique_ptr<geos::geom::MultiPolygon> geos = geos_factory.create_multipolygon(area);
+ REQUIRE(geos_to_wkb(geos.get()) == wkb);
+}
+
+SECTION("area_1outer_1inner") {
+ osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ osmium::geom::GEOSFactory<> geos_factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {0.1, 0.1}},
+ {2, {9.1, 0.1}},
+ {3, {9.1, 9.1}},
+ {4, {0.1, 9.1}},
+ {1, {0.1, 0.1}}
+ }},
+ { false, {
+ {5, {1.0, 1.0}},
+ {6, {8.0, 1.0}},
+ {7, {8.0, 8.0}},
+ {8, {1.0, 8.0}},
+ {5, {1.0, 1.0}}
+ }}
+ });
+
+ std::string wkb = wkb_factory.create_multipolygon(area);
+ std::unique_ptr<geos::geom::MultiPolygon> geos = geos_factory.create_multipolygon(area);
+ REQUIRE(geos_to_wkb(geos.get()) == wkb);
+}
+
+SECTION("area_2outer_2inner") {
+ osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ osmium::geom::GEOSFactory<> geos_factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {0.1, 0.1}},
+ {2, {9.1, 0.1}},
+ {3, {9.1, 9.1}},
+ {4, {0.1, 9.1}},
+ {1, {0.1, 0.1}}
+ }},
+ { false, {
+ {5, {1.0, 1.0}},
+ {6, {4.0, 1.0}},
+ {7, {4.0, 4.0}},
+ {8, {1.0, 4.0}},
+ {5, {1.0, 1.0}}
+ }},
+ { false, {
+ {10, {5.0, 5.0}},
+ {11, {5.0, 7.0}},
+ {12, {7.0, 7.0}},
+ {10, {5.0, 5.0}}
+ }},
+ { true, {
+ {100, {10.0, 10.0}},
+ {101, {11.0, 10.0}},
+ {102, {11.0, 11.0}},
+ {103, {10.0, 11.0}},
+ {100, {10.0, 10.0}}
+ }}
+ });
+
+ std::string wkb = wkb_factory.create_multipolygon(area);
+ std::unique_ptr<geos::geom::MultiPolygon> geos = geos_factory.create_multipolygon(area);
+ REQUIRE(geos_to_wkb(geos.get()) == wkb);
+}
+
+}
+
diff --git a/third_party/libosmium/test/t/geom/test_mercator.cpp b/third_party/libosmium/test/t/geom/test_mercator.cpp
new file mode 100644
index 0000000..cc16e55
--- /dev/null
+++ b/third_party/libosmium/test/t/geom/test_mercator.cpp
@@ -0,0 +1,37 @@
+#include "catch.hpp"
+
+#include <osmium/geom/mercator_projection.hpp>
+
+TEST_CASE("Mercator") {
+
+ SECTION("mercator_projection") {
+ osmium::geom::MercatorProjection projection;
+ REQUIRE(3857 == projection.epsg());
+ REQUIRE("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs" == projection.proj_string());
+ }
+
+ SECTION("low_level_mercator_functions") {
+ osmium::geom::Coordinates c1(17.839, -3.249);
+ osmium::geom::Coordinates r1 = osmium::geom::mercator_to_lonlat(osmium::geom::lonlat_to_mercator(c1));
+ REQUIRE(r1.x == Approx(c1.x).epsilon(0.000001));
+ REQUIRE(r1.y == Approx(c1.y).epsilon(0.000001));
+
+ osmium::geom::Coordinates c2(-89.2, 15.915);
+ osmium::geom::Coordinates r2 = osmium::geom::mercator_to_lonlat(osmium::geom::lonlat_to_mercator(c2));
+ REQUIRE(r2.x == Approx(c2.x).epsilon(0.000001));
+ REQUIRE(r2.y == Approx(c2.y).epsilon(0.000001));
+
+ osmium::geom::Coordinates c3(180.0, 85.0);
+ osmium::geom::Coordinates r3 = osmium::geom::mercator_to_lonlat(osmium::geom::lonlat_to_mercator(c3));
+ REQUIRE(r3.x == Approx(c3.x).epsilon(0.000001));
+ REQUIRE(r3.y == Approx(c3.y).epsilon(0.000001));
+ }
+
+ SECTION("mercator_bounds") {
+ osmium::Location mmax(180.0, osmium::geom::MERCATOR_MAX_LAT);
+ osmium::geom::Coordinates c = osmium::geom::lonlat_to_mercator(mmax);
+ REQUIRE(c.x == Approx(c.y).epsilon(0.001));
+ REQUIRE(osmium::geom::detail::y_to_lat(osmium::geom::detail::lon_to_x(180.0)) == Approx(osmium::geom::MERCATOR_MAX_LAT).epsilon(0.0000001));
+ }
+
+}
diff --git a/third_party/libosmium/test/t/geom/test_ogr.cpp b/third_party/libosmium/test/t/geom/test_ogr.cpp
new file mode 100644
index 0000000..28a1071
--- /dev/null
+++ b/third_party/libosmium/test/t/geom/test_ogr.cpp
@@ -0,0 +1,185 @@
+#include "catch.hpp"
+
+#include <osmium/builder/builder_helper.hpp>
+#include <osmium/geom/ogr.hpp>
+
+#include "../basic/helper.hpp"
+
+TEST_CASE("OGR_Geometry") {
+
+SECTION("point") {
+ osmium::geom::OGRFactory<> factory;
+
+ std::unique_ptr<OGRPoint> point {factory.create_point(osmium::Location(3.2, 4.2))};
+ REQUIRE(3.2 == point->getX());
+ REQUIRE(4.2 == point->getY());
+}
+
+SECTION("empty_point") {
+ osmium::geom::OGRFactory<> factory;
+
+ REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
+}
+
+SECTION("linestring") {
+ osmium::geom::OGRFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {
+ {1, {3.2, 4.2}},
+ {3, {3.5, 4.7}},
+ {4, {3.5, 4.7}},
+ {2, {3.6, 4.9}}
+ });
+
+ {
+ std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl)};
+ REQUIRE(3 == linestring->getNumPoints());
+
+ REQUIRE(3.2 == linestring->getX(0));
+ REQUIRE(3.6 == linestring->getX(2));
+ }
+
+ {
+ std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
+ REQUIRE(3 == linestring->getNumPoints());
+
+ REQUIRE(3.6 == linestring->getX(0));
+ REQUIRE(3.2 == linestring->getX(2));
+ }
+
+ {
+ std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ REQUIRE(4 == linestring->getNumPoints());
+
+ REQUIRE(3.2 == linestring->getX(0));
+ }
+
+ {
+ std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ REQUIRE(4 == linestring->getNumPoints());
+
+ REQUIRE(3.6 == linestring->getX(0));
+ }
+}
+
+SECTION("area_1outer_0inner") {
+ osmium::geom::OGRFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {3.2, 4.2}},
+ {2, {3.5, 4.7}},
+ {3, {3.6, 4.9}},
+ {1, {3.2, 4.2}}
+ }}
+ });
+
+ std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
+ REQUIRE(1 == mp->getNumGeometries());
+
+ const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
+ REQUIRE(0 == p0->getNumInteriorRings());
+
+ const OGRLineString* l0e = p0->getExteriorRing();
+ REQUIRE(4 == l0e->getNumPoints());
+
+ REQUIRE(3.5 == l0e->getX(1));
+}
+
+SECTION("area_1outer_1inner") {
+ osmium::geom::OGRFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {0.1, 0.1}},
+ {2, {9.1, 0.1}},
+ {3, {9.1, 9.1}},
+ {4, {0.1, 9.1}},
+ {1, {0.1, 0.1}}
+ }},
+ { false, {
+ {5, {1.0, 1.0}},
+ {6, {8.0, 1.0}},
+ {7, {8.0, 8.0}},
+ {8, {1.0, 8.0}},
+ {5, {1.0, 1.0}}
+ }}
+ });
+
+ std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
+ REQUIRE(1 == mp->getNumGeometries());
+
+ const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
+ REQUIRE(1 == p0->getNumInteriorRings());
+
+ const OGRLineString* l0e = p0->getExteriorRing();
+ REQUIRE(5 == l0e->getNumPoints());
+
+ const OGRLineString* l0i0 = p0->getInteriorRing(0);
+ REQUIRE(5 == l0i0->getNumPoints());
+}
+
+SECTION("area_2outer_2inner") {
+ osmium::geom::OGRFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {0.1, 0.1}},
+ {2, {9.1, 0.1}},
+ {3, {9.1, 9.1}},
+ {4, {0.1, 9.1}},
+ {1, {0.1, 0.1}}
+ }},
+ { false, {
+ {5, {1.0, 1.0}},
+ {6, {4.0, 1.0}},
+ {7, {4.0, 4.0}},
+ {8, {1.0, 4.0}},
+ {5, {1.0, 1.0}}
+ }},
+ { false, {
+ {10, {5.0, 5.0}},
+ {11, {5.0, 7.0}},
+ {12, {7.0, 7.0}},
+ {10, {5.0, 5.0}}
+ }},
+ { true, {
+ {100, {10.0, 10.0}},
+ {101, {11.0, 10.0}},
+ {102, {11.0, 11.0}},
+ {103, {10.0, 11.0}},
+ {100, {10.0, 10.0}}
+ }}
+ });
+
+ std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
+ REQUIRE(2 == mp->getNumGeometries());
+
+ const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
+ REQUIRE(2 == p0->getNumInteriorRings());
+
+ const OGRLineString* l0e = p0->getExteriorRing();
+ REQUIRE(5 == l0e->getNumPoints());
+
+ const OGRPolygon* p1 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(1));
+ REQUIRE(0 == p1->getNumInteriorRings());
+
+ const OGRLineString* l1e = p1->getExteriorRing();
+ REQUIRE(5 == l1e->getNumPoints());
+}
+
+}
+
diff --git a/third_party/libosmium/test/t/geom/test_projection.cpp b/third_party/libosmium/test/t/geom/test_projection.cpp
new file mode 100644
index 0000000..2257d7f
--- /dev/null
+++ b/third_party/libosmium/test/t/geom/test_projection.cpp
@@ -0,0 +1,131 @@
+#include "catch.hpp"
+
+#include <osmium/geom/factory.hpp>
+#include <osmium/geom/mercator_projection.hpp>
+#include <osmium/geom/projection.hpp>
+
+TEST_CASE("Projection") {
+
+SECTION("identity_projection") {
+ osmium::geom::IdentityProjection projection;
+ REQUIRE(4326 == projection.epsg());
+ REQUIRE("+proj=longlat +datum=WGS84 +no_defs" == projection.proj_string());
+}
+
+SECTION("project_location_4326") {
+ osmium::geom::Projection projection(4326);
+ REQUIRE(4326 == projection.epsg());
+ REQUIRE("+init=epsg:4326" == projection.proj_string());
+
+ const osmium::Location loc(1.0, 2.0);
+ const osmium::geom::Coordinates c {1.0, 2.0};
+ REQUIRE(c == projection(loc));
+}
+
+SECTION("project_location_4326_string") {
+ osmium::geom::Projection projection("+init=epsg:4326");
+ REQUIRE(-1 == projection.epsg());
+ REQUIRE("+init=epsg:4326" == projection.proj_string());
+
+ const osmium::Location loc(1.0, 2.0);
+ const osmium::geom::Coordinates c {1.0, 2.0};
+ REQUIRE(c == projection(loc));
+}
+
+SECTION("unknown_projection_string") {
+ REQUIRE_THROWS_AS(osmium::geom::Projection projection("abc"), osmium::projection_error);
+}
+
+SECTION("unknown_epsg_code") {
+ REQUIRE_THROWS_AS(osmium::geom::Projection projection(9999999), osmium::projection_error);
+}
+
+SECTION("project_location_3857") {
+ osmium::geom::Projection projection(3857);
+ REQUIRE(3857 == projection.epsg());
+ REQUIRE("+init=epsg:3857" == projection.proj_string());
+
+ {
+ const osmium::Location loc(0.0, 0.0);
+ const osmium::geom::Coordinates c {0.0, 0.0};
+ REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
+ REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
+ }
+ {
+ const osmium::Location loc(180.0, 0.0);
+ const osmium::geom::Coordinates c {20037508.34, 0.0};
+ REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
+ REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
+ }
+ {
+ const osmium::Location loc(180.0, 0.0);
+ const osmium::geom::Coordinates c {20037508.34, 0.0};
+ REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
+ REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
+ }
+ {
+ const osmium::Location loc(0.0, 85.0511288);
+ const osmium::geom::Coordinates c {0.0, 20037508.34};
+ REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
+ REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
+ }
+}
+
+SECTION("project_location_mercator") {
+ osmium::geom::MercatorProjection projection;
+
+ {
+ const osmium::Location loc(0.0, 0.0);
+ const osmium::geom::Coordinates c {0.0, 0.0};
+ REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
+ REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
+ }
+ {
+ const osmium::Location loc(180.0, 0.0);
+ const osmium::geom::Coordinates c {20037508.34, 0.0};
+ REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
+ REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
+ }
+ {
+ const osmium::Location loc(180.0, 0.0);
+ const osmium::geom::Coordinates c {20037508.34, 0.0};
+ REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
+ REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
+ }
+ {
+ const osmium::Location loc(0.0, 85.0511288);
+ const osmium::geom::Coordinates c {0.0, 20037508.34};
+ REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
+ REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
+ }
+}
+
+SECTION("compare_mercators") {
+ osmium::geom::MercatorProjection projection_merc;
+ osmium::geom::Projection projection_3857(3857);
+ REQUIRE(3857 == projection_3857.epsg());
+ REQUIRE("+init=epsg:3857" == projection_3857.proj_string());
+
+ {
+ const osmium::Location loc(4.2, 27.3);
+ REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
+ REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
+ }
+ {
+ const osmium::Location loc(160.789, -42.42);
+ REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
+ REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
+ }
+ {
+ const osmium::Location loc(-0.001, 0.001);
+ REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
+ REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
+ }
+ {
+ const osmium::Location loc(-85.2, -85.2);
+ REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
+ REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
+ }
+}
+
+}
diff --git a/third_party/libosmium/test/t/geom/test_wkb.cpp b/third_party/libosmium/test/t/geom/test_wkb.cpp
new file mode 100644
index 0000000..730ee75
--- /dev/null
+++ b/third_party/libosmium/test/t/geom/test_wkb.cpp
@@ -0,0 +1,133 @@
+#include "catch.hpp"
+
+#include <osmium/builder/builder_helper.hpp>
+#include <osmium/geom/wkb.hpp>
+
+#include "../basic/helper.hpp"
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+TEST_CASE("WKB_Geometry_byte_order_dependent") {
+
+SECTION("point") {
+ osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+
+ std::string wkb {factory.create_point(osmium::Location(3.2, 4.2))};
+ REQUIRE(std::string{"01010000009A99999999990940CDCCCCCCCCCC1040"} == wkb);
+}
+
+SECTION("point_ewkb") {
+ osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
+
+ std::string wkb {factory.create_point(osmium::Location(3.2, 4.2))};
+ REQUIRE(std::string{"0101000020E61000009A99999999990940CDCCCCCCCCCC1040"} == wkb);
+}
+
+SECTION("linestring") {
+ osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {
+ {1, {3.2, 4.2}},
+ {3, {3.5, 4.7}},
+ {4, {3.5, 4.7}},
+ {2, {3.6, 4.9}}
+ });
+
+ {
+ std::string wkb {factory.create_linestring(wnl)};
+ REQUIRE(std::string{"0102000000030000009A99999999990940CDCCCCCCCCCC10400000000000000C40CDCCCCCCCCCC1240CDCCCCCCCCCC0C409A99999999991340"} == wkb);
+ }
+
+ {
+ std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
+ REQUIRE(std::string{"010200000003000000CDCCCCCCCCCC0C409A999999999913400000000000000C40CDCCCCCCCCCC12409A99999999990940CDCCCCCCCCCC1040"} == wkb);
+ }
+
+ {
+ std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ REQUIRE(std::string{"0102000000040000009A99999999990940CDCCCCCCCCCC10400000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC1240CDCCCCCCCCCC0C409A99999999991340"} == wkb);
+ }
+
+ {
+ std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ REQUIRE(std::string{"010200000004000000CDCCCCCCCCCC0C409A999999999913400000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC12409A99999999990940CDCCCCCCCCCC1040"} == wkb);
+ }
+}
+
+SECTION("linestring_ewkb") {
+ osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {
+ {1, {3.2, 4.2}},
+ {3, {3.5, 4.7}},
+ {4, {3.5, 4.7}},
+ {2, {3.6, 4.9}}
+ });
+
+ std::string ewkb {factory.create_linestring(wnl)};
+ REQUIRE(std::string{"0102000020E6100000030000009A99999999990940CDCCCCCCCCCC10400000000000000C40CDCCCCCCCCCC1240CDCCCCCCCCCC0C409A99999999991340"} == ewkb);
+}
+
+SECTION("linestring_with_two_same_locations") {
+ osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {
+ {1, {3.5, 4.7}},
+ {2, {3.5, 4.7}}
+ });
+
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+
+ {
+ std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ REQUIRE(std::string{"0102000000020000000000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC1240"} == wkb);
+ }
+
+ {
+ std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ REQUIRE(std::string{"0102000000020000000000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC1240"} == wkb);
+ }
+}
+
+SECTION("linestring_with_undefined_location") {
+ osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {
+ {1, {3.5, 4.7}},
+ {2, osmium::Location()}
+ });
+
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
+}
+
+}
+
+#endif
+
+TEST_CASE("WKB_Geometry_byte_order_independent") {
+
+SECTION("empty_point") {
+ osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+
+ REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
+}
+
+SECTION("empty_linestring") {
+ osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {});
+
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
+}
+
+}
+
diff --git a/third_party/libosmium/test/t/geom/test_wkt.cpp b/third_party/libosmium/test/t/geom/test_wkt.cpp
new file mode 100644
index 0000000..ff1417c
--- /dev/null
+++ b/third_party/libosmium/test/t/geom/test_wkt.cpp
@@ -0,0 +1,198 @@
+#include "catch.hpp"
+
+#include <osmium/builder/builder_helper.hpp>
+#include <osmium/geom/wkt.hpp>
+
+#include "../basic/helper.hpp"
+
+TEST_CASE("WKT_Geometry") {
+
+SECTION("point") {
+ osmium::geom::WKTFactory<> factory;
+
+ std::string wkt {factory.create_point(osmium::Location(3.2, 4.2))};
+ REQUIRE(std::string{"POINT(3.2 4.2)"} == wkt);
+}
+
+SECTION("empty_point") {
+ osmium::geom::WKTFactory<> factory;
+
+ REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
+}
+
+SECTION("linestring") {
+ osmium::geom::WKTFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {
+ {1, {3.2, 4.2}},
+ {3, {3.5, 4.7}},
+ {4, {3.5, 4.7}},
+ {2, {3.6, 4.9}}
+ });
+
+ {
+ std::string wkt {factory.create_linestring(wnl)};
+ REQUIRE(std::string{"LINESTRING(3.2 4.2,3.5 4.7,3.6 4.9)"} == wkt);
+ }
+
+ {
+ std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
+ REQUIRE(std::string{"LINESTRING(3.6 4.9,3.5 4.7,3.2 4.2)"} == wkt);
+ }
+
+ {
+ std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ REQUIRE(std::string{"LINESTRING(3.2 4.2,3.5 4.7,3.5 4.7,3.6 4.9)"} == wkt);
+ }
+
+ {
+ std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ REQUIRE(std::string{"LINESTRING(3.6 4.9,3.5 4.7,3.5 4.7,3.2 4.2)"} == wkt);
+ }
+}
+
+SECTION("empty_linestring") {
+ osmium::geom::WKTFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {});
+
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
+}
+
+SECTION("linestring_with_two_same_locations") {
+ osmium::geom::WKTFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {
+ {1, {3.5, 4.7}},
+ {2, {3.5, 4.7}}
+ });
+
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+
+ {
+ std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ REQUIRE(std::string{"LINESTRING(3.5 4.7,3.5 4.7)"} == wkt);
+ }
+
+ {
+ std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ REQUIRE(std::string{"LINESTRING(3.5 4.7,3.5 4.7)"} == wkt);
+ }
+}
+
+SECTION("linestring_with_undefined_location") {
+ osmium::geom::WKTFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ auto& wnl = osmium::builder::build_way_node_list(buffer, {
+ {1, {3.5, 4.7}},
+ {2, osmium::Location()}
+ });
+
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
+}
+
+SECTION("area_1outer_0inner") {
+ osmium::geom::WKTFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {3.2, 4.2}},
+ {2, {3.5, 4.7}},
+ {3, {3.6, 4.9}},
+ {1, {3.2, 4.2}}
+ }}
+ });
+
+ {
+ std::string wkt {factory.create_multipolygon(area)};
+ REQUIRE(std::string{"MULTIPOLYGON(((3.2 4.2,3.5 4.7,3.6 4.9,3.2 4.2)))"} == wkt);
+ }
+}
+
+SECTION("area_1outer_1inner") {
+ osmium::geom::WKTFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {0.1, 0.1}},
+ {2, {9.1, 0.1}},
+ {3, {9.1, 9.1}},
+ {4, {0.1, 9.1}},
+ {1, {0.1, 0.1}}
+ }},
+ { false, {
+ {5, {1.0, 1.0}},
+ {6, {8.0, 1.0}},
+ {7, {8.0, 8.0}},
+ {8, {1.0, 8.0}},
+ {5, {1.0, 1.0}}
+ }}
+ });
+
+ {
+ std::string wkt {factory.create_multipolygon(area)};
+ REQUIRE(std::string{"MULTIPOLYGON(((0.1 0.1,9.1 0.1,9.1 9.1,0.1 9.1,0.1 0.1),(1 1,8 1,8 8,1 8,1 1)))"} == wkt);
+ }
+}
+
+SECTION("area_2outer_2inner") {
+ osmium::geom::WKTFactory<> factory;
+
+ osmium::memory::Buffer buffer(10000);
+ osmium::Area& area = buffer_add_area(buffer,
+ "foo",
+ {},
+ {
+ { true, {
+ {1, {0.1, 0.1}},
+ {2, {9.1, 0.1}},
+ {3, {9.1, 9.1}},
+ {4, {0.1, 9.1}},
+ {1, {0.1, 0.1}}
+ }},
+ { false, {
+ {5, {1.0, 1.0}},
+ {6, {4.0, 1.0}},
+ {7, {4.0, 4.0}},
+ {8, {1.0, 4.0}},
+ {5, {1.0, 1.0}}
+ }},
+ { false, {
+ {10, {5.0, 5.0}},
+ {11, {5.0, 7.0}},
+ {12, {7.0, 7.0}},
+ {10, {5.0, 5.0}}
+ }},
+ { true, {
+ {100, {10.0, 10.0}},
+ {101, {11.0, 10.0}},
+ {102, {11.0, 11.0}},
+ {103, {10.0, 11.0}},
+ {100, {10.0, 10.0}}
+ }}
+ });
+
+ {
+ std::string wkt {factory.create_multipolygon(area)};
+ REQUIRE(std::string{"MULTIPOLYGON(((0.1 0.1,9.1 0.1,9.1 9.1,0.1 9.1,0.1 0.1),(1 1,4 1,4 4,1 4,1 1),(5 5,5 7,7 7,5 5)),((10 10,11 10,11 11,10 11,10 10)))"} == wkt);
+ }
+}
+
+}
+
diff --git a/third_party/libosmium/test/t/index/test_id_to_location.cpp b/third_party/libosmium/test/t/index/test_id_to_location.cpp
new file mode 100644
index 0000000..4aca238
--- /dev/null
+++ b/third_party/libosmium/test/t/index/test_id_to_location.cpp
@@ -0,0 +1,170 @@
+#include "catch.hpp"
+
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/location.hpp>
+
+#include <osmium/index/map/dense_file_array.hpp>
+#include <osmium/index/map/dense_mem_array.hpp>
+#include <osmium/index/map/dense_mmap_array.hpp>
+#include <osmium/index/map/dummy.hpp>
+#include <osmium/index/map/sparse_file_array.hpp>
+#include <osmium/index/map/sparse_mem_array.hpp>
+#include <osmium/index/map/sparse_mem_map.hpp>
+#include <osmium/index/map/sparse_mem_table.hpp>
+#include <osmium/index/map/sparse_mmap_array.hpp>
+
+#include <osmium/index/node_locations_map.hpp>
+
+template <typename TIndex>
+void test_func_all(TIndex& index) {
+ osmium::unsigned_object_id_type id1 = 12;
+ osmium::unsigned_object_id_type id2 = 3;
+ osmium::Location loc1(1.2, 4.5);
+ osmium::Location loc2(3.5, -7.2);
+
+ REQUIRE_THROWS_AS(index.get(id1), osmium::not_found);
+
+ index.set(id1, loc1);
+ index.set(id2, loc2);
+
+ index.sort();
+
+ REQUIRE_THROWS_AS(index.get(5), osmium::not_found);
+ REQUIRE_THROWS_AS(index.get(100), osmium::not_found);
+}
+
+template <typename TIndex>
+void test_func_real(TIndex& index) {
+ osmium::unsigned_object_id_type id1 = 12;
+ osmium::unsigned_object_id_type id2 = 3;
+ osmium::Location loc1(1.2, 4.5);
+ osmium::Location loc2(3.5, -7.2);
+
+ index.set(id1, loc1);
+ index.set(id2, loc2);
+
+ index.sort();
+
+ REQUIRE(loc1 == index.get(id1));
+ REQUIRE(loc2 == index.get(id2));
+
+ REQUIRE_THROWS_AS(index.get(5), osmium::not_found);
+ REQUIRE_THROWS_AS(index.get(100), osmium::not_found);
+
+ index.clear();
+
+ REQUIRE_THROWS_AS(index.get(id1), osmium::not_found);
+}
+
+TEST_CASE("IdToLocation") {
+
+ SECTION("Dummy") {
+ typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_type;
+
+ index_type index1;
+
+ REQUIRE(0 == index1.size());
+ REQUIRE(0 == index1.used_memory());
+
+ test_func_all<index_type>(index1);
+
+ REQUIRE(0 == index1.size());
+ REQUIRE(0 == index1.used_memory());
+ }
+
+ SECTION("DenseMemArray") {
+ typedef osmium::index::map::DenseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
+
+ index_type index1;
+ index1.reserve(1000);
+ test_func_all<index_type>(index1);
+
+ index_type index2;
+ index2.reserve(1000);
+ test_func_real<index_type>(index2);
+ }
+
+#ifdef __linux__
+ SECTION("DenseMmapArray") {
+ typedef osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
+
+ index_type index1;
+ test_func_all<index_type>(index1);
+
+ index_type index2;
+ test_func_real<index_type>(index2);
+ }
+#else
+# pragma message("not running 'DenseMapMmap' test case on this machine")
+#endif
+
+ SECTION("DenseFileArray") {
+ typedef osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
+
+ index_type index1;
+ test_func_all<index_type>(index1);
+
+ index_type index2;
+ test_func_real<index_type>(index2);
+ }
+
+#ifdef OSMIUM_WITH_SPARSEHASH
+
+ SECTION("SparseMemTable") {
+ typedef osmium::index::map::SparseMemTable<osmium::unsigned_object_id_type, osmium::Location> index_type;
+
+ index_type index1;
+ test_func_all<index_type>(index1);
+
+ index_type index2;
+ test_func_real<index_type>(index2);
+ }
+
+#endif
+
+ SECTION("SparseMemMap") {
+ typedef osmium::index::map::SparseMemMap<osmium::unsigned_object_id_type, osmium::Location> index_type;
+
+ index_type index1;
+ test_func_all<index_type>(index1);
+
+ index_type index2;
+ test_func_real<index_type>(index2);
+ }
+
+ SECTION("SparseMemArray") {
+ typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
+
+ index_type index1;
+
+ REQUIRE(0 == index1.size());
+ REQUIRE(0 == index1.used_memory());
+
+ test_func_all<index_type>(index1);
+
+ REQUIRE(2 == index1.size());
+
+ index_type index2;
+ test_func_real<index_type>(index2);
+ }
+
+ SECTION("Dynamic map choice") {
+ typedef osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location> map_type;
+ const auto& map_factory = osmium::index::MapFactory<osmium::unsigned_object_id_type, osmium::Location>::instance();
+
+ std::vector<std::string> map_type_names = map_factory.map_types();
+ REQUIRE(map_type_names.size() >= 5);
+
+ for (const auto& map_type_name : map_type_names) {
+ std::unique_ptr<map_type> index1 = map_factory.create_map(map_type_name);
+ index1->reserve(1000);
+ test_func_all<map_type>(*index1);
+
+ std::unique_ptr<map_type> index2 = map_factory.create_map(map_type_name);
+ index2->reserve(1000);
+ test_func_real<map_type>(*index2);
+ }
+ }
+
+}
+
diff --git a/third_party/libosmium/test/t/index/test_typed_mmap.cpp b/third_party/libosmium/test/t/index/test_typed_mmap.cpp
new file mode 100644
index 0000000..bcc17bd
--- /dev/null
+++ b/third_party/libosmium/test/t/index/test_typed_mmap.cpp
@@ -0,0 +1,76 @@
+#include "catch.hpp"
+
+#include <osmium/index/detail/typed_mmap.hpp>
+
+#if defined(_MSC_VER) || (defined(__GNUC__) && defined(_WIN32))
+#include "win_mkstemp.hpp"
+#endif
+
+TEST_CASE("TypedMmap") {
+
+ SECTION("Mmap") {
+ uint64_t* data = osmium::detail::typed_mmap<uint64_t>::map(10);
+
+ data[0] = 4ul;
+ data[3] = 9ul;
+ data[9] = 25ul;
+
+ REQUIRE(4ul == data[0]);
+ REQUIRE(9ul == data[3]);
+ REQUIRE(25ul == data[9]);
+
+ osmium::detail::typed_mmap<uint64_t>::unmap(data, 10);
+ }
+
+ SECTION("MmapSizeZero") {
+ REQUIRE_THROWS_AS(osmium::detail::typed_mmap<uint64_t>::map(0), std::system_error);
+ }
+
+ SECTION("MmapHugeSize") {
+ // this is a horrible hack to only run the test on 64bit machines.
+ if (sizeof(size_t) >= 8) {
+ REQUIRE_THROWS_AS(osmium::detail::typed_mmap<uint64_t>::map(1ULL << (sizeof(size_t) * 6)), std::system_error);
+ }
+ }
+
+#ifdef __linux__
+ SECTION("Remap") {
+ uint64_t* data = osmium::detail::typed_mmap<uint64_t>::map(10);
+
+ data[0] = 4ul;
+ data[3] = 9ul;
+ data[9] = 25ul;
+
+ uint64_t* new_data = osmium::detail::typed_mmap<uint64_t>::remap(data, 10, 1000);
+
+ REQUIRE(4ul == new_data[0]);
+ REQUIRE(9ul == new_data[3]);
+ REQUIRE(25ul == new_data[9]);
+ }
+#else
+# pragma message("not running 'Remap' test case on this machine")
+#endif
+
+ SECTION("FileSize") {
+ const int size = 100;
+ char filename[] = "test_mmap_file_size_XXXXXX";
+ const int fd = mkstemp(filename);
+ REQUIRE(fd > 0);
+ REQUIRE(0 == osmium::detail::typed_mmap<uint64_t>::file_size(fd));
+ REQUIRE(0 == ftruncate(fd, size * sizeof(uint64_t)));
+ REQUIRE(size == osmium::detail::typed_mmap<uint64_t>::file_size(fd));
+
+ osmium::detail::typed_mmap<uint64_t>::grow_file(size / 2, fd);
+ REQUIRE(size == osmium::detail::typed_mmap<uint64_t>::file_size(fd));
+
+ osmium::detail::typed_mmap<uint64_t>::grow_file(size, fd);
+ REQUIRE(size == osmium::detail::typed_mmap<uint64_t>::file_size(fd));
+
+ osmium::detail::typed_mmap<uint64_t>::grow_file(size * 2, fd);
+ REQUIRE((size * 2) == osmium::detail::typed_mmap<uint64_t>::file_size(fd));
+
+ REQUIRE(0 == close(fd));
+ REQUIRE(0 == unlink(filename));
+ }
+
+}
diff --git a/third_party/libosmium/test/t/index/test_typed_mmap_grow.cpp b/third_party/libosmium/test/t/index/test_typed_mmap_grow.cpp
new file mode 100644
index 0000000..92ee0b4
--- /dev/null
+++ b/third_party/libosmium/test/t/index/test_typed_mmap_grow.cpp
@@ -0,0 +1,34 @@
+#include "catch.hpp"
+
+#include <osmium/index/detail/typed_mmap.hpp>
+
+#if defined(_MSC_VER) || (defined(__GNUC__) && defined(_WIN32))
+#include "win_mkstemp.hpp"
+#endif
+
+TEST_CASE("TypedMmapGrow") {
+
+ SECTION("GrowAndMap") {
+ const int size = 100;
+ char filename[] = "test_mmap_grow_and_map_XXXXXX";
+ const int fd = mkstemp(filename);
+ REQUIRE(fd > 0);
+
+ uint64_t* data = osmium::detail::typed_mmap<uint64_t>::grow_and_map(size, fd);
+ REQUIRE(size == osmium::detail::typed_mmap<uint64_t>::file_size(fd));
+
+ data[0] = 1ul;
+ data[1] = 8ul;
+ data[99] = 27ul;
+
+ REQUIRE(1ul == data[0]);
+ REQUIRE(8ul == data[1]);
+ REQUIRE(27ul == data[99]);
+
+ osmium::detail::typed_mmap<uint64_t>::unmap(data, size);
+
+ REQUIRE(0 == close(fd));
+ REQUIRE(0 == unlink(filename));
+ }
+
+}
diff --git a/third_party/libosmium/test/t/io/data.osm b/third_party/libosmium/test/t/io/data.osm
new file mode 100644
index 0000000..fffb77a
--- /dev/null
+++ b/third_party/libosmium/test/t/io/data.osm
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+ <node id="1" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.02" lat="1.02"/>
+</osm>
diff --git a/third_party/libosmium/test/t/io/data.osm.bz2 b/third_party/libosmium/test/t/io/data.osm.bz2
new file mode 100644
index 0000000..0f38797
Binary files /dev/null and b/third_party/libosmium/test/t/io/data.osm.bz2 differ
diff --git a/third_party/libosmium/test/t/io/data.osm.gz b/third_party/libosmium/test/t/io/data.osm.gz
new file mode 100644
index 0000000..07edb90
Binary files /dev/null and b/third_party/libosmium/test/t/io/data.osm.gz differ
diff --git a/third_party/libosmium/test/t/io/data_bzip2.txt b/third_party/libosmium/test/t/io/data_bzip2.txt
new file mode 100644
index 0000000..755d6af
--- /dev/null
+++ b/third_party/libosmium/test/t/io/data_bzip2.txt
@@ -0,0 +1 @@
+TESTDATA
diff --git a/third_party/libosmium/test/t/io/data_bzip2.txt.bz2 b/third_party/libosmium/test/t/io/data_bzip2.txt.bz2
new file mode 100644
index 0000000..f0ee7e7
Binary files /dev/null and b/third_party/libosmium/test/t/io/data_bzip2.txt.bz2 differ
diff --git a/third_party/libosmium/test/t/io/test_bzip2.cpp b/third_party/libosmium/test/t/io/test_bzip2.cpp
new file mode 100644
index 0000000..5cc30b4
--- /dev/null
+++ b/third_party/libosmium/test/t/io/test_bzip2.cpp
@@ -0,0 +1,33 @@
+#include "catch.hpp"
+#include "utils.hpp"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <osmium/io/bzip2_compression.hpp>
+
+TEST_CASE("Bzip2") {
+
+ SECTION("read_compressed_file") {
+ std::string input_file = with_data_dir("t/io/data_bzip2.txt.bz2");
+
+ int fd = ::open(input_file.c_str(), O_RDONLY);
+ REQUIRE(fd > 0);
+
+ size_t size = 0;
+ std::string all;
+ {
+ osmium::io::Bzip2Decompressor decomp(fd);
+ for (std::string data = decomp.read(); !data.empty(); data = decomp.read()) {
+ size += data.size();
+ all += data;
+ }
+ }
+
+ REQUIRE(9 == size);
+ REQUIRE("TESTDATA\n" == all);
+ }
+
+}
+
diff --git a/third_party/libosmium/test/t/io/test_file_formats.cpp b/third_party/libosmium/test/t/io/test_file_formats.cpp
new file mode 100644
index 0000000..e8785d6
--- /dev/null
+++ b/third_party/libosmium/test/t/io/test_file_formats.cpp
@@ -0,0 +1,251 @@
+#include "catch.hpp"
+
+#include <iterator>
+
+#include <osmium/io/file.hpp>
+
+TEST_CASE("FileFormats") {
+
+ SECTION("default_file_format") {
+ osmium::io::File f;
+ REQUIRE(osmium::io::file_format::unknown == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ REQUIRE_THROWS_AS(f.check(), std::runtime_error);
+ }
+
+ SECTION("stdin_stdout_empty") {
+ osmium::io::File f {""};
+ REQUIRE(osmium::io::file_format::unknown == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ REQUIRE_THROWS_AS(f.check(), std::runtime_error);
+ }
+
+ SECTION("stdin_stdout_dash") {
+ osmium::io::File f {"-"};
+ REQUIRE(osmium::io::file_format::unknown == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ REQUIRE_THROWS_AS(f.check(), std::runtime_error);
+ }
+
+ SECTION("stdin_stdout_bz2") {
+ osmium::io::File f {"-", "osm.bz2"};
+ REQUIRE("" == f.filename());
+ REQUIRE(osmium::io::file_format::xml == f.format());
+ REQUIRE(osmium::io::file_compression::bzip2 == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("detect_file_format_by_suffix_osm") {
+ osmium::io::File f {"test.osm"};
+ REQUIRE(osmium::io::file_format::xml == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("detect_file_format_by_suffix_pbf") {
+ osmium::io::File f {"test.pbf"};
+ REQUIRE(osmium::io::file_format::pbf == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("detect_file_format_by_suffix_osm_pbf") {
+ osmium::io::File f {"test.osm.pbf"};
+ REQUIRE(osmium::io::file_format::pbf == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("detect_file_format_by_suffix_opl") {
+ osmium::io::File f {"test.opl"};
+ REQUIRE(osmium::io::file_format::opl == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("detect_file_format_by_suffix_osm_opl") {
+ osmium::io::File f {"test.osm.opl"};
+ REQUIRE(osmium::io::file_format::opl == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("detect_file_format_by_suffix_osm_gz") {
+ osmium::io::File f {"test.osm.gz"};
+ REQUIRE(osmium::io::file_format::xml == f.format());
+ REQUIRE(osmium::io::file_compression::gzip == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("detect_file_format_by_suffix_opl_bz2") {
+ osmium::io::File f {"test.osm.opl.bz2"};
+ REQUIRE(osmium::io::file_format::opl == f.format());
+ REQUIRE(osmium::io::file_compression::bzip2 == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("detect_file_format_by_suffix_osc_gz") {
+ osmium::io::File f {"test.osc.gz"};
+ REQUIRE(osmium::io::file_format::xml == f.format());
+ REQUIRE(osmium::io::file_compression::gzip == f.compression());
+ REQUIRE(true == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("detect_file_format_by_suffix_opl_gz") {
+ osmium::io::File f {"test.osh.opl.gz"};
+ REQUIRE(osmium::io::file_format::opl == f.format());
+ REQUIRE(osmium::io::file_compression::gzip == f.compression());
+ REQUIRE(true == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("detect_file_format_by_suffix_osh_pbf") {
+ osmium::io::File f {"test.osh.pbf"};
+ REQUIRE(osmium::io::file_format::pbf == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(true == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("override_file_format_by_suffix_osm") {
+ osmium::io::File f {"test", "osm"};
+ REQUIRE(osmium::io::file_format::xml == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("override_file_format_by_suffix_pbf") {
+ osmium::io::File f {"test", "pbf"};
+ REQUIRE(osmium::io::file_format::pbf == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("override_file_format_by_suffix_osm_pbf") {
+ osmium::io::File f {"test", "osm.pbf"};
+ REQUIRE(osmium::io::file_format::pbf == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("override_file_format_by_suffix_opl") {
+ osmium::io::File f {"test", "opl"};
+ REQUIRE(osmium::io::file_format::opl == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("override_file_format_by_suffix_osm_opl") {
+ osmium::io::File f {"test", "osm.opl"};
+ REQUIRE(osmium::io::file_format::opl == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("override_file_format_by_suffix_osm_gz") {
+ osmium::io::File f {"test", "osm.gz"};
+ REQUIRE(osmium::io::file_format::xml == f.format());
+ REQUIRE(osmium::io::file_compression::gzip == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("override_file_format_by_suffix_osm_opl_bz2") {
+ osmium::io::File f {"test", "osm.opl.bz2"};
+ REQUIRE(osmium::io::file_format::opl == f.format());
+ REQUIRE(osmium::io::file_compression::bzip2 == f.compression());
+ REQUIRE(false == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("override_file_format_by_suffix_osc_gz") {
+ osmium::io::File f {"test", "osc.gz"};
+ REQUIRE(osmium::io::file_format::xml == f.format());
+ REQUIRE(osmium::io::file_compression::gzip == f.compression());
+ REQUIRE(true == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("override_file_format_by_suffix_osh_opl_gz") {
+ osmium::io::File f {"test", "osh.opl.gz"};
+ REQUIRE(osmium::io::file_format::opl == f.format());
+ REQUIRE(osmium::io::file_compression::gzip == f.compression());
+ REQUIRE(true == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("override_file_format_by_suffix_osh_pbf") {
+ osmium::io::File f {"test", "osh.pbf"};
+ REQUIRE(osmium::io::file_format::pbf == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(true == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("format_options_pbf_history") {
+ osmium::io::File f {"test", "pbf,history=true"};
+ REQUIRE(osmium::io::file_format::pbf == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE(true == f.has_multiple_object_versions());
+ f.check();
+ }
+
+ SECTION("format_options_pbf_foo") {
+ osmium::io::File f {"test.osm", "pbf,foo=bar"};
+ REQUIRE(osmium::io::file_format::pbf == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE("bar" == f.get("foo"));
+ f.check();
+ }
+
+ SECTION("format_options_xml_abc_something") {
+ osmium::io::File f {"test.bla", "xml,abc,some=thing"};
+ REQUIRE(osmium::io::file_format::xml == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE("true" == f.get("abc"));
+ REQUIRE("thing" == f.get("some"));
+ REQUIRE(2 == std::distance(f.begin(), f.end()));
+ f.check();
+ }
+
+ SECTION("unknown_format_foo_bar") {
+ osmium::io::File f {"test.foo.bar"};
+ REQUIRE(osmium::io::file_format::unknown == f.format());
+ REQUIRE(osmium::io::file_compression::none == f.compression());
+ REQUIRE_THROWS_AS(f.check(), std::runtime_error);
+ }
+
+ SECTION("unknown_format_foo") {
+ osmium::io::File f {"test", "foo"};
+ REQUIRE_THROWS_AS(f.check(), std::runtime_error);
+ }
+
+ SECTION("unknown_format_osm_foo") {
+ osmium::io::File f {"test", "osm.foo"};
+ REQUIRE_THROWS_AS(f.check(), std::runtime_error);
+ }
+
+ SECTION("unknown_format_bla_equals_foo") {
+ osmium::io::File f {"test", "bla=foo"};
+ REQUIRE_THROWS_AS(f.check(), std::runtime_error);
+ }
+
+}
+
diff --git a/third_party/libosmium/test/t/io/test_output_iterator.cpp b/third_party/libosmium/test/t/io/test_output_iterator.cpp
new file mode 100644
index 0000000..7a1f570
--- /dev/null
+++ b/third_party/libosmium/test/t/io/test_output_iterator.cpp
@@ -0,0 +1,37 @@
+#include "catch.hpp"
+
+#include <osmium/io/xml_output.hpp>
+#include <osmium/io/output_iterator.hpp>
+#include <osmium/io/writer.hpp>
+
+TEST_CASE("output iterator") {
+
+ SECTION("should be copy constructable") {
+ osmium::io::Header header;
+ osmium::io::Writer writer("test.osm", header, osmium::io::overwrite::allow);
+ osmium::io::OutputIterator<osmium::io::Writer> out1(writer);
+
+ osmium::io::OutputIterator<osmium::io::Writer> out2(out1);
+ }
+
+ SECTION("should be copy assignable") {
+ osmium::io::Header header;
+ osmium::io::Writer writer1("test1.osm", header, osmium::io::overwrite::allow);
+ osmium::io::Writer writer2("test2.osm", header, osmium::io::overwrite::allow);
+
+ osmium::io::OutputIterator<osmium::io::Writer> out1(writer1);
+ osmium::io::OutputIterator<osmium::io::Writer> out2(writer2);
+
+ out2 = out1;
+ }
+
+ SECTION("should be incrementable") {
+ osmium::io::Header header;
+ osmium::io::Writer writer("test.osm", header, osmium::io::overwrite::allow);
+ osmium::io::OutputIterator<osmium::io::Writer> out(writer);
+
+ ++out;
+ }
+
+}
+
diff --git a/third_party/libosmium/test/t/io/test_reader.cpp b/third_party/libosmium/test/t/io/test_reader.cpp
new file mode 100644
index 0000000..9a06d84
--- /dev/null
+++ b/third_party/libosmium/test/t/io/test_reader.cpp
@@ -0,0 +1,117 @@
+#include "catch.hpp"
+#include "utils.hpp"
+
+#include <osmium/handler.hpp>
+#include <osmium/io/any_compression.hpp>
+#include <osmium/io/xml_input.hpp>
+#include <osmium/visitor.hpp>
+#include <osmium/memory/buffer.hpp>
+
+struct CountHandler : public osmium::handler::Handler {
+
+ int count = 0;
+
+ void node(osmium::Node&) {
+ ++count;
+ }
+
+}; // class CountHandler
+
+TEST_CASE("Reader") {
+
+ SECTION("reader can be initialized with file") {
+ osmium::io::File file(with_data_dir("t/io/data.osm"));
+ osmium::io::Reader reader(file);
+ osmium::handler::Handler handler;
+
+ osmium::apply(reader, handler);
+ }
+
+ SECTION("reader can be initialized with string") {
+ osmium::io::Reader reader(with_data_dir("t/io/data.osm"));
+ osmium::handler::Handler handler;
+
+ osmium::apply(reader, handler);
+ }
+
+ SECTION("should return invalid buffer after eof") {
+ osmium::io::File file(with_data_dir("t/io/data.osm"));
+ osmium::io::Reader reader(file);
+
+ REQUIRE(!reader.eof());
+
+ while (osmium::memory::Buffer buffer = reader.read()) {
+ }
+
+ REQUIRE(reader.eof());
+
+ // extra read always returns invalid buffer
+ osmium::memory::Buffer buffer = reader.read();
+ REQUIRE(!buffer);
+ }
+
+ SECTION("should not hang when apply() is called twice on reader") {
+ osmium::io::File file(with_data_dir("t/io/data.osm"));
+ osmium::io::Reader reader(file);
+ osmium::handler::Handler handler;
+
+ osmium::apply(reader, handler);
+ osmium::apply(reader, handler);
+ }
+
+ SECTION("should work with a buffer with uncompressed data") {
+ int fd = osmium::io::detail::open_for_reading(with_data_dir("t/io/data.osm"));
+ REQUIRE(fd >= 0);
+
+ const size_t buffer_size = 1000;
+ char buffer[buffer_size];
+ auto length = ::read(fd, buffer, buffer_size);
+ REQUIRE(length > 0);
+
+ osmium::io::File file(buffer, static_cast<size_t>(length), "osm");
+ osmium::io::Reader reader(file);
+ CountHandler handler;
+
+ REQUIRE(handler.count == 0);
+ osmium::apply(reader, handler);
+ REQUIRE(handler.count == 1);
+ }
+
+ SECTION("should work with a buffer with gzip-compressed data") {
+ int fd = osmium::io::detail::open_for_reading(with_data_dir("t/io/data.osm.gz"));
+ REQUIRE(fd >= 0);
+
+ const size_t buffer_size = 1000;
+ char buffer[buffer_size];
+ auto length = ::read(fd, buffer, buffer_size);
+ REQUIRE(length > 0);
+
+ osmium::io::File file(buffer, static_cast<size_t>(length), "osm.gz");
+ osmium::io::Reader reader(file);
+ CountHandler handler;
+
+ REQUIRE(handler.count == 0);
+ osmium::apply(reader, handler);
+ REQUIRE(handler.count == 1);
+ }
+
+ SECTION("should work with a buffer with bzip2-compressed data") {
+ int fd = osmium::io::detail::open_for_reading(with_data_dir("t/io/data.osm.bz2"));
+ REQUIRE(fd >= 0);
+
+ const size_t buffer_size = 1000;
+ char buffer[buffer_size];
+ auto length = ::read(fd, buffer, buffer_size);
+ REQUIRE(length > 0);
+
+ osmium::io::File file(buffer, static_cast<size_t>(length), "osm.bz2");
+ osmium::io::Reader reader(file);
+ CountHandler handler;
+
+ REQUIRE(handler.count == 0);
+ osmium::apply(reader, handler);
+ REQUIRE(handler.count == 1);
+ }
+
+}
+
diff --git a/third_party/libosmium/test/t/tags/test_filter.cpp b/third_party/libosmium/test/t/tags/test_filter.cpp
new file mode 100644
index 0000000..eefa5b0
--- /dev/null
+++ b/third_party/libosmium/test/t/tags/test_filter.cpp
@@ -0,0 +1,216 @@
+#include "catch.hpp"
+
+#include <algorithm>
+
+#include <osmium/builder/builder_helper.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/tags/taglist.hpp>
+#include <osmium/tags/filter.hpp>
+#include <osmium/tags/regex_filter.hpp>
+
+template <class TFilter>
+void check_filter(const osmium::TagList& tag_list, const TFilter filter, const std::vector<bool>& reference) {
+ REQUIRE(tag_list.size() == reference.size());
+ auto t_it = tag_list.begin();
+ for (auto it = reference.begin(); it != reference.end(); ++t_it, ++it) {
+ REQUIRE(filter(*t_it) == *it);
+ }
+
+ typename TFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end());
+ typename TFilter::iterator fi_end(filter, tag_list.end(), tag_list.end());
+
+ REQUIRE(std::distance(fi_begin, fi_end) == std::count(reference.begin(), reference.end(), true));
+}
+
+TEST_CASE("Filter") {
+
+ SECTION("KeyFilter_matches_some_tags") {
+ osmium::tags::KeyFilter filter(false);
+ filter.add(true, "highway").add(true, "railway");
+
+ osmium::memory::Buffer buffer(10240);
+ const osmium::TagList& tag_list = osmium::builder::build_tag_list(buffer, {
+ { "highway", "primary" }, // match
+ { "name", "Main Street" }, // no match
+ { "source", "GPS" } // no match
+ });
+
+ std::vector<bool> results = { true, false, false };
+
+ check_filter(tag_list, filter, results);
+ }
+
+ SECTION("KeyFilter_iterator_filters_tags") {
+ osmium::tags::KeyFilter filter(false);
+ filter.add(true, "highway").add(true, "source");
+
+ osmium::memory::Buffer buffer(10240);
+ const osmium::TagList& tl = osmium::builder::build_tag_list(buffer, {
+ { "highway", "primary" }, // match
+ { "name", "Main Street" }, // no match
+ { "source", "GPS" } // no match
+ });
+
+ osmium::tags::KeyFilter::iterator it(filter, tl.begin(), tl.end());
+ const osmium::tags::KeyFilter::iterator end(filter, tl.end(), tl.end());
+
+ REQUIRE(2 == std::distance(it, end));
+
+ REQUIRE(it != end);
+ REQUIRE(std::string("highway") == it->key());
+ REQUIRE(std::string("primary") == it->value());
+ ++it;
+ REQUIRE(std::string("source") == it->key());
+ REQUIRE(std::string("GPS") == it->value());
+ REQUIRE(++it == end);
+ }
+
+ SECTION("KeyValueFilter_matches_some_tags") {
+ osmium::tags::KeyValueFilter filter(false);
+
+ filter.add(true, "highway", "residential").add(true, "highway", "primary").add(true, "railway");
+
+ osmium::memory::Buffer buffer(10240);
+ const osmium::TagList& tag_list = osmium::builder::build_tag_list(buffer, {
+ { "highway", "primary" },
+ { "railway", "tram" },
+ { "source", "GPS" }
+ });
+
+ std::vector<bool> results = {true, true, false};
+
+ check_filter(tag_list, filter, results);
+ }
+
+ SECTION("KeyValueFilter_ordering_matters") {
+ osmium::tags::KeyValueFilter filter1(false);
+ filter1.add(true, "highway").add(false, "highway", "road");
+
+ osmium::tags::KeyValueFilter filter2(false);
+ filter2.add(false, "highway", "road").add(true, "highway");
+
+ osmium::memory::Buffer buffer(10240);
+
+ const osmium::TagList& tag_list1 = osmium::builder::build_tag_list(buffer, {
+ { "highway", "road" },
+ { "name", "Main Street" }
+ });
+
+ const osmium::TagList& tag_list2 = osmium::builder::build_tag_list(buffer, {
+ { "highway", "primary" },
+ { "name", "Main Street" }
+ });
+
+ check_filter(tag_list1, filter1, {true, false});
+ check_filter(tag_list1, filter2, {false, false});
+ check_filter(tag_list2, filter2, {true, false});
+ }
+
+ SECTION("KeyValueFilter_matches_against_taglist_with_any") {
+ osmium::tags::KeyValueFilter filter(false);
+
+ filter.add(true, "highway", "primary").add(true, "name");
+
+ osmium::memory::Buffer buffer(10240);
+ const osmium::TagList& tag_list = osmium::builder::build_tag_list(buffer, {
+ { "highway", "primary" },
+ { "railway", "tram" },
+ { "source", "GPS" }
+ });
+
+ REQUIRE( osmium::tags::match_any_of(tag_list, filter));
+ REQUIRE(!osmium::tags::match_all_of(tag_list, filter));
+ REQUIRE(!osmium::tags::match_none_of(tag_list, filter));
+ }
+
+ SECTION("KeyValueFilter_matches_against_taglist_with_all") {
+ osmium::tags::KeyValueFilter filter(false);
+
+ filter.add(true, "highway", "primary").add(true, "name");
+
+ osmium::memory::Buffer buffer(10240);
+ const osmium::TagList& tag_list = osmium::builder::build_tag_list(buffer, {
+ { "highway", "primary" },
+ { "name", "Main Street" }
+ });
+
+ REQUIRE( osmium::tags::match_any_of(tag_list, filter));
+ REQUIRE( osmium::tags::match_all_of(tag_list, filter));
+ REQUIRE(!osmium::tags::match_none_of(tag_list, filter));
+ }
+
+ SECTION("KeyValueFilter_matches_against_taglist_with_none") {
+ osmium::tags::KeyValueFilter filter(false);
+
+ filter.add(true, "highway", "road").add(true, "source");
+
+ osmium::memory::Buffer buffer(10240);
+ const osmium::TagList& tag_list = osmium::builder::build_tag_list(buffer, {
+ { "highway", "primary" },
+ { "name", "Main Street" }
+ });
+
+ REQUIRE(!osmium::tags::match_any_of(tag_list, filter));
+ REQUIRE(!osmium::tags::match_all_of(tag_list, filter));
+ REQUIRE( osmium::tags::match_none_of(tag_list, filter));
+ }
+
+ SECTION("KeyValueFilter_matches_against_taglist_with_any_called_with_rvalue") {
+ osmium::memory::Buffer buffer(10240);
+ const osmium::TagList& tag_list = osmium::builder::build_tag_list(buffer, {
+ { "highway", "primary" },
+ { "railway", "tram" },
+ { "source", "GPS" }
+ });
+
+ REQUIRE(osmium::tags::match_any_of(tag_list,
+ osmium::tags::KeyValueFilter().add(true, "highway", "primary").add(true, "name")));
+ }
+
+ SECTION("RegexFilter_matches_some_tags") {
+ osmium::tags::RegexFilter filter(false);
+ filter.add(true, "highway", std::regex(".*_link"));
+
+ osmium::memory::Buffer buffer(10240);
+ const osmium::TagList& tag_list1 = osmium::builder::build_tag_list(buffer, {
+ { "highway", "primary_link" },
+ { "source", "GPS" }
+ });
+ const osmium::TagList& tag_list2 = osmium::builder::build_tag_list(buffer, {
+ { "highway", "primary" },
+ { "source", "GPS" }
+ });
+
+ check_filter(tag_list1, filter, {true, false});
+ check_filter(tag_list2, filter, {false, false});
+ }
+
+ SECTION("RegexFilter_matches_some_tags_with_lvalue_regex") {
+ osmium::tags::RegexFilter filter(false);
+ std::regex r(".*straße");
+ filter.add(true, "name", r);
+
+ osmium::memory::Buffer buffer(10240);
+ const osmium::TagList& tag_list = osmium::builder::build_tag_list(buffer, {
+ { "highway", "primary" },
+ { "name", "Hauptstraße" }
+ });
+
+ check_filter(tag_list, filter, {false, true});
+ }
+
+ SECTION("KeyPrefixFilter_matches_some_tags") {
+ osmium::tags::KeyPrefixFilter filter(false);
+ filter.add(true, "name:");
+
+ osmium::memory::Buffer buffer(10240);
+ const osmium::TagList& tag_list = osmium::builder::build_tag_list(buffer, {
+ { "highway", "primary" },
+ { "name:de", "Hauptstraße" }
+ });
+
+ check_filter(tag_list, filter, {false, true});
+ }
+
+}
diff --git a/third_party/libosmium/test/t/tags/test_operators.cpp b/third_party/libosmium/test/t/tags/test_operators.cpp
new file mode 100644
index 0000000..33a53c2
--- /dev/null
+++ b/third_party/libosmium/test/t/tags/test_operators.cpp
@@ -0,0 +1,61 @@
+#include "catch.hpp"
+
+#include <iterator>
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/tag.hpp>
+
+TEST_CASE("Operators") {
+
+ SECTION("Equal") {
+ osmium::memory::Buffer buffer1(10240);
+ {
+ osmium::builder::TagListBuilder tl_builder(buffer1);
+ tl_builder.add_tag("highway", "primary");
+ tl_builder.add_tag("name", "Main Street");
+ tl_builder.add_tag("source", "GPS");
+ }
+ buffer1.commit();
+
+ osmium::memory::Buffer buffer2(10240);
+ {
+ osmium::builder::TagListBuilder tl_builder(buffer2);
+ tl_builder.add_tag("highway", "primary");
+ }
+ buffer2.commit();
+
+ const osmium::TagList& tl1 = buffer1.get<const osmium::TagList>(0);
+ const osmium::TagList& tl2 = buffer2.get<const osmium::TagList>(0);
+
+ auto tagit1 = tl1.begin();
+ auto tagit2 = tl2.begin();
+ REQUIRE(*tagit1 == *tagit2);
+ ++tagit1;
+ REQUIRE(!(*tagit1 == *tagit2));
+ }
+
+ SECTION("Order") {
+ osmium::memory::Buffer buffer(10240);
+ {
+ osmium::builder::TagListBuilder tl_builder(buffer);
+ tl_builder.add_tag("highway", "residential");
+ tl_builder.add_tag("highway", "primary");
+ tl_builder.add_tag("name", "Main Street");
+ tl_builder.add_tag("amenity", "post_box");
+ }
+ buffer.commit();
+
+ const osmium::TagList& tl = buffer.get<const osmium::TagList>(0);
+ const osmium::Tag& t1 = *(tl.begin());
+ const osmium::Tag& t2 = *(std::next(tl.begin(), 1));
+ const osmium::Tag& t3 = *(std::next(tl.begin(), 2));
+ const osmium::Tag& t4 = *(std::next(tl.begin(), 3));
+
+ REQUIRE(t2 < t1);
+ REQUIRE(t1 < t3);
+ REQUIRE(t2 < t3);
+ REQUIRE(t4 < t1);
+ }
+
+}
diff --git a/third_party/libosmium/test/t/tags/test_tag_list.cpp b/third_party/libosmium/test/t/tags/test_tag_list.cpp
new file mode 100644
index 0000000..c2512d1
--- /dev/null
+++ b/third_party/libosmium/test/t/tags/test_tag_list.cpp
@@ -0,0 +1,76 @@
+#include "catch.hpp"
+
+#include <osmium/builder/builder_helper.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/tag.hpp>
+
+TEST_CASE("tag_list") {
+
+ SECTION("can_be_created_from_initializer_list") {
+ osmium::memory::Buffer buffer(10240);
+
+ const osmium::TagList& tl = osmium::builder::build_tag_list(buffer, {
+ { "highway", "primary" },
+ { "name", "Main Street" },
+ { "source", "GPS" }
+ });
+
+ REQUIRE(osmium::item_type::tag_list == tl.type());
+ REQUIRE(3 == tl.size());
+ REQUIRE(std::string("highway") == tl.begin()->key());
+ REQUIRE(std::string("primary") == tl.begin()->value());
+ }
+
+ SECTION("can_be_created_from_map") {
+ osmium::memory::Buffer buffer(10240);
+
+ const osmium::TagList& tl = osmium::builder::build_tag_list_from_map(buffer, std::map<const char*, const char*>({
+ { "highway", "primary" },
+ { "name", "Main Street" }
+ }));
+
+ REQUIRE(osmium::item_type::tag_list == tl.type());
+ REQUIRE(2 == tl.size());
+
+ if (std::string("highway") == tl.begin()->key()) {
+ REQUIRE(std::string("primary") == tl.begin()->value());
+ REQUIRE(std::string("name") == std::next(tl.begin(), 1)->key());
+ REQUIRE(std::string("Main Street") == std::next(tl.begin(), 1)->value());
+ } else {
+ REQUIRE(std::string("highway") == std::next(tl.begin(), 1)->key());
+ REQUIRE(std::string("primary") == std::next(tl.begin(), 1)->value());
+ REQUIRE(std::string("name") == tl.begin()->key());
+ REQUIRE(std::string("Main Street") == tl.begin()->value());
+ }
+ }
+
+ SECTION("can_be_created_with_callback") {
+ osmium::memory::Buffer buffer(10240);
+
+ const osmium::TagList& tl = osmium::builder::build_tag_list_from_func(buffer, [](osmium::builder::TagListBuilder& tlb) {
+ tlb.add_tag("highway", "primary");
+ tlb.add_tag("bridge", "true");
+ });
+
+ REQUIRE(osmium::item_type::tag_list == tl.type());
+ REQUIRE(2 == tl.size());
+ REQUIRE(std::string("bridge") == std::next(tl.begin(), 1)->key());
+ REQUIRE(std::string("true") == std::next(tl.begin(), 1)->value());
+ }
+
+ SECTION("returns_value_by_key") {
+ osmium::memory::Buffer buffer(10240);
+
+ const osmium::TagList& tl = osmium::builder::build_tag_list_from_func(buffer, [](osmium::builder::TagListBuilder& tlb) {
+ tlb.add_tag("highway", "primary");
+ tlb.add_tag("bridge", "true");
+ });
+
+ REQUIRE(std::string("primary") == tl.get_value_by_key("highway"));
+ REQUIRE(nullptr == tl.get_value_by_key("name"));
+ REQUIRE(std::string("foo") == tl.get_value_by_key("name", "foo"));
+
+ REQUIRE(std::string("true") == tl["bridge"]);
+ }
+
+}
diff --git a/third_party/libosmium/test/t/thread/test_pool.cpp b/third_party/libosmium/test/t/thread/test_pool.cpp
new file mode 100644
index 0000000..66bb373
--- /dev/null
+++ b/third_party/libosmium/test/t/thread/test_pool.cpp
@@ -0,0 +1,69 @@
+#include "catch.hpp"
+
+#include <chrono>
+#include <stdexcept>
+#include <thread>
+
+#include <osmium/thread/pool.hpp>
+
+static std::atomic<int> result;
+
+struct test_job_ok {
+ void operator()() const {
+ result = 1;
+ }
+};
+
+struct test_job_with_result {
+ int operator()() const {
+ return 42;
+ }
+};
+
+struct test_job_throw {
+ void operator()() const {
+ throw std::runtime_error("exception in pool thread");
+ }
+};
+
+TEST_CASE("thread") {
+
+ SECTION("can get access to thread pool") {
+ auto& pool = osmium::thread::Pool::instance();
+ REQUIRE(pool.queue_empty());
+ }
+
+ SECTION("can send job to thread pool") {
+ auto& pool = osmium::thread::Pool::instance();
+ result = 0;
+ auto future = pool.submit(test_job_ok {});
+
+ // wait a bit for the other thread to get a chance to run
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+
+ REQUIRE(result == 1);
+
+ future.get();
+
+ REQUIRE(true);
+ }
+
+ SECTION("can send job to thread pool") {
+ auto& pool = osmium::thread::Pool::instance();
+ auto future = pool.submit(test_job_with_result {});
+
+ REQUIRE(future.get() == 42);
+ }
+
+ SECTION("can throw from job in thread pool") {
+ auto& pool = osmium::thread::Pool::instance();
+ result = 0;
+
+ bool got_exception = false;
+ auto future = pool.submit(test_job_throw {});
+
+ REQUIRE_THROWS_AS(future.get(), std::runtime_error);
+ }
+
+}
+
diff --git a/third_party/libosmium/test/t/util/test_cast_with_assert.cpp b/third_party/libosmium/test/t/util/test_cast_with_assert.cpp
new file mode 100644
index 0000000..0231f30
--- /dev/null
+++ b/third_party/libosmium/test/t/util/test_cast_with_assert.cpp
@@ -0,0 +1,89 @@
+#include "catch.hpp"
+
+// Define assert() to throw this error. This enables the tests to check that
+// the assert() fails.
+struct assert_error : public std::runtime_error {
+ assert_error(const char* what_arg) : std::runtime_error(what_arg) {
+ }
+};
+#define assert(x) if (!(x)) { throw(assert_error(#x)); }
+
+#include <osmium/util/cast.hpp>
+
+TEST_CASE("static_cast_with_assert") {
+
+ SECTION("same types is always okay") {
+ int f = 10;
+ auto t = osmium::static_cast_with_assert<int>(f);
+ REQUIRE(t == f);
+ }
+
+ SECTION("casting to larger type is always okay") {
+ int16_t f = 10;
+ auto t = osmium::static_cast_with_assert<int32_t>(f);
+ REQUIRE(t == f);
+ }
+
+
+ SECTION("cast int32_t -> int_16t should not trigger assert for small int") {
+ int32_t f = 100;
+ auto t = osmium::static_cast_with_assert<int16_t>(f);
+ REQUIRE(t == f);
+ }
+
+ SECTION("cast int32_t -> int_16t should trigger assert for large int") {
+ int32_t f = 100000;
+ REQUIRE_THROWS_AS(osmium::static_cast_with_assert<int16_t>(f), assert_error);
+ }
+
+
+ SECTION("cast int16_t -> uint16_t should not trigger assert for zero") {
+ int16_t f = 0;
+ auto t = osmium::static_cast_with_assert<uint16_t>(f);
+ REQUIRE(t == f);
+ }
+
+ SECTION("cast int16_t -> uint16_t should not trigger assert for positive int") {
+ int16_t f = 1;
+ auto t = osmium::static_cast_with_assert<uint16_t>(f);
+ REQUIRE(t == f);
+ }
+
+ SECTION("cast int16_t -> uint16_t should trigger assert for negative int") {
+ int16_t f = -1;
+ REQUIRE_THROWS_AS(osmium::static_cast_with_assert<uint16_t>(f), assert_error);
+ }
+
+
+ SECTION("cast uint32_t -> uint_16t should not trigger assert for zero") {
+ uint32_t f = 0;
+ auto t = osmium::static_cast_with_assert<uint16_t>(f);
+ REQUIRE(t == f);
+ }
+
+ SECTION("cast uint32_t -> uint_16t should not trigger assert for small int") {
+ uint32_t f = 100;
+ auto t = osmium::static_cast_with_assert<uint16_t>(f);
+ REQUIRE(t == f);
+ }
+
+ SECTION("cast int32_t -> int_16t should trigger assert for large int") {
+ uint32_t f = 100000;
+ REQUIRE_THROWS_AS(osmium::static_cast_with_assert<uint16_t>(f), assert_error);
+ }
+
+
+ SECTION("cast uint16_t -> int16_t should not trigger assert for small int") {
+ uint16_t f = 1;
+ auto t = osmium::static_cast_with_assert<int16_t>(f);
+ REQUIRE(t == f);
+ }
+
+ SECTION("cast uint16_t -> int16_t should trigger assert for large int") {
+ uint16_t f = 65000;
+ REQUIRE_THROWS_AS(osmium::static_cast_with_assert<int16_t>(f), assert_error);
+ }
+
+
+}
+
diff --git a/third_party/libosmium/test/t/util/test_double.cpp b/third_party/libosmium/test/t/util/test_double.cpp
new file mode 100644
index 0000000..6cc87a0
--- /dev/null
+++ b/third_party/libosmium/test/t/util/test_double.cpp
@@ -0,0 +1,33 @@
+#include "catch.hpp"
+
+#include <osmium/util/double.hpp>
+
+TEST_CASE("Double") {
+
+ SECTION("double2string") {
+ std::string s1;
+ osmium::util::double2string(s1, 1.123, 7);
+ REQUIRE(s1 == "1.123");
+
+ std::string s2;
+ osmium::util::double2string(s2, 1.000, 7);
+ REQUIRE(s2 == "1");
+
+ std::string s3;
+ osmium::util::double2string(s3, 0.0, 7);
+ REQUIRE(s3 == "0");
+
+ std::string s4;
+ osmium::util::double2string(s4, 0.020, 7);
+ REQUIRE(s4 == "0.02");
+
+ std::string s5;
+ osmium::util::double2string(s5, -0.020, 7);
+ REQUIRE(s5 == "-0.02");
+
+ std::string s6;
+ osmium::util::double2string(s6, -0.0, 7);
+ REQUIRE(s6 == "-0");
+ }
+}
+
diff --git a/third_party/libosmium/test/t/util/test_options.cpp b/third_party/libosmium/test/t/util/test_options.cpp
new file mode 100644
index 0000000..969f201
--- /dev/null
+++ b/third_party/libosmium/test/t/util/test_options.cpp
@@ -0,0 +1,48 @@
+#include "catch.hpp"
+
+#include <iterator>
+
+#include <osmium/util/options.hpp>
+
+TEST_CASE("Options") {
+
+ SECTION("set_simple") {
+ osmium::util::Options o;
+ o.set("foo", "bar");
+ REQUIRE("bar" == o.get("foo"));
+ REQUIRE("" == o.get("empty"));
+ REQUIRE("default" == o.get("empty", "default"));
+ REQUIRE(!o.is_true("foo"));
+ REQUIRE(!o.is_true("empty"));
+ REQUIRE(1 == o.size());
+ }
+
+ SECTION("set_from_bool") {
+ osmium::util::Options o;
+ o.set("t", true);
+ o.set("f", false);
+ REQUIRE("true" == o.get("t"));
+ REQUIRE("false" == o.get("f"));
+ REQUIRE("" == o.get("empty"));
+ REQUIRE(o.is_true("t"));
+ REQUIRE(!o.is_true("f"));
+ REQUIRE(2 == o.size());
+ }
+
+ SECTION("set_from_single_string_with_equals") {
+ osmium::util::Options o;
+ o.set("foo=bar");
+ REQUIRE("bar" == o.get("foo"));
+ REQUIRE(1 == o.size());
+ }
+
+ SECTION("set_from_single_string_without_equals") {
+ osmium::util::Options o;
+ o.set("foo");
+ REQUIRE("true" == o.get("foo"));
+ REQUIRE(o.is_true("foo"));
+ REQUIRE(1 == o.size());
+ }
+
+}
+
diff --git a/third_party/libosmium/test/t/util/test_string.cpp b/third_party/libosmium/test/t/util/test_string.cpp
new file mode 100644
index 0000000..fa49787
--- /dev/null
+++ b/third_party/libosmium/test/t/util/test_string.cpp
@@ -0,0 +1,57 @@
+#include "catch.hpp"
+
+#include <osmium/util/string.hpp>
+
+TEST_CASE("split_string") {
+
+ SECTION("split_string string") {
+ std::string str { "foo,baramba,baz" };
+ std::vector<std::string> result = {"foo", "baramba", "baz"};
+
+ REQUIRE(result == osmium::split_string(str, ','));
+ }
+
+ SECTION("split_string string without sep") {
+ std::string str { "foo" };
+ std::vector<std::string> result = {"foo"};
+
+ REQUIRE(result == osmium::split_string(str, ','));
+ }
+
+ SECTION("split_string string with empty at end") {
+ std::string str { "foo,bar," };
+ std::vector<std::string> result = {"foo", "bar", ""};
+
+ REQUIRE(result == osmium::split_string(str, ','));
+ }
+
+ SECTION("split_string string with empty in middle") {
+ std::string str { "foo,,bar" };
+ std::vector<std::string> result = {"foo", "", "bar"};
+
+ REQUIRE(result == osmium::split_string(str, ','));
+ }
+
+ SECTION("split_string string with empty at start") {
+ std::string str { ",bar,baz" };
+ std::vector<std::string> result = {"", "bar", "baz"};
+
+ REQUIRE(result == osmium::split_string(str, ','));
+ }
+
+ SECTION("split_string sep") {
+ std::string str { "," };
+ std::vector<std::string> result = {"", ""};
+
+ REQUIRE(result == osmium::split_string(str, ','));
+ }
+
+ SECTION("split_string empty string") {
+ std::string str { "" };
+ std::vector<std::string> result;
+
+ REQUIRE(result == osmium::split_string(str, ','));
+ }
+
+}
+
diff --git a/third_party/libosmium/test/test_main.cpp b/third_party/libosmium/test/test_main.cpp
new file mode 100644
index 0000000..0c7c351
--- /dev/null
+++ b/third_party/libosmium/test/test_main.cpp
@@ -0,0 +1,2 @@
+#define CATCH_CONFIG_MAIN
+#include "catch.hpp"
diff --git a/third_party/libosmium/test/valgrind.supp b/third_party/libosmium/test/valgrind.supp
new file mode 100644
index 0000000..f6ef1f6
--- /dev/null
+++ b/third_party/libosmium/test/valgrind.supp
@@ -0,0 +1,47 @@
+#-----------------------------------------------------------------------------
+#
+# This file describes messages that Valgrind should suppress, because they
+# are about problems outside Libosmium that we can't fix anyway.
+#
+# See http://valgrind.org/docs/manual/manual-core.html#manual-core.suppress
+#
+#-----------------------------------------------------------------------------
+
+{
+ dl_error1
+ Memcheck:Cond
+ fun:index
+ fun:expand_dynamic_string_token
+ fun:fillin_rpath
+ fun:_dl_init_paths
+ fun:dl_main
+ fun:_dl_sysdep_start
+ fun:_dl_start
+}
+{
+ dl_error2
+ Memcheck:Cond
+ fun:index
+ fun:expand_dynamic_string_token
+ fun:_dl_map_object
+ fun:map_doit
+ fun:_dl_catch_error
+ fun:do_preload
+ fun:dl_main
+ fun:_dl_sysdep_start
+ fun:_dl_start
+}
+{
+ libpoppler_leak
+ Memcheck:Leak
+ fun:malloc
+ fun:gmalloc
+ fun:copyString
+}
+{
+ tmpfile
+ Memcheck:Leak
+ fun:malloc
+ fun:fdopen@@GLIBC_*
+ fun:tmpfile@@GLIBC_*
+}
diff --git a/third_party/osmium/thread/checked_task.hpp b/third_party/osmium/thread/checked_task.hpp
deleted file mode 100644
index 75c664c..0000000
--- a/third_party/osmium/thread/checked_task.hpp
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef OSMIUM_THREAD_CHECKED_TASK_HPP
-#define OSMIUM_THREAD_CHECKED_TASK_HPP
-
-/*
-
-This file is part of Osmium (http://osmcode.org/libosmium).
-
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
-
-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.
-
-*/
-
-#include <chrono>
-#include <future>
-#include <thread>
-#include <utility>
-
-namespace osmium {
-
- namespace thread {
-
- template <class T>
- class CheckedTask {
-
- std::thread m_thread;
- std::future<bool> m_future;
-
- public:
-
- template <class... TArgs>
- explicit CheckedTask(TArgs&&... args) {
- std::packaged_task<bool()> pack_task(T(std::forward<TArgs>(args)...));
- m_future = pack_task.get_future();
- m_thread = std::thread(std::move(pack_task));
- }
-
- ~CheckedTask() {
- // Make sure task is done.
- if (m_thread.joinable()) {
- m_thread.join();
- }
- }
-
- CheckedTask(const CheckedTask&) = delete;
- CheckedTask& operator=(const CheckedTask&) = delete;
-
- /**
- * Check task for exceptions.
- *
- * If an exception happened in the task, re-throw it in this
- * thread. This will not do anything if there was no exception.
- */
- void check_for_exception() {
- if (m_future.valid() && m_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
- m_future.get();
- }
- }
-
- /**
- * Close the task. This will raise in this thread any exception the
- * task generated in the other thread.
- */
- void close() {
- // If an exception happened in the task, re-throw
- // it in this thread. This will block if the task
- // isn't finished.
- if (m_future.valid()) {
- m_future.get();
- }
-
- // Make sure task is done.
- if (m_thread.joinable()) {
- m_thread.join();
- }
- }
-
- }; // class CheckedTask
-
- } // namespace thread
-
-} // namespace osmium
-
-#endif // OSMIUM_THREAD_CHECKED_TASK_HPP
diff --git a/third_party/osmium/thread/name.hpp b/third_party/osmium/thread/name.hpp
deleted file mode 100644
index 20ec5c4..0000000
--- a/third_party/osmium/thread/name.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef OSMIUM_THREAD_NAME_HPP
-#define OSMIUM_THREAD_NAME_HPP
-
-/*
-
-This file is part of Osmium (http://osmcode.org/libosmium).
-
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
-
-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.
-
-*/
-
-#ifdef __linux__
-# include <sys/prctl.h>
-#endif
-
-namespace osmium {
-
- namespace thread {
-
- /**
- * Set name of current thread for debugging. This only works on Linux.
- */
-#ifdef __linux__
- inline void set_thread_name(const char* name) {
- prctl(PR_SET_NAME, name, 0, 0, 0);
- }
-#else
- inline void set_thread_name(const char*) {
- // intentionally left blank
- }
-#endif
-
- } // namespace thread
-
-} // namespace osmium
-
-#endif // OSMIUM_THREAD_NAME_HPP
diff --git a/third_party/osmium/util/cast.hpp b/third_party/osmium/util/cast.hpp
deleted file mode 100644
index 7503267..0000000
--- a/third_party/osmium/util/cast.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef OSMIUM_UTIL_CAST_HPP
-#define OSMIUM_UTIL_CAST_HPP
-
-/*
-
-This file is part of Osmium (http://osmcode.org/libosmium).
-
-Copyright 2013,2014 Jochen Topf <jochen at topf.org> and others (see README).
-
-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.
-
-*/
-
-#include <cassert>
-#include <limits>
-#include <type_traits>
-
-namespace osmium {
-
- template <typename T, typename F, typename std::enable_if<std::is_integral<T>::value && std::is_integral<F>::value && std::is_signed<T>::value && std::is_signed<F>::value, int>::type = 0>
- inline T static_cast_with_assert(const F value) {
- static_assert(sizeof(T) < sizeof(F), "unnecessary static_cast_with_assert when casting into type of equal or larger size");
- assert(value >= std::numeric_limits<T>::min() && value <= std::numeric_limits<T>::max());
- return static_cast<T>(value);
- }
-
- template <typename T, typename F, typename std::enable_if<std::is_integral<T>::value && std::is_integral<F>::value && std::is_unsigned<T>::value && std::is_signed<F>::value, int>::type = 0>
- inline T static_cast_with_assert(const F value) {
- static_assert(sizeof(T) <= sizeof(F), "unnecessary static_cast_with_assert when casting into type of larger size");
- assert(value >= 0 && static_cast<typename std::make_unsigned<F>::type>(value) <= std::numeric_limits<T>::max());
- return static_cast<T>(value);
- }
-
- template <typename T, typename F, typename std::enable_if<std::is_integral<T>::value && std::is_integral<F>::value && std::is_unsigned<T>::value && std::is_unsigned<F>::value, int>::type = 0>
- inline T static_cast_with_assert(const F value) {
- static_assert(sizeof(T) < sizeof(F), "unnecessary static_cast_with_assert when casting into type of equal or larger size");
- assert(value <= std::numeric_limits<T>::max());
- return static_cast<T>(value);
- }
-
- template <typename T, typename F, typename std::enable_if<std::is_integral<T>::value && std::is_integral<F>::value && std::is_signed<T>::value && std::is_unsigned<F>::value, int>::type = 0>
- inline T static_cast_with_assert(const F value) {
- static_assert(sizeof(T) <= sizeof(F), "unnecessary static_cast_with_assert when casting into type of larger size");
- assert(value <= std::numeric_limits<T>::max());
- return static_cast<T>(value);
- }
-
-} // namespace osmium
-
-#endif // OSMIUM_UTIL_CAST_HPP
diff --git a/third_party/variant/.gitignore b/third_party/variant/.gitignore
new file mode 100644
index 0000000..5620e5d
--- /dev/null
+++ b/third_party/variant/.gitignore
@@ -0,0 +1,3 @@
+.DS_Store
+out
+profiling
\ No newline at end of file
diff --git a/third_party/variant/.travis.yml b/third_party/variant/.travis.yml
new file mode 100644
index 0000000..cd1e655
--- /dev/null
+++ b/third_party/variant/.travis.yml
@@ -0,0 +1,22 @@
+language: cpp
+
+# http://docs.travis-ci.com/user/multi-os/
+os:
+ - linux
+ - osx
+
+compiler:
+ - clang
+ - gcc
+
+before_install:
+ - true
+
+install:
+ - true
+
+before_script:
+ - true
+
+script:
+ - source "scripts/${TRAVIS_OS_NAME}.sh"
diff --git a/third_party/variant/Jamroot b/third_party/variant/Jamroot
new file mode 100644
index 0000000..aead870
--- /dev/null
+++ b/third_party/variant/Jamroot
@@ -0,0 +1,75 @@
+local BOOST_DIR = "/opt/boost" ;
+
+#using clang : : ;
+
+lib system : : <name>boost_system <search>$(BOOST_DIR)/lib ;
+lib timer : chrono : <name>boost_timer <search>$(BOOST_DIR)/lib ;
+lib chrono : system : <name>boost_chrono <search>$(BOOST_DIR)/lib ;
+
+exe variant-test
+ :
+ test/bench_variant.cpp
+ .//system
+ .//timer
+ .//chrono
+ :
+ <include>$(BOOST_DIR)/include
+ <include>./
+ <cxxflags>-std=c++11
+ #<define>SINGLE_THREADED
+ <variant>release:<cxxflags>-march=native
+ ;
+
+
+exe binary-visitor-test
+ :
+ test/binary_visitor_test.cpp
+ .//system
+ .//timer
+ .//chrono
+ :
+ <include>$(BOOST_DIR)/include
+ <include>./
+ <cxxflags>-std=c++11
+ <variant>release:<cxxflags>-march=native
+ ;
+
+exe recursive-wrapper-test
+ :
+ test/recursive_wrapper_test.cpp
+ .//system
+ .//timer
+ .//chrono
+ :
+ <include>$(BOOST_DIR)/include
+ <include>./
+ <cxxflags>-std=c++11
+ <variant>release:<cxxflags>-march=native
+ ;
+
+exe unique-ptr-test
+ :
+ test/unique_ptr_test.cpp
+ .//system
+ .//timer
+ .//chrono
+ :
+ <include>$(BOOST_DIR)/include
+ <include>./
+ <cxxflags>-std=c++11
+ <variant>release:<cxxflags>-march=native
+ ;
+
+
+exe reference_wrapper_test
+ :
+ test/reference_wrapper_test.cpp
+ .//system
+ .//timer
+ .//chrono
+ :
+ <include>$(BOOST_DIR)/include
+ <include>./
+ <cxxflags>-std=c++11
+ <variant>release:<cxxflags>-march=native
+ ;
diff --git a/Util/git_sha.cpp.in b/third_party/variant/LICENSE
similarity index 59%
copy from Util/git_sha.cpp.in
copy to third_party/variant/LICENSE
index 5b19337..6c4ce40 100644
--- a/Util/git_sha.cpp.in
+++ b/third_party/variant/LICENSE
@@ -1,16 +1,17 @@
-/*
-
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) MapBox
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.
+- 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.
+- Neither the name "MapBox" nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
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
@@ -21,11 +22,4 @@ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
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 "git_sha.hpp"
-
-#define GIT_DESCRIPTION "${GIT_DESCRIPTION}"
-char g_GIT_DESCRIPTION[] = GIT_DESCRIPTION;
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/third_party/variant/Makefile b/third_party/variant/Makefile
new file mode 100644
index 0000000..cae3d46
--- /dev/null
+++ b/third_party/variant/Makefile
@@ -0,0 +1,100 @@
+CXX := $(CXX)
+BOOST_LIBS = -lboost_timer -lboost_system -lboost_chrono
+RELEASE_FLAGS = -O3 -DNDEBUG -finline-functions -march=native -DSINGLE_THREADED
+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
+CXXFLAGS := $(CXXFLAGS)
+LDFLAGS := $(LDFLAGS)
+
+OS:=$(shell uname -s)
+ifeq ($(OS),Darwin)
+ CXXFLAGS += -stdlib=libc++
+ LDFLAGS += -stdlib=libc++ -F/ -framework CoreFoundation
+else
+ BOOST_LIBS += -lrt
+endif
+
+ifeq (sizes,$(firstword $(MAKECMDGOALS)))
+ RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
+ $(eval $(RUN_ARGS):;@:)
+ ifndef RUN_ARGS
+ $(error sizes target requires you pass full path to boost variant.hpp)
+ endif
+ .PHONY: $(RUN_ARGS)
+endif
+
+all: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test
+
+./deps/gyp:
+ git clone --depth 1 https://chromium.googlesource.com/external/gyp.git ./deps/gyp
+
+gyp: ./deps/gyp
+ deps/gyp/gyp --depth=. -Goutput_dir=./ --generator-output=./out -f make
+ make V=1 -C ./out tests
+ ./out/Release/tests
+
+out/bench-variant-debug: Makefile test/bench_variant.cpp variant.hpp
+ mkdir -p ./out
+ $(CXX) -o out/bench-variant-debug test/bench_variant.cpp -I./ $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
+
+out/bench-variant: Makefile test/bench_variant.cpp variant.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
+ 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
+ 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
+ mkdir -p ./out
+ $(CXX) -o out/binary_visitor_test test/binary_visitor_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
+
+bench: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test
+ ./out/bench-variant 100000
+ ./out/unique_ptr_test 100000
+ ./out/recursive_wrapper_test 100000
+ ./out/binary_visitor_test 100000
+
+out/unit: Makefile test/unit.cpp test/optional_unit.cpp optional.hpp variant.hpp
+ 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)
+
+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)
+
+sizes: Makefile variant.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/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/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
+ mkdir -p profiling/
+ rm -rf profiling/*
+ iprofiler -timeprofiler -d profiling/ ./out/bench-variant-debug 500000
+
+clean:
+ rm -rf ./out
+ rm -rf *.dSYM
+ rm -f unit.gc*
+ rm -f *gcov
+ rm -f test/unit.gc*
+ rm -f test/*gcov
+
+pgo: out Makefile variant.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
+
+.PHONY: sizes test
diff --git a/third_party/variant/README.md b/third_party/variant/README.md
new file mode 100644
index 0000000..791131d
--- /dev/null
+++ b/third_party/variant/README.md
@@ -0,0 +1,67 @@
+# Mapbox Variant
+
+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)
+
+# 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++:
+
+Test | Mapbox Variant | Boost Variant
+---- | -------------- | -------------
+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
+
+
+# Depends
+
+ - Compiler supporting `-std=c++11`
+
+Tested with
+
+ - g++-4.7
+ - g++-4.8
+ - clang++-3.4
+ - clang++-3.5
+ - Visual C++ Compiler November 2013 CTP
+ - Visual C++ Compiler 2014 CTP 4
+
+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
+
+There is nothing to build, just include `variant.hpp` and `recursive_wrapper.hpp` in your project.
+
+# Tests
+
+The tests depend on:
+
+ - Boost headers (for benchmarking against `boost::variant`)
+ - Boost built with `--with-timer` (used for benchmark timing)
+
+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
+
+On windows do:
+
+ vcbuild
+
+## Benchmark
+
+On Unix systems run the benchmark like:
+
+ make bench
+
+## Check object sizes
+
+ make sizes /path/to/boost/variant.hpp
+
diff --git a/third_party/variant/appveyor.yml b/third_party/variant/appveyor.yml
new file mode 100644
index 0000000..9d7c599
--- /dev/null
+++ b/third_party/variant/appveyor.yml
@@ -0,0 +1,27 @@
+
+platform:
+ - x64
+ - x86
+
+configuration:
+ - Debug
+ - Release
+
+install:
+ - SET PATH=c:\python27;%PATH%
+ - SET PATH=C:\Program Files (x86)\MSBuild\12.0\bin\;%PATH%
+ - git clone --quiet --depth 1 https://chromium.googlesource.com/external/gyp.git deps/gyp
+ # note windows requires --generator-output to be absolute
+ - python deps/gyp/gyp_main.py variant.gyp --depth=. -f msvs -G msvs_version=2013
+ - set MSBUILD_PLATFORM=%platform%
+ - if "%MSBUILD_PLATFORM%" == "x86" set MSBUILD_PLATFORM=Win32
+ - msbuild variant.sln /nologo /p:Configuration=%configuration%;Platform=%MSBUILD_PLATFORM%
+ - .\"%configuration%"\tests.exe
+
+build: OFF
+
+test: OFF
+
+test_script: OFF
+
+deploy: OFF
diff --git a/third_party/variant/common.gypi b/third_party/variant/common.gypi
new file mode 100644
index 0000000..67e333b
--- /dev/null
+++ b/third_party/variant/common.gypi
@@ -0,0 +1,143 @@
+{
+ "conditions": [
+ ["OS=='win'", {
+ "target_defaults": {
+ "default_configuration": "Release_x64",
+ "msbuild_toolset":"CTP_Nov2013",
+ "msvs_settings": {
+ "VCCLCompilerTool": {
+ "ExceptionHandling": 1, # /EHsc
+ "RuntimeTypeInfo": "true" # /GR
+ }
+ },
+ "configurations": {
+ "Debug_Win32": {
+ "msvs_configuration_platform": "Win32",
+ "defines": [ "DEBUG","_DEBUG"],
+ "msvs_settings": {
+ "VCCLCompilerTool": {
+ "RuntimeLibrary": "1", # static debug /MTd
+ "Optimization": 0, # /Od, no optimization
+ "MinimalRebuild": "false",
+ "OmitFramePointers": "false",
+ "BasicRuntimeChecks": 3 # /RTC1
+ }
+ }
+ },
+ "Debug_x64": {
+ "msvs_configuration_platform": "x64",
+ "defines": [ "DEBUG","_DEBUG"],
+ "msvs_settings": {
+ "VCCLCompilerTool": {
+ "RuntimeLibrary": "1", # static debug /MTd
+ "Optimization": 0, # /Od, no optimization
+ "MinimalRebuild": "false",
+ "OmitFramePointers": "false",
+ "BasicRuntimeChecks": 3 # /RTC1
+ }
+ }
+ },
+ "Release_Win32": {
+ "msvs_configuration_platform": "Win32",
+ "defines": [ "NDEBUG"],
+ "msvs_settings": {
+ "VCCLCompilerTool": {
+ "RuntimeLibrary": 0, # static release
+ "Optimization": 3, # /Ox, full optimization
+ "FavorSizeOrSpeed": 1, # /Ot, favour speed over size
+ "InlineFunctionExpansion": 2, # /Ob2, inline anything eligible
+ "WholeProgramOptimization": "true", # /GL, whole program optimization, needed for LTCG
+ "OmitFramePointers": "true",
+ "EnableFunctionLevelLinking": "true",
+ "EnableIntrinsicFunctions": "true",
+ "AdditionalOptions": [
+ "/MP", # compile across multiple CPUs
+ ],
+ "DebugInformationFormat": "0"
+ },
+ "VCLibrarianTool": {
+ "AdditionalOptions": [
+ "/LTCG" # link time code generation
+ ],
+ },
+ "VCLinkerTool": {
+ "LinkTimeCodeGeneration": 1, # link-time code generation
+ "OptimizeReferences": 2, # /OPT:REF
+ "EnableCOMDATFolding": 2, # /OPT:ICF
+ "LinkIncremental": 1, # disable incremental linking
+ "GenerateDebugInformation": "false"
+ }
+ }
+ },
+ "Release_x64": {
+ "msvs_configuration_platform": "x64",
+ "defines": [ "NDEBUG"],
+ "msvs_settings": {
+ "VCCLCompilerTool": {
+ "RuntimeLibrary": 0, # static release
+ "Optimization": 3, # /Ox, full optimization
+ "FavorSizeOrSpeed": 1, # /Ot, favour speed over size
+ "InlineFunctionExpansion": 2, # /Ob2, inline anything eligible
+ "WholeProgramOptimization": "true", # /GL, whole program optimization, needed for LTCG
+ "OmitFramePointers": "true",
+ "EnableFunctionLevelLinking": "true",
+ "EnableIntrinsicFunctions": "true",
+ "AdditionalOptions": [
+ "/MP", # compile across multiple CPUs
+ ],
+ "DebugInformationFormat": "0"
+ },
+ "VCLibrarianTool": {
+ "AdditionalOptions": [
+ "/LTCG" # link time code generation
+ ],
+ },
+ "VCLinkerTool": {
+ "LinkTimeCodeGeneration": 1, # link-time code generation
+ "OptimizeReferences": 2, # /OPT:REF
+ "EnableCOMDATFolding": 2, # /OPT:ICF
+ "LinkIncremental": 1, # disable incremental linking
+ "GenerateDebugInformation": "false"
+ }
+ }
+ }
+ }
+ }
+ }, {
+ "target_defaults": {
+ "default_configuration": "Release",
+ "xcode_settings": {
+ "CLANG_CXX_LIBRARY": "libc++",
+ "CLANG_CXX_LANGUAGE_STANDARD":"c++11",
+ "GCC_VERSION": "com.apple.compilers.llvm.clang.1_0",
+ },
+ "cflags_cc": ["-std=c++11"],
+ "configurations": {
+ "Debug": {
+ "defines": [
+ "DEBUG"
+ ],
+ "xcode_settings": {
+ "GCC_OPTIMIZATION_LEVEL": "0",
+ "GCC_GENERATE_DEBUGGING_SYMBOLS": "YES",
+ "OTHER_CPLUSPLUSFLAGS": [ "-Wall", "-Wextra", "-pedantic", "-g", "-O0" ]
+ }
+ },
+ "Release": {
+ "defines": [
+ "NDEBUG"
+ ],
+ "xcode_settings": {
+ "GCC_OPTIMIZATION_LEVEL": "3",
+ "GCC_GENERATE_DEBUGGING_SYMBOLS": "NO",
+ "DEAD_CODE_STRIPPING": "YES",
+ "GCC_INLINES_ARE_PRIVATE_EXTERN": "YES",
+ "OTHER_CPLUSPLUSFLAGS": [ "-Wall", "-Wextra", "-pedantic", "-O3" ]
+ }
+ }
+ }
+ }
+ }]
+ ]
+}
+
diff --git a/third_party/variant/scripts/linux.sh b/third_party/variant/scripts/linux.sh
new file mode 100644
index 0000000..f173db5
--- /dev/null
+++ b/third_party/variant/scripts/linux.sh
@@ -0,0 +1,59 @@
+#!/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
new file mode 100644
index 0000000..14149ca
--- /dev/null
+++ b/third_party/variant/scripts/osx.sh
@@ -0,0 +1,20 @@
+#!/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/test/bench_variant.cpp b/third_party/variant/test/bench_variant.cpp
new file mode 100644
index 0000000..f271245
--- /dev/null
+++ b/third_party/variant/test/bench_variant.cpp
@@ -0,0 +1,204 @@
+#include <iostream>
+#include <vector>
+#include <thread>
+#include <string>
+#include <utility>
+#include <boost/variant.hpp>
+#include <boost/timer/timer.hpp>
+#include "variant.hpp"
+
+#define TEXT "Testing various variant implementations with a longish string ........................................."
+//#define BOOST_VARIANT_MINIMIZE_SIZE
+
+using namespace mapbox;
+
+namespace test {
+
+template <typename V>
+struct Holder
+{
+ typedef V value_type;
+ std::vector<value_type> data;
+
+ template <typename T>
+ void append_move(T && obj)
+ {
+ data.emplace_back(std::forward<T>(obj));
+ }
+
+ template <typename T>
+ void append(T const& obj)
+ {
+ data.push_back(obj);
+ }
+};
+
+} // namespace test
+
+struct print : util::static_visitor<>
+{
+ template <typename T>
+ 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)
+ : v_(v) {}
+
+ template <typename T>
+ void operator() (T const& val) const
+ {
+ v_ = val;
+ }
+ V & v_;
+};
+
+template <typename V>
+struct dummy2 : util::static_visitor<>
+{
+ dummy2(V & v)
+ : v_(v) {}
+
+ template <typename T>
+ void operator() (T const& val) const
+ {
+ v_.template set<T>(val);
+ }
+ 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)
+ {
+ h.append_move(std::string(TEXT));
+ h.append_move(123);
+ h.append_move(3.14159);
+ }
+
+ boost::variant<int, double, std::string> v;
+ for (auto const& v2 : h.data)
+ {
+ dummy<boost::variant<int, double, std::string>> d(v);
+ boost::apply_visitor(d, v2);
+ }
+}
+
+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)
+ {
+ h.append_move(std::string(TEXT));
+ h.append_move(123);
+ h.append_move(3.14159);
+ }
+
+ util::variant<int, double, std::string> v;
+ for (auto const& v2 : h.data)
+ {
+ dummy2<util::variant<int, double, std::string>> d(v);
+ util::apply_visitor (d, v2);
+ }
+}
+
+int main (int argc, char** argv)
+{
+ if (argc!=2)
+ {
+ std::cerr << "Usage:" << argv[0] << " <num-runs>" << std::endl;
+ return 1;
+ }
+
+#ifndef SINGLE_THREADED
+ const std::size_t THREADS = 4;
+#endif
+ const std::size_t NUM_RUNS = static_cast<std::size_t>(std::stol(argv[1]));
+
+#ifdef SINGLE_THREADED
+ {
+ std::cerr << "custom variant: ";
+ boost::timer::auto_cpu_timer t;
+ run_variant_test(NUM_RUNS);
+ }
+ {
+ std::cerr << "boost variant: ";
+ boost::timer::auto_cpu_timer t;
+ run_boost_test(NUM_RUNS);
+ }
+ {
+ std::cerr << "custom variant: ";
+ boost::timer::auto_cpu_timer t;
+ run_variant_test(NUM_RUNS);
+ }
+ {
+ std::cerr << "boost variant: ";
+ boost::timer::auto_cpu_timer t;
+ run_boost_test(NUM_RUNS);
+ }
+#else
+ {
+ typedef std::vector<std::unique_ptr<std::thread>> thread_group;
+ typedef thread_group::value_type value_type;
+ thread_group tg;
+ std::cerr << "custom variant: ";
+ boost::timer::auto_cpu_timer timer;
+ 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();});
+ }
+
+ {
+ typedef std::vector<std::unique_ptr<std::thread>> thread_group;
+ typedef thread_group::value_type value_type;
+ thread_group tg;
+ std::cerr << "boost variant: ";
+ boost::timer::auto_cpu_timer timer;
+ 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();});
+ }
+
+ {
+ typedef std::vector<std::unique_ptr<std::thread>> thread_group;
+ typedef thread_group::value_type value_type;
+ thread_group tg;
+ std::cerr << "custom variant: ";
+ boost::timer::auto_cpu_timer timer;
+ 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();});
+ }
+
+ {
+ typedef std::vector<std::unique_ptr<std::thread>> thread_group;
+ typedef thread_group::value_type value_type;
+ thread_group tg;
+ std::cerr << "boost variant: ";
+ boost::timer::auto_cpu_timer timer;
+ 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();});
+ }
+#endif
+
+
+ return EXIT_SUCCESS;
+}
diff --git a/third_party/variant/test/binary_visitor_test.cpp b/third_party/variant/test/binary_visitor_test.cpp
new file mode 100644
index 0000000..de2a30e
--- /dev/null
+++ b/third_party/variant/test/binary_visitor_test.cpp
@@ -0,0 +1,136 @@
+#include <cstdint>
+#include <iostream>
+#include <vector>
+#include <thread>
+#include <string>
+#include <sstream>
+#include <utility>
+#include <type_traits>
+#include <boost/variant.hpp>
+#include <boost/timer/timer.hpp>
+#include "variant.hpp"
+#include "variant_io.hpp"
+
+using namespace mapbox;
+
+namespace test {
+
+template <typename T>
+struct string_to_number {};
+
+template <>
+struct string_to_number<double>
+{
+ double operator() (std::string const& str) const
+ {
+ return std::stod(str);
+ }
+};
+
+template <>
+struct string_to_number<std::int64_t>
+{
+ std::int64_t operator() (std::string const& str) const
+ {
+ return std::stoll(str);
+ }
+};
+
+template <>
+struct string_to_number<std::uint64_t>
+{
+ std::uint64_t operator() (std::string const& str) const
+ {
+ return std::stoull(str);
+ }
+};
+
+template <>
+struct string_to_number<bool>
+{
+ bool operator() (std::string const& str) const
+ {
+ bool result;
+ std::istringstream(str) >> std::boolalpha >> result;
+ return result;
+ }
+};
+
+struct javascript_equal_visitor : util::static_visitor<bool>
+{
+ template <typename T>
+ 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
+ {
+ 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
+ {
+ return string_to_number<T>()(lhs) == rhs;
+ }
+
+ template <typename T0, typename T1>
+ bool operator() (T0 lhs, T1 rhs) const
+ {
+ return lhs == static_cast<T0>(rhs);
+ }
+};
+
+template <typename T>
+struct javascript_equal
+{
+ javascript_equal(T const& lhs)
+ : lhs_(lhs) {}
+
+ bool operator() (T const& rhs) const
+ {
+ return util::apply_visitor(test::javascript_equal_visitor(), lhs_, rhs);
+ }
+ T const& lhs_;
+};
+
+} // namespace test
+
+int main (/*int argc, char** argv*/)
+{
+ typedef util::variant<bool, std::int64_t, std::uint64_t, double, std::string> variant_type;
+ variant_type v0(3.14159);
+ variant_type v1(std::string("3.14159"));
+ variant_type v2(std::uint64_t(1));
+
+ 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"));
+ vec.push_back(variant_type(std::uint64_t(2)));
+ vec.push_back(variant_type(std::uint64_t(3)));
+ vec.push_back(std::string("3.14159"));
+ vec.emplace_back(3.14159);
+
+ //auto itr = std::find_if(vec.begin(), vec.end(), [&v0](variant_type const& val) {
+ // return util::apply_visitor(test::javascript_equal_visitor(), v0, val);
+ // });
+
+ auto itr = std::find_if(vec.begin(), vec.end(), test::javascript_equal<variant_type>(v2));
+
+ if (itr != std::end(vec))
+ {
+ std::cout << "found " << *itr << std::endl;
+ }
+ else
+ {
+ std::cout << "can't find " << v2 << '\n';
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/third_party/variant/test/boost_variant_hello_world.cpp b/third_party/variant/test/boost_variant_hello_world.cpp
new file mode 100644
index 0000000..0d0925a
--- /dev/null
+++ b/third_party/variant/test/boost_variant_hello_world.cpp
@@ -0,0 +1,19 @@
+#include <boost/variant.hpp>
+#include <cstdint>
+#include <stdexcept>
+
+struct check : boost::static_visitor<>
+{
+ template <typename T>
+ void operator() (T const& val) const
+ {
+ if (val != 0) throw std::runtime_error("invalid");
+ }
+};
+
+int main() {
+ typedef boost::variant<bool, int, double> variant_type;
+ variant_type v(0);
+ boost::apply_visitor(check(), v);
+ return 0;
+}
diff --git a/third_party/variant/test/catch.hpp b/third_party/variant/test/catch.hpp
new file mode 100644
index 0000000..057c82e
--- /dev/null
+++ b/third_party/variant/test/catch.hpp
@@ -0,0 +1,8683 @@
+/*
+ * 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/optional_unit.cpp b/third_party/variant/test/optional_unit.cpp
new file mode 100644
index 0000000..a6573ca
--- /dev/null
+++ b/third_party/variant/test/optional_unit.cpp
@@ -0,0 +1,82 @@
+#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/recursive_wrapper_test.cpp b/third_party/variant/test/recursive_wrapper_test.cpp
new file mode 100644
index 0000000..3cd79b5
--- /dev/null
+++ b/third_party/variant/test/recursive_wrapper_test.cpp
@@ -0,0 +1,132 @@
+#include <iostream>
+#include <vector>
+#include <thread>
+#include <string>
+#include <sstream>
+#include <utility>
+#include <type_traits>
+#include <boost/timer/timer.hpp>
+#include "variant.hpp"
+
+using namespace mapbox;
+
+namespace test {
+
+struct add;
+struct sub;
+template <typename OpTag> struct binary_op;
+
+typedef util::variant<int ,
+ util::recursive_wrapper<binary_op<add>>,
+ util::recursive_wrapper<binary_op<sub>>
+ > expression;
+
+template <typename Op>
+struct binary_op
+{
+ expression left; // variant instantiated here...
+ expression right;
+
+ binary_op(expression && lhs, expression && rhs)
+ : left(std::move(lhs)), right(std::move(rhs))
+ {
+ }
+};
+
+struct print : util::static_visitor<void>
+{
+ template <typename T>
+ void operator() (T const& val) const
+ {
+ std::cerr << val << ":" << typeid(T).name() << std::endl;
+ }
+};
+
+
+struct test : util::static_visitor<std::string>
+{
+ template <typename T>
+ std::string operator() (T const& obj) const
+ {
+ return std::string("TYPE_ID=") + typeid(obj).name();
+ }
+};
+
+struct calculator : public util::static_visitor<int>
+{
+public:
+
+ int operator()(int value) const
+ {
+ return value;
+ }
+
+ int operator()(binary_op<add> const& binary) const
+ {
+ 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);
+ }
+};
+
+struct to_string : public util::static_visitor<std::string>
+{
+public:
+
+ std::string operator()(int value) const
+ {
+ return std::to_string(value);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+};
+
+} // namespace test
+
+int main (int argc, char** argv)
+{
+
+ if (argc != 2)
+ {
+ std::cerr << "Usage" << argv[0] << " <num-iter>" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ 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));
+
+ std::cerr << "TYPE OF RESULT-> " << util::apply_visitor(test::test(), result) << std::endl;
+
+ {
+ 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 << util::apply_visitor(test::to_string(), result) << "=" << util::apply_visitor(test::calculator(), result) << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/third_party/variant/test/reference_wrapper_test.cpp b/third_party/variant/test/reference_wrapper_test.cpp
new file mode 100644
index 0000000..2abf027
--- /dev/null
+++ b/third_party/variant/test/reference_wrapper_test.cpp
@@ -0,0 +1,74 @@
+#include <iostream>
+#include <vector>
+#include <thread>
+#include <string>
+#include <sstream>
+#include <utility>
+#include <type_traits>
+#include <boost/timer/timer.hpp>
+#include "variant.hpp"
+
+using namespace mapbox;
+
+namespace test {
+
+struct point
+{
+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> {};
+using variant = util::variant<std::reference_wrapper<const point>,
+ std::reference_wrapper<const line_string>,
+ std::reference_wrapper<const polygon>>;
+
+struct print
+{
+ using result_type = void;
+ void operator() (point const& pt) const
+ {
+ std::cerr << "Point(" << pt.x << "," << pt.y << ")" << std::endl;
+ }
+ void operator() (line_string const& line) const
+ {
+ std::cerr << "Line(";
+ for (auto const& pt : line)
+ {
+ std::cerr << pt.x << " " << pt.y << ",";
+ }
+ std::cerr << ")" << std::endl;
+ }
+ template <typename T>
+ void operator() (T const& val) const
+ {
+ std::cerr << typeid(T).name() << std::endl;
+ }
+};
+
+
+}
+
+int main (int argc, char** argv)
+{
+ 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));
+ 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));
+ 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>
+ test::print printer;
+ printer(line2);
+ return EXIT_SUCCESS;
+}
diff --git a/third_party/variant/test/unique_ptr_test.cpp b/third_party/variant/test/unique_ptr_test.cpp
new file mode 100644
index 0000000..2a51efe
--- /dev/null
+++ b/third_party/variant/test/unique_ptr_test.cpp
@@ -0,0 +1,128 @@
+#include <iostream>
+#include <vector>
+#include <thread>
+#include <string>
+#include <sstream>
+#include <utility>
+#include <type_traits>
+#include <boost/variant.hpp>
+#include <boost/timer/timer.hpp>
+#include "variant.hpp"
+
+using namespace mapbox;
+
+namespace test {
+
+struct add;
+struct sub;
+template <typename OpTag> struct binary_op;
+
+typedef util::variant<int ,
+ std::unique_ptr<binary_op<add>>,
+ std::unique_ptr<binary_op<sub>>
+ > expression;
+
+template <typename Op>
+struct binary_op
+{
+ expression left; // variant instantiated here...
+ expression right;
+
+ binary_op(expression && lhs, expression && rhs)
+ : left(std::move(lhs)), right(std::move(rhs)) {}
+};
+
+struct print : util::static_visitor<void>
+{
+ template <typename T>
+ void operator() (T const& val) const
+ {
+ std::cerr << val << ":" << typeid(T).name() << std::endl;
+ }
+};
+
+
+struct test : util::static_visitor<std::string>
+{
+ template <typename T>
+ std::string operator() (T const& obj) const
+ {
+ return std::string("TYPE_ID=") + typeid(obj).name();
+ }
+};
+
+struct calculator : public util::static_visitor<int>
+{
+public:
+
+ int operator()(int value) const
+ {
+ return value;
+ }
+
+ int operator()(std::unique_ptr<binary_op<add>> const& binary) const
+ {
+ 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);
+ }
+};
+
+struct to_string : public util::static_visitor<std::string>
+{
+public:
+
+ std::string operator()(int value) const
+ {
+ return std::to_string(value);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+};
+
+} // namespace test
+
+int main (int argc, char** argv)
+{
+ if (argc != 2)
+ {
+ std::cerr << "Usage" << argv[0] << " <num-iter>" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ const std::size_t NUM_ITER = static_cast<std::size_t>(std::stol(argv[1]));
+
+ 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;
+
+ {
+ 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 << util::apply_visitor(test::to_string(), result) << "=" << util::apply_visitor(test::calculator(), result) << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/third_party/variant/test/unit.cpp b/third_party/variant/test/unit.cpp
new file mode 100644
index 0000000..9b874c7
--- /dev/null
+++ b/third_party/variant/test/unit.cpp
@@ -0,0 +1,314 @@
+#define CATCH_CONFIG_RUNNER
+#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
new file mode 100644
index 0000000..b445fdb
--- /dev/null
+++ b/third_party/variant/test/variant_hello_world.cpp
@@ -0,0 +1,22 @@
+#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
new file mode 100644
index 0000000..712cafe
--- /dev/null
+++ b/third_party/variant/variant.gyp
@@ -0,0 +1,21 @@
+{
+ "includes": [
+ "common.gypi"
+ ],
+ "targets": [
+ {
+ "target_name": "tests",
+ "type": "executable",
+ "sources": [
+ "test/unit.cpp"
+ ],
+ "xcode_settings": {
+ "SDKROOT": "macosx",
+ "SUPPORTED_PLATFORMS":["macosx"]
+ },
+ "include_dirs": [
+ "./"
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/third_party/variant/variant.hpp b/third_party/variant/variant.hpp
index 3b56594..837b162 100644
--- a/third_party/variant/variant.hpp
+++ b/third_party/variant/variant.hpp
@@ -34,7 +34,19 @@
// translates to 100
#define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION)
-namespace mapbox { namespace util { namespace detail {
+namespace mapbox { namespace util {
+
+// static visitor
+template <typename R = void>
+struct static_visitor
+{
+ using result_type = R;
+protected:
+ static_visitor() {}
+ ~static_visitor() {}
+};
+
+namespace detail {
static constexpr std::size_t invalid_value = std::size_t(-1);
@@ -109,19 +121,39 @@ struct select_type<0, T, Types...>
using type = T;
};
-} // namespace detail
-// static visitor
-template <typename R = void>
-struct static_visitor
+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
{
- using result_type = R;
-protected:
- static_visitor() {}
- ~static_visitor() {}
+ using type = typename std::result_of<F(V&)>::type;
+};
+
+template <typename F, typename V>
+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>
+struct result_of_binary_visit
+{
+ 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 >
+{
+ using type = typename F::result_type;
+};
+
+
+} // namespace detail
+
+
template <std::size_t arg1, std::size_t ... others>
struct static_max;
@@ -218,14 +250,25 @@ struct unwrapper<recursive_wrapper<T>>
}
};
+template <typename T>
+struct unwrapper<std::reference_wrapper<T>>
+{
+ auto operator() (std::reference_wrapper<T> const& obj) const
+ -> typename std::reference_wrapper<T>::type const&
+ {
+ return obj.get();
+ }
+
+};
+
-template <typename F, typename V, typename...Types>
+template <typename F, typename V, typename R, typename...Types>
struct dispatcher;
-template <typename F, typename V, typename T, typename...Types>
-struct dispatcher<F, V, T, Types...>
+template <typename F, typename V, typename R, typename T, typename...Types>
+struct dispatcher<F, V, R, T, Types...>
{
- using result_type = typename F::result_type;
+ using result_type = R;
VARIANT_INLINE static result_type apply_const(V const& v, F f)
{
if (v.get_type_index() == sizeof...(Types))
@@ -234,7 +277,7 @@ struct dispatcher<F, V, T, Types...>
}
else
{
- return dispatcher<F, V, Types...>::apply_const(v, f);
+ return dispatcher<F, V, R, Types...>::apply_const(v, f);
}
}
@@ -246,15 +289,15 @@ struct dispatcher<F, V, T, Types...>
}
else
{
- return dispatcher<F, V, Types...>::apply(v, f);
+ return dispatcher<F, V, R, Types...>::apply(v, f);
}
}
};
-template<typename F, typename V>
-struct dispatcher<F, V>
+template<typename F, typename V, typename R>
+struct dispatcher<F, V, R>
{
- using result_type = typename F::result_type;
+ using result_type = R;
VARIANT_INLINE static result_type apply_const(V const&, F)
{
throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
@@ -267,13 +310,13 @@ struct dispatcher<F, V>
};
-template <typename F, typename V, 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 T0, typename T1, typename...Types>
-struct binary_dispatcher_rhs<F, V, T0, T1, 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 = typename F::result_type;
+ using result_type = R;
VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
{
if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
@@ -283,7 +326,7 @@ struct binary_dispatcher_rhs<F, V, T0, T1, Types...>
}
else
{
- return binary_dispatcher_rhs<F, V, T0, Types...>::apply_const(lhs, rhs, f);
+ return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, f);
}
}
@@ -296,16 +339,16 @@ struct binary_dispatcher_rhs<F, V, T0, T1, Types...>
}
else
{
- return binary_dispatcher_rhs<F, V, T0, Types...>::apply(lhs, rhs, f);
+ return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, f);
}
}
};
-template<typename F, typename V, typename T>
-struct binary_dispatcher_rhs<F, V, T>
+template<typename F, typename V, typename R, typename T>
+struct binary_dispatcher_rhs<F, V, R, T>
{
- using result_type = typename F::result_type;
+ using result_type = R;
VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
{
throw std::runtime_error("binary dispatch: FAIL");
@@ -317,13 +360,13 @@ struct binary_dispatcher_rhs<F, V, T>
};
-template <typename F, typename V, 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 T0, typename T1, typename...Types>
-struct binary_dispatcher_lhs<F, V, T0, T1, 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 = typename F::result_type;
+ using result_type = R;
VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
{
if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
@@ -332,7 +375,7 @@ struct binary_dispatcher_lhs<F, V, T0, T1, Types...>
}
else
{
- return binary_dispatcher_lhs<F, V, T0, Types...>::apply_const(lhs, rhs, f);
+ return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, f);
}
}
@@ -344,16 +387,16 @@ struct binary_dispatcher_lhs<F, V, T0, T1, Types...>
}
else
{
- return binary_dispatcher_lhs<F, V, T0, Types...>::apply(lhs, rhs, f);
+ return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, f);
}
}
};
-template<typename F, typename V, typename T>
-struct binary_dispatcher_lhs<F, V, T>
+template<typename F, typename V, typename R, typename T>
+struct binary_dispatcher_lhs<F, V, R, T>
{
- using result_type = typename F::result_type;
+ using result_type = R;
VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
{
throw std::runtime_error("binary dispatch: FAIL");
@@ -365,13 +408,13 @@ struct binary_dispatcher_lhs<F, V, T>
}
};
-template <typename F, typename V, typename...Types>
+template <typename F, typename V, typename R, typename...Types>
struct binary_dispatcher;
-template <typename F, typename V, typename T, typename...Types>
-struct binary_dispatcher<F, V, T, Types...>
+template <typename F, typename V, typename R, typename T, typename...Types>
+struct binary_dispatcher<F, V, R, T, Types...>
{
- using result_type = typename F::result_type;
+ using result_type = R;
VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f)
{
if (v0.get_type_index() == sizeof...(Types))
@@ -382,14 +425,14 @@ struct binary_dispatcher<F, V, T, Types...>
}
else
{
- return binary_dispatcher_rhs<F, V, T, Types...>::apply_const(v0, v1, f);
+ return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, f);
}
}
else if (v1.get_type_index() == sizeof...(Types))
{
- return binary_dispatcher_lhs<F, V, T, Types...>::apply_const(v0, v1, f);
+ return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, f);
}
- return binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f);
+ return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, f);
}
VARIANT_INLINE static result_type apply(V & v0, V & v1, F f)
@@ -402,21 +445,21 @@ struct binary_dispatcher<F, V, T, Types...>
}
else
{
- return binary_dispatcher_rhs<F, V, T, Types...>::apply(v0, v1, f);
+ return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, f);
}
}
else if (v1.get_type_index() == sizeof...(Types))
{
- return binary_dispatcher_lhs<F, V, T, Types...>::apply(v0, v1, f);
+ return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, f);
}
- return binary_dispatcher<F, V, Types...>::apply(v0, v1, f);
+ return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, f);
}
};
-template<typename F, typename V>
-struct binary_dispatcher<F, V>
+template<typename F, typename V, typename R>
+struct binary_dispatcher<F, V, R>
{
- using result_type = typename F::result_type;
+ using result_type = R;
VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
{
throw std::runtime_error("binary dispatch: FAIL");
@@ -448,7 +491,7 @@ struct less_comp
};
template <typename Variant, typename Comp>
-class comparer : public static_visitor<bool>
+class comparer
{
public:
explicit comparer(Variant const& lhs) noexcept
@@ -465,24 +508,6 @@ private:
Variant const& lhs_;
};
-// operator<< helper
-template <typename Out>
-class printer : public static_visitor<>
-{
-public:
- explicit printer(Out & out)
- : out_(out) {}
- printer& operator=(printer const&) = delete;
-
-// visitor
- template <typename T>
- void operator()(T const& operand) const
- {
- out_ << operand;
- }
-private:
- Out & out_;
-};
} // namespace detail
@@ -504,7 +529,6 @@ private:
public:
-
VARIANT_INLINE variant()
: type_index(sizeof...(Types) - 1)
{
@@ -588,7 +612,8 @@ public:
type_index = detail::direct_type<T, Types...>::index;
}
- template<typename T>
+ // get<T>()
+ 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)
@@ -597,11 +622,13 @@ public:
}
else
{
- throw std::runtime_error("in get()");
+ throw std::runtime_error("in get<T>()");
}
}
- template<typename T>
+ template <typename T, typename std::enable_if<
+ (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)
@@ -610,7 +637,69 @@ public:
}
else
{
- throw std::runtime_error("in get()");
+ throw std::runtime_error("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>
+ VARIANT_INLINE T& get()
+ {
+ if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
+ {
+ return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
+ }
+ else
+ {
+ throw std::runtime_error("in get<T>()");
+ }
+ }
+
+ 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)
+ {
+ return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
+ }
+ else
+ {
+ throw std::runtime_error("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>
+ VARIANT_INLINE T& get()
+ {
+ if (type_index == detail::direct_type<std::reference_wrapper<T>, Types...>::index)
+ {
+ return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
+ }
+ else
+ {
+ throw std::runtime_error("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>
+ VARIANT_INLINE T const& get() const
+ {
+ if (type_index == detail::direct_type<std::reference_wrapper<T const>, Types...>::index)
+ {
+ return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
+ }
+ else
+ {
+ throw std::runtime_error("in get<T>()");
}
}
@@ -619,22 +708,33 @@ public:
return type_index;
}
+ VARIANT_INLINE int which() const noexcept
+ {
+ 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, Types...>::apply_const(v, 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))
{
- return detail::dispatcher<F, V, Types...>::apply_const(v, 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);
}
// non-const
template <typename F, typename V>
auto VARIANT_INLINE
static visit(V & v, F f)
- -> decltype(detail::dispatcher<F, V, Types...>::apply(v, 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))
{
- return detail::dispatcher<F, V, Types...>::apply(v, 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);
}
// binary
@@ -642,17 +742,23 @@ public:
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, Types...>::apply_const(v0, v1, 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))
{
- return detail::binary_dispatcher<F, V, Types...>::apply_const(v0, v1, 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);
}
// 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, Types...>::apply(v0, v1, 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))
{
- return detail::binary_dispatcher<F, V, Types...>::apply(v0, v1, 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);
}
~variant() noexcept
@@ -713,28 +819,18 @@ auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::bin
// getter interface
template<typename ResultType, typename T>
-ResultType & get(T & var)
+ResultType & get(T & var)
{
return var.template get<ResultType>();
}
template<typename ResultType, typename T>
-ResultType const& get(T const& var)
+ResultType const& get(T const& var)
{
return var.template get<ResultType>();
}
-// 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)
-{
- detail::printer<std::basic_ostream<charT, traits>> visitor(out);
- apply_visitor(visitor, rhs);
- return out;
-}
-
}}
#endif // MAPBOX_UTIL_VARIANT_HPP
diff --git a/third_party/variant/variant_io.hpp b/third_party/variant/variant_io.hpp
new file mode 100644
index 0000000..8b0c137
--- /dev/null
+++ b/third_party/variant/variant_io.hpp
@@ -0,0 +1,39 @@
+#ifndef MAPBOX_UTIL_VARIANT_IO_HPP
+#define MAPBOX_UTIL_VARIANT_IO_HPP
+
+namespace mapbox { namespace util {
+
+namespace detail {
+// operator<< helper
+template <typename Out>
+class printer
+{
+public:
+ explicit printer(Out & out)
+ : out_(out) {}
+ printer& operator=(printer const&) = delete;
+
+// visitor
+ template <typename T>
+ void operator()(T const& operand) const
+ {
+ out_ << operand;
+ }
+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)
+{
+ detail::printer<std::basic_ostream<charT, traits>> visitor(out);
+ apply_visitor(visitor, rhs);
+ return out;
+}
+
+}}
+
+#endif //MAPBOX_UTIL_VARIANT_IO_HPP
diff --git a/third_party/variant/vcbuild.bat b/third_party/variant/vcbuild.bat
new file mode 100644
index 0000000..21489a1
--- /dev/null
+++ b/third_party/variant/vcbuild.bat
@@ -0,0 +1,8 @@
+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
index 9173dc4..2418a47 100644
--- a/tools/check-hsgr.cpp
+++ b/tools/check-hsgr.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -27,10 +27,10 @@ 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 "../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>
@@ -86,17 +86,17 @@ int main(int argc, char *argv[])
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));
+ 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));
+ std::to_string(node_u) + "," + std::to_string(data.id) +
+ "," + std::to_string(node_v) + "), eid: " +
+ std::to_string(eid));
}
}
progress.printStatus(node_u);
diff --git a/tools/components.cpp b/tools/components.cpp
index 607d86b..7ac64f8 100644
--- a/tools/components.cpp
+++ b/tools/components.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -27,16 +27,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../typedefs.h"
#include "../algorithms/tiny_components.hpp"
+#include "../data_structures/coordinate_calculation.hpp"
#include "../data_structures/dynamic_graph.hpp"
-#include "../Util/graph_loader.hpp"
-#include "../Util/make_unique.hpp"
-#include "../Util/osrm_exception.hpp"
-#include "../Util/simple_logger.hpp"
-#include "../Util/FingerPrint.h"
+#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)
+#if defined(__APPLE__) || defined(_WIN32)
#include <gdal.h>
#include <ogrsf_frmts.h>
#else
@@ -44,28 +46,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <gdal/ogrsf_frmts.h>
#endif
-#include <osrm/Coordinate.h>
+#include <osrm/coordinate.hpp>
#include <fstream>
#include <memory>
#include <string>
#include <vector>
-std::vector<QueryNode> coordinate_list;
-std::vector<TurnRestriction> restriction_list;
-std::vector<NodeID> bollard_node_list;
-std::vector<NodeID> traffic_lights_list;
+namespace
+{
struct TarjanEdgeData
{
TarjanEdgeData() : distance(INVALID_EDGE_WEIGHT), name_id(INVALID_NAMEID) {}
- TarjanEdgeData(int distance, unsigned name_id) : distance(distance), name_id(name_id) {}
- int distance;
+ TarjanEdgeData(unsigned distance, unsigned name_id) : distance(distance), name_id(name_id) {}
+ unsigned distance;
unsigned name_id;
};
-using TarjanDynamicGraph = DynamicGraph<TarjanEdgeData>;
-using TarjanEdge = TarjanDynamicGraph::InputEdge;
+using TarjanGraph = StaticGraph<TarjanEdgeData>;
+using TarjanEdge = TarjanGraph::InputEdge;
void DeleteFileIfExists(const std::string &file_name)
{
@@ -74,9 +74,15 @@ void DeleteFileIfExists(const std::string &file_name)
boost::filesystem::remove(file_name);
}
}
+}
int main(int argc, char *argv[])
{
+ std::vector<QueryNode> coordinate_list;
+ std::vector<TurnRestriction> restriction_list;
+ std::vector<NodeID> bollard_node_list;
+ std::vector<NodeID> traffic_lights_list;
+
LogPolicy::GetInstance().Unmute();
try
{
@@ -92,7 +98,8 @@ int main(int argc, char *argv[])
std::ifstream restriction_ifstream(argv[2], std::ios::binary);
const FingerPrint fingerprint_orig;
FingerPrint fingerprint_loaded;
- restriction_ifstream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
+ restriction_ifstream.read(reinterpret_cast<char *>(&fingerprint_loaded),
+ sizeof(FingerPrint));
// check fingerprint and warn if necessary
if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
@@ -106,13 +113,13 @@ int main(int argc, char *argv[])
throw osrm::exception("Could not access <osrm-restrictions> files");
}
uint32_t usable_restrictions = 0;
- restriction_ifstream.read((char *)&usable_restrictions, sizeof(uint32_t));
+ restriction_ifstream.read(reinterpret_cast<char *>(&usable_restrictions), sizeof(uint32_t));
restriction_list.resize(usable_restrictions);
// load restrictions
if (usable_restrictions > 0)
{
- restriction_ifstream.read((char *)&(restriction_list[0]),
+ restriction_ifstream.read(reinterpret_cast<char *>(&restriction_list[0]),
usable_restrictions * sizeof(TurnRestriction));
}
restriction_ifstream.close();
@@ -125,15 +132,11 @@ int main(int argc, char *argv[])
// load graph data
std::vector<ImportEdge> edge_list;
- const NodeID number_of_nodes = readBinaryOSRMGraphFromStream(input_stream,
- edge_list,
- bollard_node_list,
- traffic_lights_list,
- &coordinate_list,
- restriction_list);
+ const NodeID number_of_nodes =
+ readBinaryOSRMGraphFromStream(input_stream, edge_list, bollard_node_list,
+ traffic_lights_list, &coordinate_list, restriction_list);
input_stream.close();
-
BOOST_ASSERT_MSG(restriction_list.size() == usable_restrictions,
"size of restriction_list changed");
@@ -145,8 +148,9 @@ int main(int argc, char *argv[])
traffic_lights_list.shrink_to_fit();
// Building an node-based graph
- DeallocatingVector<TarjanEdge> graph_edge_list;
- for (const NodeBasedEdge &input_edge : edge_list)
+ std::vector<TarjanEdge> graph_edge_list;
+// DeallocatingVector<TarjanEdge> graph_edge_list;
+ for (const auto &input_edge : edge_list)
{
if (input_edge.source == input_edge.target)
{
@@ -155,17 +159,13 @@ int main(int argc, char *argv[])
if (input_edge.forward)
{
- graph_edge_list.emplace_back(input_edge.source,
- input_edge.target,
- (std::max)((int)input_edge.weight, 1),
- input_edge.name_id);
+ 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)((int)input_edge.weight, 1),
- input_edge.name_id);
+ graph_edge_list.emplace_back(input_edge.target, input_edge.source,
+ (std::max)(input_edge.weight, 1), input_edge.name_id);
}
}
edge_list.clear();
@@ -174,20 +174,20 @@ int main(int argc, char *argv[])
"input edge vector not properly deallocated");
tbb::parallel_sort(graph_edge_list.begin(), graph_edge_list.end());
- auto graph = std::make_shared<TarjanDynamicGraph>(number_of_nodes, graph_edge_list);
- edge_list.clear();
- edge_list.shrink_to_fit();
+ 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";
RestrictionMap restriction_map(restriction_list);
- auto tarjan = osrm::make_unique<TarjanSCC<TarjanDynamicGraph>>(graph,
+ auto tarjan = osrm::make_unique<TarjanSCC<TarjanGraph>>(graph,
restriction_map,
bollard_node_list);
tarjan->run();
SimpleLogger().Write() << "identified: " << tarjan->get_number_of_components()
- << " many components";
- SimpleLogger().Write() << "identified " << tarjan->get_size_one_count() << " SCCs of size 1";
+ << " many components";
+ SimpleLogger().Write() << "identified " << tarjan->get_size_one_count() << " size 1 SCCs";
// output
TIMER_START(SCC_RUN_SETUP);
@@ -197,7 +197,7 @@ int main(int argc, char *argv[])
DeleteFileIfExists("component.shx");
DeleteFileIfExists("component.shp");
- Percent p(graph->GetNumberOfNodes());
+ Percent percentage(graph->GetNumberOfNodes());
OGRRegisterAll();
@@ -225,34 +225,32 @@ int main(int argc, char *argv[])
throw osrm::exception("Layer creation failed.");
}
TIMER_STOP(SCC_RUN_SETUP);
- SimpleLogger().Write() << "shapefile setup took " << TIMER_MSEC(SCC_RUN_SETUP)/1000. << "s";
+ SimpleLogger().Write() << "shapefile setup took " << TIMER_MSEC(SCC_RUN_SETUP) / 1000.
+ << "s";
- uint64_t total_network_distance = 0;
- p.reinit(graph->GetNumberOfNodes());
+ uint64_t total_network_length = 0;
+ percentage.reinit(graph->GetNumberOfNodes());
TIMER_START(SCC_OUTPUT);
for (const NodeID source : osrm::irange(0u, graph->GetNumberOfNodes()))
{
- p.printIncrement();
+ percentage.printIncrement();
for (const auto current_edge : graph->GetAdjacentEdgeRange(source))
{
- const TarjanDynamicGraph::NodeIterator target = graph->GetTarget(current_edge);
+ const TarjanGraph::NodeIterator target = graph->GetTarget(current_edge);
- if (source < target || graph->EndEdges(target) == graph->FindEdge(target, source))
+ if (source < target || SPECIAL_EDGEID == graph->FindEdge(target, source))
{
- total_network_distance +=
- 100 * FixedPointCoordinate::ApproximateEuclideanDistance(
- coordinate_list[source].lat,
- coordinate_list[source].lon,
- coordinate_list[target].lat,
- coordinate_list[target].lon);
+ total_network_length +=
+ 100 * coordinate_calculation::euclidean_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(source),
- tarjan->get_component_size(target));
+ const unsigned size_of_containing_component = std::min(
+ tarjan->get_component_size(source), tarjan->get_component_size(target));
// edges that end on bollard nodes may actually be in two distinct components
if (size_of_containing_component < 1000)
@@ -278,10 +276,12 @@ int main(int argc, char *argv[])
OGRSpatialReference::DestroySpatialReference(poSRS);
OGRDataSource::DestroyDataSource(poDS);
TIMER_STOP(SCC_OUTPUT);
- SimpleLogger().Write() << "generating output took: " << TIMER_MSEC(SCC_OUTPUT)/1000. << "s";
+ SimpleLogger().Write() << "generating output took: " << TIMER_MSEC(SCC_OUTPUT) / 1000.
+ << "s";
SimpleLogger().Write() << "total network distance: "
- << (uint64_t)total_network_distance / 100 / 1000. << " km";
+ << static_cast<uint64_t>(total_network_length / 100 / 1000.)
+ << " km";
SimpleLogger().Write() << "finished component analysis";
}
diff --git a/tools/graph_compare.cpp b/tools/graph_compare.cpp
new file mode 100644
index 0000000..8adc06e
--- /dev/null
+++ b/tools/graph_compare.cpp
@@ -0,0 +1,199 @@
+#include "../data_structures/dynamic_graph.hpp"
+#include "../data_structures/import_edge.hpp"
+#include "../data_structures/query_node.hpp"
+#include "../data_structures/restriction.hpp"
+#include "../data_structures/static_graph.hpp"
+#include "../util/fingerprint.hpp"
+#include "../util/graph_loader.hpp"
+#include "../util/integer_range.hpp"
+#include "../util/make_unique.hpp"
+#include "../util/osrm_exception.hpp"
+#include "../util/simple_logger.hpp"
+
+#include "../typedefs.h"
+
+#include <algorithm>
+#include <fstream>
+
+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 StaticTestGraph = StaticGraph<TarjanEdgeData>;
+using DynamicTestGraph = StaticGraph<TarjanEdgeData>;
+using StaticEdge = StaticTestGraph::InputEdge;
+using DynamicEdge = DynamicTestGraph::InputEdge;
+
+int main(int argc, char *argv[])
+{
+ std::vector<QueryNode> coordinate_list;
+ std::vector<TurnRestriction> restriction_list;
+ std::vector<NodeID> bollard_node_list;
+ std::vector<NodeID> traffic_lights_list;
+
+ LogPolicy::GetInstance().Unmute();
+ try
+ {
+ // enable logging
+ if (argc < 3)
+ {
+ SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0]
+ << " <osrm> <osrm.restrictions>";
+ return -1;
+ }
+
+ SimpleLogger().Write() << "Using restrictions from file: " << argv[2];
+ std::ifstream restriction_ifstream(argv[2], std::ios::binary);
+ const FingerPrint fingerprint_orig;
+ FingerPrint fingerprint_loaded;
+ restriction_ifstream.read(reinterpret_cast<char *>(&fingerprint_loaded),
+ sizeof(FingerPrint));
+
+ // check fingerprint and warn if necessary
+ if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
+ {
+ SimpleLogger().Write(logWARNING) << argv[2] << " was prepared with a different build. "
+ "Reprocess to get rid of this warning.";
+ }
+
+ if (!restriction_ifstream.good())
+ {
+ throw osrm::exception("Could not access <osrm-restrictions> files");
+ }
+ uint32_t usable_restrictions = 0;
+ restriction_ifstream.read(reinterpret_cast<char *>(&usable_restrictions), sizeof(uint32_t));
+ restriction_list.resize(usable_restrictions);
+
+ // load restrictions
+ if (usable_restrictions > 0)
+ {
+ restriction_ifstream.read(reinterpret_cast<char *>(&restriction_list[0]),
+ usable_restrictions * sizeof(TurnRestriction));
+ }
+ restriction_ifstream.close();
+
+ std::ifstream input_stream(argv[1], std::ifstream::in | std::ifstream::binary);
+ if (!input_stream.is_open())
+ {
+ throw osrm::exception("Cannot open osrm file");
+ }
+
+ // load graph data
+ std::vector<ImportEdge> edge_list;
+ const NodeID number_of_nodes =
+ readBinaryOSRMGraphFromStream(input_stream, edge_list, bollard_node_list,
+ traffic_lights_list, &coordinate_list, restriction_list);
+ input_stream.close();
+
+ BOOST_ASSERT_MSG(restriction_list.size() == usable_restrictions,
+ "size of restriction_list changed");
+
+ SimpleLogger().Write() << restriction_list.size() << " restrictions, "
+ << bollard_node_list.size() << " bollard nodes, "
+ << traffic_lights_list.size() << " traffic lights";
+
+ traffic_lights_list.clear();
+ traffic_lights_list.shrink_to_fit();
+
+ // Building an node-based graph
+ std::vector<StaticEdge> static_graph_edge_list;
+ std::vector<DynamicEdge> dynamic_graph_edge_list;
+ for (const auto &input_edge : edge_list)
+ {
+ if (input_edge.source == input_edge.target)
+ {
+ continue;
+ }
+
+ if (input_edge.forward)
+ {
+ static_graph_edge_list.emplace_back(input_edge.source, input_edge.target,
+ (std::max)(input_edge.weight, 1),
+ input_edge.name_id);
+ dynamic_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)
+ {
+ dynamic_graph_edge_list.emplace_back(input_edge.target, input_edge.source,
+ (std::max)(input_edge.weight, 1),
+ input_edge.name_id);
+ static_graph_edge_list.emplace_back(input_edge.target, input_edge.source,
+ (std::max)(input_edge.weight, 1),
+ input_edge.name_id);
+ }
+ }
+ edge_list.clear();
+ edge_list.shrink_to_fit();
+ BOOST_ASSERT_MSG(0 == edge_list.size() && 0 == edge_list.capacity(),
+ "input edge vector not properly deallocated");
+
+ tbb::parallel_sort(static_graph_edge_list.begin(), static_graph_edge_list.end());
+ tbb::parallel_sort(dynamic_graph_edge_list.begin(), dynamic_graph_edge_list.end());
+
+ auto static_graph =
+ osrm::make_unique<StaticTestGraph>(number_of_nodes, static_graph_edge_list);
+ auto dynamic_graph =
+ osrm::make_unique<DynamicTestGraph>(number_of_nodes, dynamic_graph_edge_list);
+
+ SimpleLogger().Write() << "Starting static/dynamic graph comparison";
+
+ BOOST_ASSERT(static_graph->GetNumberOfNodes() == dynamic_graph->GetNumberOfNodes());
+ BOOST_ASSERT(static_graph->GetNumberOfEdges() == dynamic_graph->GetNumberOfEdges());
+ for (const auto node : osrm::irange(0u, static_graph->GetNumberOfNodes()))
+ {
+ const auto static_range = static_graph->GetAdjacentEdgeRange(node);
+ const auto dynamic_range = dynamic_graph->GetAdjacentEdgeRange(node);
+ SimpleLogger().Write() << "checking node " << node << "/"
+ << static_graph->GetNumberOfNodes();
+
+ BOOST_ASSERT(static_range.size() == dynamic_range.size());
+ const auto static_begin = static_graph->BeginEdges(node);
+ const auto dynamic_begin = dynamic_graph->BeginEdges(node);
+
+ // check raw interface
+ for (const auto i : osrm::irange(0u, static_range.size()))
+ {
+ const auto static_target = static_graph->GetTarget(static_begin + i);
+ const auto dynamic_target = dynamic_graph->GetTarget(dynamic_begin + i);
+ BOOST_ASSERT(static_target == dynamic_target);
+
+ const auto static_data = static_graph->GetEdgeData(static_begin + i);
+ const auto dynamic_data = dynamic_graph->GetEdgeData(dynamic_begin + i);
+
+ BOOST_ASSERT(static_data.distance == dynamic_data.distance);
+ BOOST_ASSERT(static_data.name_id == dynamic_data.name_id);
+ }
+
+ // check range interface
+ std::vector<EdgeID> static_target_ids, dynamic_target_ids;
+ std::vector<TarjanEdgeData> static_edge_data, dynamic_edge_data;
+ for (const auto static_id : static_range)
+ {
+ static_target_ids.push_back(static_graph->GetTarget(static_id));
+ static_edge_data.push_back(static_graph->GetEdgeData(static_id));
+ }
+ for (const auto dynamic_id : dynamic_range)
+ {
+ dynamic_target_ids.push_back(dynamic_graph->GetTarget(dynamic_id));
+ dynamic_edge_data.push_back(dynamic_graph->GetEdgeData(dynamic_id));
+ }
+ BOOST_ASSERT(static_target_ids.size() == dynamic_target_ids.size());
+ BOOST_ASSERT(std::equal(std::begin(static_target_ids), std::end(static_target_ids),
+ std::begin(dynamic_target_ids)));
+ }
+
+ SimpleLogger().Write() << "Graph comparison finished successfully";
+ }
+ 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
index c6da3ad..ae76327 100644
--- a/tools/io-benchmark.cpp
+++ b/tools/io-benchmark.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,10 +25,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "../Util/git_sha.hpp"
-#include "../Util/osrm_exception.hpp"
-#include "../Util/simple_logger.hpp"
-#include "../Util/timing_util.hpp"
+#include "../util/git_sha.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>
@@ -63,8 +63,8 @@ void RunStatistics(std::vector<double> &timings_vector, Statistics &stats)
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);
+ 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));
}
@@ -72,12 +72,12 @@ int main(int argc, char *argv[])
{
#ifdef __FreeBSD__
- SimpleLogger().Write() << "Not supported on FreeBSD";
- return 0;
+ SimpleLogger().Write() << "Not supported on FreeBSD";
+ return 0;
#endif
#ifdef _WIN32
- SimpleLogger().Write() << "Not supported on Windows";
- return 0;
+ SimpleLogger().Write() << "Not supported on Windows";
+ return 0;
#else
LogPolicy::GetInstance().Unmute();
@@ -206,7 +206,7 @@ int main(int argc, char *argv[])
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);
+ unsigned block_to_read = uniform_dist(e1);
off_t current_offset = block_to_read * 4096;
TIMER_START(random_access);
#ifdef __APPLE__
diff --git a/tools/simpleclient.cpp b/tools/simpleclient.cpp
index d9c8217..ce590cc 100644
--- a/tools/simpleclient.cpp
+++ b/tools/simpleclient.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,39 +25,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "../Library/OSRM.h"
-#include "../Util/git_sha.hpp"
-#include "../Util/ProgramOptions.h"
-#include "../Util/simple_logger.hpp"
+#include "../library/osrm.hpp"
+#include "../util/git_sha.hpp"
+#include "../util/json_renderer.hpp"
+#include "../util/routed_options.hpp"
+#include "../util/simple_logger.hpp"
-#include <osrm/Reply.h>
-#include <osrm/RouteParameters.h>
-#include <osrm/ServerPaths.h>
+#include <osrm/json_container.hpp>
+#include <osrm/libosrm_config.hpp>
+#include <osrm/route_parameters.hpp>
-#include <boost/property_tree/ptree.hpp>
-#include <boost/property_tree/json_parser.hpp>
-
-#include <iostream>
-#include <stack>
#include <string>
-#include <sstream>
-
-// Dude, real recursions on the OS stack? You must be brave...
-void print_tree(boost::property_tree::ptree const &property_tree, const unsigned recursion_depth)
-{
- auto end = property_tree.end();
- for (auto tree_iterator = property_tree.begin(); tree_iterator != end; ++tree_iterator)
- {
- for (unsigned current_recursion = 0; current_recursion < recursion_depth;
- ++current_recursion)
- {
- std::cout << " " << std::flush;
- }
- std::cout << tree_iterator->first << ": " << tree_iterator->second.get_value<std::string>()
- << std::endl;
- print_tree(tree_iterator->second, recursion_depth + 1);
- }
-}
int main(int argc, const char *argv[])
{
@@ -65,27 +43,25 @@ int main(int argc, const char *argv[])
try
{
std::string ip_address;
- int ip_port, requested_thread_num;
- bool use_shared_memory = false, trial_run = false;
- ServerPaths server_paths;
-
- const unsigned init_result = GenerateServerProgramOptions(argc,
- argv,
- server_paths,
- ip_address,
- ip_port,
- requested_thread_num,
- use_shared_memory,
- trial_run);
-
- if (init_result == INIT_FAILED)
+ int ip_port, requested_thread_num, max_locations_map_matching;
+ bool trial_run = false;
+ libosrm_config 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_distance_table,
+ 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, " << g_GIT_DESCRIPTION;
- OSRM routing_machine(server_paths, use_shared_memory);
+ OSRM routing_machine(lib_config);
RouteParameters route_parameters;
route_parameters.zoom_level = 18; // no generalization
@@ -93,7 +69,7 @@ int main(int argc, const char *argv[])
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 = UINT_MAX; // see wiki
+ 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
@@ -106,23 +82,10 @@ int main(int argc, const char *argv[])
// target_coordinate
route_parameters.coordinates.emplace_back(52.513191 * COORDINATE_PRECISION,
13.415852 * COORDINATE_PRECISION);
- http::Reply osrm_reply;
- routing_machine.RunQuery(route_parameters, osrm_reply);
-
- // attention: super-inefficient hack below:
-
- std::stringstream my_stream;
- for (const auto &element : osrm_reply.content)
- {
- std::cout << element;
- my_stream << element;
- }
- std::cout << std::endl;
-
- boost::property_tree::ptree property_tree;
- boost::property_tree::read_json(my_stream, property_tree);
-
- print_tree(property_tree, 0);
+ 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)
{
diff --git a/tools/springclean.cpp b/tools/springclean.cpp
index 878940a..2d89106 100644
--- a/tools/springclean.cpp
+++ b/tools/springclean.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,9 +28,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <cstdio>
#include "../data_structures/shared_memory_factory.hpp"
-#include "../Server/DataStructures/SharedDataType.h"
-#include "../Util/git_sha.hpp"
-#include "../Util/simple_logger.hpp"
+#include "../server/data_structures/shared_datatype.hpp"
+#include "../util/git_sha.hpp"
+#include "../util/simple_logger.hpp"
void delete_region(const SharedDataType region)
{
@@ -83,8 +83,8 @@ int main()
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]";
+ 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')
diff --git a/tools/unlock_all_mutexes.cpp b/tools/unlock_all_mutexes.cpp
index faef736..299aa61 100644
--- a/tools/unlock_all_mutexes.cpp
+++ b/tools/unlock_all_mutexes.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,9 +25,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "../Util/git_sha.hpp"
-#include "../Util/simple_logger.hpp"
-#include "../Server/DataStructures/SharedBarriers.h"
+#include "../util/git_sha.hpp"
+#include "../util/simple_logger.hpp"
+#include "../server/data_structures/shared_barriers.hpp"
#include <iostream>
diff --git a/UnitTests/algorithm_tests.cpp b/unit_tests/algorithm_tests.cpp
similarity index 96%
copy from UnitTests/algorithm_tests.cpp
copy to unit_tests/algorithm_tests.cpp
index 216a713..0a9f3fd 100644
--- a/UnitTests/algorithm_tests.cpp
+++ b/unit_tests/algorithm_tests.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -32,4 +32,3 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/*
* This file will contain an automatically generated main function.
*/
-
diff --git a/UnitTests/Algorithms/DouglasPeuckerTest.cpp b/unit_tests/algorithms/douglas_peucker.cpp
similarity index 74%
rename from UnitTests/Algorithms/DouglasPeuckerTest.cpp
rename to unit_tests/algorithms/douglas_peucker.cpp
index 27818e5..9654e4d 100644
--- a/UnitTests/Algorithms/DouglasPeuckerTest.cpp
+++ b/unit_tests/algorithms/douglas_peucker.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -27,20 +27,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../../algorithms/douglas_peucker.hpp"
#include "../../data_structures/segment_information.hpp"
-#include "../../Include/osrm/Coordinate.h"
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <boost/mpl/list.hpp>
+#include <osrm/coordinate.hpp>
+
#include <iostream>
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);
+ return SegmentInformation(FixedPointCoordinate(lat, lon), 0, 0, 0, TurnInstruction::HeadOn,
+ necessary, false, 0);
}
BOOST_AUTO_TEST_CASE(all_necessary_test)
@@ -52,17 +53,15 @@ BOOST_AUTO_TEST_CASE(all_necessary_test)
* / \
* x x
*/
- std::vector<SegmentInformation> info = {
- getTestInfo(5, 5, true),
- getTestInfo(6, 6, true),
- getTestInfo(10, 10, true),
- getTestInfo(5, 15, true)
- };
+ 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)
+ for (const auto &i : info)
{
BOOST_CHECK_EQUAL(i.necessary, true);
}
@@ -82,17 +81,14 @@ BOOST_AUTO_TEST_CASE(remove_second_node_test)
* 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(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],
+ 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]);
diff --git a/UnitTests/algorithm_tests.cpp b/unit_tests/algorithms/duration_parsing.cpp
similarity index 50%
copy from UnitTests/algorithm_tests.cpp
copy to unit_tests/algorithms/duration_parsing.cpp
index 216a713..ec3b819 100644
--- a/UnitTests/algorithm_tests.cpp
+++ b/unit_tests/algorithms/duration_parsing.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,11 +25,40 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define BOOST_TEST_MODULE algorithm tests
+#include "../../extractor/extraction_helper_functions.hpp"
#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
-/*
- * This file will contain an automatically generated main function.
- */
+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"), 600);
+ BOOST_CHECK_EQUAL(parseDuration("00:01:01"), 610);
+ BOOST_CHECK_EQUAL(parseDuration("01:01"), 36600);
+
+ // check all combinations of iso duration tokens
+ BOOST_CHECK_EQUAL(parseDuration("PT1M1S"), 610);
+ BOOST_CHECK_EQUAL(parseDuration("PT1H1S"), 36010);
+ BOOST_CHECK_EQUAL(parseDuration("PT15M"), 9000);
+ BOOST_CHECK_EQUAL(parseDuration("PT15S"), 150);
+ BOOST_CHECK_EQUAL(parseDuration("PT15H"), 540000);
+ BOOST_CHECK_EQUAL(parseDuration("PT1H15M"), 45000);
+ BOOST_CHECK_EQUAL(parseDuration("PT1H15M1S"), 45010);
+}
+
+BOOST_AUTO_TEST_CASE(iso_8601_durations_case_insensitive)
+{
+ BOOST_CHECK_EQUAL(parseDuration("PT15m"), 9000);
+ BOOST_CHECK_EQUAL(parseDuration("PT1h15m"), 45000);
+}
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/UnitTests/algorithm_tests.cpp b/unit_tests/algorithms/string_util.cpp
similarity index 52%
copy from UnitTests/algorithm_tests.cpp
copy to unit_tests/algorithms/string_util.cpp
index 216a713..865ddd5 100644
--- a/UnitTests/algorithm_tests.cpp
+++ b/unit_tests/algorithms/string_util.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,11 +25,51 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define BOOST_TEST_MODULE algorithm tests
+#include "../../util/string_util.hpp"
#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
-/*
- * This file will contain an automatically generated main function.
- */
+#include <iostream>
+
+BOOST_AUTO_TEST_SUITE(string_util)
+
+BOOST_AUTO_TEST_CASE(replace_all_test)
+{
+ std::string input{"ababababababa"};
+ const std::string sub{"a"};
+ const std::string other{"c"};
+ replaceAll(input, sub, other);
+
+ BOOST_CHECK_EQUAL(input, "cbcbcbcbcbcbc");
+}
+
+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/UnitTests/data_structures/BinaryHeapTest.cpp b/unit_tests/data_structures/binary_heap.cpp
similarity index 98%
rename from UnitTests/data_structures/BinaryHeapTest.cpp
rename to unit_tests/data_structures/binary_heap.cpp
index 9cfdae2..d039710 100644
--- a/UnitTests/data_structures/BinaryHeapTest.cpp
+++ b/unit_tests/data_structures/binary_heap.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/UnitTests/algorithm_tests.cpp b/unit_tests/data_structures/coordinate.cpp
similarity index 62%
rename from UnitTests/algorithm_tests.cpp
rename to unit_tests/data_structures/coordinate.cpp
index 216a713..6e89156 100644
--- a/UnitTests/algorithm_tests.cpp
+++ b/unit_tests/data_structures/coordinate.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,11 +25,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define BOOST_TEST_MODULE algorithm tests
-
#include <boost/test/unit_test.hpp>
-/*
- * This file will contain an automatically generated main function.
- */
+#include "../../data_structures/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
new file mode 100644
index 0000000..27dc7dc
--- /dev/null
+++ b/unit_tests/data_structures/dynamic_graph.cpp
@@ -0,0 +1,96 @@
+/*
+
+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 "../../util/make_unique.hpp"
+#include "../../typedefs.h"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/mpl/list.hpp>
+
+#include <random>
+#include <unordered_map>
+
+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, 4, TestData{3}},
+ TestInputEdge{4, 3, TestData{4}},
+ TestInputEdge{3, 0, TestData{5}}
+ };
+ 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/UnitTests/data_structures/RangeTableTest.cpp b/unit_tests/data_structures/range_table.cpp
similarity index 95%
rename from UnitTests/data_structures/RangeTableTest.cpp
rename to unit_tests/data_structures/range_table.cpp
index 9c92532..ec3b724 100644
--- a/UnitTests/data_structures/RangeTableTest.cpp
+++ b/unit_tests/data_structures/range_table.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -52,8 +52,9 @@ void ConstructionTest(std::vector<unsigned> lengths, std::vector<unsigned> offse
}
}
-void
-ComputeLengthsOffsets(std::vector<unsigned> &lengths, std::vector<unsigned> &offsets, unsigned num)
+void ComputeLengthsOffsets(std::vector<unsigned> &lengths,
+ std::vector<unsigned> &offsets,
+ unsigned num)
{
lengths.resize(num);
offsets.resize(num + 1);
diff --git a/UnitTests/data_structures/StaticGraphTest.cpp b/unit_tests/data_structures/static_graph.cpp
similarity index 75%
rename from UnitTests/data_structures/StaticGraphTest.cpp
rename to unit_tests/data_structures/static_graph.cpp
index 4f82f8e..ed303b7 100644
--- a/UnitTests/data_structures/StaticGraphTest.cpp
+++ b/unit_tests/data_structures/static_graph.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -40,15 +40,6 @@ BOOST_AUTO_TEST_SUITE(static_graph)
struct TestData
{
EdgeID id;
- bool shortcut;
- unsigned distance;
-};
-
-struct TestEdge
-{
- unsigned source;
- unsigned target;
- unsigned distance;
};
typedef StaticGraph<TestData> TestStaticGraph;
@@ -58,7 +49,7 @@ typedef TestStaticGraph::InputEdge TestInputEdge;
constexpr unsigned TEST_NUM_NODES = 100;
constexpr unsigned TEST_NUM_EDGES = 500;
-// Choosen by a fair W20 dice roll (this value is completely arbitrary)
+// Chosen by a fair W20 dice roll (this value is completely arbitrary)
constexpr unsigned RANDOM_SEED = 15;
template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomArrayEntryFixture
@@ -94,8 +85,7 @@ template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomArrayEntryFixture
for (unsigned i = 0; i < NUM_EDGES; i++)
{
edges.emplace_back(
- TestEdgeArrayEntry{static_cast<unsigned>(node_udist(g)),
- TestData{i, false, static_cast<unsigned>(lengths_udist(g))}});
+ TestEdgeArrayEntry{static_cast<unsigned>(node_udist(g)), TestData{i}});
}
for (unsigned i = 0; i < NUM_NODES; i++)
@@ -128,49 +118,37 @@ BOOST_FIXTURE_TEST_CASE(array_test, TestRandomArrayEntryFixture)
}
}
-TestStaticGraph GraphFromEdgeList(const std::vector<TestEdge> &edges)
-{
- std::vector<TestInputEdge> input_edges;
- unsigned i = 0;
- unsigned num_nodes = 0;
- for (const auto &e : edges)
- {
- input_edges.push_back(TestInputEdge{e.source, e.target, TestData{i++, false, e.distance}});
-
- num_nodes = std::max(num_nodes, std::max(e.source, e.target));
- }
-
- return TestStaticGraph(num_nodes, input_edges);
-}
-
BOOST_AUTO_TEST_CASE(find_test)
{
/*
* (0) -1-> (1)
* ^ ^
- * 2 1
+ * 2 5
* | |
- * (3) -4-> (4)
- * <-3-
+ * (3) -3-> (4)
+ * <-4-
*/
- TestStaticGraph simple_graph = GraphFromEdgeList({TestEdge{0, 1, 1},
- TestEdge{3, 0, 2},
- TestEdge{3, 4, 4},
- TestEdge{4, 3, 3},
- TestEdge{3, 0, 1}});
+ std::vector<TestInputEdge> input_edges = {
+ TestInputEdge{0, 1, TestData{1}},
+ TestInputEdge{3, 0, TestData{2}},
+ TestInputEdge{3, 4, TestData{3}},
+ TestInputEdge{4, 3, TestData{4}},
+ TestInputEdge{3, 0, TestData{5}}
+ };
+ TestStaticGraph simple_graph(5, input_edges);
auto eit = simple_graph.FindEdge(0, 1);
- BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 0);
+ 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, 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, 0);
+ BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 1);
BOOST_CHECK(reverse);
eit = simple_graph.FindEdge(3, 1);
@@ -179,13 +157,12 @@ BOOST_AUTO_TEST_CASE(find_test)
BOOST_CHECK_EQUAL(eit, SPECIAL_EDGEID);
eit = simple_graph.FindEdge(3, 4);
- BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 2);
+ BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 3);
eit = simple_graph.FindEdgeInEitherDirection(3, 4);
- // I think this is wrong behaviour! Should be 3.
- BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 2);
+ BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 3);
eit = simple_graph.FindEdge(3, 0);
- BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 4);
+ BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 2);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/UnitTests/data_structures/StaticRTreeTest.cpp b/unit_tests/data_structures/static_rtree.cpp
similarity index 88%
rename from UnitTests/data_structures/StaticRTreeTest.cpp
rename to unit_tests/data_structures/static_rtree.cpp
index cf3dfd0..42bc718 100644
--- a/UnitTests/data_structures/StaticRTreeTest.cpp
+++ b/unit_tests/data_structures/static_rtree.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,18 +25,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "../../data_structures/coordinate_calculation.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 "../../util/floating_point.hpp"
#include "../../typedefs.h"
-#include <osrm/Coordinate.h>
-
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <boost/mpl/list.hpp>
+#include <osrm/coordinate.hpp>
+
#include <random>
#include <unordered_set>
@@ -77,7 +78,7 @@ class LinearSearchNN
{
const FixedPointCoordinate &start = coords->at(e.u);
const FixedPointCoordinate &end = coords->at(e.v);
- float distance = FixedPointCoordinate::ApproximateEuclideanDistance(
+ float distance = coordinate_calculation::euclidean_distance(
input_coordinate.lat, input_coordinate.lon, start.lat, start.lon);
if (distance < min_dist)
{
@@ -85,7 +86,7 @@ class LinearSearchNN
min_dist = distance;
}
- distance = FixedPointCoordinate::ApproximateEuclideanDistance(
+ distance = coordinate_calculation::euclidean_distance(
input_coordinate.lat, input_coordinate.lon, end.lat, end.lon);
if (distance < min_dist)
{
@@ -112,7 +113,7 @@ class LinearSearchNN
float current_ratio = 0.;
FixedPointCoordinate nearest;
const float current_perpendicular_distance =
- FixedPointCoordinate::ComputePerpendicularDistance(
+ coordinate_calculation::perpendicular_distance(
coords->at(e.u), coords->at(e.v), input_coordinate, nearest, current_ratio);
if ((current_perpendicular_distance < min_dist) &&
@@ -148,9 +149,9 @@ class LinearSearchNN
result_phantom_node.location.lat = input_coordinate.lat;
}
- const float distance_1 = FixedPointCoordinate::ApproximateEuclideanDistance(
+ const float distance_1 = coordinate_calculation::euclidean_distance(
coords->at(nearest_edge.u), result_phantom_node.location);
- const float distance_2 = FixedPointCoordinate::ApproximateEuclideanDistance(
+ const float distance_2 = coordinate_calculation::euclidean_distance(
coords->at(nearest_edge.u), coords->at(nearest_edge.v));
const float ratio = std::min(1.f, distance_1 / distance_2);
@@ -259,17 +260,17 @@ struct GraphFixture
};
typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 3, TEST_LEAF_NODE_SIZE / 2>
-TestRandomGraphFixture_LeafHalfFull;
+ TestRandomGraphFixture_LeafHalfFull;
typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 5, TEST_LEAF_NODE_SIZE>
-TestRandomGraphFixture_LeafFull;
+ TestRandomGraphFixture_LeafFull;
typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 10, TEST_LEAF_NODE_SIZE * 2>
-TestRandomGraphFixture_TwoLeaves;
+ TestRandomGraphFixture_TwoLeaves;
typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 3,
TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR>
-TestRandomGraphFixture_Branch;
+ TestRandomGraphFixture_Branch;
typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 3,
TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 2>
-TestRandomGraphFixture_MultipleLevels;
+ TestRandomGraphFixture_MultipleLevels;
template <typename RTreeT>
void simple_verify_rtree(RTreeT &rtree,
@@ -285,11 +286,11 @@ void simple_verify_rtree(RTreeT &rtree,
bool found_u = rtree.LocateClosestEndPointForCoordinate(pu, result_u, 1);
bool found_v = rtree.LocateClosestEndPointForCoordinate(pv, result_v, 1);
BOOST_CHECK(found_u && found_v);
- float dist_u = FixedPointCoordinate::ApproximateEuclideanDistance(
- result_u.lat, result_u.lon, pu.lat, pu.lon);
+ float dist_u =
+ coordinate_calculation::euclidean_distance(result_u.lat, result_u.lon, pu.lat, pu.lon);
BOOST_CHECK_LE(dist_u, std::numeric_limits<float>::epsilon());
- float dist_v = FixedPointCoordinate::ApproximateEuclideanDistance(
- result_v.lat, result_v.lon, pv.lat, pv.lon);
+ float dist_v =
+ coordinate_calculation::euclidean_distance(result_v.lat, result_v.lon, pv.lat, pv.lon);
BOOST_CHECK_LE(dist_v, std::numeric_limits<float>::epsilon());
}
}
@@ -334,7 +335,7 @@ void build_rtree(const std::string &prefix,
const std::string coords_path = prefix + ".nodes";
boost::filesystem::ofstream node_stream(coords_path, std::ios::binary);
- const unsigned num_nodes = fixture->nodes.size();
+ 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();
@@ -388,30 +389,31 @@ BOOST_AUTO_TEST_CASE(regression_test)
{
typedef std::pair<float, float> Coord;
typedef std::pair<unsigned, unsigned> Edge;
- GraphFixture fixture({
- Coord(40.0, 0.0),
- Coord(35.0, 5.0),
+ GraphFixture fixture(
+ {
+ Coord(40.0, 0.0),
+ Coord(35.0, 5.0),
- Coord(5.0, 5.0),
- Coord(0.0, 10.0),
+ Coord(5.0, 5.0),
+ Coord(0.0, 10.0),
- Coord(20.0, 10.0),
- Coord(20.0, 5.0),
+ Coord(20.0, 10.0),
+ Coord(20.0, 5.0),
- Coord(40.0, 100.0),
- Coord(35.0, 105.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)});
+ 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)});
typedef StaticRTree<TestData, std::vector<FixedPointCoordinate>, false, 2, 3> MiniStaticRTree;
std::string leaves_path;
std::string nodes_path;
- build_rtree<GraphFixture, MiniStaticRTree>(
- "test_regression", &fixture, leaves_path, nodes_path);
+ build_rtree<GraphFixture, MiniStaticRTree>("test_regression", &fixture, leaves_path,
+ nodes_path);
MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords);
// query a node just right of the center of the gap
@@ -449,30 +451,30 @@ void TestRectangle(double width, double height, double center_lat, double center
/* Distance to line segments of rectangle */
BOOST_CHECK_EQUAL(rect.GetMinDist(north),
- FixedPointCoordinate::ApproximateEuclideanDistance(
+ coordinate_calculation::euclidean_distance(
north, FixedPointCoordinate(rect.max_lat, north.lon)));
BOOST_CHECK_EQUAL(rect.GetMinDist(south),
- FixedPointCoordinate::ApproximateEuclideanDistance(
+ coordinate_calculation::euclidean_distance(
south, FixedPointCoordinate(rect.min_lat, south.lon)));
BOOST_CHECK_EQUAL(rect.GetMinDist(west),
- FixedPointCoordinate::ApproximateEuclideanDistance(
+ coordinate_calculation::euclidean_distance(
west, FixedPointCoordinate(west.lat, rect.min_lon)));
BOOST_CHECK_EQUAL(rect.GetMinDist(east),
- FixedPointCoordinate::ApproximateEuclideanDistance(
+ coordinate_calculation::euclidean_distance(
east, FixedPointCoordinate(east.lat, rect.max_lon)));
/* Distance to corner points */
BOOST_CHECK_EQUAL(rect.GetMinDist(north_east),
- FixedPointCoordinate::ApproximateEuclideanDistance(
+ coordinate_calculation::euclidean_distance(
north_east, FixedPointCoordinate(rect.max_lat, rect.max_lon)));
BOOST_CHECK_EQUAL(rect.GetMinDist(north_west),
- FixedPointCoordinate::ApproximateEuclideanDistance(
+ coordinate_calculation::euclidean_distance(
north_west, FixedPointCoordinate(rect.max_lat, rect.min_lon)));
BOOST_CHECK_EQUAL(rect.GetMinDist(south_east),
- FixedPointCoordinate::ApproximateEuclideanDistance(
+ coordinate_calculation::euclidean_distance(
south_east, FixedPointCoordinate(rect.min_lat, rect.max_lon)));
BOOST_CHECK_EQUAL(rect.GetMinDist(south_west),
- FixedPointCoordinate::ApproximateEuclideanDistance(
+ coordinate_calculation::euclidean_distance(
south_west, FixedPointCoordinate(rect.min_lat, rect.min_lon)));
}
diff --git a/UnitTests/datastructure_tests.cpp b/unit_tests/datastructure_tests.cpp
similarity index 96%
rename from UnitTests/datastructure_tests.cpp
rename to unit_tests/datastructure_tests.cpp
index ab39d8d..850d619 100644
--- a/UnitTests/datastructure_tests.cpp
+++ b/unit_tests/datastructure_tests.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/Util/bearing.cpp b/util/bearing.cpp
similarity index 70%
copy from Util/bearing.cpp
copy to util/bearing.cpp
index 1cdcf30..48fd7f9 100644
--- a/Util/bearing.cpp
+++ b/util/bearing.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -27,37 +27,37 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "bearing.hpp"
-std::string Bearing::Get(const double heading)
+std::string bearing::get(const double heading) noexcept
{
+ if (heading <= 22.5)
+ {
+ return "N";
+ }
+ if (heading <= 67.5)
+ {
+ return "NE";
+ }
+ if (heading <= 112.5)
+ {
+ return "E";
+ }
+ if (heading <= 157.5)
+ {
+ return "SE";
+ }
if (heading <= 202.5)
{
- if (heading >= 0. && heading <= 22.5)
- {
- return "N";
- }
- if (heading > 22.5 && heading <= 67.5)
- {
- return "NE";
- }
- if (heading > 67.5 && heading <= 112.5)
- {
- return "E";
- }
- if (heading > 112.5 && heading <= 157.5)
- {
- return "SE";
- }
return "S";
}
- if (heading > 202.5 && heading <= 247.5)
+ if (heading <= 247.5)
{
return "SW";
}
- if (heading > 247.5 && heading <= 292.5)
+ if (heading <= 292.5)
{
return "W";
}
- if (heading > 292.5 && heading <= 337.5)
+ if (heading <= 337.5)
{
return "NW";
}
diff --git a/Util/bearing.hpp b/util/bearing.hpp
similarity index 87%
copy from Util/bearing.hpp
copy to util/bearing.hpp
index a30ec2f..8b16ebc 100644
--- a/Util/bearing.hpp
+++ b/util/bearing.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,14 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef BEARING_HPP_
-#define BEARING_HPP_
+#ifndef BEARING_HPP
+#define BEARING_HPP
#include <string>
-struct Bearing
+struct bearing
{
- static std::string Get(const double heading);
+ static std::string get(const double heading) noexcept;
};
-#endif // BEARING_HPP_
+#endif // BEARING_HPP
diff --git a/Util/BoostFileSystemFix.h b/util/boost_filesystem_2_fix.hpp
similarity index 98%
rename from Util/BoostFileSystemFix.h
rename to util/boost_filesystem_2_fix.hpp
index aeab380..2e41abd 100644
--- a/Util/BoostFileSystemFix.h
+++ b/util/boost_filesystem_2_fix.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/Util/cast.hpp b/util/cast.hpp
similarity index 91%
rename from Util/cast.hpp
rename to util/cast.hpp
index 9d09761..6d6ff65 100644
--- a/Util/cast.hpp
+++ b/util/cast.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -38,7 +38,8 @@ struct cast
{
// convert scoped enums to integers
template <typename Enumeration>
- static auto enum_to_underlying(Enumeration const value) -> typename std::underlying_type<Enumeration>::type
+ static auto enum_to_underlying(Enumeration const value) ->
+ typename std::underlying_type<Enumeration>::type
{
return static_cast<typename std::underlying_type<Enumeration>::type>(value);
}
@@ -108,7 +109,7 @@ struct cast
}
// source: http://tinodidriksen.com/2011/05/28/cpp-convert-string-to-double-speed/
- static double string_to_double(const char *p)
+ static double string_to_double(const char *p) noexcept
{
double r = 0.0;
bool neg = false;
@@ -145,13 +146,10 @@ struct cast
template <typename T> struct scientific_policy : boost::spirit::karma::real_policies<T>
{
// we want the numbers always to be in fixed format
- static int floatfield(T)
- {
- return boost::spirit::karma::real_policies<T>::fmtflags::fixed;
- }
+ static int floatfield(T) { return boost::spirit::karma::real_policies<T>::fmtflags::fixed; }
static unsigned int precision(T) { return 6; }
};
- typedef boost::spirit::karma::real_generator<double, scientific_policy<double>> science_type;
+ using science_type = boost::spirit::karma::real_generator<double, scientific_policy<double>>;
static std::string double_fixed_to_string(const double value)
{
@@ -174,8 +172,7 @@ struct cast
return output;
}
- static void double_with_two_digits_to_string(const double value,
- std::string &output)
+ static void double_with_two_digits_to_string(const double value, std::string &output)
{
// The largest 32-bit integer is 4294967295, that is 10 chars
// On the safe side, add 1 for sign, and 1 for trailing zero
diff --git a/Util/compute_angle.cpp b/util/compute_angle.cpp
similarity index 71%
rename from Util/compute_angle.cpp
rename to util/compute_angle.cpp
index b6350e4..8cd8aa4 100644
--- a/Util/compute_angle.cpp
+++ b/util/compute_angle.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -27,20 +27,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "compute_angle.hpp"
-#include "TrigonometryTables.h"
-#include "../Util/MercatorUtil.h"
-#include <osrm/Coordinate.h>
+#include "trigonometry_table.hpp"
+#include "../util/mercator.hpp"
+
+#include <osrm/coordinate.hpp>
#include <cmath>
-double ComputeAngle::OfThreeFixedPointCoordinates(const FixedPointCoordinate &A,
- const FixedPointCoordinate &C,
- const FixedPointCoordinate &B)
+double ComputeAngle::OfThreeFixedPointCoordinates(const FixedPointCoordinate &first,
+ const FixedPointCoordinate &second,
+ const FixedPointCoordinate &third) noexcept
{
- const double v1x = (A.lon - C.lon) / COORDINATE_PRECISION;
- const double v1y = lat2y(A.lat / COORDINATE_PRECISION) - lat2y(C.lat / COORDINATE_PRECISION);
- const double v2x = (B.lon - C.lon) / COORDINATE_PRECISION;
- const double v2y = lat2y(B.lat / COORDINATE_PRECISION) - lat2y(C.lat / COORDINATE_PRECISION);
+ 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.)
diff --git a/Util/compute_angle.hpp b/util/compute_angle.hpp
similarity index 88%
rename from Util/compute_angle.hpp
rename to util/compute_angle.hpp
index 72c861a..da84caf 100644
--- a/Util/compute_angle.hpp
+++ b/util/compute_angle.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -29,13 +29,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define COMPUTE_ANGLE_HPP
struct FixedPointCoordinate;
-struct NodeInfo;
struct ComputeAngle
{
- /* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/
- static double OfThreeFixedPointCoordinates(const FixedPointCoordinate &A,
- const FixedPointCoordinate &C,
- const FixedPointCoordinate &B);
+ // 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
similarity index 62%
rename from Util/container.hpp
rename to util/container.hpp
index 343ebe9..d455e94 100644
--- a/Util/container.hpp
+++ b/util/container.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CONTAINER_HPP_
-#define CONTAINER_HPP_
+#ifndef CONTAINER_HPP
+#define CONTAINER_HPP
#include <algorithm>
#include <iterator>
@@ -34,11 +34,28 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace osrm
{
-template <typename T> void sort_unique_resize(std::vector<T> &vector)
+namespace detail
{
- std::sort(vector.begin(), vector.end());
- const auto number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin();
- vector.resize(number_of_unique_elements);
+// 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)
@@ -47,9 +64,11 @@ template <typename T> void sort_unique_resize(std::vector<T> &vector)
// vector.shrink_to_fit();
// }
-// template <typename T> inline void remove_consecutive_duplicates_from_vector(std::vector<T> &vector)
+// 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();
+// const auto number_of_unique_elements = std::unique(vector.begin(), vector.end()) -
+// vector.begin();
// vector.resize(number_of_unique_elements);
// }
@@ -67,7 +86,8 @@ Function for_each_pair(ForwardIterator begin, ForwardIterator end, Function func
while (next != end)
{
function(*begin, *next);
- begin = std::next(begin); next = std::next(next);
+ begin = std::next(begin);
+ next = std::next(next);
}
return function;
}
@@ -78,5 +98,14 @@ 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 &&a) {}
+
+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 /* CONTAINER_HPP_ */
+
+} // namespace osrm
+#endif /* CONTAINER_HPP */
diff --git a/Util/DataStoreOptions.h b/util/datastore_options.hpp
similarity index 89%
rename from Util/DataStoreOptions.h
rename to util/datastore_options.hpp
index 389c723..76edc78 100644
--- a/Util/DataStoreOptions.h
+++ b/util/datastore_options.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,16 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DATA_STORE_OPTIONS_H
-#define DATA_STORE_OPTIONS_H
+#ifndef DATASTORE_OPTIONS_HPP
+#define DATASTORE_OPTIONS_HPP
-#include "BoostFileSystemFix.h"
+#include "boost_filesystem_2_fix.hpp"
#include "git_sha.hpp"
-#include "IniFileUtil.h"
+#include "ini_file.hpp"
#include "osrm_exception.hpp"
#include "simple_logger.hpp"
-#include <osrm/ServerPaths.h>
+#include <osrm/server_paths.hpp>
#include <boost/any.hpp>
#include <boost/filesystem.hpp>
@@ -47,34 +47,29 @@ bool GenerateDataStoreOptions(const int argc, const char *argv[], ServerPaths &p
{
// 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"),
+ 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"]),
+ "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"]),
+ "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", boost::program_options::value<boost::filesystem::path>(&paths["ramindex"]),
".ramIndex file")(
- "fileindex",
- boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
+ "fileindex", boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
".fileIndex file")(
- "namesdata",
- boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
+ "namesdata", boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
".names file")("timestamp",
boost::program_options::value<boost::filesystem::path>(&paths["timestamp"]),
".timestamp file");
@@ -83,8 +78,7 @@ bool GenerateDataStoreOptions(const int argc, const char *argv[], ServerPaths &p
// 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,b", boost::program_options::value<boost::filesystem::path>(&paths["base"]),
"base path to .osrm file");
// positional option
@@ -157,7 +151,7 @@ bool GenerateDataStoreOptions(const int argc, const char *argv[], ServerPaths &p
!option_variables.count("base"))
{
SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
- std::string ini_file_contents = ReadIniFileAndLowerContents(path_iterator->second);
+ 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);
@@ -276,4 +270,4 @@ bool GenerateDataStoreOptions(const int argc, const char *argv[], ServerPaths &p
return true;
}
-#endif /* DATA_STORE_OPTIONS_H */
+#endif /* DATASTORE_OPTIONS_HPP */
diff --git a/Util/git_sha.hpp b/util/fingerprint.cpp
similarity index 93%
copy from Util/git_sha.hpp
copy to util/fingerprint.cpp
index d1f18a6..8c7ab40 100644
--- a/Util/git_sha.hpp
+++ b/util/fingerprint.cpp
@@ -25,9 +25,5 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef GIT_SHA_HPP
-#define GIT_SHA_HPP
-
-extern char g_GIT_DESCRIPTION[];
-
-#endif //GIT_SHA_HPP
+#include "fingerprint.hpp"
+#include "fingerprint_impl.hpp"
diff --git a/Util/FingerPrint.h b/util/fingerprint.hpp
similarity index 95%
rename from Util/FingerPrint.h
rename to util/fingerprint.hpp
index 5fd04b6..82eb136 100644
--- a/Util/FingerPrint.h
+++ b/util/fingerprint.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -35,7 +35,7 @@ class FingerPrint
{
public:
FingerPrint();
- FingerPrint(const FingerPrint&) = delete;
+ FingerPrint(const FingerPrint &) = delete;
~FingerPrint();
const boost::uuids::uuid &GetFingerPrint() const;
bool IsMagicNumberOK() const;
diff --git a/Util/finger_print.cpp.in b/util/fingerprint_impl.hpp.in
similarity index 97%
rename from Util/finger_print.cpp.in
rename to util/fingerprint_impl.hpp.in
index c73756e..9259afd 100644
--- a/Util/finger_print.cpp.in
+++ b/util/fingerprint_impl.hpp.in
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,12 +25,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "FingerPrint.h"
-
#include "osrm_exception.hpp"
#include <boost/uuid/name_generator.hpp>
+#include <cstring>
+
#include <algorithm>
#include <string>
diff --git a/Util/floating_point.hpp b/util/floating_point.hpp
similarity index 96%
copy from Util/floating_point.hpp
copy to util/floating_point.hpp
index 5c48102..13f2d3b 100644
--- a/Util/floating_point.hpp
+++ b/util/floating_point.hpp
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/Util/git_sha.cpp.in b/util/git_sha.cpp.in
similarity index 96%
rename from Util/git_sha.cpp.in
rename to util/git_sha.cpp.in
index 5b19337..e3686da 100644
--- a/Util/git_sha.cpp.in
+++ b/util/git_sha.cpp.in
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/Util/git_sha.hpp b/util/git_sha.hpp
similarity index 94%
rename from Util/git_sha.hpp
rename to util/git_sha.hpp
index d1f18a6..b0a9a7c 100644
--- a/Util/git_sha.hpp
+++ b/util/git_sha.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,4 +30,4 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
extern char g_GIT_DESCRIPTION[];
-#endif //GIT_SHA_HPP
+#endif // GIT_SHA_HPP
diff --git a/util/graph_loader.hpp b/util/graph_loader.hpp
new file mode 100644
index 0000000..d741334
--- /dev/null
+++ b/util/graph_loader.hpp
@@ -0,0 +1,539 @@
+/*
+
+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 <boost/assert.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+#include <tbb/parallel_sort.h>
+
+#include <cmath>
+
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <iomanip>
+#include <unordered_map>
+#include <vector>
+
+template <typename EdgeT>
+NodeID read_undirected_osrm_stream(std::istream &input_stream,
+ std::vector<EdgeT> &edge_list,
+ std::vector<FixedPointCoordinate> &coordinate_list)
+{
+ const FingerPrint fingerprint_orig;
+ FingerPrint fingerprint_loaded;
+ input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
+
+ if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
+ {
+ SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n"
+ "Reprocess to get rid of this warning.";
+ }
+
+ std::unordered_map<NodeID, NodeID> ext_to_int_id_map;
+
+ NodeID n;
+ input_stream.read(reinterpret_cast<char *>(&n), sizeof(NodeID));
+ SimpleLogger().Write() << "Importing n = " << n << " nodes ";
+
+ ExternalMemoryNode current_node;
+ for (NodeID i = 0; i < n; ++i)
+ {
+ input_stream.read(reinterpret_cast<char *>(¤t_node), sizeof(ExternalMemoryNode));
+ coordinate_list.emplace_back(current_node.lat, current_node.lon);
+ ext_to_int_id_map.emplace(current_node.node_id, i);
+ // if (current_node.barrier)
+ // {
+ // barrier_node_list.emplace_back(i);
+ // }
+ // if (current_node.traffic_lights)
+ // {
+ // traffic_light_node_list.emplace_back(i);
+ // }
+ }
+
+ // tighten vector sizes
+ // barrier_node_list.shrink_to_fit();
+ // traffic_light_node_list.shrink_to_fit();
+
+ // renumber nodes in turn restrictions
+ // for (TurnRestriction ¤t_restriction : restriction_list)
+ // {
+ // auto internal_id_iter = ext_to_int_id_map.find(current_restriction.from.node);
+ // if (internal_id_iter == ext_to_int_id_map.end())
+ // {
+ // SimpleLogger().Write(logDEBUG) << "Unmapped from node " <<
+ // current_restriction.from.node
+ // << " of restriction";
+ // continue;
+ // }
+ // current_restriction.from.node = internal_id_iter->second;
+
+ // internal_id_iter = ext_to_int_id_map.find(current_restriction.via.node);
+ // if (internal_id_iter == ext_to_int_id_map.end())
+ // {
+ // SimpleLogger().Write(logDEBUG) << "Unmapped via node " <<
+ // current_restriction.via.node
+ // << " of restriction";
+ // continue;
+ // }
+
+ // current_restriction.via.node = internal_id_iter->second;
+
+ // internal_id_iter = ext_to_int_id_map.find(current_restriction.to.node);
+ // if (internal_id_iter == ext_to_int_id_map.end())
+ // {
+ // SimpleLogger().Write(logDEBUG) << "Unmapped to node " << current_restriction.to.node
+ // << " of restriction";
+ // continue;
+ // }
+ // current_restriction.to.node = internal_id_iter->second;
+ // }
+
+ EdgeWeight weight;
+ NodeID source, target;
+ unsigned nameID;
+ int length;
+ short dir; // direction (0 = open, 1 = forward, 2+ = open)
+ bool is_roundabout, ignore_in_grid, is_access_restricted, is_split;
+ TravelMode travel_mode;
+
+ EdgeID m;
+ input_stream.read(reinterpret_cast<char *>(&m), sizeof(unsigned));
+ edge_list.reserve(m);
+ SimpleLogger().Write() << " and " << m << " edges ";
+
+ for (EdgeID i = 0; i < m; ++i)
+ {
+ input_stream.read(reinterpret_cast<char *>(&source), sizeof(unsigned));
+ input_stream.read(reinterpret_cast<char *>(&target), sizeof(unsigned));
+ input_stream.read(reinterpret_cast<char *>(&length), sizeof(int));
+ input_stream.read(reinterpret_cast<char *>(&dir), sizeof(short));
+ input_stream.read(reinterpret_cast<char *>(&weight), sizeof(int));
+ input_stream.read(reinterpret_cast<char *>(&nameID), sizeof(unsigned));
+ input_stream.read(reinterpret_cast<char *>(&is_roundabout), sizeof(bool));
+ input_stream.read(reinterpret_cast<char *>(&ignore_in_grid), sizeof(bool));
+ input_stream.read(reinterpret_cast<char *>(&is_access_restricted), sizeof(bool));
+ input_stream.read(reinterpret_cast<char *>(&travel_mode), sizeof(TravelMode));
+ input_stream.read(reinterpret_cast<char *>(&is_split), sizeof(bool));
+
+ BOOST_ASSERT_MSG(length > 0, "loaded null length edge");
+ BOOST_ASSERT_MSG(weight > 0, "loaded null weight");
+ BOOST_ASSERT_MSG(0 <= dir && dir <= 2, "loaded bogus direction");
+
+ // bool forward = true;
+ // bool backward = true;
+ // if (1 == dir)
+ // {
+ // backward = false;
+ // }
+ // if (2 == dir)
+ // {
+ // forward = false;
+ // }
+
+ // translate the external NodeIDs to internal IDs
+ auto internal_id_iter = ext_to_int_id_map.find(source);
+ if (ext_to_int_id_map.find(source) == ext_to_int_id_map.end())
+ {
+#ifndef NDEBUG
+ SimpleLogger().Write(logWARNING) << " unresolved source NodeID: " << source;
+#endif
+ continue;
+ }
+ source = internal_id_iter->second;
+ internal_id_iter = ext_to_int_id_map.find(target);
+ if (ext_to_int_id_map.find(target) == ext_to_int_id_map.end())
+ {
+#ifndef NDEBUG
+ SimpleLogger().Write(logWARNING) << "unresolved target NodeID : " << target;
+#endif
+ continue;
+ }
+ target = internal_id_iter->second;
+ BOOST_ASSERT_MSG(source != SPECIAL_NODEID && target != SPECIAL_NODEID,
+ "nonexisting source or target");
+
+ if (source > target)
+ {
+ std::swap(source, target);
+ // std::swap(forward, backward);
+ }
+
+ edge_list.emplace_back(source, target);
+ }
+ ext_to_int_id_map.clear();
+
+ tbb::parallel_sort(edge_list.begin(), edge_list.end());
+
+ // for (unsigned i = 1; i < edge_list.size(); ++i)
+ // {
+ // if ((edge_list[i - 1].target == edge_list[i].target) &&
+ // (edge_list[i - 1].source == edge_list[i].source))
+ // {
+ // const bool edge_flags_equivalent = (edge_list[i - 1].forward == edge_list[i].forward)
+ // &&
+ // (edge_list[i - 1].backward ==
+ // edge_list[i].backward);
+ // const bool edge_flags_are_superset1 =
+ // (edge_list[i - 1].forward && edge_list[i - 1].backward) &&
+ // (edge_list[i].forward != edge_list[i].backward);
+ // const bool edge_flags_are_superset_2 =
+ // (edge_list[i].forward && edge_list[i].backward) &&
+ // (edge_list[i - 1].forward != edge_list[i - 1].backward);
+
+ // if (edge_flags_equivalent)
+ // {
+ // edge_list[i].weight = std::min(edge_list[i - 1].weight, edge_list[i].weight);
+ // edge_list[i - 1].source = SPECIAL_NODEID;
+ // }
+ // else if (edge_flags_are_superset1)
+ // {
+ // if (edge_list[i - 1].weight <= edge_list[i].weight)
+ // {
+ // // edge i-1 is smaller and goes in both directions. Throw away the other edge
+ // edge_list[i].source = SPECIAL_NODEID;
+ // }
+ // else
+ // {
+ // // edge i-1 is open in both directions, but edge i is smaller in one
+ // direction.
+ // // Close edge i-1 in this direction
+ // edge_list[i - 1].forward = !edge_list[i].forward;
+ // edge_list[i - 1].backward = !edge_list[i].backward;
+ // }
+ // }
+ // else if (edge_flags_are_superset_2)
+ // {
+ // if (edge_list[i - 1].weight <= edge_list[i].weight)
+ // {
+ // // edge i-1 is smaller for one direction. edge i is open in both. close edge
+ // i
+ // // in the other direction
+ // edge_list[i].forward = !edge_list[i - 1].forward;
+ // edge_list[i].backward = !edge_list[i - 1].backward;
+ // }
+ // else
+ // {
+ // // edge i is smaller and goes in both direction. Throw away edge i-1
+ // edge_list[i - 1].source = SPECIAL_NODEID;
+ // }
+ // }
+ // }
+ // }
+ // const auto new_end_iter =
+ // std::remove_if(edge_list.begin(), edge_list.end(), [](const EdgeT &edge)
+ // {
+ // return edge.source == SPECIAL_NODEID || edge.target == SPECIAL_NODEID;
+ // });
+ // edge_list.erase(new_end_iter, edge_list.end()); // remove excess candidates.
+ // edge_list.shrink_to_fit();
+ SimpleLogger().Write() << "Graph loaded ok and has " << edge_list.size() << " edges";
+ return n;
+}
+
+template <typename EdgeT>
+NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
+ std::vector<EdgeT> &edge_list,
+ std::vector<NodeID> &barrier_node_list,
+ std::vector<NodeID> &traffic_light_node_list,
+ std::vector<QueryNode> *int_to_ext_node_id_map,
+ std::vector<TurnRestriction> &restriction_list)
+{
+ const FingerPrint fingerprint_orig;
+ FingerPrint fingerprint_loaded;
+ input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
+
+ if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
+ {
+ SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n"
+ "Reprocess to get rid of this warning.";
+ }
+
+ std::unordered_map<NodeID, NodeID> ext_to_int_id_map;
+
+ NodeID n;
+ input_stream.read(reinterpret_cast<char *>(&n), sizeof(NodeID));
+ SimpleLogger().Write() << "Importing n = " << n << " nodes ";
+
+ ExternalMemoryNode current_node;
+ for (NodeID i = 0; i < n; ++i)
+ {
+ input_stream.read(reinterpret_cast<char *>(¤t_node), sizeof(ExternalMemoryNode));
+ int_to_ext_node_id_map->emplace_back(current_node.lat, current_node.lon,
+ current_node.node_id);
+ ext_to_int_id_map.emplace(current_node.node_id, i);
+ if (current_node.barrier)
+ {
+ barrier_node_list.emplace_back(i);
+ }
+ if (current_node.traffic_lights)
+ {
+ traffic_light_node_list.emplace_back(i);
+ }
+ }
+
+ // tighten vector sizes
+ barrier_node_list.shrink_to_fit();
+ traffic_light_node_list.shrink_to_fit();
+
+ // renumber nodes in turn restrictions
+ for (TurnRestriction ¤t_restriction : restriction_list)
+ {
+ auto internal_id_iter = ext_to_int_id_map.find(current_restriction.from.node);
+ if (internal_id_iter == ext_to_int_id_map.end())
+ {
+ SimpleLogger().Write(logDEBUG) << "Unmapped from node " << current_restriction.from.node
+ << " of restriction";
+ continue;
+ }
+ current_restriction.from.node = internal_id_iter->second;
+
+ internal_id_iter = ext_to_int_id_map.find(current_restriction.via.node);
+ if (internal_id_iter == ext_to_int_id_map.end())
+ {
+ SimpleLogger().Write(logDEBUG) << "Unmapped via node " << current_restriction.via.node
+ << " of restriction";
+ continue;
+ }
+
+ current_restriction.via.node = internal_id_iter->second;
+
+ internal_id_iter = ext_to_int_id_map.find(current_restriction.to.node);
+ if (internal_id_iter == ext_to_int_id_map.end())
+ {
+ SimpleLogger().Write(logDEBUG) << "Unmapped to node " << current_restriction.to.node
+ << " of restriction";
+ continue;
+ }
+ current_restriction.to.node = internal_id_iter->second;
+ }
+
+ EdgeWeight weight;
+ NodeID source, target;
+ unsigned nameID;
+ int length;
+ short dir; // direction (0 = open, 1 = forward, 2+ = open)
+ bool is_roundabout, ignore_in_grid, is_access_restricted, is_split;
+ TravelMode travel_mode;
+
+ EdgeID m;
+ input_stream.read(reinterpret_cast<char *>(&m), sizeof(unsigned));
+ edge_list.reserve(m);
+ SimpleLogger().Write() << " and " << m << " edges ";
+
+ for (EdgeID i = 0; i < m; ++i)
+ {
+ input_stream.read(reinterpret_cast<char *>(&source), sizeof(unsigned));
+ input_stream.read(reinterpret_cast<char *>(&target), sizeof(unsigned));
+ input_stream.read(reinterpret_cast<char *>(&length), sizeof(int));
+ input_stream.read(reinterpret_cast<char *>(&dir), sizeof(short));
+ input_stream.read(reinterpret_cast<char *>(&weight), sizeof(int));
+ input_stream.read(reinterpret_cast<char *>(&nameID), sizeof(unsigned));
+ input_stream.read(reinterpret_cast<char *>(&is_roundabout), sizeof(bool));
+ input_stream.read(reinterpret_cast<char *>(&ignore_in_grid), sizeof(bool));
+ input_stream.read(reinterpret_cast<char *>(&is_access_restricted), sizeof(bool));
+ input_stream.read(reinterpret_cast<char *>(&travel_mode), sizeof(TravelMode));
+ input_stream.read(reinterpret_cast<char *>(&is_split), sizeof(bool));
+
+ BOOST_ASSERT_MSG(length > 0, "loaded null length edge");
+ BOOST_ASSERT_MSG(weight > 0, "loaded null weight");
+ BOOST_ASSERT_MSG(0 <= dir && dir <= 2, "loaded bogus direction");
+
+ bool forward = true;
+ bool backward = true;
+ if (1 == dir)
+ {
+ backward = false;
+ }
+ if (2 == dir)
+ {
+ forward = false;
+ }
+
+ // translate the external NodeIDs to internal IDs
+ auto internal_id_iter = ext_to_int_id_map.find(source);
+ if (ext_to_int_id_map.find(source) == ext_to_int_id_map.end())
+ {
+#ifndef NDEBUG
+ SimpleLogger().Write(logWARNING) << " unresolved source NodeID: " << source;
+#endif
+ continue;
+ }
+ source = internal_id_iter->second;
+ internal_id_iter = ext_to_int_id_map.find(target);
+ if (ext_to_int_id_map.find(target) == ext_to_int_id_map.end())
+ {
+#ifndef NDEBUG
+ SimpleLogger().Write(logWARNING) << "unresolved target NodeID : " << target;
+#endif
+ continue;
+ }
+ target = internal_id_iter->second;
+ BOOST_ASSERT_MSG(source != SPECIAL_NODEID && target != SPECIAL_NODEID,
+ "nonexisting source or target");
+
+ if (source > target)
+ {
+ std::swap(source, target);
+ std::swap(forward, backward);
+ }
+
+ edge_list.emplace_back(source, target, nameID, weight, forward, backward, is_roundabout,
+ ignore_in_grid, is_access_restricted, travel_mode, is_split);
+ }
+ ext_to_int_id_map.clear();
+
+ tbb::parallel_sort(edge_list.begin(), edge_list.end());
+
+ for (unsigned i = 1; i < edge_list.size(); ++i)
+ {
+ if ((edge_list[i - 1].target == edge_list[i].target) &&
+ (edge_list[i - 1].source == edge_list[i].source))
+ {
+ const bool edge_flags_equivalent = (edge_list[i - 1].forward == edge_list[i].forward) &&
+ (edge_list[i - 1].backward == edge_list[i].backward);
+ const bool edge_flags_are_superset1 =
+ (edge_list[i - 1].forward && edge_list[i - 1].backward) &&
+ (edge_list[i].forward != edge_list[i].backward);
+ const bool edge_flags_are_superset_2 =
+ (edge_list[i].forward && edge_list[i].backward) &&
+ (edge_list[i - 1].forward != edge_list[i - 1].backward);
+
+ if (edge_flags_equivalent)
+ {
+ edge_list[i].weight = std::min(edge_list[i - 1].weight, edge_list[i].weight);
+ edge_list[i - 1].source = SPECIAL_NODEID;
+ }
+ else if (edge_flags_are_superset1)
+ {
+ if (edge_list[i - 1].weight <= edge_list[i].weight)
+ {
+ // edge i-1 is smaller and goes in both directions. Throw away the other edge
+ edge_list[i].source = SPECIAL_NODEID;
+ }
+ else
+ {
+ // edge i-1 is open in both directions, but edge i is smaller in one direction.
+ // Close edge i-1 in this direction
+ edge_list[i - 1].forward = !edge_list[i].forward;
+ edge_list[i - 1].backward = !edge_list[i].backward;
+ }
+ }
+ else if (edge_flags_are_superset_2)
+ {
+ if (edge_list[i - 1].weight <= edge_list[i].weight)
+ {
+ // edge i-1 is smaller for one direction. edge i is open in both. close edge i
+ // in the other direction
+ edge_list[i].forward = !edge_list[i - 1].forward;
+ edge_list[i].backward = !edge_list[i - 1].backward;
+ }
+ else
+ {
+ // edge i is smaller and goes in both direction. Throw away edge i-1
+ edge_list[i - 1].source = SPECIAL_NODEID;
+ }
+ }
+ }
+ }
+ const auto new_end_iter =
+ std::remove_if(edge_list.begin(), edge_list.end(), [](const EdgeT &edge)
+ {
+ return edge.source == SPECIAL_NODEID || edge.target == SPECIAL_NODEID;
+ });
+ edge_list.erase(new_end_iter, edge_list.end()); // remove excess candidates.
+ edge_list.shrink_to_fit();
+ SimpleLogger().Write() << "Graph loaded ok and has " << edge_list.size() << " edges";
+ return n;
+}
+
+template <typename NodeT, typename EdgeT>
+unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
+ std::vector<NodeT> &node_list,
+ std::vector<EdgeT> &edge_list,
+ unsigned *check_sum)
+{
+ if (!boost::filesystem::exists(hsgr_file))
+ {
+ throw osrm::exception("hsgr file does not exist");
+ }
+ if (0 == boost::filesystem::file_size(hsgr_file))
+ {
+ throw osrm::exception("hsgr file is empty");
+ }
+
+ boost::filesystem::ifstream hsgr_input_stream(hsgr_file, std::ios::binary);
+
+ FingerPrint fingerprint_loaded, fingerprint_orig;
+ hsgr_input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
+ if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
+ {
+ SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build.\n"
+ "Reprocess to get rid of this warning.";
+ }
+
+ unsigned number_of_nodes = 0;
+ unsigned number_of_edges = 0;
+ hsgr_input_stream.read(reinterpret_cast<char *>(check_sum), sizeof(unsigned));
+ hsgr_input_stream.read(reinterpret_cast<char *>(&number_of_nodes), sizeof(unsigned));
+ BOOST_ASSERT_MSG(0 != number_of_nodes, "number of nodes is zero");
+ hsgr_input_stream.read(reinterpret_cast<char *>(&number_of_edges), sizeof(unsigned));
+
+ SimpleLogger().Write() << "number_of_nodes: " << number_of_nodes
+ << ", number_of_edges: " << number_of_edges;
+
+ // BOOST_ASSERT_MSG( 0 != number_of_edges, "number of edges is zero");
+ node_list.resize(number_of_nodes);
+ hsgr_input_stream.read(reinterpret_cast<char *>(&node_list[0]),
+ number_of_nodes * sizeof(NodeT));
+
+ edge_list.resize(number_of_edges);
+ if (number_of_edges > 0)
+ {
+ 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/IniFileUtil.h b/util/ini_file.hpp
similarity index 74%
rename from Util/IniFileUtil.h
rename to util/ini_file.hpp
index ea1d7a1..b42f9ae 100644
--- a/Util/IniFileUtil.h
+++ b/util/ini_file.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,25 +25,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef INI_FILE_UTIL_H
-#define INI_FILE_UTIL_H
+#ifndef INI_FILE_HPP
+#define INI_FILE_HPP
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
-#include <boost/regex.hpp>
-#include <regex>
+#include <algorithm>
#include <string>
+namespace
+{
+
// support old capitalized option names by down-casing them with a regex replace
-inline std::string ReadIniFileAndLowerContents(const boost::filesystem::path &path)
+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>());
- boost::regex regex( "^([^=]*)" ); //match from start of line to '='
- std::string format( "\\L$1\\E" ); //replace with downcased substring
- return boost::regex_replace( ini_file_content, regex, format );
+ 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_UTIL_H
+}
+#endif // INI_FILE_HPP
diff --git a/Util/integer_range.hpp b/util/integer_range.hpp
similarity index 71%
rename from Util/integer_range.hpp
rename to util/integer_range.hpp
index 030b2fa..46b69ba 100644
--- a/Util/integer_range.hpp
+++ b/util/integer_range.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013,2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -40,28 +40,30 @@ template <typename Integer> class range
Integer iter;
public:
- range(Integer start, Integer end) : last(end), iter(start)
+ range(Integer start, Integer end) noexcept : last(end), iter(start)
{
static_assert(std::is_integral<Integer>::value, "range type must be integral");
}
// Iterable functions
- const range &begin() const { return *this; }
- const range &end() const { return *this; }
- Integer front() const { return iter; }
- Integer back() const { return last - 1; }
+ 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; }
+ Integer size() const noexcept { return last - iter; }
// Iterator functions
- bool operator!=(const range &) const { return iter < last; }
- void operator++() { ++iter; }
- Integer operator*() const { return iter; }
+ 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)
+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);
}
diff --git a/util/iso_8601_duration_parser.hpp b/util/iso_8601_duration_parser.hpp
new file mode 100644
index 0000000..1981c89
--- /dev/null
+++ b/util/iso_8601_duration_parser.hpp
@@ -0,0 +1,102 @@
+/*
+
+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
+
+#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> struct iso_8601_grammar : qi::grammar<Iterator>
+{
+ iso_8601_grammar()
+ : iso_8601_grammar::base_type(iso_period), temp(0), hours(0), minutes(0), seconds(0)
+ {
+ iso_period = qi::lit('P') >> qi::lit('T') >>
+ ((value >> hour >> value >> minute >> value >> second) |
+ (value >> hour >> value >> minute) | (value >> hour >> value >> second) |
+ (value >> hour) | (value >> minute >> value >> second) | (value >> minute) |
+ (value >> second));
+
+ value = qi::uint_[boost::bind(&iso_8601_grammar<Iterator>::set_temp, this, ::_1)];
+ second = (qi::lit('s') |
+ qi::lit('S'))[boost::bind(&iso_8601_grammar<Iterator>::set_seconds, this)];
+ minute = (qi::lit('m') |
+ qi::lit('M'))[boost::bind(&iso_8601_grammar<Iterator>::set_minutes, this)];
+ hour = (qi::lit('h') |
+ qi::lit('H'))[boost::bind(&iso_8601_grammar<Iterator>::set_hours, this)];
+ }
+
+ qi::rule<Iterator> iso_period;
+ qi::rule<Iterator, std::string()> value, hour, minute, second;
+
+ unsigned temp;
+ unsigned hours;
+ unsigned minutes;
+ unsigned seconds;
+
+ void set_temp(unsigned number) { temp = number; }
+
+ void set_hours()
+ {
+ if (temp < 24)
+ {
+ hours = temp;
+ }
+ }
+
+ void set_minutes()
+ {
+ if (temp < 60)
+ {
+ minutes = temp;
+ }
+ }
+
+ void set_seconds()
+ {
+ if (temp < 60)
+ {
+ seconds = temp;
+ }
+ }
+
+ unsigned get_duration() const
+ {
+ unsigned temp = 10 * (3600 * hours + 60 * minutes + seconds);
+ if (temp == 0)
+ {
+ temp = std::numeric_limits<unsigned>::max();
+ }
+ return temp;
+ }
+};
+
+#endif // ISO_8601_DURATION_PARSER_HPP
diff --git a/Util/iterator_range.hpp b/util/iterator_range.hpp
similarity index 60%
rename from Util/iterator_range.hpp
rename to util/iterator_range.hpp
index a057d7c..f4fa4f8 100644
--- a/Util/iterator_range.hpp
+++ b/util/iterator_range.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,20 +25,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef RANGE_HPP_
-#define RANGE_HPP_
+#ifndef ITERATOR_RANGE_HPP
+#define ITERATOR_RANGE_HPP
namespace osrm
{
-namespace util
-{
-template <typename Iterator> class Range
+template <typename Iterator> class iter_range
{
public:
- Range(Iterator begin, Iterator end) : begin_(begin), end_(end) {}
+ iter_range(Iterator begin, Iterator end) noexcept : begin_(begin), end_(end) {}
- Iterator begin() const { return begin_; }
- Iterator end() const { return end_; }
+ Iterator begin() const noexcept { return begin_; }
+ Iterator end() const noexcept { return end_; }
private:
Iterator begin_;
@@ -48,25 +46,26 @@ template <typename Iterator> class Range
// Convenience functions for template parameter inference,
// akin to std::make_pair.
-template <typename Iterator> Range<Iterator> range(Iterator begin, Iterator end)
+template <typename Iterator>
+iter_range<Iterator> integer_range(Iterator begin, Iterator end) noexcept
{
- return Range<Iterator>(begin, end);
+ return iter_range<Iterator>(begin, end);
}
template <typename Reversable>
-Range<typename Reversable::reverse_iterator> reverse(Reversable *reversable)
+iter_range<typename Reversable::reverse_iterator> reverse(Reversable *reversable) noexcept
{
- return Range<typename Reversable::reverse_iterator>(reversable->rbegin(), reversable->rend());
+ return iter_range<typename Reversable::reverse_iterator>(reversable->rbegin(),
+ reversable->rend());
}
template <typename ConstReversable>
-Range<typename ConstReversable::const_reverse_iterator>
-const_reverse(const ConstReversable *const_reversable)
+iter_range<typename ConstReversable::const_reverse_iterator>
+const_reverse(const ConstReversable *const_reversable) noexcept
{
- return Range<typename ConstReversable::const_reverse_iterator>(const_reversable->crbegin(),
- const_reversable->crend());
-}
+ return iter_range<typename ConstReversable::const_reverse_iterator>(const_reversable->crbegin(),
+ const_reversable->crend());
}
}
-#endif // RANGE_HPP_
+#endif // ITERATOR_RANGE_HPP
diff --git a/Util/bearing.cpp b/util/json_logger.hpp
similarity index 57%
rename from Util/bearing.cpp
rename to util/json_logger.hpp
index 1cdcf30..b7de7cb 100644
--- a/Util/bearing.cpp
+++ b/util/json_logger.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,41 +25,64 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "bearing.hpp"
+#ifndef JSON_LOGGER_HPP
+#define JSON_LOGGER_HPP
-std::string Bearing::Get(const double heading)
+#include <osrm/json_container.hpp>
+
+#include <boost/thread.hpp>
+
+namespace osrm
{
- if (heading <= 202.5)
+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, osrm::json::Value>;
+
+ public:
+ static Logger* get()
{
- if (heading >= 0. && heading <= 22.5)
- {
- return "N";
- }
- if (heading > 22.5 && heading <= 67.5)
- {
- return "NE";
- }
- if (heading > 67.5 && heading <= 112.5)
- {
- return "E";
- }
- if (heading > 112.5 && heading <= 157.5)
+ 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 "SE";
+ return &logger;
}
- return "S";
- }
- if (heading > 202.5 && heading <= 247.5)
- {
- return "SW";
+
+ return nullptr;
}
- if (heading > 247.5 && heading <= 292.5)
+
+ void initialize(const std::string& name)
{
- return "W";
+ if (!map.get())
+ {
+ map.reset(new MapT());
+ }
+ (*map)[name] = Object();
}
- if (heading > 292.5 && heading <= 337.5)
+
+ void render(const std::string& name, Object& obj) const
{
- return "NW";
+ obj.values["debug"] = map->at(name);
}
- return "N";
+
+ boost::thread_specific_ptr<MapT> map;
+};
+
+
+}
}
+
+#endif /* JSON_LOGGER_HPP */
diff --git a/Util/json_renderer.hpp b/util/json_renderer.hpp
similarity index 91%
rename from Util/json_renderer.hpp
rename to util/json_renderer.hpp
index dd6089c..e5bbf6f 100644
--- a/Util/json_renderer.hpp
+++ b/util/json_renderer.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -31,16 +31,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef JSON_RENDERER_HPP
#define JSON_RENDERER_HPP
-#include "../data_structures/json_container.hpp"
#include "cast.hpp"
+#include "string_util.hpp"
-namespace JSON {
+#include <osrm/json_container.hpp>
+
+namespace osrm
+{
+namespace json
+{
struct Renderer : mapbox::util::static_visitor<>
{
explicit Renderer(std::ostream &_out) : out(_out) {}
- void operator()(const String &string) const { out << "\"" << string.value << "\""; }
+ void operator()(const String &string) const
+ {
+ out << "\"";
+ out << escape_JSON(string.value);
+ out << "\"";
+ }
void operator()(const Number &number) const
{
@@ -97,7 +107,8 @@ struct ArrayRenderer : mapbox::util::static_visitor<>
void operator()(const String &string) const
{
out.push_back('\"');
- out.insert(out.end(), string.value.begin(), string.value.end());
+ const auto string_to_insert = escape_JSON(string.value);
+ out.insert(std::end(out), std::begin(string_to_insert), std::end(string_to_insert));
out.push_back('\"');
}
@@ -177,6 +188,6 @@ inline void render(std::vector<char> &out, const Object &object)
mapbox::util::apply_visitor(ArrayRenderer(out), value);
}
-} // namespace JSON
-
+} // namespace json
+} // namespace osrm
#endif // JSON_RENDERER_HPP
diff --git a/util/json_util.hpp b/util/json_util.hpp
new file mode 100644
index 0000000..bfb8a8b
--- /dev/null
+++ b/util/json_util.hpp
@@ -0,0 +1,103 @@
+/*
+
+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
similarity index 97%
rename from Util/lua_util.hpp
rename to util/lua_util.hpp
index f367949..af6277c 100644
--- a/Util/lua_util.hpp
+++ b/util/lua_util.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/Util/make_unique.hpp b/util/make_unique.hpp
similarity index 51%
rename from Util/make_unique.hpp
rename to util/make_unique.hpp
index 07786fe..83e2301 100644
--- a/Util/make_unique.hpp
+++ b/util/make_unique.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -34,24 +34,40 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace osrm
{
-// Taken from http://msdn.microsoft.com/en-us/library/dn439780.asp
-// Note, that the snippet was broken there and needed minor massaging
+// Implement make_unique according to N3656. Taken from libcxx's implementation
-// make_unique<T>
-template <class T, class... Types> std::unique_ptr<T> make_unique(Types &&... Args)
+/// \brief Constructs a `new T()` with the given args and returns a
+/// `unique_ptr<T>` which owns the object.
+///
+/// Example:
+///
+/// auto p = make_unique<int>();
+/// auto p = make_unique<std::tuple<int, int>>(0, 1);
+template <class T, class... Args>
+typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
+make_unique(Args &&... args)
{
- return (std::unique_ptr<T>(new T(std::forward<Types>(Args)...)));
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
-// make_unique<T[]>
-template <class T> std::unique_ptr<T[]> make_unique(std::size_t Size)
+/// \brief Constructs a `new T[n]` with the given args and returns a
+/// `unique_ptr<T[]>` which owns the object.
+///
+/// \param n size of the new array.
+///
+/// Example:
+///
+/// auto p = make_unique<int[]>(2); // value-initializes the array with 0's.
+template <class T>
+typename std::enable_if<std::is_array<T>::value && std::extent<T>::value == 0,
+ std::unique_ptr<T>>::type
+make_unique(size_t n)
{
- return (std::unique_ptr<T>(new T[Size]()));
+ return std::unique_ptr<T>(new typename std::remove_extent<T>::type[n]());
}
-// make_unique<T[N]> disallowed
-template <class T, class... Types>
-typename std::enable_if<std::extent<T>::value != 0, void>::type make_unique(Types &&...) = delete;
+/// This function isn't used and is only here to provide better compile errors.
+template <class T, class... Args>
+typename std::enable_if<std::extent<T>::value != 0>::type make_unique(Args &&...) = delete;
}
-
-#endif //MAKE_UNIQUE_H_
+#endif // MAKE_UNIQUE_H_
diff --git a/util/matching_debug_info.hpp b/util/matching_debug_info.hpp
new file mode 100644
index 0000000..faf878e
--- /dev/null
+++ b/util/matching_debug_info.hpp
@@ -0,0 +1,155 @@
+/*
+
+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 (unsigned t = 0; t < candidates_list.size(); t++)
+ {
+ osrm::json::Array timestamps;
+ for (unsigned s = 0; s < candidates_list[t].size(); s++)
+ {
+ osrm::json::Object state;
+ state.values["transitions"] = osrm::json::Array();
+ state.values["coordinate"] = osrm::json::make_array(
+ candidates_list[t][s].first.location.lat / COORDINATE_PRECISION,
+ candidates_list[t][s].first.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 great_circle_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, great_circle_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/MercatorUtil.h b/util/mercator.cpp
similarity index 78%
rename from Util/MercatorUtil.h
rename to util/mercator.cpp
index b4a15b7..0ccd999 100644
--- a/Util/MercatorUtil.h
+++ b/util/mercator.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,19 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MERCATOR_UTIL_H
-#define MERCATOR_UTIL_H
+#include "mercator.hpp"
#include <cmath>
-inline double y2lat(const double a)
+double mercator::y2lat(const double value) noexcept
{
- return 180. * M_1_PI * (2. * std::atan(std::exp(a * M_PI / 180.)) - M_PI_2);
+ return 180. * M_1_PI * (2. * std::atan(std::exp(value * M_PI / 180.)) - M_PI_2);
}
-inline double lat2y(const double a)
+double mercator::lat2y(const double latitude) noexcept
{
- return 180. * M_1_PI * std::log(std::tan(M_PI_4 + a * (M_PI / 180.) / 2.));
+ return 180. * M_1_PI * std::log(std::tan(M_PI_4 + latitude * (M_PI / 180.) / 2.));
}
-
-#endif // MERCATOR_UTIL_H
diff --git a/Util/bearing.hpp b/util/mercator.hpp
similarity index 84%
rename from Util/bearing.hpp
rename to util/mercator.hpp
index a30ec2f..e994c84 100644
--- a/Util/bearing.hpp
+++ b/util/mercator.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,14 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef BEARING_HPP_
-#define BEARING_HPP_
+#ifndef MERCATOR_HPP
+#define MERCATOR_HPP
-#include <string>
-
-struct Bearing
+struct mercator
{
- static std::string Get(const double heading);
+ static double y2lat(const double value) noexcept;
+
+ static double lat2y(const double latitude) noexcept;
};
-#endif // BEARING_HPP_
+#endif // MERCATOR_HPP
diff --git a/Util/osrm_exception.cpp b/util/osrm_exception.cpp
similarity index 63%
rename from Util/osrm_exception.cpp
rename to util/osrm_exception.cpp
index ebdac6d..9738b8e 100644
--- a/Util/osrm_exception.cpp
+++ b/util/osrm_exception.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -29,15 +29,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 { }
+// 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/osrm_exception.hpp b/util/osrm_exception.hpp
similarity index 97%
rename from Util/osrm_exception.hpp
rename to util/osrm_exception.hpp
index ac5044a..e9a0138 100644
--- a/Util/osrm_exception.hpp
+++ b/util/osrm_exception.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
diff --git a/Util/floating_point.hpp b/util/range_algorithms.hpp
similarity index 72%
rename from Util/floating_point.hpp
rename to util/range_algorithms.hpp
index 5c48102..4d01d29 100644
--- a/Util/floating_point.hpp
+++ b/util/range_algorithms.hpp
@@ -1,5 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -24,21 +25,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FLOATING_POINT_HPP
-#define FLOATING_POINT_HPP
-
-#include <cmath>
+#ifndef RANGE_ALGORITHMS_HPP
+#define RANGE_ALGORITHMS_HPP
-#include <limits>
-#include <type_traits>
+#include <algorithm>
namespace osrm
{
-template <typename FloatT> bool epsilon_compare(const FloatT number1, const FloatT number2)
+
+template <class Container>
+auto max_element(const Container &c) -> decltype(std::max_element(c.begin(), c.end()))
+{
+ return std::max_element(c.begin(), c.end());
+}
+
+template <class Container>
+auto max_element(const Container &c) -> decltype(std::max_element(c.cbegin(), c.cend()))
{
- static_assert(std::is_floating_point<FloatT>::value, "type must be floating point");
- return (std::abs(number1 - number2) < std::numeric_limits<FloatT>::epsilon());
+ return std::max_element(c.cbegin(), c.cend());
}
}
-#endif // FLOATING_POINT_HPP
+#endif // RANGE_ALGORITHMS_HPP
diff --git a/Util/ProgramOptions.h b/util/routed_options.hpp
similarity index 81%
rename from Util/ProgramOptions.h
rename to util/routed_options.hpp
index 3329b31..046ab71 100644
--- a/Util/ProgramOptions.h
+++ b/util/routed_options.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,22 +25,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef PROGAM_OPTIONS_H
-#define PROGAM_OPTIONS_H
+#ifndef ROUTED_OPTIONS_HPP
+#define ROUTED_OPTIONS_HPP
#include "git_sha.hpp"
-#include "IniFileUtil.h"
+#include "ini_file.hpp"
#include "osrm_exception.hpp"
#include "simple_logger.hpp"
-#include <osrm/ServerPaths.h>
-
#include <boost/any.hpp>
#include <boost/program_options.hpp>
+#include <osrm/server_paths.hpp>
+
#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;
@@ -151,61 +150,59 @@ inline unsigned GenerateServerProgramOptions(const int argc,
int &ip_port,
int &requested_num_threads,
bool &use_shared_memory,
- bool &trial)
+ bool &trial,
+ int &max_locations_distance_table,
+ int &max_locations_map_matching)
{
// 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>(&paths["config"])
- ->default_value("server.ini"),
+ "config,c", boost::program_options::value<boost::filesystem::path>(&paths["config"])
+ ->default_value("server.ini"),
"Path to a configuration file")(
- "trial",
- boost::program_options::value<bool>(&trial)->implicit_value(true),
+ "trial", boost::program_options::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",
- boost::program_options::value<boost::filesystem::path>(&paths["hsgrdata"]),
+ "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"]),
+ "edgesdata", boost::program_options::value<boost::filesystem::path>(&paths["edgesdata"]),
".edges file")("geometry",
boost::program_options::value<boost::filesystem::path>(&paths["geometries"]),
".geometry file")(
- "ramindex",
- boost::program_options::value<boost::filesystem::path>(&paths["ramindex"]),
+ "ramindex", boost::program_options::value<boost::filesystem::path>(&paths["ramindex"]),
".ramIndex file")(
- "fileindex",
- boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
+ "fileindex", boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
"File index file")(
- "namesdata",
- boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
+ "namesdata", boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
".names file")("timestamp",
boost::program_options::value<boost::filesystem::path>(&paths["timestamp"]),
".timestamp file")(
- "ip,i",
- boost::program_options::value<std::string>(&ip_address)->default_value("0.0.0.0"),
- "IP address")(
- "port,p", boost::program_options::value<int>(&ip_port)->default_value(5000), "TCP/IP port")(
- "threads,t",
- boost::program_options::value<int>(&requested_num_threads)->default_value(8),
+ "ip,i", boost::program_options::value<std::string>(&ip_address)->default_value("0.0.0.0"),
+ "IP address")("port,p", boost::program_options::value<int>(&ip_port)->default_value(5000),
+ "TCP/IP port")(
+ "threads,t", boost::program_options::value<int>(&requested_num_threads)->default_value(8),
"Number of threads to use")(
- "sharedmemory,s",
+ "shared-memory,s",
boost::program_options::value<bool>(&use_shared_memory)->implicit_value(true),
- "Load data from shared memory");
+ "Load data from shared memory")(
+ "max-table-size,m",
+ boost::program_options::value<int>(&max_locations_distance_table)->default_value(100),
+ "Max. locations supported in distance table query")(
+ "max-matching-size,m",
+ boost::program_options::value<int>(&max_locations_map_matching)->default_value(2),
+ "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",
- boost::program_options::value<boost::filesystem::path>(&paths["base"]),
+ "base,b", boost::program_options::value<boost::filesystem::path>(&paths["base"]),
"base path to .osrm file");
// positional option
@@ -251,7 +248,7 @@ inline unsigned GenerateServerProgramOptions(const int argc,
!option_variables.count("base"))
{
SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
- std::string ini_file_contents = ReadIniFileAndLowerContents(path_iterator->second);
+ 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);
@@ -272,8 +269,17 @@ inline unsigned GenerateServerProgramOptions(const int argc,
{
return INIT_OK_START_ENGINE;
}
+ if (1 > max_locations_distance_table)
+ {
+ throw osrm::exception("Max location for distance table must be a positive number");
+ }
+ if (2 > max_locations_map_matching)
+ {
+ throw osrm::exception("Max location for map matching must be at least two");
+ }
+
SimpleLogger().Write() << visible_options;
return INIT_OK_DO_NOT_START_ENGINE;
}
-#endif /* PROGRAM_OPTIONS_H */
+#endif // ROUTED_OPTIONS_HPP
diff --git a/Util/simple_logger.cpp b/util/simple_logger.cpp
similarity index 77%
rename from Util/simple_logger.cpp
rename to util/simple_logger.cpp
index dbbf348..e3f4f8e 100644
--- a/Util/simple_logger.cpp
+++ b/util/simple_logger.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -26,13 +26,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "simple_logger.hpp"
-
-#include "osrm_exception.hpp"
-
-#include <boost/assert.hpp>
-
-#include <cstdio>
-
#ifdef _MSC_VER
#include <io.h>
#define isatty _isatty
@@ -40,17 +33,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#else
#include <unistd.h>
#endif
-
-#include <ostream>
+#include <cstdio>
#include <iostream>
#include <mutex>
+#include <string>
namespace
{
-static const char COL_RESET[] { "\x1b[0m"};
-static const char RED[] { "\x1b[31m"};
+static const char COL_RESET[]{"\x1b[0m"};
+static const char RED[]{"\x1b[31m"};
#ifndef NDEBUG
-static const char YELLOW[] { "\x1b[33m"};
+static const char YELLOW[]{"\x1b[33m"};
#endif
// static const char GREEN[] { "\x1b[32m"};
// static const char BLUE[] { "\x1b[34m"};
@@ -78,34 +71,26 @@ std::mutex &SimpleLogger::get_mutex()
return mtx;
}
-std::ostringstream &SimpleLogger::Write(LogLevel lvl)
+std::ostringstream &SimpleLogger::Write(LogLevel lvl) noexcept
{
std::lock_guard<std::mutex> lock(get_mutex());
- try
+ level = lvl;
+ os << "[";
+ switch (level)
{
- level = lvl;
- os << "[";
- switch (level)
- {
- case logWARNING:
- os << "warn";
- break;
- case logDEBUG:
+ case logWARNING:
+ os << "warn";
+ break;
+ case logDEBUG:
#ifndef NDEBUG
- os << "debug";
+ os << "debug";
#endif
- break;
- default: //logINFO:
- os << "info";
- break;
- }
- os << "] ";
- }
- catch (const std::exception &e)
- {
- // encapsulate in osrm::exception
- throw osrm::exception(std::string(e.what()) + ", getting ostringstream");
+ break;
+ default: // logINFO:
+ os << "info";
+ break;
}
+ os << "] ";
return os;
}
@@ -127,7 +112,8 @@ SimpleLogger::~SimpleLogger()
<< std::endl;
#endif
break;
- default: //logINFO:
+ case logINFO:
+ default:
std::cout << os.str() << (is_terminal ? COL_RESET : "") << std::endl;
break;
}
diff --git a/Util/simple_logger.hpp b/util/simple_logger.hpp
similarity index 94%
rename from Util/simple_logger.hpp
rename to util/simple_logger.hpp
index 077fa2e..df61a9d 100644
--- a/Util/simple_logger.hpp
+++ b/util/simple_logger.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -64,7 +64,7 @@ class SimpleLogger
virtual ~SimpleLogger();
std::mutex &get_mutex();
- std::ostringstream &Write(LogLevel l = logINFO);
+ std::ostringstream &Write(LogLevel l = logINFO) noexcept;
private:
std::ostringstream os;
diff --git a/Util/std_hash.hpp b/util/std_hash.hpp
similarity index 81%
rename from Util/std_hash.hpp
rename to util/std_hash.hpp
index 59c4ad9..9e78fcc 100644
--- a/Util/std_hash.hpp
+++ b/util/std_hash.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -33,29 +33,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 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 {
+namespace
+{
-template<typename T>
-void hash_combine(std::size_t &seed, const T& val)
+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> 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)
+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 ...);
+ hash_val(seed, args...);
}
-template<typename ... Types>
-std::size_t hash_val(const Types&... args)
+template <typename... Types> std::size_t hash_val(const Types &... args)
{
std::size_t seed = 0;
hash_val(seed, args...);
diff --git a/Util/string_util.hpp b/util/string_util.hpp
similarity index 80%
rename from Util/string_util.hpp
rename to util/string_util.hpp
index 08af554..3bfce00 100644
--- a/Util/string_util.hpp
+++ b/util/string_util.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2015, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -41,32 +41,43 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// work with negative values to prevent overflowing when taking -value
template <int length, int precision> static inline char *printInt(char *buffer, int value)
{
- bool minus = true;
- if (value > 0)
+ static_assert(length > 0, "length must be positive");
+ static_assert(precision > 0, "precision must be positive");
+
+ const bool minus = [&value]
{
- minus = false;
- value = -value;
- }
+ if (value >= 0)
+ {
+ value = -value;
+ return false;
+ }
+ return true;
+ }();
+
buffer += length - 1;
- for (int i = 0; i < precision; i++)
+ for (int i = 0; i < precision; ++i)
{
*buffer = '0' - (value % 10);
value /= 10;
- buffer--;
+ --buffer;
}
*buffer = '.';
- buffer--;
- for (int i = precision + 1; i < length; i++)
+ --buffer;
+
+ for (int i = precision + 1; i < length; ++i)
{
*buffer = '0' - (value % 10);
value /= 10;
if (value == 0)
+ {
break;
- buffer--;
+ }
+ --buffer;
}
+
if (minus)
{
- buffer--;
+ --buffer;
*buffer = '-';
}
return buffer;
@@ -77,13 +88,14 @@ inline void replaceAll(std::string &s, const std::string &sub, const std::string
boost::replace_all(s, sub, other);
}
-inline std::string EscapeJSONString(const std::string &input)
+inline std::string escape_JSON(const std::string &input)
{
+ // escape and skip reallocations if possible
std::string output;
- output.reserve(input.size());
- for (auto iter = input.begin(); iter != input.end(); ++iter)
+ output.reserve(input.size() + 4); // +4 assumes two backslashes on avg
+ for (const char letter : input)
{
- switch (iter[0])
+ switch (letter)
{
case '\\':
output += "\\\\";
@@ -110,23 +122,19 @@ inline std::string EscapeJSONString(const std::string &input)
output += "\\t";
break;
default:
- output += *iter;
+ output.append(1, letter);
break;
}
}
return output;
}
-static std::string originals[] = {"&", "\"", "<", ">", "'", "[", "]", "\\"};
-static std::string entities[] = {
- "&", """, "<", ">", "'", "&91;", "&93;", " \"};
-
inline std::size_t URIDecode(const std::string &input, std::string &output)
{
- auto src_iter = input.begin();
+ auto src_iter = std::begin(input);
output.resize(input.size() + 1);
std::size_t decoded_length = 0;
- for (decoded_length = 0; src_iter != input.end(); ++decoded_length)
+ for (decoded_length = 0; src_iter != std::end(input); ++decoded_length)
{
if (src_iter[0] == '%' && src_iter[1] && src_iter[2] && isxdigit(src_iter[1]) &&
isxdigit(src_iter[2]))
diff --git a/Util/timing_util.hpp b/util/timing_util.hpp
similarity index 55%
rename from Util/timing_util.hpp
rename to util/timing_util.hpp
index 1bbea47..c0c59c8 100644
--- a/Util/timing_util.hpp
+++ b/util/timing_util.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -42,39 +42,49 @@ struct GlobalTimer
class GlobalTimerFactory
{
-public:
- static GlobalTimerFactory& get()
+ public:
+ static GlobalTimerFactory &get()
{
static GlobalTimerFactory instance;
return instance;
}
- GlobalTimer& getGlobalTimer(const std::string& name)
+ GlobalTimer &getGlobalTimer(const std::string &name)
{
std::lock_guard<std::mutex> lock(map_mutex);
return timer_map[name];
}
-private:
+ private:
std::mutex map_mutex;
std::unordered_map<std::string, GlobalTimer> timer_map;
};
-#define GLOBAL_TIMER_AQUIRE(_X) auto& _X##_global_timer = GlobalTimerFactory::get().getGlobalTimer(#_X)
+#define GLOBAL_TIMER_AQUIRE(_X) \
+ auto &_X##_global_timer = GlobalTimerFactory::get().getGlobalTimer(#_X)
#define GLOBAL_TIMER_RESET(_X) _X##_global_timer.time = 0
#define GLOBAL_TIMER_START(_X) TIMER_START(_X)
-#define GLOBAL_TIMER_STOP(_X) TIMER_STOP(_X); _X##_global_timer.time += TIMER_NSEC(_X)
+#define GLOBAL_TIMER_STOP(_X) \
+ TIMER_STOP(_X); \
+ _X##_global_timer.time += TIMER_NSEC(_X)
#define GLOBAL_TIMER_NSEC(_X) static_cast<double>(_X##_global_timer.time)
#define GLOBAL_TIMER_USEC(_X) (_X##_global_timer.time / 1000.0)
#define GLOBAL_TIMER_MSEC(_X) (_X##_global_timer.time / 1000.0 / 1000.0)
-#define GLOBAL_TIMER_SEC(_X) (_X##_global_timer.time / 1000.0 / 1000.0 / 1000.0)
+#define GLOBAL_TIMER_SEC(_X) (_X##_global_timer.time / 1000.0 / 1000.0 / 1000.0)
#define TIMER_START(_X) auto _X##_start = std::chrono::steady_clock::now(), _X##_stop = _X##_start
#define TIMER_STOP(_X) _X##_stop = std::chrono::steady_clock::now()
-#define TIMER_NSEC(_X) std::chrono::duration_cast<std::chrono::nanoseconds>(_X##_stop - _X##_start).count()
-#define TIMER_USEC(_X) std::chrono::duration_cast<std::chrono::microseconds>(_X##_stop - _X##_start).count()
-#define TIMER_MSEC(_X) (0.000001*std::chrono::duration_cast<std::chrono::nanoseconds>(_X##_stop - _X##_start).count())
-#define TIMER_SEC(_X) (0.000001*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()
+#define TIMER_NSEC(_X) \
+ std::chrono::duration_cast<std::chrono::nanoseconds>(_X##_stop - _X##_start).count()
+#define TIMER_USEC(_X) \
+ std::chrono::duration_cast<std::chrono::microseconds>(_X##_stop - _X##_start).count()
+#define TIMER_MSEC(_X) \
+ (0.000001 * \
+ std::chrono::duration_cast<std::chrono::nanoseconds>(_X##_stop - _X##_start).count())
+#define TIMER_SEC(_X) \
+ (0.000001 * \
+ 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/util/trigonometry_table.hpp
new file mode 100644
index 0000000..234a94e
--- /dev/null
+++ b/util/trigonometry_table.hpp
@@ -0,0 +1,448 @@
+/*
+
+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 <cmath>
+
+#include <limits>
+
+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,
+ 0x01e9, 0x01fd, 0x0211, 0x0226, 0x023a, 0x024e, 0x0263, 0x0277, 0x028c, 0x02a0, 0x02b4, 0x02c9,
+ 0x02dd, 0x02f1, 0x0306, 0x031a, 0x032f, 0x0343, 0x0357, 0x036c, 0x0380, 0x0394, 0x03a9, 0x03bd,
+ 0x03d2, 0x03e6, 0x03fa, 0x040f, 0x0423, 0x0437, 0x044c, 0x0460, 0x0475, 0x0489, 0x049d, 0x04b2,
+ 0x04c6, 0x04da, 0x04ef, 0x0503, 0x0517, 0x052c, 0x0540, 0x0555, 0x0569, 0x057d, 0x0592, 0x05a6,
+ 0x05ba, 0x05cf, 0x05e3, 0x05f8, 0x060c, 0x0620, 0x0635, 0x0649, 0x065d, 0x0672, 0x0686, 0x069b,
+ 0x06af, 0x06c3, 0x06d8, 0x06ec, 0x0700, 0x0715, 0x0729, 0x073d, 0x0752, 0x0766, 0x077b, 0x078f,
+ 0x07a3, 0x07b8, 0x07cc, 0x07e0, 0x07f5, 0x0809, 0x081d, 0x0832, 0x0846, 0x085b, 0x086f, 0x0883,
+ 0x0898, 0x08ac, 0x08c0, 0x08d5, 0x08e9, 0x08fd, 0x0912, 0x0926, 0x093b, 0x094f, 0x0963, 0x0978,
+ 0x098c, 0x09a0, 0x09b5, 0x09c9, 0x09dd, 0x09f2, 0x0a06, 0x0a1a, 0x0a2f, 0x0a43, 0x0a58, 0x0a6c,
+ 0x0a80, 0x0a95, 0x0aa9, 0x0abd, 0x0ad2, 0x0ae6, 0x0afa, 0x0b0f, 0x0b23, 0x0b37, 0x0b4c, 0x0b60,
+ 0x0b75, 0x0b89, 0x0b9d, 0x0bb2, 0x0bc6, 0x0bda, 0x0bef, 0x0c03, 0x0c17, 0x0c2c, 0x0c40, 0x0c54,
+ 0x0c69, 0x0c7d, 0x0c91, 0x0ca6, 0x0cba, 0x0cce, 0x0ce3, 0x0cf7, 0x0d0b, 0x0d20, 0x0d34, 0x0d48,
+ 0x0d5d, 0x0d71, 0x0d86, 0x0d9a, 0x0dae, 0x0dc3, 0x0dd7, 0x0deb, 0x0e00, 0x0e14, 0x0e28, 0x0e3d,
+ 0x0e51, 0x0e65, 0x0e7a, 0x0e8e, 0x0ea2, 0x0eb7, 0x0ecb, 0x0edf, 0x0ef4, 0x0f08, 0x0f1c, 0x0f31,
+ 0x0f45, 0x0f59, 0x0f6e, 0x0f82, 0x0f96, 0x0fab, 0x0fbf, 0x0fd3, 0x0fe8, 0x0ffc, 0x1010, 0x1025,
+ 0x1039, 0x104d, 0x1062, 0x1076, 0x108a, 0x109e, 0x10b3, 0x10c7, 0x10db, 0x10f0, 0x1104, 0x1118,
+ 0x112d, 0x1141, 0x1155, 0x116a, 0x117e, 0x1192, 0x11a7, 0x11bb, 0x11cf, 0x11e4, 0x11f8, 0x120c,
+ 0x1221, 0x1235, 0x1249, 0x125d, 0x1272, 0x1286, 0x129a, 0x12af, 0x12c3, 0x12d7, 0x12ec, 0x1300,
+ 0x1314, 0x1329, 0x133d, 0x1351, 0x1365, 0x137a, 0x138e, 0x13a2, 0x13b7, 0x13cb, 0x13df, 0x13f4,
+ 0x1408, 0x141c, 0x1431, 0x1445, 0x1459, 0x146d, 0x1482, 0x1496, 0x14aa, 0x14bf, 0x14d3, 0x14e7,
+ 0x14fb, 0x1510, 0x1524, 0x1538, 0x154d, 0x1561, 0x1575, 0x1589, 0x159e, 0x15b2, 0x15c6, 0x15db,
+ 0x15ef, 0x1603, 0x1617, 0x162c, 0x1640, 0x1654, 0x1669, 0x167d, 0x1691, 0x16a5, 0x16ba, 0x16ce,
+ 0x16e2, 0x16f7, 0x170b, 0x171f, 0x1733, 0x1748, 0x175c, 0x1770, 0x1784, 0x1799, 0x17ad, 0x17c1,
+ 0x17d6, 0x17ea, 0x17fe, 0x1812, 0x1827, 0x183b, 0x184f, 0x1863, 0x1878, 0x188c, 0x18a0, 0x18b4,
+ 0x18c9, 0x18dd, 0x18f1, 0x1905, 0x191a, 0x192e, 0x1942, 0x1957, 0x196b, 0x197f, 0x1993, 0x19a8,
+ 0x19bc, 0x19d0, 0x19e4, 0x19f9, 0x1a0d, 0x1a21, 0x1a35, 0x1a49, 0x1a5e, 0x1a72, 0x1a86, 0x1a9a,
+ 0x1aaf, 0x1ac3, 0x1ad7, 0x1aeb, 0x1b00, 0x1b14, 0x1b28, 0x1b3c, 0x1b51, 0x1b65, 0x1b79, 0x1b8d,
+ 0x1ba2, 0x1bb6, 0x1bca, 0x1bde, 0x1bf2, 0x1c07, 0x1c1b, 0x1c2f, 0x1c43, 0x1c58, 0x1c6c, 0x1c80,
+ 0x1c94, 0x1ca8, 0x1cbd, 0x1cd1, 0x1ce5, 0x1cf9, 0x1d0e, 0x1d22, 0x1d36, 0x1d4a, 0x1d5e, 0x1d73,
+ 0x1d87, 0x1d9b, 0x1daf, 0x1dc3, 0x1dd8, 0x1dec, 0x1e00, 0x1e14, 0x1e28, 0x1e3d, 0x1e51, 0x1e65,
+ 0x1e79, 0x1e8d, 0x1ea2, 0x1eb6, 0x1eca, 0x1ede, 0x1ef2, 0x1f07, 0x1f1b, 0x1f2f, 0x1f43, 0x1f57,
+ 0x1f6c, 0x1f80, 0x1f94, 0x1fa8, 0x1fbc, 0x1fd1, 0x1fe5, 0x1ff9, 0x200d, 0x2021, 0x2035, 0x204a,
+ 0x205e, 0x2072, 0x2086, 0x209a, 0x20ae, 0x20c3, 0x20d7, 0x20eb, 0x20ff, 0x2113, 0x2127, 0x213c,
+ 0x2150, 0x2164, 0x2178, 0x218c, 0x21a0, 0x21b5, 0x21c9, 0x21dd, 0x21f1, 0x2205, 0x2219, 0x222e,
+ 0x2242, 0x2256, 0x226a, 0x227e, 0x2292, 0x22a6, 0x22bb, 0x22cf, 0x22e3, 0x22f7, 0x230b, 0x231f,
+ 0x2333, 0x2348, 0x235c, 0x2370, 0x2384, 0x2398, 0x23ac, 0x23c0, 0x23d5, 0x23e9, 0x23fd, 0x2411,
+ 0x2425, 0x2439, 0x244d, 0x2461, 0x2476, 0x248a, 0x249e, 0x24b2, 0x24c6, 0x24da, 0x24ee, 0x2502,
+ 0x2517, 0x252b, 0x253f, 0x2553, 0x2567, 0x257b, 0x258f, 0x25a3, 0x25b7, 0x25cb, 0x25e0, 0x25f4,
+ 0x2608, 0x261c, 0x2630, 0x2644, 0x2658, 0x266c, 0x2680, 0x2694, 0x26a9, 0x26bd, 0x26d1, 0x26e5,
+ 0x26f9, 0x270d, 0x2721, 0x2735, 0x2749, 0x275d, 0x2771, 0x2785, 0x279a, 0x27ae, 0x27c2, 0x27d6,
+ 0x27ea, 0x27fe, 0x2812, 0x2826, 0x283a, 0x284e, 0x2862, 0x2876, 0x288a, 0x289e, 0x28b3, 0x28c7,
+ 0x28db, 0x28ef, 0x2903, 0x2917, 0x292b, 0x293f, 0x2953, 0x2967, 0x297b, 0x298f, 0x29a3, 0x29b7,
+ 0x29cb, 0x29df, 0x29f3, 0x2a07, 0x2a1b, 0x2a2f, 0x2a43, 0x2a58, 0x2a6c, 0x2a80, 0x2a94, 0x2aa8,
+ 0x2abc, 0x2ad0, 0x2ae4, 0x2af8, 0x2b0c, 0x2b20, 0x2b34, 0x2b48, 0x2b5c, 0x2b70, 0x2b84, 0x2b98,
+ 0x2bac, 0x2bc0, 0x2bd4, 0x2be8, 0x2bfc, 0x2c10, 0x2c24, 0x2c38, 0x2c4c, 0x2c60, 0x2c74, 0x2c88,
+ 0x2c9c, 0x2cb0, 0x2cc4, 0x2cd8, 0x2cec, 0x2d00, 0x2d14, 0x2d28, 0x2d3c, 0x2d50, 0x2d64, 0x2d78,
+ 0x2d8c, 0x2da0, 0x2db4, 0x2dc8, 0x2ddc, 0x2df0, 0x2e04, 0x2e18, 0x2e2c, 0x2e40, 0x2e54, 0x2e68,
+ 0x2e7c, 0x2e90, 0x2ea3, 0x2eb7, 0x2ecb, 0x2edf, 0x2ef3, 0x2f07, 0x2f1b, 0x2f2f, 0x2f43, 0x2f57,
+ 0x2f6b, 0x2f7f, 0x2f93, 0x2fa7, 0x2fbb, 0x2fcf, 0x2fe3, 0x2ff7, 0x300b, 0x301e, 0x3032, 0x3046,
+ 0x305a, 0x306e, 0x3082, 0x3096, 0x30aa, 0x30be, 0x30d2, 0x30e6, 0x30fa, 0x310e, 0x3122, 0x3135,
+ 0x3149, 0x315d, 0x3171, 0x3185, 0x3199, 0x31ad, 0x31c1, 0x31d5, 0x31e9, 0x31fd, 0x3210, 0x3224,
+ 0x3238, 0x324c, 0x3260, 0x3274, 0x3288, 0x329c, 0x32b0, 0x32c3, 0x32d7, 0x32eb, 0x32ff, 0x3313,
+ 0x3327, 0x333b, 0x334f, 0x3363, 0x3376, 0x338a, 0x339e, 0x33b2, 0x33c6, 0x33da, 0x33ee, 0x3401,
+ 0x3415, 0x3429, 0x343d, 0x3451, 0x3465, 0x3479, 0x348c, 0x34a0, 0x34b4, 0x34c8, 0x34dc, 0x34f0,
+ 0x3504, 0x3517, 0x352b, 0x353f, 0x3553, 0x3567, 0x357b, 0x358e, 0x35a2, 0x35b6, 0x35ca, 0x35de,
+ 0x35f2, 0x3605, 0x3619, 0x362d, 0x3641, 0x3655, 0x3668, 0x367c, 0x3690, 0x36a4, 0x36b8, 0x36cb,
+ 0x36df, 0x36f3, 0x3707, 0x371b, 0x372f, 0x3742, 0x3756, 0x376a, 0x377e, 0x3791, 0x37a5, 0x37b9,
+ 0x37cd, 0x37e1, 0x37f4, 0x3808, 0x381c, 0x3830, 0x3844, 0x3857, 0x386b, 0x387f, 0x3893, 0x38a6,
+ 0x38ba, 0x38ce, 0x38e2, 0x38f5, 0x3909, 0x391d, 0x3931, 0x3944, 0x3958, 0x396c, 0x3980, 0x3993,
+ 0x39a7, 0x39bb, 0x39cf, 0x39e2, 0x39f6, 0x3a0a, 0x3a1e, 0x3a31, 0x3a45, 0x3a59, 0x3a6d, 0x3a80,
+ 0x3a94, 0x3aa8, 0x3abb, 0x3acf, 0x3ae3, 0x3af7, 0x3b0a, 0x3b1e, 0x3b32, 0x3b45, 0x3b59, 0x3b6d,
+ 0x3b81, 0x3b94, 0x3ba8, 0x3bbc, 0x3bcf, 0x3be3, 0x3bf7, 0x3c0b, 0x3c1e, 0x3c32, 0x3c46, 0x3c59,
+ 0x3c6d, 0x3c81, 0x3c94, 0x3ca8, 0x3cbc, 0x3ccf, 0x3ce3, 0x3cf7, 0x3d0a, 0x3d1e, 0x3d32, 0x3d45,
+ 0x3d59, 0x3d6d, 0x3d80, 0x3d94, 0x3da8, 0x3dbb, 0x3dcf, 0x3de3, 0x3df6, 0x3e0a, 0x3e1e, 0x3e31,
+ 0x3e45, 0x3e59, 0x3e6c, 0x3e80, 0x3e93, 0x3ea7, 0x3ebb, 0x3ece, 0x3ee2, 0x3ef6, 0x3f09, 0x3f1d,
+ 0x3f30, 0x3f44, 0x3f58, 0x3f6b, 0x3f7f, 0x3f93, 0x3fa6, 0x3fba, 0x3fcd, 0x3fe1, 0x3ff5, 0x4008,
+ 0x401c, 0x402f, 0x4043, 0x4057, 0x406a, 0x407e, 0x4091, 0x40a5, 0x40b8, 0x40cc, 0x40e0, 0x40f3,
+ 0x4107, 0x411a, 0x412e, 0x4142, 0x4155, 0x4169, 0x417c, 0x4190, 0x41a3, 0x41b7, 0x41ca, 0x41de,
+ 0x41f2, 0x4205, 0x4219, 0x422c, 0x4240, 0x4253, 0x4267, 0x427a, 0x428e, 0x42a1, 0x42b5, 0x42c9,
+ 0x42dc, 0x42f0, 0x4303, 0x4317, 0x432a, 0x433e, 0x4351, 0x4365, 0x4378, 0x438c, 0x439f, 0x43b3,
+ 0x43c6, 0x43da, 0x43ed, 0x4401, 0x4414, 0x4428, 0x443b, 0x444f, 0x4462, 0x4476, 0x4489, 0x449d,
+ 0x44b0, 0x44c4, 0x44d7, 0x44eb, 0x44fe, 0x4512, 0x4525, 0x4539, 0x454c, 0x4560, 0x4573, 0x4586,
+ 0x459a, 0x45ad, 0x45c1, 0x45d4, 0x45e8, 0x45fb, 0x460f, 0x4622, 0x4636, 0x4649, 0x465c, 0x4670,
+ 0x4683, 0x4697, 0x46aa, 0x46be, 0x46d1, 0x46e5, 0x46f8, 0x470b, 0x471f, 0x4732, 0x4746, 0x4759,
+ 0x476c, 0x4780, 0x4793, 0x47a7, 0x47ba, 0x47cd, 0x47e1, 0x47f4, 0x4808, 0x481b, 0x482e, 0x4842,
+ 0x4855, 0x4869, 0x487c, 0x488f, 0x48a3, 0x48b6, 0x48ca, 0x48dd, 0x48f0, 0x4904, 0x4917, 0x492a,
+ 0x493e, 0x4951, 0x4965, 0x4978, 0x498b, 0x499f, 0x49b2, 0x49c5, 0x49d9, 0x49ec, 0x49ff, 0x4a13,
+ 0x4a26, 0x4a39, 0x4a4d, 0x4a60, 0x4a73, 0x4a87, 0x4a9a, 0x4aad, 0x4ac1, 0x4ad4, 0x4ae7, 0x4afb,
+ 0x4b0e, 0x4b21, 0x4b35, 0x4b48, 0x4b5b, 0x4b6f, 0x4b82, 0x4b95, 0x4ba8, 0x4bbc, 0x4bcf, 0x4be2,
+ 0x4bf6, 0x4c09, 0x4c1c, 0x4c2f, 0x4c43, 0x4c56, 0x4c69, 0x4c7d, 0x4c90, 0x4ca3, 0x4cb6, 0x4cca,
+ 0x4cdd, 0x4cf0, 0x4d03, 0x4d17, 0x4d2a, 0x4d3d, 0x4d50, 0x4d64, 0x4d77, 0x4d8a, 0x4d9d, 0x4db1,
+ 0x4dc4, 0x4dd7, 0x4dea, 0x4dfe, 0x4e11, 0x4e24, 0x4e37, 0x4e4b, 0x4e5e, 0x4e71, 0x4e84, 0x4e97,
+ 0x4eab, 0x4ebe, 0x4ed1, 0x4ee4, 0x4ef7, 0x4f0b, 0x4f1e, 0x4f31, 0x4f44, 0x4f57, 0x4f6b, 0x4f7e,
+ 0x4f91, 0x4fa4, 0x4fb7, 0x4fcb, 0x4fde, 0x4ff1, 0x5004, 0x5017, 0x502a, 0x503e, 0x5051, 0x5064,
+ 0x5077, 0x508a, 0x509d, 0x50b1, 0x50c4, 0x50d7, 0x50ea, 0x50fd, 0x5110, 0x5123, 0x5137, 0x514a,
+ 0x515d, 0x5170, 0x5183, 0x5196, 0x51a9, 0x51bc, 0x51d0, 0x51e3, 0x51f6, 0x5209, 0x521c, 0x522f,
+ 0x5242, 0x5255, 0x5268, 0x527c, 0x528f, 0x52a2, 0x52b5, 0x52c8, 0x52db, 0x52ee, 0x5301, 0x5314,
+ 0x5327, 0x533a, 0x534e, 0x5361, 0x5374, 0x5387, 0x539a, 0x53ad, 0x53c0, 0x53d3, 0x53e6, 0x53f9,
+ 0x540c, 0x541f, 0x5432, 0x5445, 0x5458, 0x546b, 0x547e, 0x5491, 0x54a5, 0x54b8, 0x54cb, 0x54de,
+ 0x54f1, 0x5504, 0x5517, 0x552a, 0x553d, 0x5550, 0x5563, 0x5576, 0x5589, 0x559c, 0x55af, 0x55c2,
+ 0x55d5, 0x55e8, 0x55fb, 0x560e, 0x5621, 0x5634, 0x5647, 0x565a, 0x566d, 0x5680, 0x5693, 0x56a6,
+ 0x56b9, 0x56cb, 0x56de, 0x56f1, 0x5704, 0x5717, 0x572a, 0x573d, 0x5750, 0x5763, 0x5776, 0x5789,
+ 0x579c, 0x57af, 0x57c2, 0x57d5, 0x57e8, 0x57fb, 0x580e, 0x5820, 0x5833, 0x5846, 0x5859, 0x586c,
+ 0x587f, 0x5892, 0x58a5, 0x58b8, 0x58cb, 0x58de, 0x58f0, 0x5903, 0x5916, 0x5929, 0x593c, 0x594f,
+ 0x5962, 0x5975, 0x5988, 0x599a, 0x59ad, 0x59c0, 0x59d3, 0x59e6, 0x59f9, 0x5a0c, 0x5a1f, 0x5a31,
+ 0x5a44, 0x5a57, 0x5a6a, 0x5a7d, 0x5a90, 0x5aa2, 0x5ab5, 0x5ac8, 0x5adb, 0x5aee, 0x5b01, 0x5b13,
+ 0x5b26, 0x5b39, 0x5b4c, 0x5b5f, 0x5b72, 0x5b84, 0x5b97, 0x5baa, 0x5bbd, 0x5bd0, 0x5be2, 0x5bf5,
+ 0x5c08, 0x5c1b, 0x5c2e, 0x5c40, 0x5c53, 0x5c66, 0x5c79, 0x5c8c, 0x5c9e, 0x5cb1, 0x5cc4, 0x5cd7,
+ 0x5ce9, 0x5cfc, 0x5d0f, 0x5d22, 0x5d34, 0x5d47, 0x5d5a, 0x5d6d, 0x5d7f, 0x5d92, 0x5da5, 0x5db8,
+ 0x5dca, 0x5ddd, 0x5df0, 0x5e03, 0x5e15, 0x5e28, 0x5e3b, 0x5e4d, 0x5e60, 0x5e73, 0x5e86, 0x5e98,
+ 0x5eab, 0x5ebe, 0x5ed0, 0x5ee3, 0x5ef6, 0x5f09, 0x5f1b, 0x5f2e, 0x5f41, 0x5f53, 0x5f66, 0x5f79,
+ 0x5f8b, 0x5f9e, 0x5fb1, 0x5fc3, 0x5fd6, 0x5fe9, 0x5ffb, 0x600e, 0x6021, 0x6033, 0x6046, 0x6059,
+ 0x606b, 0x607e, 0x6091, 0x60a3, 0x60b6, 0x60c8, 0x60db, 0x60ee, 0x6100, 0x6113, 0x6126, 0x6138,
+ 0x614b, 0x615d, 0x6170, 0x6183, 0x6195, 0x61a8, 0x61ba, 0x61cd, 0x61e0, 0x61f2, 0x6205, 0x6217,
+ 0x622a, 0x623d, 0x624f, 0x6262, 0x6274, 0x6287, 0x6299, 0x62ac, 0x62bf, 0x62d1, 0x62e4, 0x62f6,
+ 0x6309, 0x631b, 0x632e, 0x6340, 0x6353, 0x6366, 0x6378, 0x638b, 0x639d, 0x63b0, 0x63c2, 0x63d5,
+ 0x63e7, 0x63fa, 0x640c, 0x641f, 0x6431, 0x6444, 0x6456, 0x6469, 0x647b, 0x648e, 0x64a0, 0x64b3,
+ 0x64c5, 0x64d8, 0x64ea, 0x64fd, 0x650f, 0x6522, 0x6534, 0x6547, 0x6559, 0x656c, 0x657e, 0x6591,
+ 0x65a3, 0x65b5, 0x65c8, 0x65da, 0x65ed, 0x65ff, 0x6612, 0x6624, 0x6637, 0x6649, 0x665b, 0x666e,
+ 0x6680, 0x6693, 0x66a5, 0x66b8, 0x66ca, 0x66dc, 0x66ef, 0x6701, 0x6714, 0x6726, 0x6738, 0x674b,
+ 0x675d, 0x6770, 0x6782, 0x6794, 0x67a7, 0x67b9, 0x67cc, 0x67de, 0x67f0, 0x6803, 0x6815, 0x6827,
+ 0x683a, 0x684c, 0x685e, 0x6871, 0x6883, 0x6896, 0x68a8, 0x68ba, 0x68cd, 0x68df, 0x68f1, 0x6904,
+ 0x6916, 0x6928, 0x693b, 0x694d, 0x695f, 0x6972, 0x6984, 0x6996, 0x69a8, 0x69bb, 0x69cd, 0x69df,
+ 0x69f2, 0x6a04, 0x6a16, 0x6a29, 0x6a3b, 0x6a4d, 0x6a5f, 0x6a72, 0x6a84, 0x6a96, 0x6aa9, 0x6abb,
+ 0x6acd, 0x6adf, 0x6af2, 0x6b04, 0x6b16, 0x6b28, 0x6b3b, 0x6b4d, 0x6b5f, 0x6b71, 0x6b84, 0x6b96,
+ 0x6ba8, 0x6bba, 0x6bcd, 0x6bdf, 0x6bf1, 0x6c03, 0x6c15, 0x6c28, 0x6c3a, 0x6c4c, 0x6c5e, 0x6c70,
+ 0x6c83, 0x6c95, 0x6ca7, 0x6cb9, 0x6ccb, 0x6cde, 0x6cf0, 0x6d02, 0x6d14, 0x6d26, 0x6d39, 0x6d4b,
+ 0x6d5d, 0x6d6f, 0x6d81, 0x6d93, 0x6da6, 0x6db8, 0x6dca, 0x6ddc, 0x6dee, 0x6e00, 0x6e12, 0x6e25,
+ 0x6e37, 0x6e49, 0x6e5b, 0x6e6d, 0x6e7f, 0x6e91, 0x6ea3, 0x6eb6, 0x6ec8, 0x6eda, 0x6eec, 0x6efe,
+ 0x6f10, 0x6f22, 0x6f34, 0x6f46, 0x6f58, 0x6f6b, 0x6f7d, 0x6f8f, 0x6fa1, 0x6fb3, 0x6fc5, 0x6fd7,
+ 0x6fe9, 0x6ffb, 0x700d, 0x701f, 0x7031, 0x7043, 0x7055, 0x7068, 0x707a, 0x708c, 0x709e, 0x70b0,
+ 0x70c2, 0x70d4, 0x70e6, 0x70f8, 0x710a, 0x711c, 0x712e, 0x7140, 0x7152, 0x7164, 0x7176, 0x7188,
+ 0x719a, 0x71ac, 0x71be, 0x71d0, 0x71e2, 0x71f4, 0x7206, 0x7218, 0x722a, 0x723c, 0x724e, 0x7260,
+ 0x7272, 0x7284, 0x7296, 0x72a8, 0x72ba, 0x72cc, 0x72dd, 0x72ef, 0x7301, 0x7313, 0x7325, 0x7337,
+ 0x7349, 0x735b, 0x736d, 0x737f, 0x7391, 0x73a3, 0x73b5, 0x73c7, 0x73d8, 0x73ea, 0x73fc, 0x740e,
+ 0x7420, 0x7432, 0x7444, 0x7456, 0x7468, 0x747a, 0x748b, 0x749d, 0x74af, 0x74c1, 0x74d3, 0x74e5,
+ 0x74f7, 0x7509, 0x751a, 0x752c, 0x753e, 0x7550, 0x7562, 0x7574, 0x7585, 0x7597, 0x75a9, 0x75bb,
+ 0x75cd, 0x75df, 0x75f0, 0x7602, 0x7614, 0x7626, 0x7638, 0x764a, 0x765b, 0x766d, 0x767f, 0x7691,
+ 0x76a3, 0x76b4, 0x76c6, 0x76d8, 0x76ea, 0x76fb, 0x770d, 0x771f, 0x7731, 0x7743, 0x7754, 0x7766,
+ 0x7778, 0x778a, 0x779b, 0x77ad, 0x77bf, 0x77d1, 0x77e2, 0x77f4, 0x7806, 0x7818, 0x7829, 0x783b,
+ 0x784d, 0x785e, 0x7870, 0x7882, 0x7894, 0x78a5, 0x78b7, 0x78c9, 0x78da, 0x78ec, 0x78fe, 0x7910,
+ 0x7921, 0x7933, 0x7945, 0x7956, 0x7968, 0x797a, 0x798b, 0x799d, 0x79af, 0x79c0, 0x79d2, 0x79e4,
+ 0x79f5, 0x7a07, 0x7a19, 0x7a2a, 0x7a3c, 0x7a4e, 0x7a5f, 0x7a71, 0x7a82, 0x7a94, 0x7aa6, 0x7ab7,
+ 0x7ac9, 0x7adb, 0x7aec, 0x7afe, 0x7b0f, 0x7b21, 0x7b33, 0x7b44, 0x7b56, 0x7b67, 0x7b79, 0x7b8b,
+ 0x7b9c, 0x7bae, 0x7bbf, 0x7bd1, 0x7be2, 0x7bf4, 0x7c06, 0x7c17, 0x7c29, 0x7c3a, 0x7c4c, 0x7c5d,
+ 0x7c6f, 0x7c81, 0x7c92, 0x7ca4, 0x7cb5, 0x7cc7, 0x7cd8, 0x7cea, 0x7cfb, 0x7d0d, 0x7d1e, 0x7d30,
+ 0x7d41, 0x7d53, 0x7d64, 0x7d76, 0x7d87, 0x7d99, 0x7daa, 0x7dbc, 0x7dcd, 0x7ddf, 0x7df0, 0x7e02,
+ 0x7e13, 0x7e25, 0x7e36, 0x7e48, 0x7e59, 0x7e6b, 0x7e7c, 0x7e8e, 0x7e9f, 0x7eb0, 0x7ec2, 0x7ed3,
+ 0x7ee5, 0x7ef6, 0x7f08, 0x7f19, 0x7f2b, 0x7f3c, 0x7f4d, 0x7f5f, 0x7f70, 0x7f82, 0x7f93, 0x7fa4,
+ 0x7fb6, 0x7fc7, 0x7fd9, 0x7fea, 0x7ffb, 0x800d, 0x801e, 0x8030, 0x8041, 0x8052, 0x8064, 0x8075,
+ 0x8086, 0x8098, 0x80a9, 0x80bb, 0x80cc, 0x80dd, 0x80ef, 0x8100, 0x8111, 0x8123, 0x8134, 0x8145,
+ 0x8157, 0x8168, 0x8179, 0x818b, 0x819c, 0x81ad, 0x81bf, 0x81d0, 0x81e1, 0x81f3, 0x8204, 0x8215,
+ 0x8226, 0x8238, 0x8249, 0x825a, 0x826c, 0x827d, 0x828e, 0x829f, 0x82b1, 0x82c2, 0x82d3, 0x82e5,
+ 0x82f6, 0x8307, 0x8318, 0x832a, 0x833b, 0x834c, 0x835d, 0x836f, 0x8380, 0x8391, 0x83a2, 0x83b3,
+ 0x83c5, 0x83d6, 0x83e7, 0x83f8, 0x840a, 0x841b, 0x842c, 0x843d, 0x844e, 0x8460, 0x8471, 0x8482,
+ 0x8493, 0x84a4, 0x84b6, 0x84c7, 0x84d8, 0x84e9, 0x84fa, 0x850b, 0x851d, 0x852e, 0x853f, 0x8550,
+ 0x8561, 0x8572, 0x8584, 0x8595, 0x85a6, 0x85b7, 0x85c8, 0x85d9, 0x85ea, 0x85fb, 0x860d, 0x861e,
+ 0x862f, 0x8640, 0x8651, 0x8662, 0x8673, 0x8684, 0x8695, 0x86a7, 0x86b8, 0x86c9, 0x86da, 0x86eb,
+ 0x86fc, 0x870d, 0x871e, 0x872f, 0x8740, 0x8751, 0x8762, 0x8773, 0x8784, 0x8796, 0x87a7, 0x87b8,
+ 0x87c9, 0x87da, 0x87eb, 0x87fc, 0x880d, 0x881e, 0x882f, 0x8840, 0x8851, 0x8862, 0x8873, 0x8884,
+ 0x8895, 0x88a6, 0x88b7, 0x88c8, 0x88d9, 0x88ea, 0x88fb, 0x890c, 0x891d, 0x892e, 0x893f, 0x8950,
+ 0x8961, 0x8972, 0x8983, 0x8994, 0x89a5, 0x89b6, 0x89c6, 0x89d7, 0x89e8, 0x89f9, 0x8a0a, 0x8a1b,
+ 0x8a2c, 0x8a3d, 0x8a4e, 0x8a5f, 0x8a70, 0x8a81, 0x8a92, 0x8aa3, 0x8ab3, 0x8ac4, 0x8ad5, 0x8ae6,
+ 0x8af7, 0x8b08, 0x8b19, 0x8b2a, 0x8b3b, 0x8b4b, 0x8b5c, 0x8b6d, 0x8b7e, 0x8b8f, 0x8ba0, 0x8bb1,
+ 0x8bc1, 0x8bd2, 0x8be3, 0x8bf4, 0x8c05, 0x8c16, 0x8c27, 0x8c37, 0x8c48, 0x8c59, 0x8c6a, 0x8c7b,
+ 0x8c8c, 0x8c9c, 0x8cad, 0x8cbe, 0x8ccf, 0x8ce0, 0x8cf0, 0x8d01, 0x8d12, 0x8d23, 0x8d34, 0x8d44,
+ 0x8d55, 0x8d66, 0x8d77, 0x8d87, 0x8d98, 0x8da9, 0x8dba, 0x8dca, 0x8ddb, 0x8dec, 0x8dfd, 0x8e0d,
+ 0x8e1e, 0x8e2f, 0x8e40, 0x8e50, 0x8e61, 0x8e72, 0x8e83, 0x8e93, 0x8ea4, 0x8eb5, 0x8ec5, 0x8ed6,
+ 0x8ee7, 0x8ef8, 0x8f08, 0x8f19, 0x8f2a, 0x8f3a, 0x8f4b, 0x8f5c, 0x8f6c, 0x8f7d, 0x8f8e, 0x8f9e,
+ 0x8faf, 0x8fc0, 0x8fd0, 0x8fe1, 0x8ff2, 0x9002, 0x9013, 0x9024, 0x9034, 0x9045, 0x9056, 0x9066,
+ 0x9077, 0x9088, 0x9098, 0x90a9, 0x90b9, 0x90ca, 0x90db, 0x90eb, 0x90fc, 0x910c, 0x911d, 0x912e,
+ 0x913e, 0x914f, 0x915f, 0x9170, 0x9181, 0x9191, 0x91a2, 0x91b2, 0x91c3, 0x91d3, 0x91e4, 0x91f5,
+ 0x9205, 0x9216, 0x9226, 0x9237, 0x9247, 0x9258, 0x9268, 0x9279, 0x9289, 0x929a, 0x92aa, 0x92bb,
+ 0x92cc, 0x92dc, 0x92ed, 0x92fd, 0x930e, 0x931e, 0x932f, 0x933f, 0x9350, 0x9360, 0x9370, 0x9381,
+ 0x9391, 0x93a2, 0x93b2, 0x93c3, 0x93d3, 0x93e4, 0x93f4, 0x9405, 0x9415, 0x9426, 0x9436, 0x9447,
+ 0x9457, 0x9467, 0x9478, 0x9488, 0x9499, 0x94a9, 0x94ba, 0x94ca, 0x94da, 0x94eb, 0x94fb, 0x950c,
+ 0x951c, 0x952c, 0x953d, 0x954d, 0x955e, 0x956e, 0x957e, 0x958f, 0x959f, 0x95af, 0x95c0, 0x95d0,
+ 0x95e1, 0x95f1, 0x9601, 0x9612, 0x9622, 0x9632, 0x9643, 0x9653, 0x9663, 0x9674, 0x9684, 0x9694,
+ 0x96a5, 0x96b5, 0x96c5, 0x96d6, 0x96e6, 0x96f6, 0x9707, 0x9717, 0x9727, 0x9738, 0x9748, 0x9758,
+ 0x9768, 0x9779, 0x9789, 0x9799, 0x97aa, 0x97ba, 0x97ca, 0x97da, 0x97eb, 0x97fb, 0x980b, 0x981b,
+ 0x982c, 0x983c, 0x984c, 0x985c, 0x986d, 0x987d, 0x988d, 0x989d, 0x98ad, 0x98be, 0x98ce, 0x98de,
+ 0x98ee, 0x98ff, 0x990f, 0x991f, 0x992f, 0x993f, 0x9950, 0x9960, 0x9970, 0x9980, 0x9990, 0x99a0,
+ 0x99b1, 0x99c1, 0x99d1, 0x99e1, 0x99f1, 0x9a01, 0x9a12, 0x9a22, 0x9a32, 0x9a42, 0x9a52, 0x9a62,
+ 0x9a72, 0x9a83, 0x9a93, 0x9aa3, 0x9ab3, 0x9ac3, 0x9ad3, 0x9ae3, 0x9af3, 0x9b04, 0x9b14, 0x9b24,
+ 0x9b34, 0x9b44, 0x9b54, 0x9b64, 0x9b74, 0x9b84, 0x9b94, 0x9ba4, 0x9bb5, 0x9bc5, 0x9bd5, 0x9be5,
+ 0x9bf5, 0x9c05, 0x9c15, 0x9c25, 0x9c35, 0x9c45, 0x9c55, 0x9c65, 0x9c75, 0x9c85, 0x9c95, 0x9ca5,
+ 0x9cb5, 0x9cc5, 0x9cd5, 0x9ce5, 0x9cf5, 0x9d05, 0x9d15, 0x9d25, 0x9d35, 0x9d45, 0x9d55, 0x9d65,
+ 0x9d75, 0x9d85, 0x9d95, 0x9da5, 0x9db5, 0x9dc5, 0x9dd5, 0x9de5, 0x9df5, 0x9e05, 0x9e15, 0x9e25,
+ 0x9e35, 0x9e45, 0x9e55, 0x9e65, 0x9e74, 0x9e84, 0x9e94, 0x9ea4, 0x9eb4, 0x9ec4, 0x9ed4, 0x9ee4,
+ 0x9ef4, 0x9f04, 0x9f14, 0x9f23, 0x9f33, 0x9f43, 0x9f53, 0x9f63, 0x9f73, 0x9f83, 0x9f93, 0x9fa3,
+ 0x9fb2, 0x9fc2, 0x9fd2, 0x9fe2, 0x9ff2, 0xa002, 0xa012, 0xa021, 0xa031, 0xa041, 0xa051, 0xa061,
+ 0xa071, 0xa080, 0xa090, 0xa0a0, 0xa0b0, 0xa0c0, 0xa0cf, 0xa0df, 0xa0ef, 0xa0ff, 0xa10f, 0xa11e,
+ 0xa12e, 0xa13e, 0xa14e, 0xa15e, 0xa16d, 0xa17d, 0xa18d, 0xa19d, 0xa1ac, 0xa1bc, 0xa1cc, 0xa1dc,
+ 0xa1eb, 0xa1fb, 0xa20b, 0xa21b, 0xa22a, 0xa23a, 0xa24a, 0xa25a, 0xa269, 0xa279, 0xa289, 0xa298,
+ 0xa2a8, 0xa2b8, 0xa2c8, 0xa2d7, 0xa2e7, 0xa2f7, 0xa306, 0xa316, 0xa326, 0xa335, 0xa345, 0xa355,
+ 0xa364, 0xa374, 0xa384, 0xa393, 0xa3a3, 0xa3b3, 0xa3c2, 0xa3d2, 0xa3e2, 0xa3f1, 0xa401, 0xa411,
+ 0xa420, 0xa430, 0xa440, 0xa44f, 0xa45f, 0xa46e, 0xa47e, 0xa48e, 0xa49d, 0xa4ad, 0xa4bc, 0xa4cc,
+ 0xa4dc, 0xa4eb, 0xa4fb, 0xa50a, 0xa51a, 0xa52a, 0xa539, 0xa549, 0xa558, 0xa568, 0xa577, 0xa587,
+ 0xa597, 0xa5a6, 0xa5b6, 0xa5c5, 0xa5d5, 0xa5e4, 0xa5f4, 0xa603, 0xa613, 0xa622, 0xa632, 0xa641,
+ 0xa651, 0xa660, 0xa670, 0xa67f, 0xa68f, 0xa69e, 0xa6ae, 0xa6bd, 0xa6cd, 0xa6dc, 0xa6ec, 0xa6fb,
+ 0xa70b, 0xa71a, 0xa72a, 0xa739, 0xa749, 0xa758, 0xa768, 0xa777, 0xa787, 0xa796, 0xa7a5, 0xa7b5,
+ 0xa7c4, 0xa7d4, 0xa7e3, 0xa7f3, 0xa802, 0xa812, 0xa821, 0xa830, 0xa840, 0xa84f, 0xa85f, 0xa86e,
+ 0xa87d, 0xa88d, 0xa89c, 0xa8ac, 0xa8bb, 0xa8ca, 0xa8da, 0xa8e9, 0xa8f8, 0xa908, 0xa917, 0xa927,
+ 0xa936, 0xa945, 0xa955, 0xa964, 0xa973, 0xa983, 0xa992, 0xa9a1, 0xa9b1, 0xa9c0, 0xa9cf, 0xa9df,
+ 0xa9ee, 0xa9fd, 0xaa0d, 0xaa1c, 0xaa2b, 0xaa3b, 0xaa4a, 0xaa59, 0xaa69, 0xaa78, 0xaa87, 0xaa96,
+ 0xaaa6, 0xaab5, 0xaac4, 0xaad4, 0xaae3, 0xaaf2, 0xab01, 0xab11, 0xab20, 0xab2f, 0xab3e, 0xab4e,
+ 0xab5d, 0xab6c, 0xab7b, 0xab8b, 0xab9a, 0xaba9, 0xabb8, 0xabc7, 0xabd7, 0xabe6, 0xabf5, 0xac04,
+ 0xac14, 0xac23, 0xac32, 0xac41, 0xac50, 0xac60, 0xac6f, 0xac7e, 0xac8d, 0xac9c, 0xacab, 0xacbb,
+ 0xacca, 0xacd9, 0xace8, 0xacf7, 0xad06, 0xad16, 0xad25, 0xad34, 0xad43, 0xad52, 0xad61, 0xad70,
+ 0xad80, 0xad8f, 0xad9e, 0xadad, 0xadbc, 0xadcb, 0xadda, 0xade9, 0xadf8, 0xae08, 0xae17, 0xae26,
+ 0xae35, 0xae44, 0xae53, 0xae62, 0xae71, 0xae80, 0xae8f, 0xae9e, 0xaead, 0xaebd, 0xaecc, 0xaedb,
+ 0xaeea, 0xaef9, 0xaf08, 0xaf17, 0xaf26, 0xaf35, 0xaf44, 0xaf53, 0xaf62, 0xaf71, 0xaf80, 0xaf8f,
+ 0xaf9e, 0xafad, 0xafbc, 0xafcb, 0xafda, 0xafe9, 0xaff8, 0xb007, 0xb016, 0xb025, 0xb034, 0xb043,
+ 0xb052, 0xb061, 0xb070, 0xb07f, 0xb08e, 0xb09d, 0xb0ac, 0xb0bb, 0xb0ca, 0xb0d9, 0xb0e8, 0xb0f6,
+ 0xb105, 0xb114, 0xb123, 0xb132, 0xb141, 0xb150, 0xb15f, 0xb16e, 0xb17d, 0xb18c, 0xb19b, 0xb1aa,
+ 0xb1b8, 0xb1c7, 0xb1d6, 0xb1e5, 0xb1f4, 0xb203, 0xb212, 0xb221, 0xb22f, 0xb23e, 0xb24d, 0xb25c,
+ 0xb26b, 0xb27a, 0xb289, 0xb297, 0xb2a6, 0xb2b5, 0xb2c4, 0xb2d3, 0xb2e2, 0xb2f1, 0xb2ff, 0xb30e,
+ 0xb31d, 0xb32c, 0xb33b, 0xb349, 0xb358, 0xb367, 0xb376, 0xb385, 0xb393, 0xb3a2, 0xb3b1, 0xb3c0,
+ 0xb3cf, 0xb3dd, 0xb3ec, 0xb3fb, 0xb40a, 0xb418, 0xb427, 0xb436, 0xb445, 0xb453, 0xb462, 0xb471,
+ 0xb480, 0xb48e, 0xb49d, 0xb4ac, 0xb4bb, 0xb4c9, 0xb4d8, 0xb4e7, 0xb4f6, 0xb504, 0xb513, 0xb522,
+ 0xb530, 0xb53f, 0xb54e, 0xb55c, 0xb56b, 0xb57a, 0xb588, 0xb597, 0xb5a6, 0xb5b5, 0xb5c3, 0xb5d2,
+ 0xb5e1, 0xb5ef, 0xb5fe, 0xb60d, 0xb61b, 0xb62a, 0xb638, 0xb647, 0xb656, 0xb664, 0xb673, 0xb682,
+ 0xb690, 0xb69f, 0xb6ae, 0xb6bc, 0xb6cb, 0xb6d9, 0xb6e8, 0xb6f7, 0xb705, 0xb714, 0xb722, 0xb731,
+ 0xb740, 0xb74e, 0xb75d, 0xb76b, 0xb77a, 0xb788, 0xb797, 0xb7a6, 0xb7b4, 0xb7c3, 0xb7d1, 0xb7e0,
+ 0xb7ee, 0xb7fd, 0xb80b, 0xb81a, 0xb829, 0xb837, 0xb846, 0xb854, 0xb863, 0xb871, 0xb880, 0xb88e,
+ 0xb89d, 0xb8ab, 0xb8ba, 0xb8c8, 0xb8d7, 0xb8e5, 0xb8f4, 0xb902, 0xb911, 0xb91f, 0xb92e, 0xb93c,
+ 0xb94b, 0xb959, 0xb968, 0xb976, 0xb984, 0xb993, 0xb9a1, 0xb9b0, 0xb9be, 0xb9cd, 0xb9db, 0xb9ea,
+ 0xb9f8, 0xba06, 0xba15, 0xba23, 0xba32, 0xba40, 0xba4f, 0xba5d, 0xba6b, 0xba7a, 0xba88, 0xba97,
+ 0xbaa5, 0xbab3, 0xbac2, 0xbad0, 0xbade, 0xbaed, 0xbafb, 0xbb0a, 0xbb18, 0xbb26, 0xbb35, 0xbb43,
+ 0xbb51, 0xbb60, 0xbb6e, 0xbb7c, 0xbb8b, 0xbb99, 0xbba8, 0xbbb6, 0xbbc4, 0xbbd3, 0xbbe1, 0xbbef,
+ 0xbbfd, 0xbc0c, 0xbc1a, 0xbc28, 0xbc37, 0xbc45, 0xbc53, 0xbc62, 0xbc70, 0xbc7e, 0xbc8c, 0xbc9b,
+ 0xbca9, 0xbcb7, 0xbcc6, 0xbcd4, 0xbce2, 0xbcf0, 0xbcff, 0xbd0d, 0xbd1b, 0xbd29, 0xbd38, 0xbd46,
+ 0xbd54, 0xbd62, 0xbd71, 0xbd7f, 0xbd8d, 0xbd9b, 0xbdaa, 0xbdb8, 0xbdc6, 0xbdd4, 0xbde2, 0xbdf1,
+ 0xbdff, 0xbe0d, 0xbe1b, 0xbe29, 0xbe38, 0xbe46, 0xbe54, 0xbe62, 0xbe70, 0xbe7f, 0xbe8d, 0xbe9b,
+ 0xbea9, 0xbeb7, 0xbec5, 0xbed4, 0xbee2, 0xbef0, 0xbefe, 0xbf0c, 0xbf1a, 0xbf28, 0xbf37, 0xbf45,
+ 0xbf53, 0xbf61, 0xbf6f, 0xbf7d, 0xbf8b, 0xbf99, 0xbfa7, 0xbfb6, 0xbfc4, 0xbfd2, 0xbfe0, 0xbfee,
+ 0xbffc, 0xc00a, 0xc018, 0xc026, 0xc034, 0xc042, 0xc051, 0xc05f, 0xc06d, 0xc07b, 0xc089, 0xc097,
+ 0xc0a5, 0xc0b3, 0xc0c1, 0xc0cf, 0xc0dd, 0xc0eb, 0xc0f9, 0xc107, 0xc115, 0xc123, 0xc131, 0xc13f,
+ 0xc14d, 0xc15b, 0xc169, 0xc177, 0xc185, 0xc193, 0xc1a1, 0xc1af, 0xc1bd, 0xc1cb, 0xc1d9, 0xc1e7,
+ 0xc1f5, 0xc203, 0xc211, 0xc21f, 0xc22d, 0xc23b, 0xc249, 0xc257, 0xc265, 0xc273, 0xc281, 0xc28f,
+ 0xc29d, 0xc2ab, 0xc2b8, 0xc2c6, 0xc2d4, 0xc2e2, 0xc2f0, 0xc2fe, 0xc30c, 0xc31a, 0xc328, 0xc336,
+ 0xc344, 0xc352, 0xc35f, 0xc36d, 0xc37b, 0xc389, 0xc397, 0xc3a5, 0xc3b3, 0xc3c1, 0xc3ce, 0xc3dc,
+ 0xc3ea, 0xc3f8, 0xc406, 0xc414, 0xc422, 0xc42f, 0xc43d, 0xc44b, 0xc459, 0xc467, 0xc475, 0xc482,
+ 0xc490, 0xc49e, 0xc4ac, 0xc4ba, 0xc4c7, 0xc4d5, 0xc4e3, 0xc4f1, 0xc4ff, 0xc50d, 0xc51a, 0xc528,
+ 0xc536, 0xc544, 0xc551, 0xc55f, 0xc56d, 0xc57b, 0xc589, 0xc596, 0xc5a4, 0xc5b2, 0xc5c0, 0xc5cd,
+ 0xc5db, 0xc5e9, 0xc5f7, 0xc604, 0xc612, 0xc620, 0xc62d, 0xc63b, 0xc649, 0xc657, 0xc664, 0xc672,
+ 0xc680, 0xc68d, 0xc69b, 0xc6a9, 0xc6b7, 0xc6c4, 0xc6d2, 0xc6e0, 0xc6ed, 0xc6fb, 0xc709, 0xc716,
+ 0xc724, 0xc732, 0xc73f, 0xc74d, 0xc75b, 0xc768, 0xc776, 0xc784, 0xc791, 0xc79f, 0xc7ad, 0xc7ba,
+ 0xc7c8, 0xc7d6, 0xc7e3, 0xc7f1, 0xc7fe, 0xc80c, 0xc81a, 0xc827, 0xc835, 0xc842, 0xc850, 0xc85e,
+ 0xc86b, 0xc879, 0xc886, 0xc894, 0xc8a2, 0xc8af, 0xc8bd, 0xc8ca, 0xc8d8, 0xc8e5, 0xc8f3, 0xc901,
+ 0xc90e, 0xc91c, 0xc929, 0xc937, 0xc944, 0xc952, 0xc95f, 0xc96d, 0xc97b, 0xc988, 0xc996, 0xc9a3,
+ 0xc9b1, 0xc9be, 0xc9cc, 0xc9d9, 0xc9e7, 0xc9f4, 0xca02, 0xca0f, 0xca1d, 0xca2a, 0xca38, 0xca45,
+ 0xca53, 0xca60, 0xca6e, 0xca7b, 0xca89, 0xca96, 0xcaa4, 0xcab1, 0xcabe, 0xcacc, 0xcad9, 0xcae7,
+ 0xcaf4, 0xcb02, 0xcb0f, 0xcb1d, 0xcb2a, 0xcb37, 0xcb45, 0xcb52, 0xcb60, 0xcb6d, 0xcb7b, 0xcb88,
+ 0xcb95, 0xcba3, 0xcbb0, 0xcbbe, 0xcbcb, 0xcbd8, 0xcbe6, 0xcbf3, 0xcc01, 0xcc0e, 0xcc1b, 0xcc29,
+ 0xcc36, 0xcc43, 0xcc51, 0xcc5e, 0xcc6c, 0xcc79, 0xcc86, 0xcc94, 0xcca1, 0xccae, 0xccbc, 0xccc9,
+ 0xccd6, 0xcce4, 0xccf1, 0xccfe, 0xcd0c, 0xcd19, 0xcd26, 0xcd34, 0xcd41, 0xcd4e, 0xcd5b, 0xcd69,
+ 0xcd76, 0xcd83, 0xcd91, 0xcd9e, 0xcdab, 0xcdb9, 0xcdc6, 0xcdd3, 0xcde0, 0xcdee, 0xcdfb, 0xce08,
+ 0xce15, 0xce23, 0xce30, 0xce3d, 0xce4a, 0xce58, 0xce65, 0xce72, 0xce7f, 0xce8d, 0xce9a, 0xcea7,
+ 0xceb4, 0xcec2, 0xcecf, 0xcedc, 0xcee9, 0xcef6, 0xcf04, 0xcf11, 0xcf1e, 0xcf2b, 0xcf38, 0xcf46,
+ 0xcf53, 0xcf60, 0xcf6d, 0xcf7a, 0xcf87, 0xcf95, 0xcfa2, 0xcfaf, 0xcfbc, 0xcfc9, 0xcfd6, 0xcfe4,
+ 0xcff1, 0xcffe, 0xd00b, 0xd018, 0xd025, 0xd032, 0xd040, 0xd04d, 0xd05a, 0xd067, 0xd074, 0xd081,
+ 0xd08e, 0xd09b, 0xd0a9, 0xd0b6, 0xd0c3, 0xd0d0, 0xd0dd, 0xd0ea, 0xd0f7, 0xd104, 0xd111, 0xd11e,
+ 0xd12b, 0xd139, 0xd146, 0xd153, 0xd160, 0xd16d, 0xd17a, 0xd187, 0xd194, 0xd1a1, 0xd1ae, 0xd1bb,
+ 0xd1c8, 0xd1d5, 0xd1e2, 0xd1ef, 0xd1fc, 0xd209, 0xd216, 0xd223, 0xd230, 0xd23d, 0xd24a, 0xd257,
+ 0xd264, 0xd271, 0xd27e, 0xd28b, 0xd298, 0xd2a5, 0xd2b2, 0xd2bf, 0xd2cc, 0xd2d9, 0xd2e6, 0xd2f3,
+ 0xd300, 0xd30d, 0xd31a, 0xd327, 0xd334, 0xd341, 0xd34e, 0xd35b, 0xd368, 0xd375, 0xd382, 0xd38f,
+ 0xd39c, 0xd3a8, 0xd3b5, 0xd3c2, 0xd3cf, 0xd3dc, 0xd3e9, 0xd3f6, 0xd403, 0xd410, 0xd41d, 0xd42a,
+ 0xd436, 0xd443, 0xd450, 0xd45d, 0xd46a, 0xd477, 0xd484, 0xd491, 0xd49e, 0xd4aa, 0xd4b7, 0xd4c4,
+ 0xd4d1, 0xd4de, 0xd4eb, 0xd4f8, 0xd504, 0xd511, 0xd51e, 0xd52b, 0xd538, 0xd545, 0xd551, 0xd55e,
+ 0xd56b, 0xd578, 0xd585, 0xd591, 0xd59e, 0xd5ab, 0xd5b8, 0xd5c5, 0xd5d1, 0xd5de, 0xd5eb, 0xd5f8,
+ 0xd605, 0xd611, 0xd61e, 0xd62b, 0xd638, 0xd645, 0xd651, 0xd65e, 0xd66b, 0xd678, 0xd684, 0xd691,
+ 0xd69e, 0xd6ab, 0xd6b7, 0xd6c4, 0xd6d1, 0xd6de, 0xd6ea, 0xd6f7, 0xd704, 0xd710, 0xd71d, 0xd72a,
+ 0xd737, 0xd743, 0xd750, 0xd75d, 0xd769, 0xd776, 0xd783, 0xd78f, 0xd79c, 0xd7a9, 0xd7b6, 0xd7c2,
+ 0xd7cf, 0xd7dc, 0xd7e8, 0xd7f5, 0xd802, 0xd80e, 0xd81b, 0xd828, 0xd834, 0xd841, 0xd84e, 0xd85a,
+ 0xd867, 0xd873, 0xd880, 0xd88d, 0xd899, 0xd8a6, 0xd8b3, 0xd8bf, 0xd8cc, 0xd8d8, 0xd8e5, 0xd8f2,
+ 0xd8fe, 0xd90b, 0xd917, 0xd924, 0xd931, 0xd93d, 0xd94a, 0xd956, 0xd963, 0xd970, 0xd97c, 0xd989,
+ 0xd995, 0xd9a2, 0xd9ae, 0xd9bb, 0xd9c8, 0xd9d4, 0xd9e1, 0xd9ed, 0xd9fa, 0xda06, 0xda13, 0xda1f,
+ 0xda2c, 0xda38, 0xda45, 0xda51, 0xda5e, 0xda6a, 0xda77, 0xda84, 0xda90, 0xda9d, 0xdaa9, 0xdab6,
+ 0xdac2, 0xdacf, 0xdadb, 0xdae7, 0xdaf4, 0xdb00, 0xdb0d, 0xdb19, 0xdb26, 0xdb32, 0xdb3f, 0xdb4b,
+ 0xdb58, 0xdb64, 0xdb71, 0xdb7d, 0xdb8a, 0xdb96, 0xdba2, 0xdbaf, 0xdbbb, 0xdbc8, 0xdbd4, 0xdbe1,
+ 0xdbed, 0xdbf9, 0xdc06, 0xdc12, 0xdc1f, 0xdc2b, 0xdc38, 0xdc44, 0xdc50, 0xdc5d, 0xdc69, 0xdc76,
+ 0xdc82, 0xdc8e, 0xdc9b, 0xdca7, 0xdcb3, 0xdcc0, 0xdccc, 0xdcd9, 0xdce5, 0xdcf1, 0xdcfe, 0xdd0a,
+ 0xdd16, 0xdd23, 0xdd2f, 0xdd3b, 0xdd48, 0xdd54, 0xdd60, 0xdd6d, 0xdd79, 0xdd85, 0xdd92, 0xdd9e,
+ 0xddaa, 0xddb7, 0xddc3, 0xddcf, 0xdddc, 0xdde8, 0xddf4, 0xde01, 0xde0d, 0xde19, 0xde25, 0xde32,
+ 0xde3e, 0xde4a, 0xde57, 0xde63, 0xde6f, 0xde7b, 0xde88, 0xde94, 0xdea0, 0xdeac, 0xdeb9, 0xdec5,
+ 0xded1, 0xdedd, 0xdeea, 0xdef6, 0xdf02, 0xdf0e, 0xdf1b, 0xdf27, 0xdf33, 0xdf3f, 0xdf4c, 0xdf58,
+ 0xdf64, 0xdf70, 0xdf7c, 0xdf89, 0xdf95, 0xdfa1, 0xdfad, 0xdfb9, 0xdfc6, 0xdfd2, 0xdfde, 0xdfea,
+ 0xdff6, 0xe003, 0xe00f, 0xe01b, 0xe027, 0xe033, 0xe03f, 0xe04c, 0xe058, 0xe064, 0xe070, 0xe07c,
+ 0xe088, 0xe094, 0xe0a1, 0xe0ad, 0xe0b9, 0xe0c5, 0xe0d1, 0xe0dd, 0xe0e9, 0xe0f5, 0xe102, 0xe10e,
+ 0xe11a, 0xe126, 0xe132, 0xe13e, 0xe14a, 0xe156, 0xe162, 0xe16e, 0xe17b, 0xe187, 0xe193, 0xe19f,
+ 0xe1ab, 0xe1b7, 0xe1c3, 0xe1cf, 0xe1db, 0xe1e7, 0xe1f3, 0xe1ff, 0xe20b, 0xe217, 0xe223, 0xe22f,
+ 0xe23c, 0xe248, 0xe254, 0xe260, 0xe26c, 0xe278, 0xe284, 0xe290, 0xe29c, 0xe2a8, 0xe2b4, 0xe2c0,
+ 0xe2cc, 0xe2d8, 0xe2e4, 0xe2f0, 0xe2fc, 0xe308, 0xe314, 0xe320, 0xe32c, 0xe338, 0xe344, 0xe350,
+ 0xe35c, 0xe368, 0xe374, 0xe380, 0xe38b, 0xe397, 0xe3a3, 0xe3af, 0xe3bb, 0xe3c7, 0xe3d3, 0xe3df,
+ 0xe3eb, 0xe3f7, 0xe403, 0xe40f, 0xe41b, 0xe427, 0xe433, 0xe43f, 0xe44a, 0xe456, 0xe462, 0xe46e,
+ 0xe47a, 0xe486, 0xe492, 0xe49e, 0xe4aa, 0xe4b6, 0xe4c1, 0xe4cd, 0xe4d9, 0xe4e5, 0xe4f1, 0xe4fd,
+ 0xe509, 0xe515, 0xe520, 0xe52c, 0xe538, 0xe544, 0xe550, 0xe55c, 0xe567, 0xe573, 0xe57f, 0xe58b,
+ 0xe597, 0xe5a3, 0xe5af, 0xe5ba, 0xe5c6, 0xe5d2, 0xe5de, 0xe5ea, 0xe5f5, 0xe601, 0xe60d, 0xe619,
+ 0xe625, 0xe630, 0xe63c, 0xe648, 0xe654, 0xe660, 0xe66b, 0xe677, 0xe683, 0xe68f, 0xe69a, 0xe6a6,
+ 0xe6b2, 0xe6be, 0xe6ca, 0xe6d5, 0xe6e1, 0xe6ed, 0xe6f9, 0xe704, 0xe710, 0xe71c, 0xe727, 0xe733,
+ 0xe73f, 0xe74b, 0xe756, 0xe762, 0xe76e, 0xe77a, 0xe785, 0xe791, 0xe79d, 0xe7a8, 0xe7b4, 0xe7c0,
+ 0xe7cb, 0xe7d7, 0xe7e3, 0xe7ef, 0xe7fa, 0xe806, 0xe812, 0xe81d, 0xe829, 0xe835, 0xe840, 0xe84c,
+ 0xe858, 0xe863, 0xe86f, 0xe87b, 0xe886, 0xe892, 0xe89e, 0xe8a9, 0xe8b5, 0xe8c0, 0xe8cc, 0xe8d8,
+ 0xe8e3, 0xe8ef, 0xe8fb, 0xe906, 0xe912, 0xe91d, 0xe929, 0xe935, 0xe940, 0xe94c, 0xe958, 0xe963,
+ 0xe96f, 0xe97a, 0xe986, 0xe991, 0xe99d, 0xe9a9, 0xe9b4, 0xe9c0, 0xe9cb, 0xe9d7, 0xe9e3, 0xe9ee,
+ 0xe9fa, 0xea05, 0xea11, 0xea1c, 0xea28, 0xea33, 0xea3f, 0xea4a, 0xea56, 0xea62, 0xea6d, 0xea79,
+ 0xea84, 0xea90, 0xea9b, 0xeaa7, 0xeab2, 0xeabe, 0xeac9, 0xead5, 0xeae0, 0xeaec, 0xeaf7, 0xeb03,
+ 0xeb0e, 0xeb1a, 0xeb25, 0xeb31, 0xeb3c, 0xeb48, 0xeb53, 0xeb5f, 0xeb6a, 0xeb76, 0xeb81, 0xeb8d,
+ 0xeb98, 0xeba3, 0xebaf, 0xebba, 0xebc6, 0xebd1, 0xebdd, 0xebe8, 0xebf4, 0xebff, 0xec0a, 0xec16,
+ 0xec21, 0xec2d, 0xec38, 0xec44, 0xec4f, 0xec5a, 0xec66, 0xec71, 0xec7d, 0xec88, 0xec93, 0xec9f,
+ 0xecaa, 0xecb6, 0xecc1, 0xeccc, 0xecd8, 0xece3, 0xecef, 0xecfa, 0xed05, 0xed11, 0xed1c, 0xed27,
+ 0xed33, 0xed3e, 0xed4a, 0xed55, 0xed60, 0xed6c, 0xed77, 0xed82, 0xed8e, 0xed99, 0xeda4, 0xedb0,
+ 0xedbb, 0xedc6, 0xedd2, 0xeddd, 0xede8, 0xedf4, 0xedff, 0xee0a, 0xee15, 0xee21, 0xee2c, 0xee37,
+ 0xee43, 0xee4e, 0xee59, 0xee65, 0xee70, 0xee7b, 0xee86, 0xee92, 0xee9d, 0xeea8, 0xeeb3, 0xeebf,
+ 0xeeca, 0xeed5, 0xeee1, 0xeeec, 0xeef7, 0xef02, 0xef0e, 0xef19, 0xef24, 0xef2f, 0xef3a, 0xef46,
+ 0xef51, 0xef5c, 0xef67, 0xef73, 0xef7e, 0xef89, 0xef94, 0xef9f, 0xefab, 0xefb6, 0xefc1, 0xefcc,
+ 0xefd7, 0xefe3, 0xefee, 0xeff9, 0xf004, 0xf00f, 0xf01b, 0xf026, 0xf031, 0xf03c, 0xf047, 0xf052,
+ 0xf05e, 0xf069, 0xf074, 0xf07f, 0xf08a, 0xf095, 0xf0a1, 0xf0ac, 0xf0b7, 0xf0c2, 0xf0cd, 0xf0d8,
+ 0xf0e3, 0xf0ef, 0xf0fa, 0xf105, 0xf110, 0xf11b, 0xf126, 0xf131, 0xf13c, 0xf147, 0xf153, 0xf15e,
+ 0xf169, 0xf174, 0xf17f, 0xf18a, 0xf195, 0xf1a0, 0xf1ab, 0xf1b6, 0xf1c2, 0xf1cd, 0xf1d8, 0xf1e3,
+ 0xf1ee, 0xf1f9, 0xf204, 0xf20f, 0xf21a, 0xf225, 0xf230, 0xf23b, 0xf246, 0xf251, 0xf25c, 0xf267,
+ 0xf272, 0xf27d, 0xf288, 0xf293, 0xf29f, 0xf2aa, 0xf2b5, 0xf2c0, 0xf2cb, 0xf2d6, 0xf2e1, 0xf2ec,
+ 0xf2f7, 0xf302, 0xf30d, 0xf318, 0xf323, 0xf32e, 0xf339, 0xf344, 0xf34f, 0xf35a, 0xf364, 0xf36f,
+ 0xf37a, 0xf385, 0xf390, 0xf39b, 0xf3a6, 0xf3b1, 0xf3bc, 0xf3c7, 0xf3d2, 0xf3dd, 0xf3e8, 0xf3f3,
+ 0xf3fe, 0xf409, 0xf414, 0xf41f, 0xf42a, 0xf435, 0xf43f, 0xf44a, 0xf455, 0xf460, 0xf46b, 0xf476,
+ 0xf481, 0xf48c, 0xf497, 0xf4a2, 0xf4ad, 0xf4b7, 0xf4c2, 0xf4cd, 0xf4d8, 0xf4e3, 0xf4ee, 0xf4f9,
+ 0xf504, 0xf50f, 0xf519, 0xf524, 0xf52f, 0xf53a, 0xf545, 0xf550, 0xf55b, 0xf565, 0xf570, 0xf57b,
+ 0xf586, 0xf591, 0xf59c, 0xf5a6, 0xf5b1, 0xf5bc, 0xf5c7, 0xf5d2, 0xf5dd, 0xf5e7, 0xf5f2, 0xf5fd,
+ 0xf608, 0xf613, 0xf61d, 0xf628, 0xf633, 0xf63e, 0xf649, 0xf653, 0xf65e, 0xf669, 0xf674, 0xf67f,
+ 0xf689, 0xf694, 0xf69f, 0xf6aa, 0xf6b4, 0xf6bf, 0xf6ca, 0xf6d5, 0xf6e0, 0xf6ea, 0xf6f5, 0xf700,
+ 0xf70b, 0xf715, 0xf720, 0xf72b, 0xf736, 0xf740, 0xf74b, 0xf756, 0xf760, 0xf76b, 0xf776, 0xf781,
+ 0xf78b, 0xf796, 0xf7a1, 0xf7ab, 0xf7b6, 0xf7c1, 0xf7cc, 0xf7d6, 0xf7e1, 0xf7ec, 0xf7f6, 0xf801,
+ 0xf80c, 0xf816, 0xf821, 0xf82c, 0xf836, 0xf841, 0xf84c, 0xf856, 0xf861, 0xf86c, 0xf876, 0xf881,
+ 0xf88c, 0xf896, 0xf8a1, 0xf8ac, 0xf8b6, 0xf8c1, 0xf8cc, 0xf8d6, 0xf8e1, 0xf8ec, 0xf8f6, 0xf901,
+ 0xf90b, 0xf916, 0xf921, 0xf92b, 0xf936, 0xf941, 0xf94b, 0xf956, 0xf960, 0xf96b, 0xf976, 0xf980,
+ 0xf98b, 0xf995, 0xf9a0, 0xf9aa, 0xf9b5, 0xf9c0, 0xf9ca, 0xf9d5, 0xf9df, 0xf9ea, 0xf9f4, 0xf9ff,
+ 0xfa0a, 0xfa14, 0xfa1f, 0xfa29, 0xfa34, 0xfa3e, 0xfa49, 0xfa53, 0xfa5e, 0xfa69, 0xfa73, 0xfa7e,
+ 0xfa88, 0xfa93, 0xfa9d, 0xfaa8, 0xfab2, 0xfabd, 0xfac7, 0xfad2, 0xfadc, 0xfae7, 0xfaf1, 0xfafc,
+ 0xfb06, 0xfb11, 0xfb1b, 0xfb26, 0xfb30, 0xfb3b, 0xfb45, 0xfb50, 0xfb5a, 0xfb65, 0xfb6f, 0xfb7a,
+ 0xfb84, 0xfb8f, 0xfb99, 0xfba4, 0xfbae, 0xfbb8, 0xfbc3, 0xfbcd, 0xfbd8, 0xfbe2, 0xfbed, 0xfbf7,
+ 0xfc02, 0xfc0c, 0xfc16, 0xfc21, 0xfc2b, 0xfc36, 0xfc40, 0xfc4b, 0xfc55, 0xfc5f, 0xfc6a, 0xfc74,
+ 0xfc7f, 0xfc89, 0xfc93, 0xfc9e, 0xfca8, 0xfcb3, 0xfcbd, 0xfcc7, 0xfcd2, 0xfcdc, 0xfce7, 0xfcf1,
+ 0xfcfb, 0xfd06, 0xfd10, 0xfd1a, 0xfd25, 0xfd2f, 0xfd3a, 0xfd44, 0xfd4e, 0xfd59, 0xfd63, 0xfd6d,
+ 0xfd78, 0xfd82, 0xfd8c, 0xfd97, 0xfda1, 0xfdab, 0xfdb6, 0xfdc0, 0xfdca, 0xfdd5, 0xfddf, 0xfde9,
+ 0xfdf4, 0xfdfe, 0xfe08, 0xfe13, 0xfe1d, 0xfe27, 0xfe32, 0xfe3c, 0xfe46, 0xfe50, 0xfe5b, 0xfe65,
+ 0xfe6f, 0xfe7a, 0xfe84, 0xfe8e, 0xfe98, 0xfea3, 0xfead, 0xfeb7, 0xfec1, 0xfecc, 0xfed6, 0xfee0,
+ 0xfeeb, 0xfef5, 0xfeff, 0xff09, 0xff14, 0xff1e, 0xff28, 0xff32, 0xff3c, 0xff47, 0xff51, 0xff5b,
+ 0xff65, 0xff70, 0xff7a, 0xff84, 0xff8e, 0xff98, 0xffa3, 0xffad, 0xffb7, 0xffc1, 0xffcc, 0xffd6,
+ 0xffe0, 0xffea, 0xfff4, 0xffff};
+
+// max value is pi/4
+constexpr double SCALING_FACTOR = 4. / M_PI * 0xFFFF;
+
+inline double atan2_lookup(double y, double x)
+{
+ if (std::abs(x) < std::numeric_limits<double>::epsilon())
+ {
+ if (y >= 0.)
+ {
+ return M_PI / 2.;
+ }
+ else
+ {
+ return -M_PI / 2.;
+ }
+ }
+
+ unsigned octant = 0;
+
+ if (x < 0.)
+ {
+ octant = 1;
+ x = -x;
+ }
+ if (y < 0.)
+ {
+ octant |= 2;
+ y = -y;
+ }
+
+ double t = y / x;
+ if (t > 1.0)
+ {
+ octant |= 4;
+ t = 1.0 / t;
+ }
+
+ double angle = atan_table[(unsigned)(t * 4095)] / SCALING_FACTOR;
+
+ switch (octant)
+ {
+ case 0:
+ break;
+ case 1:
+ angle = M_PI - angle;
+ break;
+ case 2:
+ angle = -angle;
+ break;
+ case 3:
+ angle = -M_PI + angle;
+ break;
+ case 4:
+ angle = M_PI / 2.0 - angle;
+ break;
+ case 5:
+ angle = M_PI / 2.0 + angle;
+ break;
+ case 6:
+ angle = -M_PI / 2.0 + angle;
+ break;
+ case 7:
+ angle = -M_PI / 2.0 - angle;
+ break;
+ }
+ return angle;
+}
+
+#endif // TRIGONOMETRY_TABLE_HPP
diff --git a/Util/xml_renderer.hpp b/util/xml_renderer.hpp
similarity index 81%
rename from Util/xml_renderer.hpp
rename to util/xml_renderer.hpp
index 46e0501..4ef1e5d 100644
--- a/Util/xml_renderer.hpp
+++ b/util/xml_renderer.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,10 +28,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef XML_RENDERER_HPP
#define XML_RENDERER_HPP
-#include "../data_structures/json_container.hpp"
#include "cast.hpp"
-namespace JSON {
+#include <osrm/json_container.hpp>
+
+namespace osrm
+{
+namespace json
+{
struct XMLToArrayRenderer : mapbox::util::static_visitor<>
{
@@ -65,7 +69,6 @@ struct XMLToArrayRenderer : mapbox::util::static_visitor<>
out.push_back(' ');
out.insert(out.end(), ++(*iterator).first.begin(), (*iterator).first.end());
out.push_back('=');
-
}
mapbox::util::apply_visitor(XMLToArrayRenderer(out), (*iterator).second);
if (iterator->first.at(0) != '_')
@@ -110,31 +113,30 @@ struct XMLToArrayRenderer : mapbox::util::static_visitor<>
std::vector<char> &out;
};
-template<class JSONObject>
-inline void xml_render(std::vector<char> &out, const JSONObject &object)
+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)
+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>"};
+ 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>"};
+ const std::string footer{"</rte></gpx>"};
out.insert(out.end(), footer.begin(), footer.end());
}
-} // namespace JSON
-
+} // 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