[osrm] 01/13: Imported Upstream version 4.5.0
Christopher Baines
cbaines-guest at moszumanska.debian.org
Sat Apr 4 16:04:06 UTC 2015
This is an automated email from the git hooks/post-receive script.
cbaines-guest pushed a commit to branch master
in repository osrm.
commit 60426464adc792402dd530a3406d502135476ea9
Author: Christopher Baines <mail at cbaines.net>
Date: Sat Apr 4 14:09:47 2015 +0100
Imported Upstream version 4.5.0
---
.gitignore | 7 +-
.travis.yml | 18 +-
Algorithms/BFSComponentExplorer.h | 148 ----
Algorithms/ObjectToBase64.h | 99 ---
Algorithms/StronglyConnectedComponents.h | 447 ----------
CMakeLists.txt | 194 +++--
Contractor/TemporaryStorage.cpp | 172 ----
Contractor/TemporaryStorage.h | 96 ---
DataStructures/DeallocatingVector.h | 401 ---------
DataStructures/NodeBasedGraph.h | 166 ----
DataStructures/PhantomNodes.h | 173 ----
Descriptors/GPXDescriptor.h | 100 ---
Docs/webclient.txt | 3 -
Extractor/BaseParser.cpp | 139 ---
Extractor/BaseParser.h | 67 --
Extractor/ExtractionWay.h | 79 --
Extractor/ExtractorCallbacks.cpp | 171 ----
Extractor/ExtractorStructs.h | 114 ---
Extractor/PBFParser.cpp | 664 ---------------
Extractor/PBFParser.h | 103 ---
Extractor/ScriptingEnvironment.cpp | 121 ---
Extractor/XMLParser.cpp | 353 --------
Extractor/XMLParser.h | 54 --
Include/osrm/Coordinate.h | 34 +-
Include/osrm/Header.h | 2 +-
Include/osrm/RouteParameters.h | 9 +
Library/OSRM.h | 6 +-
Library/OSRM_impl.cpp | 40 +-
Library/OSRM_impl.h | 11 +-
Plugins/ViaRoutePlugin.h | 173 ----
README.md | 7 +-
Rakefile | 9 +-
Server/APIGrammar.h | 9 +-
Server/Connection.cpp | 4 +-
Server/Connection.h | 4 +-
Server/DataStructures/BaseDataFacade.h | 41 +-
Server/DataStructures/InternalDataFacade.h | 155 ++--
Server/DataStructures/SharedDataFacade.h | 171 ++--
Server/DataStructures/SharedDataType.h | 15 +-
Server/Http/CompressionType.h | 2 +-
Server/Http/Reply.cpp | 7 +-
Server/RequestHandler.cpp | 31 +-
Server/RequestHandler.h | 2 +-
Server/RequestParser.cpp | 28 +-
Server/RequestParser.h | 4 +-
Server/Server.h | 31 +-
Server/ServerFactory.h | 49 --
Tools/components.cpp | 136 ---
UnitTests/Algorithms/DouglasPeuckerTest.cpp | 109 +++
.../algorithm_tests.cpp | 12 +-
UnitTests/data_structures/BinaryHeapTest.cpp | 178 ++++
UnitTests/data_structures/RangeTableTest.cpp | 131 +++
UnitTests/data_structures/StaticGraphTest.cpp | 191 +++++
UnitTests/data_structures/StaticRTreeTest.cpp | 488 +++++++++++
.../datastructure_tests.cpp | 11 +-
Util/Azimuth.h | 73 --
Util/BoostFileSystemFix.h | 17 +-
Util/DataStoreOptions.h | 31 +-
Util/FingerPrint.h | 1 -
Util/MercatorUtil.h | 8 +-
Util/ProgramOptions.h | 197 +++--
Util/SimpleLogger.h | 158 ----
Util/StringUtil.h | 318 -------
Util/TimingUtil.h | 39 -
Util/{MachineInfo.h => bearing.cpp} | 54 +-
Util/{GitDescription.h => bearing.hpp} | 13 +-
Util/cast.hpp | 188 ++++
Util/{ComputeAngle.h => compute_angle.cpp} | 20 +-
Library/OSRM.h => Util/compute_angle.hpp | 31 +-
Util/{ContainerUtils.h => container.hpp} | 57 +-
Util/{FingerPrint.cpp.in => finger_print.cpp.in} | 15 +-
Library/OSRM.h => Util/floating_point.hpp | 32 +-
Util/{GitDescription.cpp.in => git_sha.cpp.in} | 4 +-
Util/{GitDescription.h => git_sha.hpp} | 8 +-
Util/{GraphLoader.h => graph_loader.hpp} | 95 ++-
.../SearchEngine.h => Util/integer_range.hpp | 54 +-
.../HashTable.h => Util/iterator_range.hpp | 80 +-
.../JSONContainer.h => Util/json_renderer.hpp | 111 +--
Util/{LuaUtil.h => lua_util.hpp} | 8 +-
.../ScriptingEnvironment.h => Util/make_unique.hpp | 39 +-
Include/osrm/Header.h => Util/osrm_exception.cpp | 38 +-
Util/{OSRMException.h => osrm_exception.hpp} | 25 +-
Util/range_algorithms.hpp | 42 +
Util/simple_logger.cpp | 135 +++
Server/RequestHandler.h => Util/simple_logger.hpp | 55 +-
Util/{StdHashExtensions.h => std_hash.hpp} | 18 +-
Util/string_util.hpp | 150 ++++
Util/timing_util.hpp | 80 ++
Util/xml_renderer.hpp | 140 +++
algorithms/bfs_components.hpp | 174 ++++
.../crc32_processor.hpp | 118 +--
.../douglas_peucker.cpp | 97 +--
.../douglas_peucker.hpp | 38 +-
algorithms/object_encoder.hpp | 94 ++
.../polyline_compressor.cpp | 70 +-
.../polyline_compressor.hpp | 10 +-
.../polyline_formatter.cpp | 50 +-
.../polyline_formatter.hpp | 18 +-
.../route_name_extraction.hpp | 6 +-
algorithms/tiny_components.hpp | 253 ++++++
appveyor.yml | 15 +-
benchmarks/static_rtree.cpp | 189 +++++
cmake/CPackDebianConfig.cmake | 44 +
cmake/FindDebArch.cmake | 19 +
cmake/FingerPrint-Config.cmake | 6 +-
cmake/check_luabind.cmake | 40 +
cmake/postinst.in | 2 +
.../Contractor.h => contractor/contractor.hpp | 224 +++--
.../edge_based_graph_factory.cpp | 315 +++----
.../edge_based_graph_factory.hpp | 44 +-
.../geometry_compressor.cpp | 20 +-
.../geometry_compressor.hpp | 14 +-
contractor/processing_chain.cpp | 581 +++++++++++++
contractor/processing_chain.hpp | 95 +++
{DataStructures => data_structures}/Coordinate.cpp | 111 ++-
.../InputReaderFactory.h | 0
.../binary_heap.hpp | 7 +-
.../concurrent_queue.hpp | 10 +-
data_structures/deallocating_vector.hpp | 313 +++++++
.../dynamic_graph.hpp | 167 ++--
.../edge_based_node.hpp | 57 +-
.../external_memory_node.cpp | 30 +-
.../external_memory_node.hpp | 28 +-
data_structures/fixed_point_number.hpp | 216 +++++
.../hilbert_value.cpp | 4 +-
.../hilbert_value.hpp | 8 +-
.../import_edge.cpp | 10 +-
.../import_edge.hpp | 15 +-
.../json_container.hpp | 89 +-
.../LRUCache.h => data_structures/lru_cache.hpp | 8 +-
data_structures/node_based_graph.hpp | 271 ++++++
.../node_id.hpp | 24 +-
.../original_edge_data.hpp | 20 +-
.../Percent.h => data_structures/percent.hpp | 10 +-
data_structures/phantom_node.cpp | 124 +++
data_structures/phantom_node.hpp | 129 +++
.../QueryEdge.h => data_structures/query_edge.hpp | 25 +-
.../QueryNode.h => data_structures/query_node.hpp | 36 +-
.../range_table.hpp | 51 +-
.../raw_route_data.hpp | 36 +-
data_structures/rectangle.hpp | 199 +++++
.../restriction.hpp | 84 +-
.../restriction_map.cpp | 131 +--
.../restriction_map.hpp | 97 ++-
.../route_parameters.cpp | 30 +-
.../search_engine.hpp | 16 +-
.../search_engine_data.cpp | 4 +-
.../search_engine_data.hpp | 14 +-
.../segment_information.hpp | 22 +-
.../shared_memory_factory.hpp | 25 +-
.../shared_memory_vector_wrapper.hpp | 18 +-
.../static_graph.hpp | 79 +-
.../static_kdtree.hpp | 8 +-
.../static_rtree.hpp | 501 +++++++----
.../travel_mode.hpp | 23 +-
.../turn_instructions.hpp | 10 +-
.../xor_fast_hash.hpp | 10 +-
.../xor_fast_hash_storage.hpp | 16 +-
datastore.cpp | 196 ++---
.../description_factory.cpp | 71 +-
.../description_factory.hpp | 55 +-
.../descriptor_base.hpp | 40 +-
descriptors/gpx_descriptor.hpp | 92 ++
.../json_descriptor.hpp | 120 +--
Server/Http/CompressionType.h => extract.cpp | 27 +-
extractor.cpp | 286 -------
.../extraction_containers.cpp | 100 ++-
.../extraction_containers.hpp | 29 +-
.../extraction_helper_functions.hpp | 25 +-
.../extraction_node.hpp | 26 +-
extractor/extraction_way.hpp | 120 +++
extractor/extractor.cpp | 268 ++++++
extractor/extractor.hpp | 13 +
extractor/extractor_callbacks.cpp | 223 +++++
.../extractor_callbacks.hpp | 23 +-
extractor/extractor_options.cpp | 167 ++++
.../extractor_options.hpp | 40 +-
extractor/first_and_last_segment_of_way.hpp | 88 ++
.../internal_extractor_edge.hpp | 32 +-
extractor/restriction_parser.cpp | 241 ++++++
.../restriction_parser.hpp | 38 +-
extractor/scripting_environment.cpp | 146 ++++
.../scripting_environment.hpp | 19 +-
features/bicycle/mode.feature | 228 +++--
features/bicycle/pushing.feature | 26 +-
features/car/ferry.feature | 37 +-
features/car/link.feature | 111 +++
features/car/maxspeed.feature | 52 +-
features/car/restrictions.feature | 69 ++
features/car/speed.feature | 28 +-
features/car/surface.feature | 141 +++
features/foot/ferry.feature | 18 +-
features/options/extract/files.feature | 6 +-
features/options/prepare/files.feature | 6 +-
features/options/routed/files.feature | 13 +-
features/step_definitions/data.rb | 16 +
features/step_definitions/distance_matrix.rb | 56 ++
features/step_definitions/locate.rb | 2 +-
features/step_definitions/nearest.rb | 2 +-
features/step_definitions/options.rb | 26 +-
features/step_definitions/requests.rb | 34 +-
features/step_definitions/routability.rb | 10 +-
features/step_definitions/routing.rb | 16 +-
features/step_definitions/timestamp.rb | 4 +-
features/support/data.rb | 78 +-
features/support/env.rb | 34 +-
features/support/exceptions.rb | 6 +
features/support/hash.rb | 26 +-
features/support/hooks.rb | 6 +-
features/support/launch.rb | 168 ++--
features/support/log.rb | 6 +-
features/support/route.rb | 5 +
features/support/run.rb | 20 +-
features/testbot/bad.feature | 2 +-
features/testbot/basic.feature | 2 +-
features/testbot/bearing.feature | 2 +-
features/testbot/bearing_param.feature | 2 +-
features/testbot/compression.feature | 22 +
features/testbot/datastore.feature | 31 +
features/testbot/distance.feature | 52 +-
features/testbot/distance_matrix.feature | 102 +++
features/testbot/fastest.feature | 2 +-
features/testbot/geometry.feature | 2 +-
features/testbot/graph.feature | 21 +-
features/testbot/load.feature | 63 ++
features/testbot/loop.feature | 8 +-
features/testbot/mode.feature | 227 ++++-
features/testbot/oneway.feature | 64 +-
features/testbot/origin.feature | 2 +-
features/testbot/penalty.feature | 2 +-
features/testbot/planetary.feature | 2 +-
features/testbot/projection.feature | 2 +-
features/testbot/protobuffer.feature | 2 +-
features/testbot/snap.feature | 2 +-
features/testbot/status.feature | 2 +-
features/testbot/time.feature | 2 +-
features/testbot/turns.feature | 2 +-
features/testbot/utf.feature | 2 +-
features/testbot/uturn.feature | 69 ++
features/testbot/via.feature | 24 +-
.../distance_table.hpp | 71 +-
.../HelloWorldPlugin.h => plugins/hello_world.hpp | 34 +-
Plugins/LocatePlugin.h => plugins/locate.hpp | 23 +-
Plugins/NearestPlugin.h => plugins/nearest.hpp | 70 +-
Plugins/BasePlugin.h => plugins/plugin_base.hpp | 16 +-
Plugins/TimestampPlugin.h => plugins/timestamp.hpp | 14 +-
plugins/viaroute.hpp | 190 +++++
prepare.cpp | 476 +----------
profiles/bicycle.lua | 263 +++---
profiles/car.lua | 340 +++++---
profiles/examples/postgis.lua | 4 +-
profiles/foot.lua | 128 +--
profiles/lib/access.lua | 6 +-
profiles/lib/maxspeed.lua | 17 +
profiles/testbot.lua | 76 +-
routed.cpp | 45 +-
.../alternative_path.hpp | 198 +++--
.../many_to_many.hpp | 18 +-
.../routing_base.hpp | 118 +--
.../shortest_path.hpp | 115 +--
taginfo.json | 84 ++
third_party/osmium/area/assembler.hpp | 783 +++++++++++++++++
.../osmium/area/detail/node_ref_segment.hpp | 262 ++++++
third_party/osmium/area/detail/proto_ring.hpp | 274 ++++++
third_party/osmium/area/detail/segment_list.hpp | 216 +++++
third_party/osmium/area/multipolygon_collector.hpp | 212 +++++
third_party/osmium/area/problem_reporter.hpp | 149 ++++
.../osmium/area/problem_reporter_exception.hpp | 96 +++
third_party/osmium/area/problem_reporter_ogr.hpp | 206 +++++
.../osmium/area/problem_reporter_stream.hpp | 96 +++
third_party/osmium/builder/builder.hpp | 220 +++++
third_party/osmium/builder/builder_helper.hpp | 103 +++
third_party/osmium/builder/osm_object_builder.hpp | 283 ++++++
third_party/osmium/config/constexpr.hpp | 43 +
third_party/osmium/diff_handler.hpp | 67 ++
third_party/osmium/diff_iterator.hpp | 129 +++
third_party/osmium/diff_visitor.hpp | 104 +++
third_party/osmium/dynamic_handler.hpp | 195 +++++
third_party/osmium/experimental/flex_reader.hpp | 131 +++
third_party/osmium/geom/coordinates.hpp | 97 +++
third_party/osmium/geom/factory.hpp | 328 +++++++
third_party/osmium/geom/geojson.hpp | 152 ++++
third_party/osmium/geom/geos.hpp | 224 +++++
third_party/osmium/geom/haversine.hpp | 94 ++
third_party/osmium/geom/mercator_projection.hpp | 109 +++
third_party/osmium/geom/ogr.hpp | 179 ++++
third_party/osmium/geom/projection.hpp | 159 ++++
third_party/osmium/geom/relations.hpp | 57 ++
third_party/osmium/geom/util.hpp | 75 ++
third_party/osmium/geom/wkb.hpp | 279 ++++++
third_party/osmium/geom/wkt.hpp | 148 ++++
third_party/osmium/handler.hpp | 101 +++
third_party/osmium/handler/chain.hpp | 128 +++
third_party/osmium/handler/disk_store.hpp | 111 +++
third_party/osmium/handler/dump.hpp | 294 +++++++
.../osmium/handler/node_locations_for_ways.hpp | 177 ++++
third_party/osmium/handler/object_relations.hpp | 106 +++
.../osmium/index/detail/mmap_vector_anon.hpp | 78 ++
.../osmium/index/detail/mmap_vector_base.hpp | 183 ++++
.../osmium/index/detail/mmap_vector_file.hpp | 82 ++
third_party/osmium/index/detail/tmpfile.hpp | 62 ++
third_party/osmium/index/detail/typed_mmap.hpp | 229 +++++
third_party/osmium/index/index.hpp | 100 +++
third_party/osmium/index/map.hpp | 155 ++++
third_party/osmium/index/map/dummy.hpp | 87 ++
third_party/osmium/index/map/mmap_vector_anon.hpp | 61 ++
third_party/osmium/index/map/mmap_vector_file.hpp | 57 ++
third_party/osmium/index/map/sparse_table.hpp | 140 +++
third_party/osmium/index/map/stl_map.hpp | 112 +++
third_party/osmium/index/map/stl_vector.hpp | 61 ++
third_party/osmium/index/map/vector.hpp | 208 +++++
third_party/osmium/index/multimap.hpp | 129 +++
third_party/osmium/index/multimap/hybrid.hpp | 199 +++++
.../osmium/index/multimap/mmap_vector_anon.hpp | 58 ++
.../osmium/index/multimap/mmap_vector_file.hpp | 54 ++
third_party/osmium/index/multimap/stl_multimap.hpp | 151 ++++
third_party/osmium/index/multimap/stl_vector.hpp | 58 ++
third_party/osmium/index/multimap/vector.hpp | 151 ++++
third_party/osmium/io/any_compression.hpp | 39 +
third_party/osmium/io/any_input.hpp | 41 +
third_party/osmium/io/any_output.hpp | 42 +
third_party/osmium/io/bzip2_compression.hpp | 277 ++++++
third_party/osmium/io/compression.hpp | 279 ++++++
third_party/osmium/io/detail/input_format.hpp | 160 ++++
third_party/osmium/io/detail/opl_output_format.hpp | 315 +++++++
third_party/osmium/io/detail/output_format.hpp | 156 ++++
third_party/osmium/io/detail/pbf.hpp | 100 +++
third_party/osmium/io/detail/pbf_input_format.hpp | 240 ++++++
third_party/osmium/io/detail/pbf_output_format.hpp | 944 +++++++++++++++++++++
third_party/osmium/io/detail/pbf_parser.hpp | 449 ++++++++++
third_party/osmium/io/detail/pbf_stringtable.hpp | 204 +++++
third_party/osmium/io/detail/read_thread.hpp | 106 +++
third_party/osmium/io/detail/read_write.hpp | 156 ++++
third_party/osmium/io/detail/write_thread.hpp | 86 ++
third_party/osmium/io/detail/xml_input_format.hpp | 726 ++++++++++++++++
third_party/osmium/io/detail/xml_output_format.hpp | 481 +++++++++++
third_party/osmium/io/detail/zlib.hpp | 99 +++
third_party/osmium/io/error.hpp | 57 ++
third_party/osmium/io/file.hpp | 343 ++++++++
third_party/osmium/io/file_compression.hpp | 72 ++
third_party/osmium/io/file_format.hpp | 78 ++
third_party/osmium/io/gzip_compression.hpp | 238 ++++++
third_party/osmium/io/header.hpp | 122 +++
third_party/osmium/io/input_iterator.hpp | 139 +++
third_party/osmium/io/opl_output.hpp | 39 +
third_party/osmium/io/output_iterator.hpp | 116 +++
third_party/osmium/io/overwrite.hpp | 52 ++
third_party/osmium/io/pbf_input.hpp | 39 +
third_party/osmium/io/pbf_output.hpp | 39 +
third_party/osmium/io/reader.hpp | 303 +++++++
third_party/osmium/io/reader_iterator.hpp | 51 ++
third_party/osmium/io/writer.hpp | 145 ++++
third_party/osmium/io/xml_input.hpp | 39 +
third_party/osmium/io/xml_output.hpp | 39 +
third_party/osmium/memory/buffer.hpp | 534 ++++++++++++
third_party/osmium/memory/collection.hpp | 153 ++++
third_party/osmium/memory/item.hpp | 179 ++++
third_party/osmium/memory/item_iterator.hpp | 234 +++++
third_party/osmium/object_pointer_collection.hpp | 112 +++
third_party/osmium/osm.hpp | 48 ++
third_party/osmium/osm/area.hpp | 193 +++++
third_party/osmium/osm/box.hpp | 207 +++++
third_party/osmium/osm/changeset.hpp | 336 ++++++++
third_party/osmium/osm/diff_object.hpp | 156 ++++
third_party/osmium/osm/entity.hpp | 74 ++
third_party/osmium/osm/entity_bits.hpp | 99 +++
third_party/osmium/osm/item_type.hpp | 173 ++++
third_party/osmium/osm/location.hpp | 285 +++++++
third_party/osmium/osm/node.hpp | 76 ++
third_party/osmium/osm/node_ref.hpp | 173 ++++
third_party/osmium/osm/node_ref_list.hpp | 135 +++
third_party/osmium/osm/object.hpp | 437 ++++++++++
third_party/osmium/osm/object_comparisons.hpp | 110 +++
third_party/osmium/osm/relation.hpp | 189 +++++
third_party/osmium/osm/segment.hpp | 105 +++
third_party/osmium/osm/tag.hpp | 140 +++
third_party/osmium/osm/timestamp.hpp | 169 ++++
third_party/osmium/osm/types.hpp | 83 ++
third_party/osmium/osm/undirected_segment.hpp | 100 +++
third_party/osmium/osm/way.hpp | 115 +++
third_party/osmium/relations/collector.hpp | 544 ++++++++++++
.../osmium/relations/detail/member_meta.hpp | 158 ++++
.../osmium/relations/detail/relation_meta.hpp | 136 +++
third_party/osmium/tags/filter.hpp | 148 ++++
third_party/osmium/tags/regex_filter.hpp | 58 ++
third_party/osmium/tags/taglist.hpp | 67 ++
third_party/osmium/thread/checked_task.hpp | 106 +++
third_party/osmium/thread/function_wrapper.hpp | 110 +++
third_party/osmium/thread/name.hpp | 61 ++
third_party/osmium/thread/pool.hpp | 180 ++++
third_party/osmium/thread/queue.hpp | 178 ++++
third_party/osmium/thread/sorted_queue.hpp | 159 ++++
third_party/osmium/thread/util.hpp | 87 ++
third_party/osmium/util/cast.hpp | 72 ++
third_party/osmium/util/compatibility.hpp | 47 +
third_party/osmium/util/config.hpp | 73 ++
third_party/osmium/util/double.hpp | 91 ++
third_party/osmium/util/options.hpp | 155 ++++
third_party/osmium/util/verbose_output.hpp | 139 +++
third_party/osmium/visitor.hpp | 255 ++++++
third_party/variant/optional.hpp | 69 ++
third_party/variant/recursive_wrapper.hpp | 127 +++
third_party/variant/variant.hpp | 740 ++++++++++++++++
{Tools => tools}/.gitignore | 0
tools/check-hsgr.cpp | 112 +++
tools/components.cpp | 293 +++++++
{Tools => tools}/io-benchmark.cpp | 112 +--
{Tools => tools}/simpleclient.cpp | 30 +-
tools/springclean.cpp | 102 +++
{Tools => tools}/unlock_all_mutexes.cpp | 9 +-
typedefs.h | 16 +-
411 files changed, 36356 insertions(+), 9007 deletions(-)
diff --git a/.gitignore b/.gitignore
index 5642924..b905eea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,8 +36,9 @@ Thumbs.db
# build related files #
#######################
/build/
-/Util/FingerPrint.cpp
-/Util/GitDescription.cpp
+/Util/finger_print.cpp
+/Util/git_sha.cpp
+/cmake/postinst
# Eclipse related files #
#########################
@@ -79,6 +80,8 @@ stxxl.errlog
/osrm-prepare
/osrm-unlock-all
/osrm-cli
+/osrm-check-hsgr
+/osrm-springclean
/nohup.out
# Sandbox folder #
diff --git a/.travis.yml b/.travis.yml
index 8817e38..643e00d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,13 +7,17 @@ install:
- sudo apt-add-repository -y ppa:ubuntu-toolchain-r/test
- sudo add-apt-repository -y ppa:boost-latest/ppa
- sudo apt-get update >/dev/null
- - sudo apt-get -q install libprotoc-dev libprotobuf7 libprotobuf-dev libosmpbf-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.7
+ - 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
- #luabind
+ # luabind
- curl https://gist.githubusercontent.com/DennisOSRM/f2eb7b948e6fe1ae319e/raw/install-luabind.sh | sudo bash
- #osmosis
+ # osmosis
- curl -s https://gist.githubusercontent.com/DennisOSRM/803a64a9178ec375069f/raw/ | sudo bash
+ # cmake
+ - curl -s https://gist.githubusercontent.com/DennisOSRM/5fad9bee5c7f09fd7fc9/raw/ | sudo bash
+ # osmpbf library
+ - curl -s https://gist.githubusercontent.com/DennisOSRM/13b1b4fe38a57ead850e/raw/install_osmpbf.sh | sudo bash
before_script:
- rvm use 1.9.3
- gem install bundler
@@ -23,6 +27,8 @@ before_script:
- cmake .. $CMAKEOPTIONS
script:
- make -j 2
+ - make -j 2 tests
+ - ./datastructure-tests
- cd ..
- cucumber -p verify
after_script:
@@ -36,8 +42,8 @@ cache:
- bundler
- apt
env:
- - CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-4.7" OSRM_PORT=5000 OSRM_TIMEOUT=60
- - CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=g++-4.7" OSRM_PORT=5010 OSRM_TIMEOUT=60
+ - 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
notifications:
irc:
channels:
diff --git a/Algorithms/BFSComponentExplorer.h b/Algorithms/BFSComponentExplorer.h
deleted file mode 100644
index 7bc7ecb..0000000
--- a/Algorithms/BFSComponentExplorer.h
+++ /dev/null
@@ -1,148 +0,0 @@
-#ifndef __BFS_COMPONENT_EXPLORER_H__
-#define __BFS_COMPONENT_EXPLORER_H__
-
-#include "../typedefs.h"
-#include "../DataStructures/DynamicGraph.h"
-#include "../DataStructures/RestrictionMap.h"
-
-#include <queue>
-#include <unordered_set>
-
-// Explores the components of the given graph while respecting turn restrictions
-// and barriers.
-template <typename GraphT> class BFSComponentExplorer
-{
- public:
- BFSComponentExplorer(const GraphT &dynamicGraph,
- const RestrictionMap &restrictions,
- const std::unordered_set<NodeID> &barrier_nodes)
- : m_graph(dynamicGraph), m_restriction_map(restrictions), m_barrier_nodes(barrier_nodes)
- {
- BOOST_ASSERT(m_graph.GetNumberOfNodes() > 0);
- }
-
- /*!
- * Returns the size of the component that the node belongs to.
- */
- inline unsigned int GetComponentSize(NodeID node)
- {
- BOOST_ASSERT(node < m_component_index_list.size());
-
- return m_component_index_size[m_component_index_list[node]];
- }
-
- inline unsigned int GetNumberOfComponents() { return m_component_index_size.size(); }
-
- /*!
- * Computes the component sizes.
- */
- void run()
- {
- std::queue<std::pair<NodeID, NodeID>> bfs_queue;
- unsigned current_component = 0;
-
- BOOST_ASSERT(m_component_index_list.empty());
- BOOST_ASSERT(m_component_index_size.empty());
-
- unsigned num_nodes = m_graph.GetNumberOfNodes();
-
- m_component_index_list.resize(num_nodes, std::numeric_limits<unsigned>::max());
-
- BOOST_ASSERT(num_nodes > 0);
-
- // put unexplorered node with parent pointer into queue
- for (NodeID node = 0; node < num_nodes; ++node)
- {
- if (std::numeric_limits<unsigned>::max() == m_component_index_list[node])
- {
- unsigned size = ExploreComponent(bfs_queue, node, current_component);
-
- // push size into vector
- m_component_index_size.emplace_back(size);
- ++current_component;
- }
- }
- }
-
- private:
- /*!
- * Explores the current component that starts at node using BFS.
- */
- inline unsigned ExploreComponent(std::queue<std::pair<NodeID, NodeID>> &bfs_queue,
- NodeID node,
- unsigned current_component)
- {
- /*
- Graphical representation of variables:
-
- u v w
- *---------->*---------->*
- e2
- */
-
- bfs_queue.emplace(node, node);
- // mark node as read
- m_component_index_list[node] = current_component;
-
- unsigned current_component_size = 1;
-
- while (!bfs_queue.empty())
- {
- // fetch element from BFS queue
- std::pair<NodeID, NodeID> current_queue_item = bfs_queue.front();
- bfs_queue.pop();
-
- const NodeID v = current_queue_item.first; // current node
- const NodeID u = current_queue_item.second; // parent
- // increment size counter of current component
- ++current_component_size;
- const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end());
- if (!is_barrier_node)
- {
- const NodeID to_node_of_only_restriction =
- m_restriction_map.CheckForEmanatingIsOnlyTurn(u, v);
-
- for (auto e2 : m_graph.GetAdjacentEdgeRange(v))
- {
- const NodeID w = m_graph.GetTarget(e2);
-
- if (to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
- w != to_node_of_only_restriction)
- {
- // At an only_-restriction but not at the right turn
- continue;
- }
-
- if (u != w)
- {
- // only add an edge if turn is not a U-turn except
- // when it is at the end of a dead-end street.
- if (!m_restriction_map.CheckIfTurnIsRestricted(u, v, w))
- {
- // only add an edge if turn is not prohibited
- if (std::numeric_limits<unsigned>::max() == m_component_index_list[w])
- {
- // insert next (node, parent) only if w has
- // not yet been explored
- // mark node as read
- m_component_index_list[w] = current_component;
- bfs_queue.emplace(w, v);
- }
- }
- }
- }
- }
- }
-
- return current_component_size;
- }
-
- std::vector<unsigned> m_component_index_list;
- std::vector<NodeID> m_component_index_size;
-
- const GraphT &m_graph;
- const RestrictionMap &m_restriction_map;
- const std::unordered_set<NodeID> &m_barrier_nodes;
-};
-
-#endif
diff --git a/Algorithms/ObjectToBase64.h b/Algorithms/ObjectToBase64.h
deleted file mode 100644
index 2599283..0000000
--- a/Algorithms/ObjectToBase64.h
+++ /dev/null
@@ -1,99 +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 OBJECTTOBASE64_H_
-#define OBJECTTOBASE64_H_
-
-#include "../Util/StringUtil.h"
-
-#include <boost/assert.hpp>
-#include <boost/archive/iterators/base64_from_binary.hpp>
-#include <boost/archive/iterators/binary_from_base64.hpp>
-#include <boost/archive/iterators/transform_width.hpp>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-typedef
- boost::archive::iterators::base64_from_binary<
- boost::archive::iterators::transform_width<const char *, 6, 8>
- > base64_t;
-
-typedef
- boost::archive::iterators::transform_width<
- boost::archive::iterators::binary_from_base64<
- std::string::const_iterator>, 8, 6
- > binary_t;
-
-template<class ObjectT>
-static void EncodeObjectToBase64(const ObjectT & object, std::string& encoded) {
- const char * char_ptr_to_object = (const char *)&object;
- std::vector<unsigned char> data(sizeof(object));
- std::copy(
- char_ptr_to_object,
- char_ptr_to_object + sizeof(ObjectT),
- data.begin()
- );
-
- unsigned char number_of_padded_chars = 0; // is in {0,1,2};
- while(data.size() % 3 != 0) {
- ++number_of_padded_chars;
- data.push_back(0x00);
- }
-
- BOOST_ASSERT_MSG(
- 0 == data.size() % 3,
- "base64 input data size is not a multiple of 3!"
- );
- encoded.resize(sizeof(ObjectT));
- encoded.assign(
- base64_t( &data[0] ),
- base64_t( &data[0] + (data.size() - number_of_padded_chars) )
- );
- replaceAll(encoded, "+", "-");
- replaceAll(encoded, "/", "_");
-}
-
-template<class ObjectT>
-static void DecodeObjectFromBase64(const std::string& input, ObjectT & object) {
- try {
- std::string encoded(input);
- //replace "-" with "+" and "_" with "/"
- replaceAll(encoded, "-", "+");
- replaceAll(encoded, "_", "/");
-
- std::copy (
- binary_t( encoded.begin() ),
- binary_t( encoded.begin() + encoded.length() - 1),
- (char *)&object
- );
-
- } catch(...) { }
-}
-
-#endif /* OBJECTTOBASE64_H_ */
diff --git a/Algorithms/StronglyConnectedComponents.h b/Algorithms/StronglyConnectedComponents.h
deleted file mode 100644
index e0c31f9..0000000
--- a/Algorithms/StronglyConnectedComponents.h
+++ /dev/null
@@ -1,447 +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 STRONGLYCONNECTEDCOMPONENTS_H_
-#define STRONGLYCONNECTEDCOMPONENTS_H_
-
-#include "../typedefs.h"
-#include "../DataStructures/DeallocatingVector.h"
-#include "../DataStructures/DynamicGraph.h"
-#include "../DataStructures/ImportEdge.h"
-#include "../DataStructures/QueryNode.h"
-#include "../DataStructures/Percent.h"
-#include "../DataStructures/Restriction.h"
-#include "../DataStructures/TurnInstructions.h"
-
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/StdHashExtensions.h"
-
-#include <osrm/Coordinate.h>
-
-#include <boost/assert.hpp>
-#include <boost/filesystem.hpp>
-
-#ifdef __APPLE__
-#include <gdal.h>
-#include <ogrsf_frmts.h>
-#else
-#include <gdal/gdal.h>
-#include <gdal/ogrsf_frmts.h>
-#endif
-
-#include <cstdint>
-
-#include <memory>
-#include <stack>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-class TarjanSCC
-{
- private:
- struct TarjanNode
- {
- TarjanNode() : index(UINT_MAX), low_link(UINT_MAX), on_stack(false) {}
- unsigned index;
- unsigned low_link;
- bool on_stack;
- };
-
- struct TarjanEdgeData
- {
- int distance;
- unsigned name_id : 31;
- bool shortcut : 1;
- short type;
- bool forward : 1;
- bool backward : 1;
- bool reversedEdge : 1;
- };
-
- struct TarjanStackFrame
- {
- explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {}
- NodeID v;
- NodeID parent;
- };
-
- typedef DynamicGraph<TarjanEdgeData> TarjanDynamicGraph;
- typedef TarjanDynamicGraph::InputEdge TarjanEdge;
- typedef std::pair<NodeID, NodeID> RestrictionSource;
- typedef std::pair<NodeID, bool> restriction_target;
- typedef std::vector<restriction_target> EmanatingRestrictionsVector;
- typedef std::unordered_map<RestrictionSource, unsigned> RestrictionMap;
-
- std::vector<NodeInfo> m_coordinate_list;
- std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
- std::shared_ptr<TarjanDynamicGraph> m_node_based_graph;
- std::unordered_set<NodeID> m_barrier_node_list;
- std::unordered_set<NodeID> m_traffic_light_list;
- unsigned m_restriction_counter;
- RestrictionMap m_restriction_map;
-
- public:
- TarjanSCC(int number_of_nodes,
- std::vector<NodeBasedEdge> &input_edges,
- std::vector<NodeID> &bn,
- std::vector<NodeID> &tl,
- std::vector<TurnRestriction> &irs,
- std::vector<NodeInfo> &nI)
- : m_coordinate_list(nI), m_restriction_counter(irs.size())
- {
- for (const TurnRestriction &restriction : irs)
- {
- std::pair<NodeID, NodeID> restrictionSource = {restriction.fromNode,
- restriction.viaNode};
- unsigned index;
- RestrictionMap::iterator restriction_iterator =
- m_restriction_map.find(restrictionSource);
- if (restriction_iterator == m_restriction_map.end())
- {
- index = m_restriction_bucket_list.size();
- m_restriction_bucket_list.resize(index + 1);
- m_restriction_map.emplace(restrictionSource, index);
- }
- else
- {
- index = restriction_iterator->second;
- // Map already contains an is_only_*-restriction
- if (m_restriction_bucket_list.at(index).begin()->second)
- {
- continue;
- }
- else if (restriction.flags.isOnly)
- {
- // We are going to insert an is_only_*-restriction. There can be only one.
- m_restriction_bucket_list.at(index).clear();
- }
- }
-
- m_restriction_bucket_list.at(index)
- .emplace_back(restriction.toNode, restriction.flags.isOnly);
- }
-
- m_barrier_node_list.insert(bn.begin(), bn.end());
- m_traffic_light_list.insert(tl.begin(), tl.end());
-
- DeallocatingVector<TarjanEdge> edge_list;
- for (const NodeBasedEdge &input_edge : input_edges)
- {
- if (input_edge.source == input_edge.target)
- {
- continue;
- }
-
- TarjanEdge edge;
- if (input_edge.forward)
- {
- edge.source = input_edge.source;
- edge.target = input_edge.target;
- edge.data.forward = input_edge.forward;
- edge.data.backward = input_edge.backward;
- }
- else
- {
- edge.source = input_edge.target;
- edge.target = input_edge.source;
- edge.data.backward = input_edge.forward;
- edge.data.forward = input_edge.backward;
- }
-
- edge.data.distance = (std::max)((int)input_edge.weight, 1);
- BOOST_ASSERT(edge.data.distance > 0);
- edge.data.shortcut = false;
- edge.data.name_id = input_edge.name_id;
- edge.data.type = input_edge.type;
- edge.data.reversedEdge = false;
- edge_list.push_back(edge);
- if (edge.data.backward)
- {
- std::swap(edge.source, edge.target);
- edge.data.forward = input_edge.backward;
- edge.data.backward = input_edge.forward;
- edge.data.reversedEdge = true;
- edge_list.push_back(edge);
- }
- }
- input_edges.shrink_to_fit();
- BOOST_ASSERT_MSG(0 == input_edges.size() && 0 == input_edges.capacity(),
- "input edge vector not properly deallocated");
-
- std::sort(edge_list.begin(), edge_list.end());
- m_node_based_graph = std::make_shared<TarjanDynamicGraph>(number_of_nodes, edge_list);
- }
-
- ~TarjanSCC() { m_node_based_graph.reset(); }
-
- void Run()
- {
- // remove files from previous run if exist
- DeleteFileIfExists("component.dbf");
- DeleteFileIfExists("component.shx");
- DeleteFileIfExists("component.shp");
-
- Percent p(m_node_based_graph->GetNumberOfNodes());
-
- OGRRegisterAll();
-
- const char *pszDriverName = "ESRI Shapefile";
- OGRSFDriver *poDriver =
- OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(pszDriverName);
- if (nullptr == poDriver)
- {
- throw OSRMException("ESRI Shapefile driver not available");
- }
- OGRDataSource *poDS = poDriver->CreateDataSource("component.shp", nullptr);
-
- if (nullptr == poDS)
- {
- throw OSRMException("Creation of output file failed");
- }
-
- OGRLayer *poLayer = poDS->CreateLayer("component", nullptr, wkbLineString, nullptr);
-
- if (nullptr == poLayer)
- {
- throw OSRMException("Layer creation failed.");
- }
-
- // The following is a hack to distinguish between stuff that happens
- // before the recursive call and stuff that happens after
- std::stack<std::pair<bool, TarjanStackFrame>> recursion_stack;
- // true = stuff before, false = stuff after call
- std::stack<NodeID> tarjan_stack;
- std::vector<unsigned> components_index(m_node_based_graph->GetNumberOfNodes(), UINT_MAX);
- std::vector<NodeID> component_size_vector;
- std::vector<TarjanNode> tarjan_node_list(m_node_based_graph->GetNumberOfNodes());
- unsigned component_index = 0, size_of_current_component = 0;
- int index = 0;
- NodeID last_node = m_node_based_graph->GetNumberOfNodes();
- for (NodeID node = 0; node < last_node; ++node)
- {
- if (UINT_MAX == components_index[node])
- {
- recursion_stack.emplace(true, TarjanStackFrame(node, node));
- }
-
- while (!recursion_stack.empty())
- {
- const bool before_recursion = recursion_stack.top().first;
- TarjanStackFrame currentFrame = recursion_stack.top().second;
- NodeID v = currentFrame.v;
- recursion_stack.pop();
-
- if (before_recursion)
- {
- // Mark frame to handle tail of recursion
- recursion_stack.emplace(false, currentFrame);
-
- // Mark essential information for SCC
- tarjan_node_list[v].index = index;
- tarjan_node_list[v].low_link = index;
- tarjan_stack.push(v);
- tarjan_node_list[v].on_stack = true;
- ++index;
-
- // Traverse outgoing edges
- for (auto e2 : m_node_based_graph->GetAdjacentEdgeRange(v))
- {
- const TarjanDynamicGraph::NodeIterator vprime =
- m_node_based_graph->GetTarget(e2);
- if (UINT_MAX == tarjan_node_list[vprime].index)
- {
- recursion_stack.emplace(true, TarjanStackFrame(vprime, v));
- }
- else
- {
- if (tarjan_node_list[vprime].on_stack &&
- tarjan_node_list[vprime].index < tarjan_node_list[v].low_link)
- {
- tarjan_node_list[v].low_link = tarjan_node_list[vprime].index;
- }
- }
- }
- }
- else
- {
- tarjan_node_list[currentFrame.parent].low_link =
- std::min(tarjan_node_list[currentFrame.parent].low_link,
- tarjan_node_list[v].low_link);
- // after recursion, lets do cycle checking
- // Check if we found a cycle. This is the bottom part of the recursion
- if (tarjan_node_list[v].low_link == tarjan_node_list[v].index)
- {
- NodeID vprime;
- do
- {
- vprime = tarjan_stack.top();
- tarjan_stack.pop();
- tarjan_node_list[vprime].on_stack = false;
- components_index[vprime] = component_index;
- ++size_of_current_component;
- } while (v != vprime);
-
- component_size_vector.emplace_back(size_of_current_component);
-
- if (size_of_current_component > 1000)
- {
- SimpleLogger().Write() << "large component [" << component_index
- << "]=" << size_of_current_component;
- }
-
- ++component_index;
- size_of_current_component = 0;
- }
- }
- }
- }
-
- SimpleLogger().Write() << "identified: " << component_size_vector.size()
- << " many components, marking small components";
-
- unsigned size_one_counter = std::count_if(component_size_vector.begin(),
- component_size_vector.end(),
- [] (unsigned value) { return 1 == value;});
-
- SimpleLogger().Write() << "identified " << size_one_counter << " SCCs of size 1";
-
- uint64_t total_network_distance = 0;
- p.reinit(m_node_based_graph->GetNumberOfNodes());
- NodeID last_u_node = m_node_based_graph->GetNumberOfNodes();
- for (NodeID u = 0; u < last_u_node; ++u)
- {
- p.printIncrement();
- for (auto e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
- {
- if (!m_node_based_graph->GetEdgeData(e1).reversedEdge)
- {
- continue;
- }
- const TarjanDynamicGraph::NodeIterator v = m_node_based_graph->GetTarget(e1);
-
- total_network_distance +=
- 100 * FixedPointCoordinate::ApproximateDistance(m_coordinate_list[u].lat,
- m_coordinate_list[u].lon,
- m_coordinate_list[v].lat,
- m_coordinate_list[v].lon);
-
- if (SHRT_MAX != m_node_based_graph->GetEdgeData(e1).type)
- {
- BOOST_ASSERT(e1 != UINT_MAX);
- BOOST_ASSERT(u != UINT_MAX);
- BOOST_ASSERT(v != UINT_MAX);
-
- const unsigned size_of_containing_component =
- std::min(component_size_vector[components_index[u]],
- component_size_vector[components_index[v]]);
-
- // edges that end on bollard nodes may actually be in two distinct components
- if (size_of_containing_component < 10)
- {
- OGRLineString lineString;
- lineString.addPoint(m_coordinate_list[u].lon / COORDINATE_PRECISION,
- m_coordinate_list[u].lat / COORDINATE_PRECISION);
- lineString.addPoint(m_coordinate_list[v].lon / COORDINATE_PRECISION,
- m_coordinate_list[v].lat / COORDINATE_PRECISION);
-
- OGRFeature *poFeature = OGRFeature::CreateFeature(poLayer->GetLayerDefn());
-
- poFeature->SetGeometry(&lineString);
- if (OGRERR_NONE != poLayer->CreateFeature(poFeature))
- {
- throw OSRMException("Failed to create feature in shapefile.");
- }
- OGRFeature::DestroyFeature(poFeature);
- }
- }
- }
- }
- OGRDataSource::DestroyDataSource(poDS);
- std::vector<NodeID>().swap(component_size_vector);
- BOOST_ASSERT_MSG(0 == component_size_vector.size() && 0 == component_size_vector.capacity(),
- "component_size_vector not properly deallocated");
-
- std::vector<NodeID>().swap(components_index);
- BOOST_ASSERT_MSG(0 == components_index.size() && 0 == components_index.capacity(),
- "icomponents_index not properly deallocated");
-
- SimpleLogger().Write() << "total network distance: " << (uint64_t)total_network_distance /
- 100 / 1000. << " km";
- }
-
- private:
- unsigned CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const
- {
- std::pair<NodeID, NodeID> restriction_source = {u, v};
- RestrictionMap::const_iterator restriction_iterator =
- m_restriction_map.find(restriction_source);
- if (restriction_iterator != m_restriction_map.end())
- {
- const unsigned index = restriction_iterator->second;
- for (const RestrictionSource &restriction_target : m_restriction_bucket_list.at(index))
- {
- if (restriction_target.second)
- {
- return restriction_target.first;
- }
- }
- }
- return UINT_MAX;
- }
-
- bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const
- {
- // only add an edge if turn is not a U-turn except it is the end of dead-end street.
- std::pair<NodeID, NodeID> restriction_source = {u, v};
- RestrictionMap::const_iterator restriction_iterator =
- m_restriction_map.find(restriction_source);
- if (restriction_iterator != m_restriction_map.end())
- {
- const unsigned index = restriction_iterator->second;
- for (const restriction_target &restriction_target : m_restriction_bucket_list.at(index))
- {
- if (w == restriction_target.first)
- {
- return true;
- }
- }
- }
- return false;
- }
-
- void DeleteFileIfExists(const std::string &file_name) const
- {
- if (boost::filesystem::exists(file_name))
- {
- boost::filesystem::remove(file_name);
- }
- }
-};
-
-#endif /* STRONGLYCONNECTEDCOMPONENTS_H_ */
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dc202c8..b6a40f9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,11 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.8)
+
+if(CMAKE_SOURCE_DIR STREQUAL CMAKE_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)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
include(CheckCXXCompilerFlag)
@@ -20,43 +27,56 @@ 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 ORSM tools" 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/)
-add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp FingerPrint.cpp.alwaysbuild
+add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/finger_print.cpp finger_print.cpp.alwaysbuild
COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR}
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FingerPrint-Config.cmake
DEPENDS
- ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp.in
- COMMENT "Configuring FingerPrint.cpp"
+ ${CMAKE_SOURCE_DIR}/Util/finger_print.cpp.in
+ COMMENT "Configuring finger_print.cpp"
VERBATIM)
-add_custom_target(FingerPrintConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp)
+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)
+set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework)
configure_file(
- ${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp.in
- ${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp
+ ${CMAKE_SOURCE_DIR}/Util/git_sha.cpp.in
+ ${CMAKE_SOURCE_DIR}/Util/git_sha.cpp
)
-file(GLOB ExtractorGlob Extractor/*.cpp)
-file(GLOB ImporterGlob DataStructures/Import*.cpp)
-add_library(IMPORT STATIC ${ImporterGlob})
-set(ExtractorSources extractor.cpp ${ExtractorGlob})
-add_executable(osrm-extract ${ExtractorSources})
+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(PHANTOMNODE OBJECT data_structures/phantom_node.cpp)
+add_library(EXCEPTION OBJECT Util/osrm_exception.cpp)
-file(GLOB PrepareGlob Contractor/*.cpp DataStructures/HilbertValue.cpp DataStructures/RestrictionMap.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_library(RESTRICTION OBJECT data_structures/restriction_map.cpp)
+
+file(GLOB PrepareGlob contractor/*.cpp data_structures/hilbert_value.cpp Util/compute_angle.cpp {RestrictionMapGlob})
set(PrepareSources prepare.cpp ${PrepareGlob})
-add_executable(osrm-prepare ${PrepareSources})
+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>)
file(GLOB ServerGlob Server/*.cpp)
-file(GLOB DescriptorGlob Descriptors/*.cpp)
-file(GLOB DatastructureGlob DataStructures/SearchEngineData.cpp DataStructures/RouteParameters.cpp)
-file(GLOB CoordinateGlob DataStructures/Coordinate.cpp)
-file(GLOB AlgorithmGlob Algorithms/*.cpp)
+file(GLOB DescriptorGlob descriptors/*.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 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)
set(
OSRMSources
@@ -67,14 +87,21 @@ set(
${AlgorithmGlob}
${HttpGlob}
)
-add_library(COORDLIB STATIC ${CoordinateGlob})
-add_library(FINGERPRINT STATIC Util/FingerPrint.cpp)
-add_library(OSRM ${OSRMSources} Util/GitDescription.cpp Util/FingerPrint.cpp)
-add_library(GITDESCRIPTION STATIC Util/GitDescription.cpp)
+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_dependencies(FINGERPRINT FingerPrintConfigure)
-add_executable(osrm-routed routed.cpp ${ServerGlob})
-add_executable(osrm-datastore datastore.cpp)
+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>)
+
+# 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>)
+
+# Benchmarks
+add_executable(rtree-bench EXCLUDE_FROM_ALL benchmarks/static_rtree.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION>)
# Check the release mode
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
@@ -98,7 +125,7 @@ if(CMAKE_BUILD_TYPE MATCHES Release)
# 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
- NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0")
+ 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")
@@ -106,18 +133,27 @@ if(CMAKE_BUILD_TYPE MATCHES Release)
endif (HAS_LTO_FLAG)
endif()
+if (NOT WIN32)
+add_definitions(-DBOOST_TEST_DYN_LINK)
+endif()
+
# Configuring compilers
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")
+ set(COLOR_FLAG "-fdiagnostics-color=auto")
+ 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")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -fPIC ${COLOR_FLAG}")
if (WIN32) # using mingw
- add_definitions(-DM_PI=3.141592653589793238462643383) # define M_PI
+ 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_OMP_LIB gomp)
endif()
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
# using Intel C++
@@ -129,20 +165,11 @@ elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
add_definitions(-DNOMINMAX) # avoid min and max macros that can break compilation
add_definitions(-D_USE_MATH_DEFINES) # define M_PI
add_definitions(-D_WIN32_WINNT=0x0501)
+ add_definitions(-DXML_STATIC)
+ find_library(ws2_32_LIBRARY_PATH ws2_32)
+ target_link_libraries(osrm-extract wsock32 ws2_32)
endif()
-# disable partitioning of LTO process when possible (fixes Debian issues)
-set(LTO_PARTITION_FLAGS "")
-CHECK_CXX_COMPILER_FLAG("-flto-partition=none" HAS_LTO_PARTITION_FLAG)
-if (HAS_LTO_PARTITION_FLAG)
- set(LTO_PARTITION_FLAGS "${LTO_PARTITION_FLAGS} -flto-partition=none")
-endif (HAS_LTO_PARTITION_FLAG)
-
-# Add Link-Time-Optimization flags, if supported (GCC >= 4.7) and enabled
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LTO_FLAGS}")
-set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LTO_FLAGS} ${LTO_PARTITION_FLAGS}")
-set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LTO_FLAGS} ${LTO_PARTITION_FLAGS}")
-
# Activate C++11
if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
ADD_DEFINITIONS(-std=c++11)
@@ -177,16 +204,23 @@ if(NOT Boost_FOUND)
endif()
include_directories(${Boost_INCLUDE_DIRS})
-target_link_libraries(OSRM ${Boost_LIBRARIES} COORDLIB)
-target_link_libraries(osrm-extract ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB IMPORT)
-target_link_libraries(osrm-prepare ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB IMPORT)
-target_link_libraries(osrm-routed ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM FINGERPRINT GITDESCRIPTION)
-target_link_libraries(osrm-datastore ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB)
+target_link_libraries(OSRM ${Boost_LIBRARIES})
+target_link_libraries(osrm-extract ${Boost_LIBRARIES})
+target_link_libraries(osrm-prepare ${Boost_LIBRARIES})
+target_link_libraries(osrm-routed ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
+target_link_libraries(osrm-datastore ${Boost_LIBRARIES})
+target_link_libraries(datastructure-tests ${Boost_LIBRARIES})
+target_link_libraries(algorithm-tests ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
+target_link_libraries(rtree-bench ${Boost_LIBRARIES})
find_package(Threads REQUIRED)
-target_link_libraries(osrm-extract ${CMAKE_THREAD_LIBS_INIT} ${OPTIONAL_OMP_LIB})
+target_link_libraries(osrm-extract ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(osrm-datastore ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(osrm-prepare ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(OSRM ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(datastructure-tests ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(algorithm-tests ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(rtree-bench ${CMAKE_THREAD_LIBS_INIT})
find_package(TBB REQUIRED)
if(WIN32 AND CMAKE_BUILD_TYPE MATCHES Debug)
@@ -196,21 +230,14 @@ target_link_libraries(osrm-datastore ${TBB_LIBRARIES})
target_link_libraries(osrm-extract ${TBB_LIBRARIES})
target_link_libraries(osrm-prepare ${TBB_LIBRARIES})
target_link_libraries(osrm-routed ${TBB_LIBRARIES})
+target_link_libraries(datastructure-tests ${TBB_LIBRARIES})
+target_link_libraries(algorithm-tests ${TBB_LIBRARIES})
+target_link_libraries(rtree-bench ${TBB_LIBRARIES})
include_directories(${TBB_INCLUDE_DIR})
-find_package(Lua52)
-if(NOT LUA52_FOUND)
- find_package(Lua51 REQUIRED)
- if(NOT APPLE)
- find_package(LuaJIT 5.1)
- endif()
-else()
- if(NOT APPLE)
- find_package(LuaJIT 5.2)
- endif()
-endif()
-
find_package( Luabind REQUIRED )
+include(check_luabind)
+
include_directories(${LUABIND_INCLUDE_DIR})
target_link_libraries(osrm-extract ${LUABIND_LIBRARY})
target_link_libraries(osrm-prepare ${LUABIND_LIBRARY})
@@ -224,9 +251,9 @@ else()
endif()
include_directories(${LUA_INCLUDE_DIR})
-find_package(LibXml2 REQUIRED)
-include_directories(${LIBXML2_INCLUDE_DIR})
-target_link_libraries(osrm-extract ${LIBXML2_LIBRARIES})
+find_package(EXPAT REQUIRED)
+include_directories(${EXPAT_INCLUDE_DIRS})
+target_link_libraries(osrm-extract ${EXPAT_LIBRARIES})
find_package( STXXL REQUIRED )
include_directories(${STXXL_INCLUDE_DIR})
@@ -234,6 +261,11 @@ 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)
+endif()
+
find_package( OSMPBF REQUIRED )
include_directories(${OSMPBF_INCLUDE_DIR})
target_link_libraries(osrm-extract ${OSMPBF_LIBRARY})
@@ -253,29 +285,40 @@ include_directories(${ZLIB_INCLUDE_DIRS})
target_link_libraries(osrm-extract ${ZLIB_LIBRARY})
target_link_libraries(osrm-routed ${ZLIB_LIBRARY})
-if(WITH_TOOLS)
+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_link_libraries(osrm-components ${TBB_LIBRARIES} IMPORT)
+ 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_link_libraries(osrm-components ${TBB_LIBRARIES})
include_directories(${GDAL_INCLUDE_DIR})
target_link_libraries(
osrm-components
- ${GDAL_LIBRARIES} ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB)
+ ${GDAL_LIBRARIES} ${Boost_LIBRARIES})
+ install(TARGETS osrm-components DESTINATION bin)
else()
message(FATAL_ERROR "libgdal and/or development headers not found")
endif()
- add_executable(osrm-cli Tools/simpleclient.cpp)
- target_link_libraries(osrm-cli ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM FINGERPRINT GITDESCRIPTION)
+ add_executable(osrm-cli tools/simpleclient.cpp $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER>)
+ 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_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES} GITDESCRIPTION)
- add_executable(osrm-unlock-all Tools/unlock_all_mutexes.cpp)
- target_link_libraries(osrm-unlock-all ${Boost_LIBRARIES} GITDESCRIPTION)
+ add_executable(osrm-io-benchmark tools/io-benchmark.cpp $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:LOGGER>)
+ target_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES})
+ add_executable(osrm-unlock-all tools/unlock_all_mutexes.cpp $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:EXCEPTION>)
+ target_link_libraries(osrm-unlock-all ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
if(UNIX AND NOT APPLE)
target_link_libraries(osrm-unlock-all rt)
endif()
+ add_executable(osrm-check-hsgr tools/check-hsgr.cpp $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:FINGERPRINT> $<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})
+
+ install(TARGETS osrm-cli DESTINATION bin)
+ install(TARGETS osrm-io-benchmark DESTINATION bin)
+ install(TARGETS osrm-unlock-all DESTINATION bin)
+ install(TARGETS osrm-check-hsgr DESTINATION bin)
+ install(TARGETS osrm-springclean DESTINATION bin)
endif()
file(GLOB InstallGlob Include/osrm/*.h Library/OSRM.h)
@@ -305,3 +348,8 @@ endforeach ()
configure_file(${CMAKE_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION lib/pkgconfig)
+
+if(BUILD_DEBIAN_PACKAGE)
+ include(CPackDebianConfig)
+ include(CPack)
+endif()
diff --git a/Contractor/TemporaryStorage.cpp b/Contractor/TemporaryStorage.cpp
deleted file mode 100644
index f9d4287..0000000
--- a/Contractor/TemporaryStorage.cpp
+++ /dev/null
@@ -1,172 +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 "TemporaryStorage.h"
-
-StreamData::StreamData()
- : write_mode(true),
- temp_path(boost::filesystem::unique_path(temp_directory / TemporaryFilePattern)),
- temp_file(new boost::filesystem::fstream(
- temp_path, std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary)),
- readWriteMutex(std::make_shared<boost::mutex>())
-{
- if (temp_file->fail())
- {
- throw OSRMException("temporary file could not be created");
- }
-}
-
-TemporaryStorage::TemporaryStorage() { temp_directory = boost::filesystem::temp_directory_path(); }
-
-TemporaryStorage &TemporaryStorage::GetInstance()
-{
- static TemporaryStorage static_instance;
- return static_instance;
-}
-
-TemporaryStorage::~TemporaryStorage() { RemoveAll(); }
-
-void TemporaryStorage::RemoveAll()
-{
- boost::mutex::scoped_lock lock(mutex);
- for (unsigned slot_id = 0; slot_id < stream_data_list.size(); ++slot_id)
- {
- DeallocateSlot(slot_id);
- }
- stream_data_list.clear();
-}
-
-int TemporaryStorage::AllocateSlot()
-{
- boost::mutex::scoped_lock lock(mutex);
- try { stream_data_list.push_back(StreamData()); }
- catch (boost::filesystem::filesystem_error &e) { Abort(e); }
- CheckIfTemporaryDeviceFull();
- return stream_data_list.size() - 1;
-}
-
-void TemporaryStorage::DeallocateSlot(const int slot_id)
-{
- try
- {
- StreamData &data = stream_data_list[slot_id];
- boost::mutex::scoped_lock lock(*data.readWriteMutex);
- if (!boost::filesystem::exists(data.temp_path))
- {
- return;
- }
- if (data.temp_file->is_open())
- {
- data.temp_file->close();
- }
-
- boost::filesystem::remove(data.temp_path);
- }
- catch (boost::filesystem::filesystem_error &e) { Abort(e); }
-}
-
-void TemporaryStorage::WriteToSlot(const int slot_id, char *pointer, const std::size_t size)
-{
- try
- {
- StreamData &data = stream_data_list[slot_id];
- BOOST_ASSERT(data.write_mode);
-
- boost::mutex::scoped_lock lock(*data.readWriteMutex);
- BOOST_ASSERT_MSG(data.write_mode, "Writing after first read is not allowed");
- if (1073741824 < data.buffer.size())
- {
- data.temp_file->write(&data.buffer[0], data.buffer.size());
- // data.temp_file->write(pointer, size);
- data.buffer.clear();
- CheckIfTemporaryDeviceFull();
- }
- data.buffer.insert(data.buffer.end(), pointer, pointer + size);
- }
- catch (boost::filesystem::filesystem_error &e) { Abort(e); }
-}
-void TemporaryStorage::ReadFromSlot(const int slot_id, char *pointer, const std::size_t size)
-{
- try
- {
- StreamData &data = stream_data_list[slot_id];
- boost::mutex::scoped_lock lock(*data.readWriteMutex);
- if (data.write_mode)
- {
- data.write_mode = false;
- data.temp_file->write(&data.buffer[0], data.buffer.size());
- data.buffer.clear();
- data.temp_file->seekg(data.temp_file->beg);
- BOOST_ASSERT(data.temp_file->beg == data.temp_file->tellg());
- }
- BOOST_ASSERT(!data.write_mode);
- data.temp_file->read(pointer, size);
- }
- catch (boost::filesystem::filesystem_error &error) { Abort(error); }
-}
-
-uint64_t TemporaryStorage::GetFreeBytesOnTemporaryDevice()
-{
- uint64_t value = -1;
- try
- {
- boost::filesystem::path path = boost::filesystem::temp_directory_path();
- boost::filesystem::space_info space_info = boost::filesystem::space(path);
- value = space_info.free;
- }
- catch (boost::filesystem::filesystem_error &error) { Abort(error); }
- return value;
-}
-
-void TemporaryStorage::CheckIfTemporaryDeviceFull()
-{
- boost::filesystem::path path = boost::filesystem::temp_directory_path();
- boost::filesystem::space_info space_info = boost::filesystem::space(path);
- if ((1024 * 1024) > space_info.free)
- {
- throw OSRMException("temporary device is full");
- }
-}
-
-boost::filesystem::fstream::pos_type TemporaryStorage::Tell(const int slot_id)
-{
- boost::filesystem::fstream::pos_type position;
- try
- {
- StreamData &data = stream_data_list[slot_id];
- boost::mutex::scoped_lock lock(*data.readWriteMutex);
- position = data.temp_file->tellp();
- }
- catch (boost::filesystem::filesystem_error &e) { Abort(e); }
- return position;
-}
-
-void TemporaryStorage::Abort(const boost::filesystem::filesystem_error &error)
-{
- RemoveAll();
- throw OSRMException(error.what());
-}
diff --git a/Contractor/TemporaryStorage.h b/Contractor/TemporaryStorage.h
deleted file mode 100644
index ca8598b..0000000
--- a/Contractor/TemporaryStorage.h
+++ /dev/null
@@ -1,96 +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 TEMPORARYSTORAGE_H_
-#define TEMPORARYSTORAGE_H_
-
-#include "../Util/BoostFileSystemFix.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../typedefs.h"
-
-#include <boost/assert.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-#include <boost/thread/mutex.hpp>
-
-#include <cstdint>
-
-#include <vector>
-#include <fstream>
-#include <memory>
-
-struct StreamData
-{
- bool write_mode;
- boost::filesystem::path temp_path;
- std::shared_ptr<boost::filesystem::fstream> temp_file;
- std::shared_ptr<boost::mutex> readWriteMutex;
- std::vector<char> buffer;
-
- StreamData();
-};
-
-// This class implements a singleton file storage for temporary data.
-// temporary slots can be accessed by other objects through an int
-// On deallocation every slot gets deallocated
-//
-// Access is sequential, which means, that there is no random access
-// -> Data is written in first phase and reread in second.
-
-static boost::filesystem::path temp_directory;
-static std::string TemporaryFilePattern("OSRM-%%%%-%%%%-%%%%");
-class TemporaryStorage
-{
- public:
- static TemporaryStorage &GetInstance();
- virtual ~TemporaryStorage();
-
- int AllocateSlot();
- void DeallocateSlot(const int slot_id);
- void WriteToSlot(const int slot_id, char *pointer, const std::size_t size);
- void ReadFromSlot(const int slot_id, char *pointer, const std::size_t size);
- // returns the number of free bytes
- uint64_t GetFreeBytesOnTemporaryDevice();
- boost::filesystem::fstream::pos_type Tell(const int slot_id);
- void RemoveAll();
-
- private:
- TemporaryStorage();
- TemporaryStorage(TemporaryStorage const &) {};
-
- TemporaryStorage &operator=(TemporaryStorage const &) { return *this; }
-
- void Abort(const boost::filesystem::filesystem_error &e);
- void CheckIfTemporaryDeviceFull();
-
- // vector of file streams that is used to store temporary data
- boost::mutex mutex;
- std::vector<StreamData> stream_data_list;
-};
-
-#endif /* TEMPORARYSTORAGE_H_ */
diff --git a/DataStructures/DeallocatingVector.h b/DataStructures/DeallocatingVector.h
deleted file mode 100644
index 013cc1d..0000000
--- a/DataStructures/DeallocatingVector.h
+++ /dev/null
@@ -1,401 +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 DEALLOCATINGVECTOR_H_
-#define DEALLOCATINGVECTOR_H_
-
-#include <boost/assert.hpp>
-#include <cstring>
-#include <vector>
-
-template <typename ElementT,
- std::size_t bucketSizeC = 8388608 / sizeof(ElementT),
- bool DeallocateC = false>
-class DeallocatingVectorIterator : public std::iterator<std::random_access_iterator_tag, ElementT>
-{
- protected:
- class DeallocatingVectorIteratorState
- {
- private:
- // make constructors explicit, so we do not mix random access and deallocation iterators.
- DeallocatingVectorIteratorState();
-
- public:
- explicit DeallocatingVectorIteratorState(const DeallocatingVectorIteratorState &r)
- : index(r.index), bucket_list(r.bucket_list)
- {
- }
- explicit DeallocatingVectorIteratorState(const std::size_t idx,
- std::vector<ElementT *> &input_list)
- : index(idx), bucket_list(input_list)
- {
- }
- std::size_t index;
- std::vector<ElementT *> &bucket_list;
-
- inline bool operator!=(const DeallocatingVectorIteratorState &other)
- {
- return index != other.index;
- }
-
- inline bool operator==(const DeallocatingVectorIteratorState &other)
- {
- return index == other.index;
- }
-
- bool operator<(const DeallocatingVectorIteratorState &other) const
- {
- return index < other.index;
- }
-
- bool operator>(const DeallocatingVectorIteratorState &other) const
- {
- return index > other.index;
- }
-
- bool operator>=(const DeallocatingVectorIteratorState &other) const
- {
- return index >= other.index;
- }
-
- // This is a hack to make assignment operator possible with reference member
- inline DeallocatingVectorIteratorState &operator=(const DeallocatingVectorIteratorState &a)
- {
- if (this != &a)
- {
- this->DeallocatingVectorIteratorState::
- ~DeallocatingVectorIteratorState(); // explicit non-virtual destructor
- new (this) DeallocatingVectorIteratorState(a); // placement new
- }
- return *this;
- }
- };
-
- DeallocatingVectorIteratorState current_state;
-
- public:
- typedef std::random_access_iterator_tag iterator_category;
- typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::value_type
- value_type;
- typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::difference_type
- difference_type;
- typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::reference reference;
- typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::pointer pointer;
-
- DeallocatingVectorIterator() {}
-
- template <typename T2>
- explicit DeallocatingVectorIterator(const DeallocatingVectorIterator<T2> &r)
- : current_state(r.current_state)
- {
- }
-
- DeallocatingVectorIterator(std::size_t idx, std::vector<ElementT *> &input_list)
- : current_state(idx, input_list)
- {
- }
- explicit DeallocatingVectorIterator(const DeallocatingVectorIteratorState &r) : current_state(r) {}
-
- template <typename T2>
- DeallocatingVectorIterator &operator=(const DeallocatingVectorIterator<T2> &r)
- {
- if (DeallocateC)
- {
- BOOST_ASSERT(false);
- }
- current_state = r.current_state;
- return *this;
- }
-
- inline DeallocatingVectorIterator &operator++()
- { // prefix
- ++current_state.index;
- return *this;
- }
-
- inline DeallocatingVectorIterator &operator--()
- { // prefix
- if (DeallocateC)
- {
- BOOST_ASSERT(false);
- }
- --current_state.index;
- return *this;
- }
-
- inline DeallocatingVectorIterator operator++(int)
- { // postfix
- DeallocatingVectorIteratorState my_state(current_state);
- current_state.index++;
- return DeallocatingVectorIterator(my_state);
- }
- inline DeallocatingVectorIterator operator--(int)
- { // postfix
- if (DeallocateC)
- {
- BOOST_ASSERT(false);
- }
- DeallocatingVectorIteratorState my_state(current_state);
- current_state.index--;
- return DeallocatingVectorIterator(my_state);
- }
-
- inline DeallocatingVectorIterator operator+(const difference_type &n) const
- {
- DeallocatingVectorIteratorState my_state(current_state);
- my_state.index += n;
- return DeallocatingVectorIterator(my_state);
- }
-
- inline DeallocatingVectorIterator &operator+=(const difference_type &n)
- {
- current_state.index += n;
- return *this;
- }
-
- inline DeallocatingVectorIterator operator-(const difference_type &n) const
- {
- if (DeallocateC)
- {
- BOOST_ASSERT(false);
- }
- DeallocatingVectorIteratorState my_state(current_state);
- my_state.index -= n;
- return DeallocatingVectorIterator(my_state);
- }
-
- inline DeallocatingVectorIterator &operator-=(const difference_type &n) const
- {
- if (DeallocateC)
- {
- BOOST_ASSERT(false);
- }
- current_state.index -= n;
- return *this;
- }
-
- inline reference operator*() const
- {
- std::size_t current_bucket = current_state.index / bucketSizeC;
- std::size_t current_index = current_state.index % bucketSizeC;
- return (current_state.bucket_list[current_bucket][current_index]);
- }
-
- inline pointer operator->() const
- {
- std::size_t current_bucket = current_state.index / bucketSizeC;
- std::size_t current_index = current_state.index % bucketSizeC;
- return &(current_state.bucket_list[current_bucket][current_index]);
- }
-
- inline bool operator!=(const DeallocatingVectorIterator &other)
- {
- return current_state != other.current_state;
- }
-
- inline bool operator==(const DeallocatingVectorIterator &other)
- {
- return current_state == other.current_state;
- }
-
- inline bool operator<(const DeallocatingVectorIterator &other) const
- {
- return current_state < other.current_state;
- }
-
- inline bool operator>(const DeallocatingVectorIterator &other) const
- {
- return current_state > other.current_state;
- }
-
- inline bool operator>=(const DeallocatingVectorIterator &other) const
- {
- return current_state >= other.current_state;
- }
-
- difference_type operator-(const DeallocatingVectorIterator &other)
- {
- if (DeallocateC)
- {
- BOOST_ASSERT(false);
- }
- return current_state.index - other.current_state.index;
- }
-};
-
-template <typename ElementT, std::size_t bucketSizeC = 8388608 / sizeof(ElementT)>
-class DeallocatingVector
-{
- private:
- std::size_t current_size;
- std::vector<ElementT *> bucket_list;
-
- public:
- typedef ElementT value_type;
- typedef DeallocatingVectorIterator<ElementT, bucketSizeC, false> iterator;
- typedef DeallocatingVectorIterator<ElementT, bucketSizeC, false> const_iterator;
-
- // this iterator deallocates all buckets that have been visited. Iterators to visited objects
- // become invalid.
- typedef DeallocatingVectorIterator<ElementT, bucketSizeC, true> deallocation_iterator;
-
- DeallocatingVector() : current_size(0)
- {
- // initial bucket
- bucket_list.emplace_back(new ElementT[bucketSizeC]);
- }
-
- ~DeallocatingVector() { clear(); }
-
- inline void swap(DeallocatingVector<ElementT, bucketSizeC> &other)
- {
- std::swap(current_size, other.current_size);
- bucket_list.swap(other.bucket_list);
- }
-
- inline void clear()
- {
- // Delete[]'ing ptr's to all Buckets
- for (unsigned i = 0; i < bucket_list.size(); ++i)
- {
- if (nullptr != bucket_list[i])
- {
- delete[] bucket_list[i];
- bucket_list[i] = nullptr;
- }
- }
- // Removing all ptrs from vector
- std::vector<ElementT *>().swap(bucket_list);
- current_size = 0;
- }
-
- inline void push_back(const ElementT &element)
- {
- const std::size_t current_capacity = capacity();
- if (current_size == current_capacity)
- {
- bucket_list.push_back(new ElementT[bucketSizeC]);
- }
-
- std::size_t current_index = size() % bucketSizeC;
- bucket_list.back()[current_index] = element;
- ++current_size;
- }
-
- inline void emplace_back(const ElementT &&element)
- {
- const std::size_t current_capacity = capacity();
- if (current_size == current_capacity)
- {
- bucket_list.push_back(new ElementT[bucketSizeC]);
- }
-
- const std::size_t current_index = size() % bucketSizeC;
- bucket_list.back()[current_index] = element;
- ++current_size;
- }
-
- inline void reserve(const std::size_t) const
- {
- // don't do anything
- }
-
- inline void resize(const std::size_t new_size)
- {
- if (new_size > current_size)
- {
- while (capacity() < new_size)
- {
- bucket_list.push_back(new ElementT[bucketSizeC]);
- }
- current_size = new_size;
- }
- if (new_size < current_size)
- {
- const std::size_t number_of_necessary_buckets = 1 + (new_size / bucketSizeC);
-
- for (std::size_t i = number_of_necessary_buckets; i < bucket_list.size(); ++i)
- {
- delete[] bucket_list[i];
- }
- bucket_list.resize(number_of_necessary_buckets);
- current_size = new_size;
- }
- }
-
- inline std::size_t size() const { return current_size; }
-
- inline std::size_t capacity() const { return bucket_list.size() * bucketSizeC; }
-
- inline iterator begin() { return iterator(static_cast<std::size_t>(0), bucket_list); }
-
- inline iterator end() { return iterator(size(), bucket_list); }
-
- inline deallocation_iterator dbegin()
- {
- return deallocation_iterator(static_cast<std::size_t>(0), bucket_list);
- }
-
- inline deallocation_iterator dend() { return deallocation_iterator(size(), bucket_list); }
-
- inline 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); }
-
- inline ElementT &operator[](const std::size_t index)
- {
- std::size_t _bucket = index / bucketSizeC;
- std::size_t _index = index % bucketSizeC;
- return (bucket_list[_bucket][_index]);
- }
-
- const inline ElementT &operator[](const std::size_t index) const
- {
- std::size_t _bucket = index / bucketSizeC;
- std::size_t _index = index % bucketSizeC;
- return (bucket_list[_bucket][_index]);
- }
-
- inline ElementT &back()
- {
- std::size_t _bucket = current_size / bucketSizeC;
- std::size_t _index = current_size % bucketSizeC;
- return (bucket_list[_bucket][_index]);
- }
-
- const inline ElementT &back() const
- {
- std::size_t _bucket = current_size / bucketSizeC;
- std::size_t _index = current_size % bucketSizeC;
- return (bucket_list[_bucket][_index]);
- }
-};
-
-#endif /* DEALLOCATINGVECTOR_H_ */
diff --git a/DataStructures/NodeBasedGraph.h b/DataStructures/NodeBasedGraph.h
deleted file mode 100644
index 98393fb..0000000
--- a/DataStructures/NodeBasedGraph.h
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef __NODE_BASED_GRAPH_H__
-#define __NODE_BASED_GRAPH_H__
-
-#include "DynamicGraph.h"
-#include "ImportEdge.h"
-#include "../Util/SimpleLogger.h"
-
-#include <tbb/parallel_sort.h>
-
-#include <memory>
-
-struct NodeBasedEdgeData
-{
- NodeBasedEdgeData()
- : distance(INVALID_EDGE_WEIGHT), edgeBasedNodeID(SPECIAL_NODEID),
- nameID(std::numeric_limits<unsigned>::max()), type(std::numeric_limits<short>::max()),
- isAccessRestricted(false), shortcut(false), forward(false), backward(false),
- roundabout(false), ignore_in_grid(false), contraFlow(false)
- {
- }
-
- int distance;
- unsigned edgeBasedNodeID;
- unsigned nameID;
- short type;
- bool isAccessRestricted : 1;
- bool shortcut : 1;
- bool forward : 1;
- bool backward : 1;
- bool roundabout : 1;
- bool ignore_in_grid : 1;
- bool contraFlow : 1;
-
- void SwapDirectionFlags()
- {
- bool temp_flag = forward;
- forward = backward;
- backward = temp_flag;
- }
-
- bool IsEqualTo(const NodeBasedEdgeData &other) const
- {
- return (forward == other.forward) && (backward == other.backward) &&
- (nameID == other.nameID) && (ignore_in_grid == other.ignore_in_grid) &&
- (contraFlow == other.contraFlow);
- }
-};
-
-typedef DynamicGraph<NodeBasedEdgeData> NodeBasedDynamicGraph;
-
-// Factory method to create NodeBasedDynamicGraph from ImportEdges
-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");
- // tbb::parallel_sort(input_edge_list.begin(), input_edge_list.end());
-
- DeallocatingVector<NodeBasedDynamicGraph::InputEdge> edges_list;
- NodeBasedDynamicGraph::InputEdge edge;
- for (const ImportEdge &import_edge : input_edge_list)
- {
- if (import_edge.forward)
- {
- edge.source = import_edge.source;
- edge.target = import_edge.target;
- edge.data.forward = import_edge.forward;
- edge.data.backward = import_edge.backward;
- }
- else
- {
- edge.source = import_edge.target;
- edge.target = import_edge.source;
- edge.data.backward = import_edge.forward;
- edge.data.forward = import_edge.backward;
- }
-
- if (edge.source == edge.target)
- {
- continue;
- }
-
- edge.data.distance = (std::max)((int)import_edge.weight, 1);
- BOOST_ASSERT(edge.data.distance > 0);
- edge.data.shortcut = false;
- edge.data.roundabout = import_edge.roundabout;
- edge.data.ignore_in_grid = import_edge.in_tiny_cc;
- edge.data.nameID = import_edge.name_id;
- edge.data.type = import_edge.type;
- edge.data.isAccessRestricted = import_edge.access_restricted;
- edge.data.contraFlow = import_edge.contra_flow;
- edges_list.push_back(edge);
-
- if (!import_edge.is_split)
- {
- using std::swap; // enable ADL
- swap(edge.source, edge.target);
- edge.data.SwapDirectionFlags();
- edges_list.push_back(edge);
- }
- }
-
- // remove duplicate edges
- std::sort(edges_list.begin(), edges_list.end());
- NodeID edge_count = 0;
- for (NodeID i = 0; i < edges_list.size(); )
- {
- const NodeID source = edges_list[i].source;
- const NodeID target = edges_list[i].target;
- // remove eigenloops
- if (source == target)
- {
- i++;
- continue;
- }
- NodeBasedDynamicGraph::InputEdge forward_edge;
- NodeBasedDynamicGraph::InputEdge reverse_edge;
- forward_edge = reverse_edge = edges_list[i];
- 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();
- // remove parallel edges
- while (i < edges_list.size() && edges_list[i].source == source && edges_list[i].target == target)
- {
- if (edges_list[i].data.forward)
- {
- forward_edge.data.distance =
- std::min(edges_list[i].data.distance, forward_edge.data.distance);
- }
- if (edges_list[i].data.backward)
- {
- reverse_edge.data.distance =
- std::min(edges_list[i].data.distance, reverse_edge.data.distance);
- }
- ++i;
- }
- // 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())
- {
- forward_edge.data.backward = true;
- edges_list[edge_count++] = forward_edge;
- }
- }
- else
- { // insert seperate edges
- if (((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())
- {
- 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();
-
- auto graph = std::make_shared<NodeBasedDynamicGraph>(number_of_nodes, edges_list);
- return graph;
-}
-
-#endif // __NODE_BASED_GRAPH_H__
diff --git a/DataStructures/PhantomNodes.h b/DataStructures/PhantomNodes.h
deleted file mode 100644
index 2a2a924..0000000
--- a/DataStructures/PhantomNodes.h
+++ /dev/null
@@ -1,173 +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 PHANTOM_NODES_H
-#define PHANTOM_NODES_H
-
-#include <osrm/Coordinate.h>
-#include "../Util/SimpleLogger.h"
-#include "../typedefs.h"
-
-#include <vector>
-
-struct PhantomNode
-{
- PhantomNode(NodeID forward_node_id, NodeID reverse_node_id, unsigned name_id,
- int forward_weight, int reverse_weight, int forward_offset, int reverse_offset,
- unsigned packed_geometry_id, FixedPointCoordinate &location,
- unsigned short fwd_segment_position) :
- 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),
- location(location),
- fwd_segment_position(fwd_segment_position)
- { }
-
- 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),
- fwd_segment_position(0)
- { }
-
- 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;
- FixedPointCoordinate location;
- unsigned short fwd_segment_position;
-
- int GetForwardWeightPlusOffset() const
- {
- if (SPECIAL_NODEID == forward_node_id)
- {
- return 0;
- }
- const int result = (forward_offset + forward_weight);
- return result;
- }
-
- int GetReverseWeightPlusOffset() const
- {
- if (SPECIAL_NODEID == reverse_node_id)
- {
- return 0;
- }
- const int result = (reverse_offset + reverse_weight);
- return result;
- }
-
- bool isBidirected() const
- {
- return (forward_node_id != SPECIAL_NODEID) &&
- (reverse_node_id != SPECIAL_NODEID);
- }
-
- bool IsCompressed() const
- {
- return (forward_offset != 0) || (reverse_offset != 0);
- }
-
- bool isValid(const unsigned numberOfNodes) const
- {
- return
- location.isValid() &&
- (
- (forward_node_id < numberOfNodes) ||
- (reverse_node_id < numberOfNodes)
- ) &&
- (
- (forward_weight != INVALID_EDGE_WEIGHT) ||
- (reverse_weight != INVALID_EDGE_WEIGHT)
- ) &&
- (name_id != std::numeric_limits<unsigned>::max()
- );
- }
-
- bool isValid() const
- {
- return location.isValid() &&
- (name_id != std::numeric_limits<unsigned>::max());
- }
-
- bool operator==(const PhantomNode & other) const
- {
- return location == other.location;
- }
-};
-
-typedef std::vector<std::vector<PhantomNode>> PhantomNodeArray;
-
-struct PhantomNodeLists
-{
- std::vector<PhantomNode> source_phantom_list;
- std::vector<PhantomNode> target_phantom_list;
-};
-
-struct PhantomNodes
-{
- PhantomNode source_phantom;
- PhantomNode target_phantom;
-};
-
-inline std::ostream& operator<<(std::ostream &out, const PhantomNodes & pn)
-{
- out << "source_coord: " << pn.source_phantom.location << "\n";
- out << "target_coord: " << pn.target_phantom.location << std::endl;
- return out;
-}
-
-inline std::ostream& operator<<(std::ostream &out, const PhantomNode & pn)
-{
- out << "node1: " << pn.forward_node_id << ", " <<
- "node2: " << pn.reverse_node_id << ", " <<
- "name: " << pn.name_id << ", " <<
- "fwd-w: " << pn.forward_weight << ", " <<
- "rev-w: " << pn.reverse_weight << ", " <<
- "fwd-o: " << pn.forward_offset << ", " <<
- "rev-o: " << pn.reverse_offset << ", " <<
- "geom: " << pn.packed_geometry_id << ", " <<
- "pos: " << pn.fwd_segment_position << ", " <<
- "loc: " << pn.location;
- return out;
-}
-
-#endif // PHANTOM_NODES_H
diff --git a/Descriptors/GPXDescriptor.h b/Descriptors/GPXDescriptor.h
deleted file mode 100644
index 50efd9a..0000000
--- a/Descriptors/GPXDescriptor.h
+++ /dev/null
@@ -1,100 +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 GPX_DESCRIPTOR_H
-#define GPX_DESCRIPTOR_H
-
-#include "BaseDescriptor.h"
-
-template <class DataFacadeT> class GPXDescriptor : public BaseDescriptor<DataFacadeT>
-{
- private:
- DescriptorConfig config;
- FixedPointCoordinate current;
- DataFacadeT * facade;
-
- void AddRoutePoint(const FixedPointCoordinate & coordinate, std::vector<char> & output)
- {
- const std::string route_point_head = "<rtept lat=\"";
- const std::string route_point_middle = " lon=\"";
- const std::string route_point_tail = "\"></rtept>";
-
- std::string tmp;
-
- FixedPointCoordinate::convertInternalLatLonToString(coordinate.lat, tmp);
- output.insert(output.end(), route_point_head.begin(), route_point_head.end());
- output.insert(output.end(), tmp.begin(), tmp.end());
- output.push_back('\"');
-
- FixedPointCoordinate::convertInternalLatLonToString(coordinate.lon, tmp);
- output.insert(output.end(), route_point_middle.begin(), route_point_middle.end());
- output.insert(output.end(), tmp.begin(), tmp.end());
- output.insert(output.end(), route_point_tail.begin(), route_point_tail.end());
- }
-
- public:
- GPXDescriptor(DataFacadeT *facade) : facade(facade) {}
-
- void SetConfig(const DescriptorConfig &c) { config = c; }
-
- // TODO: reorder parameters
- void Run(const RawRouteData &raw_route, http::Reply &reply)
- {
- 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.topografix.com/GPX/1/1 gpx.xsd"
- "\">"
- "<metadata><copyright author=\"Project OSRM\"><license>Data (c)"
- " OpenStreetMap contributors (ODbL)</license></copyright>"
- "</metadata>"
- "<rte>");
- reply.content.insert(reply.content.end(), header.begin(), header.end());
- const bool found_route = (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT) &&
- (!raw_route.unpacked_path_segments.front().empty());
- if (found_route)
- {
- AddRoutePoint(raw_route.segment_end_coordinates.front().source_phantom.location, reply.content);
-
- for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
- {
- for (const PathData &path_data : path_data_vector)
- {
- const FixedPointCoordinate current_coordinate =
- facade->GetCoordinateOfNode(path_data.node);
- AddRoutePoint(current_coordinate, reply.content);
- }
- }
- AddRoutePoint(raw_route.segment_end_coordinates.back().target_phantom.location, reply.content);
-
- }
- std::string footer("</rte></gpx>");
- reply.content.insert(reply.content.end(), footer.begin(), footer.end());
- }
-};
-#endif // GPX_DESCRIPTOR_H
diff --git a/Docs/webclient.txt b/Docs/webclient.txt
deleted file mode 100644
index 55fcd15..0000000
--- a/Docs/webclient.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-The javascript based web client is a seperate project available at
-
-https://github.com/DennisSchiefer/Project-OSRM-Web
\ No newline at end of file
diff --git a/Extractor/BaseParser.cpp b/Extractor/BaseParser.cpp
deleted file mode 100644
index 4ab090f..0000000
--- a/Extractor/BaseParser.cpp
+++ /dev/null
@@ -1,139 +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 "BaseParser.h"
-#include "ExtractionWay.h"
-#include "ScriptingEnvironment.h"
-
-#include "../DataStructures/ImportNode.h"
-#include "../Util/LuaUtil.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-
-#include <boost/algorithm/string.hpp>
-#include <boost/algorithm/string/regex.hpp>
-#include <boost/ref.hpp>
-#include <boost/regex.hpp>
-
-BaseParser::BaseParser(ExtractorCallbacks *extractor_callbacks,
- ScriptingEnvironment &scripting_environment)
- : extractor_callbacks(extractor_callbacks),
- lua_state(scripting_environment.getLuaState()),
- scripting_environment(scripting_environment), use_turn_restrictions(true)
-{
- ReadUseRestrictionsSetting();
- ReadRestrictionExceptions();
-}
-
-void BaseParser::ReadUseRestrictionsSetting()
-{
- if (0 != luaL_dostring(lua_state, "return use_turn_restrictions\n"))
- {
- throw OSRMException("ERROR occured in scripting block");
- }
- if (lua_isboolean(lua_state, -1))
- {
- use_turn_restrictions = lua_toboolean(lua_state, -1);
- }
- if (use_turn_restrictions)
- {
- SimpleLogger().Write() << "Using turn restrictions";
- }
- else
- {
- SimpleLogger().Write() << "Ignoring turn restrictions";
- }
-}
-
-void BaseParser::ReadRestrictionExceptions()
-{
- if (lua_function_exists(lua_state, "get_exceptions"))
- {
- // get list of turn restriction exceptions
- luabind::call_function<void>(
- lua_state, "get_exceptions", boost::ref(restriction_exceptions));
- const unsigned exception_count = restriction_exceptions.size();
- SimpleLogger().Write() << "Found " << exception_count
- << " exceptions to turn restrictions:";
- for (const std::string &str : restriction_exceptions)
- {
- SimpleLogger().Write() << " " << str;
- }
- }
- else
- {
- SimpleLogger().Write() << "Found no exceptions to turn restrictions";
- }
-}
-
-void BaseParser::report_errors(lua_State *lua_state, const int status) const
-{
- if (0 != status)
- {
- std::cerr << "-- " << lua_tostring(lua_state, -1) << std::endl;
- lua_pop(lua_state, 1); // remove error message
- }
-}
-
-void BaseParser::ParseNodeInLua(ImportNode &node, lua_State *local_lua_state)
-{
- luabind::call_function<void>(local_lua_state, "node_function", boost::ref(node));
-}
-
-void BaseParser::ParseWayInLua(ExtractionWay &way, lua_State *local_lua_state)
-{
- luabind::call_function<void>(local_lua_state, "way_function", boost::ref(way));
-}
-
-bool BaseParser::ShouldIgnoreRestriction(const std::string &except_tag_string) const
-{
- // should this restriction be ignored? yes if there's an overlap between:
- // a) the list of modes in the except tag of the restriction
- // (except_tag_string), eg: except=bus;bicycle
- // b) the lua profile defines a hierachy of modes,
- // eg: [access, vehicle, bicycle]
-
- if (except_tag_string.empty())
- {
- return false;
- }
-
- // Be warned, this is quadratic work here, but we assume that
- // only a few exceptions are actually defined.
- std::vector<std::string> exceptions;
- boost::algorithm::split_regex(exceptions, except_tag_string, boost::regex("[;][ ]*"));
- 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;
-}
diff --git a/Extractor/BaseParser.h b/Extractor/BaseParser.h
deleted file mode 100644
index b18da34..0000000
--- a/Extractor/BaseParser.h
+++ /dev/null
@@ -1,67 +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 BASEPARSER_H_
-#define BASEPARSER_H_
-
-#include <string>
-#include <vector>
-
-struct lua_State;
-class ExtractorCallbacks;
-class ScriptingEnvironment;
-struct ExtractionWay;
-struct ImportNode;
-
-class BaseParser
-{
- public:
- BaseParser() = delete;
- BaseParser(const BaseParser &) = delete;
- BaseParser(ExtractorCallbacks *extractor_callbacks,
- ScriptingEnvironment &scripting_environment);
- virtual ~BaseParser() {}
- virtual bool ReadHeader() = 0;
- virtual bool Parse() = 0;
-
- virtual void ParseNodeInLua(ImportNode &node, lua_State *lua_state);
- virtual void ParseWayInLua(ExtractionWay &way, lua_State *lua_state);
- virtual void report_errors(lua_State *lua_state, const int status) const;
-
- protected:
- virtual void ReadUseRestrictionsSetting();
- virtual void ReadRestrictionExceptions();
- virtual bool ShouldIgnoreRestriction(const std::string &except_tag_string) const;
-
- ExtractorCallbacks *extractor_callbacks;
- lua_State *lua_state;
- ScriptingEnvironment &scripting_environment;
- std::vector<std::string> restriction_exceptions;
- bool use_turn_restrictions;
-};
-
-#endif /* BASEPARSER_H_ */
diff --git a/Extractor/ExtractionWay.h b/Extractor/ExtractionWay.h
deleted file mode 100644
index 6c3c93d..0000000
--- a/Extractor/ExtractionWay.h
+++ /dev/null
@@ -1,79 +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 EXTRACTION_WAY_H
-#define EXTRACTION_WAY_H
-
-#include "../DataStructures/HashTable.h"
-#include "../typedefs.h"
-
-#include <string>
-#include <vector>
-
-struct ExtractionWay
-{
- ExtractionWay() { Clear(); }
-
- inline void Clear()
- {
- id = SPECIAL_NODEID;
- nameID = INVALID_NAMEID;
- path.clear();
- keyVals.Clear();
- direction = ExtractionWay::notSure;
- speed = -1;
- backward_speed = -1;
- duration = -1;
- type = -1;
- access = true;
- roundabout = false;
- isAccessRestricted = false;
- ignoreInGrid = false;
- }
-
- enum Directions
- { notSure = 0,
- oneway,
- bidirectional,
- opposite };
- unsigned id;
- unsigned nameID;
- double speed;
- double backward_speed;
- double duration;
- Directions direction;
- std::string name;
- short type;
- bool access;
- bool roundabout;
- bool isAccessRestricted;
- bool ignoreInGrid;
- std::vector<NodeID> path;
- HashTable<std::string, std::string> keyVals;
-};
-
-#endif // EXTRACTION_WAY_H
diff --git a/Extractor/ExtractorCallbacks.cpp b/Extractor/ExtractorCallbacks.cpp
deleted file mode 100644
index 5e27817..0000000
--- a/Extractor/ExtractorCallbacks.cpp
+++ /dev/null
@@ -1,171 +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 "ExtractorCallbacks.h"
-#include "ExtractionContainers.h"
-#include "ExtractionWay.h"
-
-#include "../DataStructures/Restriction.h"
-#include "../DataStructures/ImportNode.h"
-#include "../Util/SimpleLogger.h"
-
-#include <osrm/Coordinate.h>
-
-#include <limits>
-#include <string>
-#include <vector>
-
-ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers,
- std::unordered_map<std::string, NodeID> &string_map)
- : string_map(string_map), external_memory(extraction_containers)
-{
-}
-
-/** warning: caller needs to take care of synchronization! */
-void ExtractorCallbacks::ProcessNode(const ExternalMemoryNode &n)
-{
- if (n.lat <= 85 * COORDINATE_PRECISION && n.lat >= -85 * COORDINATE_PRECISION)
- {
- external_memory.all_nodes_list.push_back(n);
- }
-}
-
-bool ExtractorCallbacks::ProcessRestriction(const InputRestrictionContainer &restriction)
-{
- external_memory.restrictions_list.push_back(restriction);
- return true;
-}
-
-/** warning: caller needs to take care of synchronization! */
-void ExtractorCallbacks::ProcessWay(ExtractionWay &parsed_way)
-{
- if ((0 >= parsed_way.speed) && (0 >= parsed_way.duration))
- { // Only true if the way is specified by the speed profile
- return;
- }
-
- if (parsed_way.path.size() <= 1)
- { // safe-guard against broken data
- return;
- }
-
- if (std::numeric_limits<unsigned>::max() == parsed_way.id)
- {
- SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << parsed_way.id
- << " of size " << parsed_way.path.size();
- return;
- }
-
- if (0 < parsed_way.duration)
- {
- // TODO: iterate all way segments and set duration corresponding to the length of each
- // segment
- parsed_way.speed = parsed_way.duration / (parsed_way.path.size() - 1);
- }
-
- if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.speed))
- {
- SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << parsed_way.id;
- return;
- }
-
- // Get the unique identifier for the street name
- const auto &string_map_iterator = string_map.find(parsed_way.name);
- if (string_map.end() == string_map_iterator)
- {
- parsed_way.nameID = external_memory.name_list.size();
- external_memory.name_list.push_back(parsed_way.name);
- string_map.insert(std::make_pair(parsed_way.name, parsed_way.nameID));
- }
- else
- {
- parsed_way.nameID = string_map_iterator->second;
- }
-
- if (ExtractionWay::opposite == parsed_way.direction)
- {
- std::reverse(parsed_way.path.begin(), parsed_way.path.end());
- parsed_way.direction = ExtractionWay::oneway;
- }
-
- const bool split_edge =
- (parsed_way.backward_speed > 0) && (parsed_way.speed != parsed_way.backward_speed);
-
- for (unsigned n = 0; n < (parsed_way.path.size() - 1); ++n)
- {
- external_memory.all_edges_list.push_back(InternalExtractorEdge(
- parsed_way.path[n],
- parsed_way.path[n + 1],
- parsed_way.type,
- (split_edge ? ExtractionWay::oneway : parsed_way.direction),
- parsed_way.speed,
- parsed_way.nameID,
- parsed_way.roundabout,
- parsed_way.ignoreInGrid,
- (0 < parsed_way.duration),
- parsed_way.isAccessRestricted,
- false,
- split_edge));
- external_memory.used_node_id_list.push_back(parsed_way.path[n]);
- }
- external_memory.used_node_id_list.push_back(parsed_way.path.back());
-
- // The following information is needed to identify start and end segments of restrictions
- external_memory.way_start_end_id_list.push_back(
- WayIDStartAndEndEdge(parsed_way.id,
- parsed_way.path[0],
- parsed_way.path[1],
- parsed_way.path[parsed_way.path.size() - 2],
- parsed_way.path.back()));
-
- if (split_edge)
- { // Only true if the way should be split
- std::reverse(parsed_way.path.begin(), parsed_way.path.end());
- for (std::vector<NodeID>::size_type n = 0; n < parsed_way.path.size() - 1; ++n)
- {
- external_memory.all_edges_list.push_back(
- InternalExtractorEdge(parsed_way.path[n],
- parsed_way.path[n + 1],
- parsed_way.type,
- ExtractionWay::oneway,
- parsed_way.backward_speed,
- parsed_way.nameID,
- parsed_way.roundabout,
- parsed_way.ignoreInGrid,
- (0 < parsed_way.duration),
- parsed_way.isAccessRestricted,
- (ExtractionWay::oneway == parsed_way.direction),
- split_edge));
- }
- external_memory.way_start_end_id_list.push_back(
- WayIDStartAndEndEdge(parsed_way.id,
- parsed_way.path[0],
- parsed_way.path[1],
- parsed_way.path[parsed_way.path.size() - 2],
- parsed_way.path.back()));
- }
-}
diff --git a/Extractor/ExtractorStructs.h b/Extractor/ExtractorStructs.h
deleted file mode 100644
index 51a74c3..0000000
--- a/Extractor/ExtractorStructs.h
+++ /dev/null
@@ -1,114 +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 EXTRACTORSTRUCTS_H_
-#define EXTRACTORSTRUCTS_H_
-
-#include "../DataStructures/HashTable.h"
-#include "../DataStructures/ImportNode.h"
-#include "../typedefs.h"
-
-#include <limits>
-#include <string>
-
-struct ExtractorRelation
-{
- ExtractorRelation() : type(unknown) {}
- enum
- { unknown = 0,
- ferry,
- turnRestriction } type;
- HashTable<std::string, std::string> keyVals;
-};
-
-struct WayIDStartAndEndEdge
-{
- unsigned wayID;
- NodeID firstStart;
- NodeID firstTarget;
- NodeID lastStart;
- NodeID lastTarget;
- WayIDStartAndEndEdge()
- : wayID(std::numeric_limits<unsigned>::max()), firstStart(std::numeric_limits<unsigned>::max()), firstTarget(std::numeric_limits<unsigned>::max()), lastStart(std::numeric_limits<unsigned>::max()),
- lastTarget(std::numeric_limits<unsigned>::max())
- {
- }
-
- explicit WayIDStartAndEndEdge(unsigned w, NodeID fs, NodeID ft, NodeID ls, NodeID lt)
- : wayID(w), firstStart(fs), firstTarget(ft), lastStart(ls), lastTarget(lt)
- {
- }
-
- static WayIDStartAndEndEdge min_value()
- {
- return WayIDStartAndEndEdge((std::numeric_limits<unsigned>::min)(),
- (std::numeric_limits<unsigned>::min)(),
- (std::numeric_limits<unsigned>::min)(),
- (std::numeric_limits<unsigned>::min)(),
- (std::numeric_limits<unsigned>::min)());
- }
- static WayIDStartAndEndEdge max_value()
- {
- return WayIDStartAndEndEdge((std::numeric_limits<unsigned>::max)(),
- (std::numeric_limits<unsigned>::max)(),
- (std::numeric_limits<unsigned>::max)(),
- (std::numeric_limits<unsigned>::max)(),
- (std::numeric_limits<unsigned>::max)());
- }
-};
-
-struct CmpWayByID
-{
- typedef WayIDStartAndEndEdge value_type;
- bool operator()(const WayIDStartAndEndEdge &a, const WayIDStartAndEndEdge &b) const
- {
- return a.wayID < b.wayID;
- }
- value_type max_value() { return WayIDStartAndEndEdge::max_value(); }
- value_type min_value() { return WayIDStartAndEndEdge::min_value(); }
-};
-
-struct Cmp
-{
- typedef NodeID value_type;
- bool operator()(const NodeID left, const NodeID right) const { return left < right; }
- value_type max_value() { return 0xffffffff; }
- value_type min_value() { return 0x0; }
-};
-
-struct CmpNodeByID
-{
- typedef ExternalMemoryNode value_type;
- bool operator()(const ExternalMemoryNode &left, const ExternalMemoryNode &right) const
- {
- return left.node_id < right.node_id;
- }
- value_type max_value() { return ExternalMemoryNode::max_value(); }
- value_type min_value() { return ExternalMemoryNode::min_value(); }
-};
-
-#endif /* EXTRACTORSTRUCTS_H_ */
diff --git a/Extractor/PBFParser.cpp b/Extractor/PBFParser.cpp
deleted file mode 100644
index 1abc480..0000000
--- a/Extractor/PBFParser.cpp
+++ /dev/null
@@ -1,664 +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 "PBFParser.h"
-
-#include "ExtractionWay.h"
-#include "ExtractorCallbacks.h"
-#include "ScriptingEnvironment.h"
-
-#include "../DataStructures/HashTable.h"
-#include "../DataStructures/ImportNode.h"
-#include "../DataStructures/Restriction.h"
-#include "../Util/MachineInfo.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../typedefs.h"
-
-#include <boost/assert.hpp>
-
-#include <tbb/parallel_for.h>
-#include <tbb/task_scheduler_init.h>
-
-#include <osrm/Coordinate.h>
-
-#include <zlib.h>
-
-#include <functional>
-#include <limits>
-#include <thread>
-
-PBFParser::PBFParser(const char *fileName,
- ExtractorCallbacks *extractor_callbacks,
- ScriptingEnvironment &scripting_environment,
- unsigned num_threads)
- : BaseParser(extractor_callbacks, scripting_environment)
-{
- if (0 == num_threads)
- {
- num_parser_threads = tbb::task_scheduler_init::default_num_threads();
- }
- else
- {
- num_parser_threads = num_threads;
- }
-
- GOOGLE_PROTOBUF_VERIFY_VERSION;
- // TODO: What is the bottleneck here? Filling the queue or reading the stuff from disk?
- // NOTE: With Lua scripting, it is parsing the stuff. I/O is virtually for free.
-
- // Max 2500 items in queue, hardcoded.
- thread_data_queue = std::make_shared<ConcurrentQueue<ParserThreadData *>>(2500);
- input.open(fileName, std::ios::in | std::ios::binary);
-
- if (!input)
- {
- throw OSRMException("pbf file not found.");
- }
-
- block_count = 0;
- group_count = 0;
-}
-
-PBFParser::~PBFParser()
-{
- if (input.is_open())
- {
- input.close();
- }
-
- // Clean up any leftover ThreadData objects in the queue
- ParserThreadData *thread_data;
- while (thread_data_queue->try_pop(thread_data))
- {
- delete thread_data;
- }
- google::protobuf::ShutdownProtobufLibrary();
-
- SimpleLogger().Write(logDEBUG) << "parsed " << block_count << " blocks from pbf with "
- << group_count << " groups";
-}
-
-inline bool PBFParser::ReadHeader()
-{
- ParserThreadData init_data;
- /** read Header */
- if (!readPBFBlobHeader(input, &init_data))
- {
- return false;
- }
-
- if (readBlob(input, &init_data))
- {
- if (!init_data.PBFHeaderBlock.ParseFromArray(&(init_data.charBuffer[0]),
- static_cast<int>(init_data.charBuffer.size())))
- {
- std::cerr << "[error] Header not parseable!" << std::endl;
- return false;
- }
-
- const auto feature_size = init_data.PBFHeaderBlock.required_features_size();
- for (int i = 0; i < feature_size; ++i)
- {
- const std::string &feature = init_data.PBFHeaderBlock.required_features(i);
- bool supported = false;
- if ("OsmSchema-V0.6" == feature)
- {
- supported = true;
- }
- else if ("DenseNodes" == feature)
- {
- supported = true;
- }
-
- if (!supported)
- {
- std::cerr << "[error] required feature not supported: " << feature.data()
- << std::endl;
- return false;
- }
- }
- }
- else
- {
- std::cerr << "[error] blob not loaded!" << std::endl;
- }
- return true;
-}
-
-inline void PBFParser::ReadData()
-{
- bool keep_running = true;
- do
- {
- ParserThreadData *thread_data = new ParserThreadData();
- keep_running = readNextBlock(input, thread_data);
-
- if (keep_running)
- {
- thread_data_queue->push(thread_data);
- }
- else
- {
- // No more data to read, parse stops when nullptr encountered
- thread_data_queue->push(nullptr);
- delete thread_data;
- }
- } while (keep_running);
-}
-
-inline void PBFParser::ParseData()
-{
- tbb::task_scheduler_init init(num_parser_threads);
-
- while (true)
- {
- ParserThreadData *thread_data;
- thread_data_queue->wait_and_pop(thread_data);
- if (nullptr == thread_data)
- {
- thread_data_queue->push(nullptr); // Signal end of data for other threads
- break;
- }
-
- loadBlock(thread_data);
-
- int group_size = thread_data->PBFprimitiveBlock.primitivegroup_size();
- for (int i = 0; i < group_size; ++i)
- {
- thread_data->currentGroupID = i;
- loadGroup(thread_data);
-
- if (thread_data->entityTypeIndicator == TypeNode)
- {
- parseNode(thread_data);
- }
- if (thread_data->entityTypeIndicator == TypeWay)
- {
- parseWay(thread_data);
- }
- if (thread_data->entityTypeIndicator == TypeRelation)
- {
- parseRelation(thread_data);
- }
- if (thread_data->entityTypeIndicator == TypeDenseNode)
- {
- parseDenseNode(thread_data);
- }
- }
-
- delete thread_data;
- thread_data = nullptr;
- }
-}
-
-inline bool PBFParser::Parse()
-{
- // Start the read and parse threads
- std::thread read_thread(std::bind(&PBFParser::ReadData, this));
-
- // Open several parse threads that are synchronized before call to
- std::thread parse_thread(std::bind(&PBFParser::ParseData, this));
-
- // Wait for the threads to finish
- read_thread.join();
- parse_thread.join();
-
- return true;
-}
-
-inline void PBFParser::parseDenseNode(ParserThreadData *thread_data)
-{
- const OSMPBF::DenseNodes &dense =
- thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).dense();
- int denseTagIndex = 0;
- int64_t m_lastDenseID = 0;
- int64_t m_lastDenseLatitude = 0;
- int64_t m_lastDenseLongitude = 0;
-
- const int number_of_nodes = dense.id_size();
- std::vector<ImportNode> extracted_nodes_vector(number_of_nodes);
- for (int i = 0; i < number_of_nodes; ++i)
- {
- m_lastDenseID += dense.id(i);
- m_lastDenseLatitude += dense.lat(i);
- m_lastDenseLongitude += dense.lon(i);
- extracted_nodes_vector[i].node_id = static_cast<NodeID>(m_lastDenseID);
- extracted_nodes_vector[i].lat = static_cast<int>(
- COORDINATE_PRECISION *
- ((double)m_lastDenseLatitude * thread_data->PBFprimitiveBlock.granularity() +
- thread_data->PBFprimitiveBlock.lat_offset()) /
- NANO);
- extracted_nodes_vector[i].lon = static_cast<int>(
- COORDINATE_PRECISION *
- ((double)m_lastDenseLongitude * thread_data->PBFprimitiveBlock.granularity() +
- thread_data->PBFprimitiveBlock.lon_offset()) /
- NANO);
- while (denseTagIndex < dense.keys_vals_size())
- {
- const int tagValue = dense.keys_vals(denseTagIndex);
- if (0 == tagValue)
- {
- ++denseTagIndex;
- break;
- }
- const int keyValue = dense.keys_vals(denseTagIndex + 1);
- const std::string &key = thread_data->PBFprimitiveBlock.stringtable().s(tagValue);
- const std::string &value = thread_data->PBFprimitiveBlock.stringtable().s(keyValue);
- extracted_nodes_vector[i].keyVals.Add(std::move(key), std::move(value));
- denseTagIndex += 2;
- }
- }
-
- tbb::parallel_for(tbb::blocked_range<size_t>(0, extracted_nodes_vector.size()),
- [this, &extracted_nodes_vector](const tbb::blocked_range<size_t> &range)
- {
- lua_State *lua_state = this->scripting_environment.getLuaState();
- for (size_t i = range.begin(); i != range.end(); ++i)
- {
- ImportNode &import_node = extracted_nodes_vector[i];
- ParseNodeInLua(import_node, lua_state);
- }
- });
-
- for (const ImportNode &import_node : extracted_nodes_vector)
- {
- extractor_callbacks->ProcessNode(import_node);
- }
-}
-
-inline void PBFParser::parseNode(ParserThreadData *)
-{
- throw OSRMException("Parsing of simple nodes not supported. PBF should use dense nodes");
-}
-
-inline void PBFParser::parseRelation(ParserThreadData *thread_data)
-{
- // TODO: leave early, if relation is not a restriction
- // TODO: reuse rawRestriction container
- if (!use_turn_restrictions)
- {
- return;
- }
- const OSMPBF::PrimitiveGroup &group =
- thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID);
-
- for (int i = 0, relation_size = group.relations_size(); i < relation_size; ++i)
- {
- std::string except_tag_string;
- const OSMPBF::Relation &inputRelation =
- thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).relations(i);
- bool is_restriction = false;
- bool is_only_restriction = false;
- for (int k = 0, endOfKeys = inputRelation.keys_size(); k < endOfKeys; ++k)
- {
- const std::string &key =
- thread_data->PBFprimitiveBlock.stringtable().s(inputRelation.keys(k));
- const std::string &val =
- thread_data->PBFprimitiveBlock.stringtable().s(inputRelation.vals(k));
- if ("type" == key)
- {
- if ("restriction" == val)
- {
- is_restriction = true;
- }
- else
- {
- break;
- }
- }
- if (("restriction" == key) && (val.find("only_") == 0))
- {
- is_only_restriction = true;
- }
- if ("except" == key)
- {
- except_tag_string = val;
- }
- }
-
- if (is_restriction && ShouldIgnoreRestriction(except_tag_string))
- {
- continue;
- }
-
- if (is_restriction)
- {
- int64_t last_ref = 0;
- InputRestrictionContainer current_restriction_container(is_only_restriction);
- for (int rolesIndex = 0, last_role = inputRelation.roles_sid_size();
- rolesIndex < last_role;
- ++rolesIndex)
- {
- const std::string &role = thread_data->PBFprimitiveBlock.stringtable().s(
- inputRelation.roles_sid(rolesIndex));
- last_ref += inputRelation.memids(rolesIndex);
-
- if (!("from" == role || "to" == role || "via" == role))
- {
- continue;
- }
-
- switch (inputRelation.types(rolesIndex))
- {
- case 0: // node
- if ("from" == role || "to" == role)
- { // Only via should be a node
- continue;
- }
- BOOST_ASSERT("via" == role);
- if (std::numeric_limits<unsigned>::max() !=
- current_restriction_container.viaNode)
- {
- current_restriction_container.viaNode =
- std::numeric_limits<unsigned>::max();
- }
- BOOST_ASSERT(std::numeric_limits<unsigned>::max() ==
- current_restriction_container.viaNode);
- current_restriction_container.restriction.viaNode =
- static_cast<NodeID>(last_ref);
- break;
- case 1: // way
- BOOST_ASSERT("from" == role || "to" == role || "via" == role);
- if ("from" == role)
- {
- current_restriction_container.fromWay = static_cast<EdgeID>(last_ref);
- }
- if ("to" == role)
- {
- current_restriction_container.toWay = static_cast<EdgeID>(last_ref);
- }
- if ("via" == role)
- {
- BOOST_ASSERT(current_restriction_container.restriction.toNode ==
- std::numeric_limits<unsigned>::max());
- current_restriction_container.viaNode = static_cast<NodeID>(last_ref);
- }
- break;
- case 2: // relation, not used. relations relating to relations are evil.
- continue;
- BOOST_ASSERT(false);
- break;
-
- default: // should not happen
- BOOST_ASSERT(false);
- break;
- }
- }
- if (!extractor_callbacks->ProcessRestriction(current_restriction_container))
- {
- std::cerr << "[PBFParser] relation not parsed" << std::endl;
- }
- }
- }
-}
-
-inline void PBFParser::parseWay(ParserThreadData *thread_data)
-{
- const int number_of_ways =
- thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).ways_size();
- std::vector<ExtractionWay> parsed_way_vector(number_of_ways);
- for (int i = 0; i < number_of_ways; ++i)
- {
- const OSMPBF::Way &input_way =
- thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).ways(i);
- parsed_way_vector[i].id = static_cast<EdgeID>(input_way.id());
- unsigned node_id_in_path = 0;
- const auto number_of_referenced_nodes = input_way.refs_size();
- for (auto j = 0; j < number_of_referenced_nodes; ++j)
- {
- node_id_in_path += static_cast<NodeID>(input_way.refs(j));
- parsed_way_vector[i].path.push_back(node_id_in_path);
- }
- BOOST_ASSERT(input_way.keys_size() == input_way.vals_size());
- const auto number_of_keys = input_way.keys_size();
- for (auto j = 0; j < number_of_keys; ++j)
- {
- const std::string &key =
- thread_data->PBFprimitiveBlock.stringtable().s(input_way.keys(j));
- const std::string &val =
- thread_data->PBFprimitiveBlock.stringtable().s(input_way.vals(j));
- parsed_way_vector[i].keyVals.Add(std::move(key), std::move(val));
- }
- }
-
- // TODO: investigate if schedule guided will be handled by tbb automatically
- tbb::parallel_for(tbb::blocked_range<size_t>(0, parsed_way_vector.size()),
- [this, &parsed_way_vector](const tbb::blocked_range<size_t> &range)
- {
- lua_State *lua_state = this->scripting_environment.getLuaState();
- for (size_t i = range.begin(); i != range.end(); i++)
- {
- ExtractionWay &extraction_way = parsed_way_vector[i];
- if (2 <= extraction_way.path.size())
- {
- ParseWayInLua(extraction_way, lua_state);
- }
- }
- });
-
- for (ExtractionWay &extraction_way : parsed_way_vector)
- {
- if (2 <= extraction_way.path.size())
- {
- extractor_callbacks->ProcessWay(extraction_way);
- }
- }
-}
-
-inline void PBFParser::loadGroup(ParserThreadData *thread_data)
-{
-#ifndef NDEBUG
- ++group_count;
-#endif
-
- const OSMPBF::PrimitiveGroup &group =
- thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID);
- thread_data->entityTypeIndicator = TypeDummy;
- if (0 != group.nodes_size())
- {
- thread_data->entityTypeIndicator = TypeNode;
- }
- if (0 != group.ways_size())
- {
- thread_data->entityTypeIndicator = TypeWay;
- }
- if (0 != group.relations_size())
- {
- thread_data->entityTypeIndicator = TypeRelation;
- }
- if (group.has_dense())
- {
- thread_data->entityTypeIndicator = TypeDenseNode;
- BOOST_ASSERT(0 != group.dense().id_size());
- }
- BOOST_ASSERT(thread_data->entityTypeIndicator != TypeDummy);
-}
-
-inline void PBFParser::loadBlock(ParserThreadData *thread_data)
-{
- ++block_count;
- thread_data->currentGroupID = 0;
- thread_data->currentEntityID = 0;
-}
-
-inline bool PBFParser::readPBFBlobHeader(std::fstream &stream, ParserThreadData *thread_data)
-{
- int size(0);
- stream.read((char *)&size, sizeof(int));
- size = SwapEndian(size);
- if (stream.eof())
- {
- return false;
- }
- if (size > MAX_BLOB_HEADER_SIZE || size < 0)
- {
- return false;
- }
- char *data = new char[size];
- stream.read(data, size * sizeof(data[0]));
-
- bool dataSuccessfullyParsed = (thread_data->PBFBlobHeader).ParseFromArray(data, size);
- delete[] data;
- return dataSuccessfullyParsed;
-}
-
-inline bool PBFParser::unpackZLIB(ParserThreadData *thread_data)
-{
- auto raw_size = thread_data->PBFBlob.raw_size();
- char *unpacked_data_array = new char[raw_size];
- z_stream compressed_data_stream;
- compressed_data_stream.next_in = (unsigned char *)thread_data->PBFBlob.zlib_data().data();
- compressed_data_stream.avail_in = thread_data->PBFBlob.zlib_data().size();
- compressed_data_stream.next_out = (unsigned char *)unpacked_data_array;
- compressed_data_stream.avail_out = raw_size;
- compressed_data_stream.zalloc = Z_NULL;
- compressed_data_stream.zfree = Z_NULL;
- compressed_data_stream.opaque = Z_NULL;
- int return_code = inflateInit(&compressed_data_stream);
- if (return_code != Z_OK)
- {
- std::cerr << "[error] failed to init zlib stream" << std::endl;
- delete[] unpacked_data_array;
- return false;
- }
-
- return_code = inflate(&compressed_data_stream, Z_FINISH);
- if (return_code != Z_STREAM_END)
- {
- std::cerr << "[error] failed to inflate zlib stream" << std::endl;
- std::cerr << "[error] Error type: " << return_code << std::endl;
- delete[] unpacked_data_array;
- return false;
- }
-
- return_code = inflateEnd(&compressed_data_stream);
- if (return_code != Z_OK)
- {
- std::cerr << "[error] failed to deinit zlib stream" << std::endl;
- delete[] unpacked_data_array;
- return false;
- }
-
- thread_data->charBuffer.clear();
- thread_data->charBuffer.resize(raw_size);
- std::copy(unpacked_data_array, unpacked_data_array + raw_size, thread_data->charBuffer.begin());
- delete[] unpacked_data_array;
- return true;
-}
-
-inline bool PBFParser::unpackLZMA(ParserThreadData *) { return false; }
-
-inline bool PBFParser::readBlob(std::fstream &stream, ParserThreadData *thread_data)
-{
- if (stream.eof())
- {
- return false;
- }
-
- const int size = thread_data->PBFBlobHeader.datasize();
- if (size < 0 || size > MAX_BLOB_SIZE)
- {
- std::cerr << "[error] invalid Blob size:" << size << std::endl;
- return false;
- }
-
- char *data = new char[size];
- stream.read(data, sizeof(data[0]) * size);
-
- if (!thread_data->PBFBlob.ParseFromArray(data, size))
- {
- std::cerr << "[error] failed to parse blob" << std::endl;
- delete[] data;
- return false;
- }
-
- if (thread_data->PBFBlob.has_raw())
- {
- const std::string &data = thread_data->PBFBlob.raw();
- thread_data->charBuffer.clear();
- thread_data->charBuffer.resize(data.size());
- std::copy(data.begin(), data.end(), thread_data->charBuffer.begin());
- }
- else if (thread_data->PBFBlob.has_zlib_data())
- {
- if (!unpackZLIB(thread_data))
- {
- std::cerr << "[error] zlib data encountered that could not be unpacked" << std::endl;
- delete[] data;
- return false;
- }
- }
- else if (thread_data->PBFBlob.has_lzma_data())
- {
- if (!unpackLZMA(thread_data))
- {
- std::cerr << "[error] lzma data encountered that could not be unpacked" << std::endl;
- }
- delete[] data;
- return false;
- }
- else
- {
- std::cerr << "[error] Blob contains no data" << std::endl;
- delete[] data;
- return false;
- }
- delete[] data;
- return true;
-}
-
-bool PBFParser::readNextBlock(std::fstream &stream, ParserThreadData *thread_data)
-{
- if (stream.eof())
- {
- return false;
- }
-
- if (!readPBFBlobHeader(stream, thread_data))
- {
- return false;
- }
-
- if (thread_data->PBFBlobHeader.type() != "OSMData")
- {
- return false;
- }
-
- if (!readBlob(stream, thread_data))
- {
- return false;
- }
-
- if (!thread_data->PBFprimitiveBlock.ParseFromArray(&(thread_data->charBuffer[0]),
- thread_data->charBuffer.size()))
- {
- std::cerr << "failed to parse PrimitiveBlock" << std::endl;
- return false;
- }
- return true;
-}
diff --git a/Extractor/PBFParser.h b/Extractor/PBFParser.h
deleted file mode 100644
index c65a29d..0000000
--- a/Extractor/PBFParser.h
+++ /dev/null
@@ -1,103 +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 PBFPARSER_H_
-#define PBFPARSER_H_
-
-#include "BaseParser.h"
-#include "../DataStructures/ConcurrentQueue.h"
-
-#include <osmpbf/fileformat.pb.h>
-#include <osmpbf/osmformat.pb.h>
-
-#include <fstream>
-#include <memory>
-
-class PBFParser : public BaseParser
-{
-
- enum EntityType
- { TypeDummy = 0,
- TypeNode = 1,
- TypeWay = 2,
- TypeRelation = 4,
- TypeDenseNode = 8 };
-
- struct ParserThreadData
- {
- int currentGroupID;
- int currentEntityID;
- EntityType entityTypeIndicator;
-
- OSMPBF::BlobHeader PBFBlobHeader;
- OSMPBF::Blob PBFBlob;
-
- OSMPBF::HeaderBlock PBFHeaderBlock;
- OSMPBF::PrimitiveBlock PBFprimitiveBlock;
-
- std::vector<char> charBuffer;
- };
-
- public:
- PBFParser(const char *file_name,
- ExtractorCallbacks *extractor_callbacks,
- ScriptingEnvironment &scripting_environment,
- unsigned num_parser_threads = 0);
- virtual ~PBFParser();
-
- inline bool ReadHeader();
- inline bool Parse();
-
- private:
- inline void ReadData();
- inline void ParseData();
- inline void parseDenseNode(ParserThreadData *thread_data);
- inline void parseNode(ParserThreadData *thread_data);
- inline void parseRelation(ParserThreadData *thread_data);
- inline void parseWay(ParserThreadData *thread_data);
-
- inline void loadGroup(ParserThreadData *thread_data);
- inline void loadBlock(ParserThreadData *thread_data);
- inline bool readPBFBlobHeader(std::fstream &stream, ParserThreadData *thread_data);
- inline bool unpackZLIB(ParserThreadData *thread_data);
- inline bool unpackLZMA(ParserThreadData *thread_data);
- inline bool readBlob(std::fstream &stream, ParserThreadData *thread_data);
- inline bool readNextBlock(std::fstream &stream, ParserThreadData *thread_data);
-
- static const int NANO = 1000 * 1000 * 1000;
- static const int MAX_BLOB_HEADER_SIZE = 64 * 1024;
- static const int MAX_BLOB_SIZE = 32 * 1024 * 1024;
-
- unsigned group_count;
- unsigned block_count;
-
- std::fstream input; // the input stream to parse
- std::shared_ptr<ConcurrentQueue<ParserThreadData *>> thread_data_queue;
- unsigned num_parser_threads;
-};
-
-#endif /* PBFPARSER_H_ */
diff --git a/Extractor/ScriptingEnvironment.cpp b/Extractor/ScriptingEnvironment.cpp
deleted file mode 100644
index 01dee39..0000000
--- a/Extractor/ScriptingEnvironment.cpp
+++ /dev/null
@@ -1,121 +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 "ScriptingEnvironment.h"
-
-#include "ExtractionHelperFunctions.h"
-#include "ExtractionWay.h"
-#include "../DataStructures/ImportNode.h"
-#include "../Util/LuaUtil.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../typedefs.h"
-
-ScriptingEnvironment::ScriptingEnvironment() {}
-ScriptingEnvironment::ScriptingEnvironment(const char *file_name)
-: file_name(file_name)
-{
- SimpleLogger().Write() << "Using script " << file_name;
-}
-
-void ScriptingEnvironment::initLuaState(lua_State* lua_state)
-{
- luabind::open(lua_state);
- // open utility libraries string library;
- luaL_openlibs(lua_state);
-
- luaAddScriptFolderToLoadPath(lua_state, file_name.c_str());
-
- // Add our function to the state's global scope
- luabind::module(lua_state)[
- luabind::def("print", LUA_print<std::string>),
- luabind::def("durationIsValid", durationIsValid),
- luabind::def("parseDuration", parseDuration)
- ];
-
- luabind::module(lua_state)[luabind::class_<HashTable<std::string, std::string>>("keyVals")
- .def("Add", &HashTable<std::string, std::string>::Add)
- .def("Find", &HashTable<std::string, std::string>::Find)
- .def("Holds", &HashTable<std::string, std::string>::Holds)];
-
- luabind::module(lua_state)[luabind::class_<ImportNode>("Node")
- .def(luabind::constructor<>())
- .def_readwrite("lat", &ImportNode::lat)
- .def_readwrite("lon", &ImportNode::lon)
- .def_readonly("id", &ImportNode::node_id)
- .def_readwrite("bollard", &ImportNode::bollard)
- .def_readwrite("traffic_light", &ImportNode::trafficLight)
- .def_readwrite("tags", &ImportNode::keyVals)];
-
- luabind::module(lua_state)
- [luabind::class_<ExtractionWay>("Way")
- .def(luabind::constructor<>())
- .def_readonly("id", &ExtractionWay::id)
- .def_readwrite("name", &ExtractionWay::name)
- .def_readwrite("speed", &ExtractionWay::speed)
- .def_readwrite("backward_speed", &ExtractionWay::backward_speed)
- .def_readwrite("duration", &ExtractionWay::duration)
- .def_readwrite("type", &ExtractionWay::type)
- .def_readwrite("access", &ExtractionWay::access)
- .def_readwrite("roundabout", &ExtractionWay::roundabout)
- .def_readwrite("is_access_restricted", &ExtractionWay::isAccessRestricted)
- .def_readwrite("ignore_in_grid", &ExtractionWay::ignoreInGrid)
- .def_readwrite("tags", &ExtractionWay::keyVals)
- .def_readwrite("direction", &ExtractionWay::direction)
- .enum_("constants")[
- luabind::value("notSure", 0),
- luabind::value("oneway", 1),
- luabind::value("bidirectional", 2),
- luabind::value("opposite", 3)
- ]];
-
- // fails on c++11/OS X 10.9
- luabind::module(lua_state)[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))];
-
- if (0 != luaL_dofile(lua_state, file_name.c_str()))
- {
- throw OSRMException("ERROR occured in scripting block");
- }
-}
-
-lua_State *ScriptingEnvironment::getLuaState()
-{
- bool initialized = false;
- auto& ref = script_contexts.local(initialized);
- if (!initialized)
- {
- std::shared_ptr<lua_State> state(luaL_newstate(), lua_close);
- ref = state;
- initLuaState(ref.get());
- }
-
- return ref.get();
-}
-
diff --git a/Extractor/XMLParser.cpp b/Extractor/XMLParser.cpp
deleted file mode 100644
index 3a5446e..0000000
--- a/Extractor/XMLParser.cpp
+++ /dev/null
@@ -1,353 +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 "XMLParser.h"
-
-#include "ExtractionWay.h"
-#include "ExtractorCallbacks.h"
-
-#include "../DataStructures/HashTable.h"
-#include "../DataStructures/ImportNode.h"
-#include "../DataStructures/InputReaderFactory.h"
-#include "../DataStructures/Restriction.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/StringUtil.h"
-#include "../typedefs.h"
-
-#include <osrm/Coordinate.h>
-
-XMLParser::XMLParser(const char *filename,
- ExtractorCallbacks *extractor_callbacks,
- ScriptingEnvironment &scripting_environment)
- : BaseParser(extractor_callbacks, scripting_environment)
-{
- inputReader = inputReaderFactory(filename);
-}
-
-bool XMLParser::ReadHeader() { return xmlTextReaderRead(inputReader) == 1; }
-bool XMLParser::Parse()
-{
- while (xmlTextReaderRead(inputReader) == 1)
- {
- const int type = xmlTextReaderNodeType(inputReader);
-
- // 1 is Element
- if (type != 1)
- {
- continue;
- }
-
- xmlChar *currentName = xmlTextReaderName(inputReader);
- if (currentName == nullptr)
- {
- continue;
- }
-
- if (xmlStrEqual(currentName, (const xmlChar *)"node") == 1)
- {
- ImportNode current_node = ReadXMLNode();
- ParseNodeInLua(current_node, lua_state);
- extractor_callbacks->ProcessNode(current_node);
- }
-
- if (xmlStrEqual(currentName, (const xmlChar *)"way") == 1)
- {
- ExtractionWay way = ReadXMLWay();
- ParseWayInLua(way, lua_state);
- extractor_callbacks->ProcessWay(way);
- }
- if (use_turn_restrictions && xmlStrEqual(currentName, (const xmlChar *)"relation") == 1)
- {
- InputRestrictionContainer current_restriction = ReadXMLRestriction();
- if ((UINT_MAX != current_restriction.fromWay) &&
- !extractor_callbacks->ProcessRestriction(current_restriction))
- {
- std::cerr << "[XMLParser] restriction not parsed" << std::endl;
- }
- }
- xmlFree(currentName);
- }
- return true;
-}
-
-InputRestrictionContainer XMLParser::ReadXMLRestriction()
-{
-
- InputRestrictionContainer restriction;
-
- if (xmlTextReaderIsEmptyElement(inputReader) == 1)
- {
- return restriction;
- }
-
- std::string except_tag_string;
- const int depth = xmlTextReaderDepth(inputReader);
- while (xmlTextReaderRead(inputReader) == 1)
- {
- const int child_type = xmlTextReaderNodeType(inputReader);
- if (child_type != 1 && child_type != 15)
- {
- continue;
- }
- const int child_depth = xmlTextReaderDepth(inputReader);
- xmlChar *child_name = xmlTextReaderName(inputReader);
- if (child_name == nullptr)
- {
- continue;
- }
- if (depth == child_depth && child_type == 15 &&
- xmlStrEqual(child_name, (const xmlChar *)"relation") == 1)
- {
- xmlFree(child_name);
- break;
- }
- if (child_type != 1)
- {
- xmlFree(child_name);
- continue;
- }
-
- if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
- {
- xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
- xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
- if (key != nullptr && value != nullptr)
- {
- if (xmlStrEqual(key, (const xmlChar *)"restriction") &&
- StringStartsWith((const char *)value, "only_"))
- {
- restriction.restriction.flags.isOnly = true;
- }
- if (xmlStrEqual(key, (const xmlChar *)"except"))
- {
- except_tag_string = (const char *)value;
- }
- }
-
- if (key != nullptr)
- {
- xmlFree(key);
- }
- if (value != nullptr)
- {
- xmlFree(value);
- }
- }
- else if (xmlStrEqual(child_name, (const xmlChar *)"member") == 1)
- {
- xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
- if (ref != nullptr)
- {
- xmlChar *role = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"role");
- xmlChar *type = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"type");
-
- if (xmlStrEqual(role, (const xmlChar *)"to") &&
- xmlStrEqual(type, (const xmlChar *)"way"))
- {
- restriction.toWay = StringToUint((const char *)ref);
- }
- if (xmlStrEqual(role, (const xmlChar *)"from") &&
- xmlStrEqual(type, (const xmlChar *)"way"))
- {
- restriction.fromWay = StringToUint((const char *)ref);
- }
- if (xmlStrEqual(role, (const xmlChar *)"via") &&
- xmlStrEqual(type, (const xmlChar *)"node"))
- {
- restriction.restriction.viaNode = StringToUint((const char *)ref);
- }
-
- if (nullptr != type)
- {
- xmlFree(type);
- }
- if (nullptr != role)
- {
- xmlFree(role);
- }
- if (nullptr != ref)
- {
- xmlFree(ref);
- }
- }
- }
- xmlFree(child_name);
- }
-
- if (ShouldIgnoreRestriction(except_tag_string))
- {
- restriction.fromWay = UINT_MAX; // workaround to ignore the restriction
- }
- return restriction;
-}
-
-ExtractionWay XMLParser::ReadXMLWay()
-{
- ExtractionWay way;
- if (xmlTextReaderIsEmptyElement(inputReader) == 1)
- {
- return way;
- }
- const int depth = xmlTextReaderDepth(inputReader);
- while (xmlTextReaderRead(inputReader) == 1)
- {
- const int child_type = xmlTextReaderNodeType(inputReader);
- if (child_type != 1 && child_type != 15)
- {
- continue;
- }
- const int child_depth = xmlTextReaderDepth(inputReader);
- xmlChar *child_name = xmlTextReaderName(inputReader);
- if (child_name == nullptr)
- {
- continue;
- }
-
- if (depth == child_depth && child_type == 15 &&
- xmlStrEqual(child_name, (const xmlChar *)"way") == 1)
- {
- xmlChar *node_id = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
- way.id = StringToUint((char *)node_id);
- xmlFree(node_id);
- xmlFree(child_name);
- break;
- }
- if (child_type != 1)
- {
- xmlFree(child_name);
- continue;
- }
-
- if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
- {
- xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
- xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
-
- if (key != nullptr && value != nullptr)
- {
- way.keyVals.Add(std::string((char *)key), std::string((char *)value));
- }
- if (key != nullptr)
- {
- xmlFree(key);
- }
- if (value != nullptr)
- {
- xmlFree(value);
- }
- }
- else if (xmlStrEqual(child_name, (const xmlChar *)"nd") == 1)
- {
- xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
- if (ref != nullptr)
- {
- way.path.push_back(StringToUint((const char *)ref));
- xmlFree(ref);
- }
- }
- xmlFree(child_name);
- }
- return way;
-}
-
-ImportNode XMLParser::ReadXMLNode()
-{
- ImportNode node;
-
- xmlChar *attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lat");
- if (attribute != nullptr)
- {
- node.lat = static_cast<int>(COORDINATE_PRECISION * StringToDouble((const char *)attribute));
- xmlFree(attribute);
- }
- attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lon");
- if (attribute != nullptr)
- {
- node.lon = static_cast<int>(COORDINATE_PRECISION * StringToDouble((const char *)attribute));
- xmlFree(attribute);
- }
- attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
- if (attribute != nullptr)
- {
- node.node_id = StringToUint((const char *)attribute);
- xmlFree(attribute);
- }
-
- if (xmlTextReaderIsEmptyElement(inputReader) == 1)
- {
- return node;
- }
- const int depth = xmlTextReaderDepth(inputReader);
- while (xmlTextReaderRead(inputReader) == 1)
- {
- const int child_type = xmlTextReaderNodeType(inputReader);
- // 1 = Element, 15 = EndElement
- if (child_type != 1 && child_type != 15)
- {
- continue;
- }
- const int child_depth = xmlTextReaderDepth(inputReader);
- xmlChar *child_name = xmlTextReaderName(inputReader);
- if (child_name == nullptr)
- {
- continue;
- }
-
- if (depth == child_depth && child_type == 15 &&
- xmlStrEqual(child_name, (const xmlChar *)"node") == 1)
- {
- xmlFree(child_name);
- break;
- }
- if (child_type != 1)
- {
- xmlFree(child_name);
- continue;
- }
-
- if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
- {
- xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
- xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
- if (key != nullptr && value != nullptr)
- {
- node.keyVals.Add(std::string((char *)(key)), std::string((char *)(value)));
- }
- if (key != nullptr)
- {
- xmlFree(key);
- }
- if (value != nullptr)
- {
- xmlFree(value);
- }
- }
-
- xmlFree(child_name);
- }
- return node;
-}
diff --git a/Extractor/XMLParser.h b/Extractor/XMLParser.h
deleted file mode 100644
index 178747a..0000000
--- a/Extractor/XMLParser.h
+++ /dev/null
@@ -1,54 +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 XMLPARSER_H_
-#define XMLPARSER_H_
-
-#include "BaseParser.h"
-#include "../DataStructures/Restriction.h"
-
-#include <libxml/xmlreader.h>
-
-class ExtractorCallbacks;
-
-class XMLParser : public BaseParser
-{
- public:
- XMLParser(const char *filename,
- ExtractorCallbacks *extractor_callbacks,
- ScriptingEnvironment &scripting_environment);
- bool ReadHeader();
- bool Parse();
-
- private:
- InputRestrictionContainer ReadXMLRestriction();
- ExtractionWay ReadXMLWay();
- ImportNode ReadXMLNode();
- xmlTextReaderPtr inputReader;
-};
-
-#endif /* XMLPARSER_H_ */
diff --git a/Include/osrm/Coordinate.h b/Include/osrm/Coordinate.h
index dc05855..baac61f 100644
--- a/Include/osrm/Coordinate.h
+++ b/Include/osrm/Coordinate.h
@@ -28,22 +28,32 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef FIXED_POINT_COORDINATE_H_
#define FIXED_POINT_COORDINATE_H_
-#include <functional>
#include <iosfwd> //for std::ostream
#include <string>
+#include <type_traits>
-const float COORDINATE_PRECISION = 1000000.f;
-
+namespace
+{
+constexpr float COORDINATE_PRECISION = 1000000.f;
+}
struct FixedPointCoordinate
{
int lat;
int lon;
FixedPointCoordinate();
- explicit FixedPointCoordinate(int lat, int lon);
+ 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 isValid() const;
+ bool is_valid() const;
bool operator==(const FixedPointCoordinate &other) const;
static double
@@ -55,10 +65,8 @@ struct FixedPointCoordinate
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
+ ApproximateEuclideanDistance(const int lat1, const int lon1, const int lat2, const int lon2);
static float ApproximateSquaredEuclideanDistance(const FixedPointCoordinate &first_coordinate,
const FixedPointCoordinate &second_coordinate);
@@ -81,10 +89,10 @@ struct FixedPointCoordinate
FixedPointCoordinate &nearest_location,
float &ratio);
- static int OrderedPerpendicularDistanceApproximation(const FixedPointCoordinate& segment_source,
- const FixedPointCoordinate& segment_target,
- const FixedPointCoordinate& query_location);
-
+ static int
+ OrderedPerpendicularDistanceApproximation(const FixedPointCoordinate &segment_source,
+ const FixedPointCoordinate &segment_target,
+ const FixedPointCoordinate &query_location);
static float GetBearing(const FixedPointCoordinate &A, const FixedPointCoordinate &B);
diff --git a/Include/osrm/Header.h b/Include/osrm/Header.h
index de0b2ab..d126c4c 100644
--- a/Include/osrm/Header.h
+++ b/Include/osrm/Header.h
@@ -37,7 +37,7 @@ struct Header
{
Header& operator=(const Header& other) = default;
Header(const std::string & name, const std::string & value) : name(name), value(value) {}
- Header(const Header && other) : name(std::move(other.name)), value(std::move(other.value)) {}
+ Header(Header && other) : name(std::move(other.name)), value(std::move(other.value)) {}
void Clear()
{
diff --git a/Include/osrm/RouteParameters.h b/Include/osrm/RouteParameters.h
index 89a1774..fd570a1 100644
--- a/Include/osrm/RouteParameters.h
+++ b/Include/osrm/RouteParameters.h
@@ -40,9 +40,15 @@ struct RouteParameters
RouteParameters();
void setZoomLevel(const short level);
+
+ void setNumberOfResults(const short number);
void setAlternateRouteFlag(const bool flag);
+ void setUTurn(const bool flag);
+
+ void setAllUTurns(const bool flag);
+
void setDeprecatedAPIFlag(const std::string &);
void setChecksum(const unsigned check_sum);
@@ -71,12 +77,15 @@ struct RouteParameters
bool geometry;
bool compression;
bool deprecatedAPI;
+ bool uturn_default;
unsigned check_sum;
+ short num_results;
std::string service;
std::string output_format;
std::string jsonp_parameter;
std::string language;
std::vector<std::string> hints;
+ std::vector<bool> uturns;
std::vector<FixedPointCoordinate> coordinates;
};
diff --git a/Library/OSRM.h b/Library/OSRM.h
index 16b9977..372e82c 100644
--- a/Library/OSRM.h
+++ b/Library/OSRM.h
@@ -30,6 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <osrm/ServerPaths.h>
+#include <memory>
+
class OSRM_impl;
struct RouteParameters;
@@ -41,10 +43,10 @@ class Reply;
class OSRM
{
private:
- OSRM_impl *OSRM_pimpl_;
+ std::unique_ptr<OSRM_impl> OSRM_pimpl_;
public:
- explicit OSRM(const ServerPaths &paths, const bool use_shared_memory = false);
+ explicit OSRM(ServerPaths paths, const bool use_shared_memory = false);
~OSRM();
void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
};
diff --git a/Library/OSRM_impl.cpp b/Library/OSRM_impl.cpp
index 5c20b5a..40fef68 100644
--- a/Library/OSRM_impl.cpp
+++ b/Library/OSRM_impl.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -34,18 +34,19 @@ namespace boost { namespace interprocess { class named_mutex; } }
#include <osrm/RouteParameters.h>
#include <osrm/ServerPaths.h>
-#include "../Plugins/BasePlugin.h"
-#include "../Plugins/DistanceTablePlugin.h"
-#include "../Plugins/HelloWorldPlugin.h"
-#include "../Plugins/LocatePlugin.h"
-#include "../Plugins/NearestPlugin.h"
-#include "../Plugins/TimestampPlugin.h"
-#include "../Plugins/ViaRoutePlugin.h"
+#include "../plugins/distance_table.hpp"
+#include "../plugins/hello_world.hpp"
+#include "../plugins/locate.hpp"
+#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/SimpleLogger.h"
+#include "../Util/make_unique.hpp"
+#include "../Util/ProgramOptions.h"
+#include "../Util/simple_logger.hpp"
#include <boost/assert.hpp>
#include <boost/interprocess/sync/named_condition.hpp>
@@ -56,16 +57,17 @@ namespace boost { namespace interprocess { class named_mutex; } }
#include <utility>
#include <vector>
-OSRM_impl::OSRM_impl(const ServerPaths &server_paths, const bool use_shared_memory)
- : use_shared_memory(use_shared_memory)
+OSRM_impl::OSRM_impl(ServerPaths server_paths, const bool use_shared_memory)
{
if (use_shared_memory)
{
- barrier = new SharedBarriers();
+ barrier = osrm::make_unique<SharedBarriers>();
query_data_facade = new SharedDataFacade<QueryEdge::EdgeData>();
}
else
{
+ // populate base path
+ populate_base_path(server_paths);
query_data_facade = new InternalDataFacade<QueryEdge::EdgeData>(server_paths);
}
@@ -85,10 +87,6 @@ OSRM_impl::~OSRM_impl()
{
delete plugin_pointer.second;
}
- if (use_shared_memory)
- {
- delete barrier;
- }
}
void OSRM_impl::RegisterPlugin(BasePlugin *plugin)
@@ -108,7 +106,7 @@ void OSRM_impl::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
if (plugin_map.end() != iter)
{
reply.status = http::Reply::ok;
- if (use_shared_memory)
+ if (barrier)
{
// lock update pending
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
@@ -129,7 +127,7 @@ void OSRM_impl::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
}
iter->second->HandleRequest(route_parameters, reply);
- if (use_shared_memory)
+ if (barrier)
{
// lock query
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
@@ -154,12 +152,12 @@ void OSRM_impl::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
// proxy code for compilation firewall
-OSRM::OSRM(const ServerPaths &paths, const bool use_shared_memory)
- : OSRM_pimpl_(new OSRM_impl(paths, use_shared_memory))
+OSRM::OSRM(ServerPaths paths, const bool use_shared_memory)
+ : OSRM_pimpl_(osrm::make_unique<OSRM_impl>(paths, use_shared_memory))
{
}
-OSRM::~OSRM() { delete OSRM_pimpl_; }
+OSRM::~OSRM() { OSRM_pimpl_.reset(); }
void OSRM::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
{
diff --git a/Library/OSRM_impl.h b/Library/OSRM_impl.h
index 8ad98bb..e8b47df 100644
--- a/Library/OSRM_impl.h
+++ b/Library/OSRM_impl.h
@@ -34,8 +34,9 @@ struct RouteParameters;
#include <osrm/ServerPaths.h>
-#include "../DataStructures/QueryEdge.h"
+#include "../data_structures/query_edge.hpp"
+#include <memory>
#include <unordered_map>
#include <string>
@@ -45,10 +46,10 @@ template <class EdgeDataT> class BaseDataFacade;
class OSRM_impl
{
private:
- typedef std::unordered_map<std::string, BasePlugin *> PluginMap;
+ using PluginMap = std::unordered_map<std::string, BasePlugin *>;
public:
- OSRM_impl(const ServerPaths &paths, const bool use_shared_memory);
+ OSRM_impl(ServerPaths paths, const bool use_shared_memory);
OSRM_impl(const OSRM_impl &) = delete;
virtual ~OSRM_impl();
void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
@@ -56,8 +57,8 @@ class OSRM_impl
private:
void RegisterPlugin(BasePlugin *plugin);
PluginMap plugin_map;
- bool use_shared_memory;
- SharedBarriers *barrier;
+ // will only be initialized if shared memory is used
+ std::unique_ptr<SharedBarriers> barrier;
// base class pointer to the objects
BaseDataFacade<QueryEdge::EdgeData> *query_data_facade;
};
diff --git a/Plugins/ViaRoutePlugin.h b/Plugins/ViaRoutePlugin.h
deleted file mode 100644
index b82d514..0000000
--- a/Plugins/ViaRoutePlugin.h
+++ /dev/null
@@ -1,173 +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 VIA_ROUTE_PLUGIN_H
-#define VIA_ROUTE_PLUGIN_H
-
-#include "BasePlugin.h"
-
-#include "../Algorithms/ObjectToBase64.h"
-
-#include "../DataStructures/QueryEdge.h"
-#include "../DataStructures/SearchEngine.h"
-#include "../Descriptors/BaseDescriptor.h"
-#include "../Descriptors/GPXDescriptor.h"
-#include "../Descriptors/JSONDescriptor.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/StringUtil.h"
-#include "../Util/TimingUtil.h"
-
-#include <cstdlib>
-
-#include <algorithm>
-#include <memory>
-#include <unordered_map>
-#include <string>
-#include <vector>
-
-template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
-{
- private:
- std::unordered_map<std::string, unsigned> descriptor_table;
- std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
-
- public:
- explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade)
- {
- search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
-
- descriptor_table.emplace("json", 0);
- descriptor_table.emplace("gpx", 1);
- // descriptor_table.emplace("geojson", 2);
- }
-
- virtual ~ViaRoutePlugin() {}
-
- const std::string GetDescriptor() const { return descriptor_string; }
-
- void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
- {
- // check number of parameters
- if (2 > route_parameters.coordinates.size() ||
- std::any_of(begin(route_parameters.coordinates),
- end(route_parameters.coordinates),
- [&](FixedPointCoordinate coordinate)
- { return !coordinate.isValid(); }))
- {
- reply = http::Reply::StockReply(http::Reply::badRequest);
- return;
- }
-
- RawRouteData raw_route;
- raw_route.check_sum = facade->GetCheckSum();
- for (const FixedPointCoordinate &coordinate : route_parameters.coordinates)
- {
- raw_route.raw_via_node_coordinates.emplace_back(coordinate);
- }
-
- std::vector<PhantomNode> phantom_node_vector(raw_route.raw_via_node_coordinates.size());
- const bool checksum_OK = (route_parameters.check_sum == raw_route.check_sum);
-
- for (unsigned i = 0; i < raw_route.raw_via_node_coordinates.size(); ++i)
- {
- if (checksum_OK && i < route_parameters.hints.size() &&
- !route_parameters.hints[i].empty())
- {
- DecodeObjectFromBase64(route_parameters.hints[i], phantom_node_vector[i]);
- if (phantom_node_vector[i].isValid(facade->GetNumberOfNodes()))
- {
- continue;
- }
- }
- facade->FindPhantomNodeForCoordinate(raw_route.raw_via_node_coordinates[i],
- phantom_node_vector[i],
- route_parameters.zoom_level);
- }
-
- PhantomNodes current_phantom_node_pair;
- for (unsigned i = 0; i < phantom_node_vector.size() - 1; ++i)
- {
- current_phantom_node_pair.source_phantom = phantom_node_vector[i];
- current_phantom_node_pair.target_phantom = phantom_node_vector[i + 1];
- raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
- }
-
- const bool is_alternate_requested = route_parameters.alternate_route;
- const bool is_only_one_segment = (1 == raw_route.segment_end_coordinates.size());
- if (is_alternate_requested && is_only_one_segment)
- {
- search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
- raw_route);
- }
- else
- {
- search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, raw_route);
- }
-
- if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
- {
- SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
- }
- reply.status = http::Reply::ok;
-
- DescriptorConfig descriptor_config;
-
- auto iter = descriptor_table.find(route_parameters.output_format);
- unsigned descriptor_type = (iter != descriptor_table.end() ? iter->second : 0);
-
- descriptor_config.zoom_level = route_parameters.zoom_level;
- descriptor_config.instructions = route_parameters.print_instructions;
- descriptor_config.geometry = route_parameters.geometry;
- descriptor_config.encode_geometry = route_parameters.compression;
-
- std::shared_ptr<BaseDescriptor<DataFacadeT>> descriptor;
- switch (descriptor_type)
- {
- // case 0:
- // descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>();
- // break;
- case 1:
- descriptor = std::make_shared<GPXDescriptor<DataFacadeT>>(facade);
- break;
- // case 2:
- // descriptor = std::make_shared<GEOJSONDescriptor<DataFacadeT>>();
- // break;
- default:
- descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>(facade);
- break;
- }
-
- descriptor->SetConfig(descriptor_config);
- descriptor->Run(raw_route, reply);
- }
-
- private:
- std::string descriptor_string;
- DataFacadeT *facade;
-};
-
-#endif // VIA_ROUTE_PLUGIN_H
diff --git a/README.md b/README.md
index 1c77f72..624cc1d 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
For instructions on how to compile and run OSRM, please consult the Wiki at
-https://github.com/DennisOSRM/Project-OSRM/wiki
+https://github.com/Project-OSRM/osrm-backend/wiki
or use our free and daily updated online service at
@@ -35,6 +35,7 @@ When using the code in a (scientific) publication, please cite
| build config | branch | status |
|:-------------|:--------|:------------|
-| Project OSRM | master | [![Build Status](https://travis-ci.org/DennisOSRM/Project-OSRM.png?branch=master)](https://travis-ci.org/DennisOSRM/Project-OSRM) |
-| Project OSRM | develop | [![Build Status](https://travis-ci.org/DennisOSRM/Project-OSRM.png?branch=develop)](https://travis-ci.org/DennisOSRM/Project-OSRM) |
+| Linux | master | [![Build Status](https://travis-ci.org/Project-OSRM/osrm-backend.png?branch=master)](https://travis-ci.org/DennisOSRM/Project-OSRM) |
+| Linux | develop | [![Build Status](https://travis-ci.org/Project-OSRM/osrm-backend.png?branch=develop)](https://travis-ci.org/DennisOSRM/Project-OSRM) |
+| Windows | master/develop | [![Build status](https://ci.appveyor.com/api/projects/status/4iuo3s9gxprmcjjh)](https://ci.appveyor.com/project/DennisOSRM/osrm-backend) |
| LUAbind fork | master | [![Build Status](https://travis-ci.org/DennisOSRM/luabind.png?branch=master)](https://travis-ci.org/DennisOSRM/luabind) |
diff --git a/Rakefile b/Rakefile
index 1c2ce9d..1c848bb 100644
--- a/Rakefile
+++ b/Rakefile
@@ -6,7 +6,7 @@ require 'sys/proctable'
BUILD_FOLDER = 'build'
DATA_FOLDER = 'sandbox'
-PROFILE = 'examples/postgis'
+PROFILE = 'bicycle'
OSRM_PORT = 5000
PROFILES_FOLDER = '../profiles'
@@ -181,3 +181,10 @@ end
desc "Stop, reprocess and restart."
task :update => [:down,:process,:up] do
end
+
+
+desc "Remove test cache files."
+task :sweep do
+ system "rm test/cache/*"
+end
+
diff --git a/Server/APIGrammar.h b/Server/APIGrammar.h
index 4c339d0..83a5cd0 100644
--- a/Server/APIGrammar.h
+++ b/Server/APIGrammar.h
@@ -39,8 +39,8 @@ struct APIGrammar : qi::grammar<Iterator>
{
explicit APIGrammar(HandlerT * h) : APIGrammar::base_type(api_call), handler(h)
{
- api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >> *(query);
- query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | cmp | language | instruction | geometry | alt_route | old_API) ) ;
+ 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)];
@@ -51,9 +51,12 @@ struct APIGrammar : qi::grammar<Iterator>
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_.-"));
@@ -63,7 +66,7 @@ struct APIGrammar : qi::grammar<Iterator>
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, old_API;
+ cmp, alt_route, u, uturns, old_API, num_results;
HandlerT * handler;
};
diff --git a/Server/Connection.cpp b/Server/Connection.cpp
index 674fe62..82402a6 100644
--- a/Server/Connection.cpp
+++ b/Server/Connection.cpp
@@ -69,10 +69,10 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
CompressionType compression_type(noCompression);
boost::tribool result;
boost::tie(result, boost::tuples::ignore) =
- request_parser.Parse(request,
+ RequestParser().Parse(request,
incoming_data_buffer.data(),
incoming_data_buffer.data() + bytes_transferred,
- &compression_type);
+ compression_type);
// the request has been parsed
if (result)
diff --git a/Server/Connection.h b/Server/Connection.h
index bc03c15..41b06d3 100644
--- a/Server/Connection.h
+++ b/Server/Connection.h
@@ -28,7 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CONNECTION_H
#define CONNECTION_H
-#include "RequestParser.h"
+// #include "RequestParser.h"
#include "Http/CompressionType.h"
#include "Http/Request.h"
@@ -40,7 +40,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/version.hpp>
#include <memory>
- #include <string>
#include <vector>
//workaround for incomplete std::shared_ptr compatibility in old boost versions
@@ -97,7 +96,6 @@ class Connection : public std::enable_shared_from_this<Connection>
RequestHandler &request_handler;
boost::array<char, 8192> incoming_data_buffer;
Request request;
- RequestParser request_parser;
Reply reply;
};
diff --git a/Server/DataStructures/BaseDataFacade.h b/Server/DataStructures/BaseDataFacade.h
index 7897ca4..3ea391c 100644
--- a/Server/DataStructures/BaseDataFacade.h
+++ b/Server/DataStructures/BaseDataFacade.h
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -30,21 +30,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Exposes all data access interfaces to the algorithms via base class ptr
-#include "../../DataStructures/EdgeBasedNode.h"
-#include "../../DataStructures/ImportNode.h"
-#include "../../DataStructures/PhantomNodes.h"
-#include "../../DataStructures/TurnInstructions.h"
-#include "../../Util/OSRMException.h"
-#include "../../Util/StringUtil.h"
+#include "../../data_structures/edge_based_node.hpp"
+#include "../../data_structures/external_memory_node.hpp"
+#include "../../data_structures/phantom_node.hpp"
+#include "../../data_structures/turn_instructions.hpp"
+#include "../../Util/integer_range.hpp"
+#include "../../Util/osrm_exception.hpp"
+#include "../../Util/string_util.hpp"
#include "../../typedefs.h"
-#include <boost/range/irange.hpp>
-
#include <osrm/Coordinate.h>
#include <string>
-typedef decltype(boost::irange(0u,0u)) EdgeRange;
+typedef osrm::range<EdgeID> EdgeRange;
template <class EdgeDataT> class BaseDataFacade
{
@@ -63,9 +62,9 @@ template <class EdgeDataT> class BaseDataFacade
virtual NodeID GetTarget(const EdgeID e) const = 0;
- virtual EdgeDataT &GetEdgeData(const EdgeID e) = 0;
+ // virtual EdgeDataT &GetEdgeData(const EdgeID e) = 0;
- // virtual const EdgeDataT &GetEdgeData( const EdgeID e ) const = 0;
+ virtual const EdgeDataT &GetEdgeData(const EdgeID e) const = 0;
virtual EdgeID BeginEdges(const NodeID n) const = 0;
@@ -93,18 +92,20 @@ template <class EdgeDataT> class BaseDataFacade
virtual TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const = 0;
+ virtual TravelMode GetTravelModeForEdgeID(const unsigned id) const = 0;
+
virtual bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
FixedPointCoordinate &result,
- const unsigned zoom_level = 18) const = 0;
+ const unsigned zoom_level = 18) = 0;
- virtual bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
- PhantomNode &resulting_phantom_node,
- const unsigned zoom_level) const = 0;
+ virtual bool
+ IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ std::vector<PhantomNode> &resulting_phantom_node_vector,
+ const unsigned number_of_results) = 0;
- virtual bool IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
- std::vector<PhantomNode> &resulting_phantom_node_vector,
- const unsigned zoom_level,
- const unsigned number_of_results) const = 0;
+ virtual bool
+ IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ PhantomNode &resulting_phantom_node) = 0;
virtual unsigned GetCheckSum() const = 0;
diff --git a/Server/DataStructures/InternalDataFacade.h b/Server/DataStructures/InternalDataFacade.h
index c2055bb..d4f715c 100644
--- a/Server/DataStructures/InternalDataFacade.h
+++ b/Server/DataStructures/InternalDataFacade.h
@@ -32,19 +32,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "BaseDataFacade.h"
-#include "../../DataStructures/OriginalEdgeData.h"
-#include "../../DataStructures/QueryNode.h"
-#include "../../DataStructures/QueryEdge.h"
-#include "../../DataStructures/SharedMemoryVectorWrapper.h"
-#include "../../DataStructures/StaticGraph.h"
-#include "../../DataStructures/StaticRTree.h"
-#include "../../DataStructures/RangeTable.h"
+#include "../../data_structures/original_edge_data.hpp"
+#include "../../data_structures/query_node.hpp"
+#include "../../data_structures/query_edge.hpp"
+#include "../../data_structures/shared_memory_vector_wrapper.hpp"
+#include "../../data_structures/static_graph.hpp"
+#include "../../data_structures/static_rtree.hpp"
+#include "../../data_structures/range_table.hpp"
#include "../../Util/BoostFileSystemFix.h"
-#include "../../Util/GraphLoader.h"
-#include "../../Util/ProgramOptions.h"
-#include "../../Util/SimpleLogger.h"
+#include "../../Util/graph_loader.hpp"
+#include "../../Util/simple_logger.hpp"
#include <osrm/Coordinate.h>
+#include <osrm/ServerPaths.h>
template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<EdgeDataT>
{
@@ -66,13 +66,16 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
ShM<NodeID, false>::vector m_via_node_list;
ShM<unsigned, false>::vector m_name_ID_list;
ShM<TurnInstruction, false>::vector m_turn_instruction_list;
+ ShM<TravelMode, false>::vector m_travel_mode_list;
ShM<char, false>::vector m_names_char_list;
- ShM<bool, false>::vector m_egde_is_compressed;
+ ShM<bool, false>::vector m_edge_is_compressed;
ShM<unsigned, false>::vector m_geometry_indices;
ShM<unsigned, false>::vector m_geometry_list;
- std::shared_ptr<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>>
- m_static_rtree;
+ boost::thread_specific_ptr<
+ StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>> m_static_rtree;
+ boost::filesystem::path ram_index_path;
+ boost::filesystem::path file_index_path;
RangeTable<16, false> m_name_table;
void LoadTimestamp(const boost::filesystem::path ×tamp_path)
@@ -123,14 +126,14 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
{
boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
- NodeInfo current_node;
+ QueryNode current_node;
unsigned number_of_coordinates = 0;
nodes_input_stream.read((char *)&number_of_coordinates, sizeof(unsigned));
m_coordinate_list =
std::make_shared<std::vector<FixedPointCoordinate>>(number_of_coordinates);
for (unsigned i = 0; i < number_of_coordinates; ++i)
{
- nodes_input_stream.read((char *)¤t_node, sizeof(NodeInfo));
+ nodes_input_stream.read((char *)¤t_node, sizeof(QueryNode));
m_coordinate_list->at(i) = FixedPointCoordinate(current_node.lat, current_node.lon);
BOOST_ASSERT((std::abs(m_coordinate_list->at(i).lat) >> 30) == 0);
BOOST_ASSERT((std::abs(m_coordinate_list->at(i).lon) >> 30) == 0);
@@ -143,7 +146,8 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
m_via_node_list.resize(number_of_edges);
m_name_ID_list.resize(number_of_edges);
m_turn_instruction_list.resize(number_of_edges);
- m_egde_is_compressed.resize(number_of_edges);
+ m_travel_mode_list.resize(number_of_edges);
+ m_edge_is_compressed.resize(number_of_edges);
unsigned compressed = 0;
@@ -154,8 +158,9 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
m_via_node_list[i] = current_edge_data.via_node;
m_name_ID_list[i] = current_edge_data.name_id;
m_turn_instruction_list[i] = current_edge_data.turn_instruction;
- m_egde_is_compressed[i] = current_edge_data.compressed_geometry;
- if (m_egde_is_compressed[i])
+ m_travel_mode_list[i] = current_edge_data.travel_mode;
+ m_edge_is_compressed[i] = current_edge_data.compressed_geometry;
+ if (m_edge_is_compressed[i])
{
++compressed;
}
@@ -192,13 +197,12 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
geometry_stream.close();
}
- void LoadRTree(const boost::filesystem::path &ram_index_path,
- const boost::filesystem::path &file_index_path)
+ void LoadRTree()
{
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
- m_static_rtree = std::make_shared<StaticRTree<RTreeLeaf>>(
- ram_index_path, file_index_path, m_coordinate_list);
+ m_static_rtree.reset(
+ new StaticRTree<RTreeLeaf>(ram_index_path, file_index_path, m_coordinate_list));
}
void LoadStreetNames(const boost::filesystem::path &names_file)
@@ -220,7 +224,7 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
}
public:
- ~InternalDataFacade()
+ virtual ~InternalDataFacade()
{
delete m_query_graph;
m_static_rtree.reset();
@@ -231,31 +235,31 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
// generate paths of data files
if (server_paths.find("hsgrdata") == server_paths.end())
{
- throw OSRMException("no hsgr file given in ini file");
+ throw osrm::exception("no hsgr file given in ini file");
}
if (server_paths.find("ramindex") == server_paths.end())
{
- throw OSRMException("no ram index file given in ini file");
+ throw osrm::exception("no ram index file given in ini file");
}
if (server_paths.find("fileindex") == server_paths.end())
{
- throw OSRMException("no leaf index file given in ini file");
+ throw osrm::exception("no leaf index file given in ini file");
}
if (server_paths.find("geometries") == server_paths.end())
{
- throw OSRMException("no geometries file given in ini file");
+ throw osrm::exception("no geometries file given in ini file");
}
if (server_paths.find("nodesdata") == server_paths.end())
{
- throw OSRMException("no nodes file given in ini file");
+ throw osrm::exception("no nodes file given in ini file");
}
if (server_paths.find("edgesdata") == server_paths.end())
{
- throw OSRMException("no edges file given in ini file");
+ throw osrm::exception("no edges file given in ini file");
}
if (server_paths.find("namesdata") == server_paths.end())
{
- throw OSRMException("no names file given in ini file");
+ throw osrm::exception("no names file given in ini file");
}
ServerPaths::const_iterator paths_iterator = server_paths.find("hsgrdata");
@@ -266,10 +270,10 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
const boost::filesystem::path ×tamp_path = paths_iterator->second;
paths_iterator = server_paths.find("ramindex");
BOOST_ASSERT(server_paths.end() != paths_iterator);
- const boost::filesystem::path &ram_index_path = paths_iterator->second;
+ ram_index_path = paths_iterator->second;
paths_iterator = server_paths.find("fileindex");
BOOST_ASSERT(server_paths.end() != paths_iterator);
- const boost::filesystem::path &file_index_path = paths_iterator->second;
+ file_index_path = paths_iterator->second;
paths_iterator = server_paths.find("nodesdata");
BOOST_ASSERT(server_paths.end() != paths_iterator);
const boost::filesystem::path &nodes_data_path = paths_iterator->second;
@@ -287,7 +291,7 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
SimpleLogger().Write() << "loading graph data";
AssertPathExists(hsgr_path);
LoadGraph(hsgr_path);
- SimpleLogger().Write() << "loading egde information";
+ SimpleLogger().Write() << "loading edge information";
AssertPathExists(nodes_data_path);
AssertPathExists(edges_data_path);
LoadNodeAndEdgeInformation(nodes_data_path, edges_data_path);
@@ -297,7 +301,6 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
SimpleLogger().Write() << "loading r-tree";
AssertPathExists(ram_index_path);
AssertPathExists(file_index_path);
- LoadRTree(ram_index_path, file_index_path);
SimpleLogger().Write() << "loading timestamp";
LoadTimestamp(timestamp_path);
SimpleLogger().Write() << "loading street names";
@@ -306,90 +309,112 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
}
// search graph access
- unsigned GetNumberOfNodes() const { return m_query_graph->GetNumberOfNodes(); }
+ unsigned GetNumberOfNodes() const final { return m_query_graph->GetNumberOfNodes(); }
- unsigned GetNumberOfEdges() const { return m_query_graph->GetNumberOfEdges(); }
+ unsigned GetNumberOfEdges() const final { return m_query_graph->GetNumberOfEdges(); }
- unsigned GetOutDegree(const NodeID n) const { return m_query_graph->GetOutDegree(n); }
+ unsigned GetOutDegree(const NodeID n) const final { return m_query_graph->GetOutDegree(n); }
- NodeID GetTarget(const EdgeID e) const { return m_query_graph->GetTarget(e); }
+ NodeID GetTarget(const EdgeID e) const final { return m_query_graph->GetTarget(e); }
- EdgeDataT &GetEdgeData(const EdgeID e) { return m_query_graph->GetEdgeData(e); }
+ // EdgeDataT &GetEdgeData(const EdgeID e) final { return m_query_graph->GetEdgeData(e); }
- const EdgeDataT &GetEdgeData(const EdgeID e) const { return m_query_graph->GetEdgeData(e); }
+ EdgeDataT &GetEdgeData(const EdgeID e) const final { return m_query_graph->GetEdgeData(e); }
- EdgeID BeginEdges(const NodeID n) const { return m_query_graph->BeginEdges(n); }
+ EdgeID BeginEdges(const NodeID n) const final { return m_query_graph->BeginEdges(n); }
- EdgeID EndEdges(const NodeID n) const { return m_query_graph->EndEdges(n); }
+ EdgeID EndEdges(const NodeID n) const final { return m_query_graph->EndEdges(n); }
- EdgeRange GetAdjacentEdgeRange(const NodeID node) const
+ EdgeRange GetAdjacentEdgeRange(const NodeID node) const final
{
return m_query_graph->GetAdjacentEdgeRange(node);
};
// searches for a specific edge
- EdgeID FindEdge(const NodeID from, const NodeID to) const
+ EdgeID FindEdge(const NodeID from, const NodeID to) const final
{
return m_query_graph->FindEdge(from, to);
}
- EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const
+ EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const final
{
return m_query_graph->FindEdgeInEitherDirection(from, to);
}
- EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const
+ EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const final
{
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
}
// node and edge information access
- FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const
+ FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const final
{
return m_coordinate_list->at(id);
};
- bool EdgeIsCompressed(const unsigned id) const { return m_egde_is_compressed.at(id); }
+ bool EdgeIsCompressed(const unsigned id) const { return m_edge_is_compressed.at(id); }
- TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const
+ TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const final
{
return m_turn_instruction_list.at(id);
}
+ TravelMode GetTravelModeForEdgeID(const unsigned id) const
+ {
+ return m_travel_mode_list.at(id);
+ }
+
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
FixedPointCoordinate &result,
- const unsigned zoom_level = 18) const
+ const unsigned zoom_level = 18) final
{
+ if (!m_static_rtree.get())
+ {
+ LoadRTree();
+ }
+
return m_static_rtree->LocateClosestEndPointForCoordinate(
input_coordinate, result, zoom_level);
}
- bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
- PhantomNode &resulting_phantom_node,
- const unsigned zoom_level) const
+ bool
+ IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ PhantomNode &resulting_phantom_node) final
{
- return m_static_rtree->FindPhantomNodeForCoordinate(
- input_coordinate, resulting_phantom_node, zoom_level);
+ std::vector<PhantomNode> resulting_phantom_node_vector;
+ auto result = IncrementalFindPhantomNodeForCoordinate(input_coordinate,
+ 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 zoom_level,
- const unsigned number_of_results) const
+ const unsigned number_of_results) final
{
+ if (!m_static_rtree.get())
+ {
+ LoadRTree();
+ }
+
return m_static_rtree->IncrementalFindPhantomNodeForCoordinate(
- input_coordinate, resulting_phantom_node_vector, zoom_level, number_of_results);
+ input_coordinate, resulting_phantom_node_vector, number_of_results);
}
- unsigned GetCheckSum() const { return m_check_sum; }
+ unsigned GetCheckSum() const final { return m_check_sum; }
- unsigned GetNameIndexFromEdgeID(const unsigned id) const
+ unsigned GetNameIndexFromEdgeID(const unsigned id) const final
{
return m_name_ID_list.at(id);
};
- void GetName(const unsigned name_id, std::string &result) const
+ void GetName(const unsigned name_id, std::string &result) const final
{
if (UINT_MAX == name_id)
{
@@ -408,13 +433,13 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
}
}
- virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const
+ virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const final
{
return m_via_node_list.at(id);
}
- virtual void GetUncompressedGeometry(const unsigned id, std::vector<unsigned> &result_nodes)
- const
+ virtual void GetUncompressedGeometry(const unsigned id,
+ std::vector<unsigned> &result_nodes) const final
{
const unsigned begin = m_geometry_indices.at(id);
const unsigned end = m_geometry_indices.at(id + 1);
@@ -424,7 +449,7 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
result_nodes.begin(), m_geometry_list.begin() + begin, m_geometry_list.begin() + end);
}
- std::string GetTimestamp() const { return m_timestamp; }
+ std::string GetTimestamp() const final { return m_timestamp; }
};
#endif // INTERNAL_DATA_FACADE
diff --git a/Server/DataStructures/SharedDataFacade.h b/Server/DataStructures/SharedDataFacade.h
index a2cb990..9120f82 100644
--- a/Server/DataStructures/SharedDataFacade.h
+++ b/Server/DataStructures/SharedDataFacade.h
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -33,12 +33,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "BaseDataFacade.h"
#include "SharedDataType.h"
-#include "../../DataStructures/RangeTable.h"
-#include "../../DataStructures/StaticGraph.h"
-#include "../../DataStructures/StaticRTree.h"
+#include "../../data_structures/range_table.hpp"
+#include "../../data_structures/static_graph.hpp"
+#include "../../data_structures/static_rtree.hpp"
#include "../../Util/BoostFileSystemFix.h"
-#include "../../Util/ProgramOptions.h"
-#include "../../Util/SimpleLogger.h"
+#include "../../Util/make_unique.hpp"
+#include "../../Util/simple_logger.hpp"
#include <algorithm>
#include <memory>
@@ -55,8 +55,9 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
typedef typename RangeTable<16, true>::BlockT NameIndexBlock;
typedef typename QueryGraph::InputEdge InputEdge;
typedef typename super::RTreeLeaf RTreeLeaf;
- typedef typename StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode
- RTreeNode;
+ using SharedRTree = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>;
+ using TimeStampedRTreePair = std::pair<unsigned, std::shared_ptr<SharedRTree>>;
+ using RTreeNode = typename SharedRTree::TreeNode;
SharedDataLayout *data_layout;
char *shared_memory;
@@ -67,24 +68,24 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
unsigned CURRENT_TIMESTAMP;
unsigned m_check_sum;
- unsigned m_number_of_nodes;
- std::shared_ptr<QueryGraph> m_query_graph;
- std::shared_ptr<SharedMemory> m_layout_memory;
- std::shared_ptr<SharedMemory> m_large_memory;
+ std::unique_ptr<QueryGraph> m_query_graph;
+ std::unique_ptr<SharedMemory> m_layout_memory;
+ std::unique_ptr<SharedMemory> m_large_memory;
std::string m_timestamp;
std::shared_ptr<ShM<FixedPointCoordinate, true>::vector> m_coordinate_list;
ShM<NodeID, true>::vector m_via_node_list;
ShM<unsigned, true>::vector m_name_ID_list;
ShM<TurnInstruction, true>::vector m_turn_instruction_list;
+ ShM<TravelMode, true>::vector m_travel_mode_list;
ShM<char, true>::vector m_names_char_list;
ShM<unsigned, true>::vector m_name_begin_indices;
- ShM<bool, true>::vector m_egde_is_compressed;
+ ShM<bool, true>::vector m_edge_is_compressed;
ShM<unsigned, true>::vector m_geometry_indices;
ShM<unsigned, true>::vector m_geometry_list;
- std::shared_ptr<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>>
- m_static_rtree;
+ boost::thread_specific_ptr<std::pair<unsigned, std::shared_ptr<SharedRTree>>> m_static_rtree;
+ boost::filesystem::path file_index_path;
std::shared_ptr<RangeTable<16, true>> m_name_table;
@@ -105,23 +106,22 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
m_timestamp.begin());
}
- void LoadRTree(const boost::filesystem::path &file_index_path)
+ void LoadRTree()
{
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
RTreeNode *tree_ptr =
data_layout->GetBlockPtr<RTreeNode>(shared_memory, SharedDataLayout::R_SEARCH_TREE);
- m_static_rtree =
- std::make_shared<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>>(
+ m_static_rtree.reset(new TimeStampedRTreePair(CURRENT_TIMESTAMP,
+ osrm::make_unique<SharedRTree>(
tree_ptr,
data_layout->num_entries[SharedDataLayout::R_SEARCH_TREE],
file_index_path,
- m_coordinate_list);
+ m_coordinate_list)));
}
void LoadGraph()
{
- m_number_of_nodes = data_layout->num_entries[SharedDataLayout::GRAPH_NODE_LIST];
GraphNode *graph_nodes_ptr =
data_layout->GetBlockPtr<GraphNode>(shared_memory, SharedDataLayout::GRAPH_NODE_LIST);
@@ -140,9 +140,16 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
FixedPointCoordinate *coordinate_list_ptr = data_layout->GetBlockPtr<FixedPointCoordinate>(
shared_memory, SharedDataLayout::COORDINATE_LIST);
- m_coordinate_list = std::make_shared<ShM<FixedPointCoordinate, true>::vector>(
+ m_coordinate_list = osrm::make_unique<ShM<FixedPointCoordinate, true>::vector>(
coordinate_list_ptr, data_layout->num_entries[SharedDataLayout::COORDINATE_LIST]);
+ TravelMode *travel_mode_list_ptr = data_layout->GetBlockPtr<TravelMode>(
+ shared_memory, SharedDataLayout::TRAVEL_MODE);
+ typename ShM<TravelMode, true>::vector travel_mode_list(
+ travel_mode_list_ptr,
+ data_layout->num_entries[SharedDataLayout::TRAVEL_MODE]);
+ m_travel_mode_list.swap(travel_mode_list);
+
TurnInstruction *turn_instruction_list_ptr = data_layout->GetBlockPtr<TurnInstruction>(
shared_memory, SharedDataLayout::TURN_INSTRUCTION);
typename ShM<TurnInstruction, true>::vector turn_instruction_list(
@@ -181,8 +188,8 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::NAME_CHAR_LIST);
typename ShM<char, true>::vector names_char_list(
names_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_CHAR_LIST]);
- m_name_table = std::make_shared<RangeTable<16, true>>(
- name_offsets, name_blocks, names_char_list.size());
+ m_name_table = osrm::make_unique<RangeTable<16, true>>(
+ name_offsets, name_blocks, static_cast<unsigned>(names_char_list.size()));
m_names_char_list.swap(names_char_list);
}
@@ -191,10 +198,10 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
{
unsigned *geometries_compressed_ptr = data_layout->GetBlockPtr<unsigned>(
shared_memory, SharedDataLayout::GEOMETRIES_INDICATORS);
- typename ShM<bool, true>::vector egde_is_compressed(
+ typename ShM<bool, true>::vector edge_is_compressed(
geometries_compressed_ptr,
data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDICATORS]);
- m_egde_is_compressed.swap(egde_is_compressed);
+ m_edge_is_compressed.swap(edge_is_compressed);
unsigned *geometries_index_ptr =
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_INDEX);
@@ -210,11 +217,12 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
}
public:
+ virtual ~SharedDataFacade() {}
+
SharedDataFacade()
{
data_timestamp_ptr = (SharedDataTimestamp *)SharedMemoryFactory::Get(
CURRENT_REGIONS, sizeof(SharedDataTimestamp), false, false)->Ptr();
-
CURRENT_LAYOUT = LAYOUT_NONE;
CURRENT_DATA = DATA_NONE;
CURRENT_TIMESTAMP = 0;
@@ -244,17 +252,13 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
m_large_memory.reset(SharedMemoryFactory::Get(CURRENT_DATA));
shared_memory = (char *)(m_large_memory->Ptr());
- std::ofstream out("debug.bin");
- out.write(shared_memory, data_layout->GetSizeOfLayout());
- out.close();
-
const char *file_index_ptr =
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::FILE_INDEX_PATH);
- boost::filesystem::path file_index_path(file_index_ptr);
+ file_index_path = boost::filesystem::path(file_index_ptr);
if (!boost::filesystem::exists(file_index_path))
{
SimpleLogger().Write(logDEBUG) << "Leaf file name " << file_index_path.string();
- throw OSRMException("Could not load leaf index file."
+ throw osrm::exception("Could not load leaf index file."
"Is any data loaded into shared memory?");
}
@@ -262,65 +266,72 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
LoadChecksum();
LoadNodeAndEdgeInformation();
LoadGeometries();
- LoadRTree(file_index_path);
LoadTimestamp();
LoadViaNodeList();
LoadNames();
data_layout->PrintInformation();
+
+ SimpleLogger().Write() << "number of geometries: " << m_coordinate_list->size();
+ for (unsigned i = 0; i < m_coordinate_list->size(); ++i)
+ {
+ if (!GetCoordinateOfNode(i).is_valid())
+ {
+ SimpleLogger().Write() << "coordinate " << i << " not valid";
+ }
+ }
}
}
// search graph access
- unsigned GetNumberOfNodes() const { return m_query_graph->GetNumberOfNodes(); }
-
- unsigned GetNumberOfEdges() const { return m_query_graph->GetNumberOfEdges(); }
+ unsigned GetNumberOfNodes() const final { return m_query_graph->GetNumberOfNodes(); }
- unsigned GetOutDegree(const NodeID n) const { return m_query_graph->GetOutDegree(n); }
+ unsigned GetNumberOfEdges() const final { return m_query_graph->GetNumberOfEdges(); }
- NodeID GetTarget(const EdgeID e) const { return m_query_graph->GetTarget(e); }
+ unsigned GetOutDegree(const NodeID n) const final { return m_query_graph->GetOutDegree(n); }
- EdgeDataT &GetEdgeData(const EdgeID e) { return m_query_graph->GetEdgeData(e); }
+ NodeID GetTarget(const EdgeID e) const final { return m_query_graph->GetTarget(e); }
- // const EdgeDataT &GetEdgeData( const EdgeID e ) const {
- // return m_query_graph->GetEdgeData(e);
- // }
+ EdgeDataT &GetEdgeData(const EdgeID e) const final { return m_query_graph->GetEdgeData(e); }
- EdgeID BeginEdges(const NodeID n) const { return m_query_graph->BeginEdges(n); }
+ EdgeID BeginEdges(const NodeID n) const final { return m_query_graph->BeginEdges(n); }
- EdgeID EndEdges(const NodeID n) const { return m_query_graph->EndEdges(n); }
+ EdgeID EndEdges(const NodeID n) const final { return m_query_graph->EndEdges(n); }
- EdgeRange GetAdjacentEdgeRange(const NodeID node) const
+ EdgeRange GetAdjacentEdgeRange(const NodeID node) const final
{
return m_query_graph->GetAdjacentEdgeRange(node);
};
// searches for a specific edge
- EdgeID FindEdge(const NodeID from, const NodeID to) const
+ EdgeID FindEdge(const NodeID from, const NodeID to) const final
{
return m_query_graph->FindEdge(from, to);
}
- EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const
+ EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const final
{
return m_query_graph->FindEdgeInEitherDirection(from, to);
}
- EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const
+ EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const final
{
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
}
// node and edge information access
- FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const
+ FixedPointCoordinate GetCoordinateOfNode(const NodeID id) const final
{
return m_coordinate_list->at(id);
};
- virtual bool EdgeIsCompressed(const unsigned id) const { return m_egde_is_compressed.at(id); }
+ virtual bool EdgeIsCompressed(const unsigned id) const final
+ {
+ return m_edge_is_compressed.at(id);
+ }
- virtual void GetUncompressedGeometry(const unsigned id, std::vector<unsigned> &result_nodes)
- const
+ virtual void GetUncompressedGeometry(const unsigned id,
+ std::vector<unsigned> &result_nodes) const final
{
const unsigned begin = m_geometry_indices.at(id);
const unsigned end = m_geometry_indices.at(id + 1);
@@ -330,50 +341,72 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
result_nodes.begin(), m_geometry_list.begin() + begin, m_geometry_list.begin() + end);
}
- virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const
+ virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const final
{
return m_via_node_list.at(id);
}
- TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const
+ TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const final
{
return m_turn_instruction_list.at(id);
}
+ TravelMode GetTravelModeForEdgeID(const unsigned id) const
+ {
+ return m_travel_mode_list.at(id);
+ }
+
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
FixedPointCoordinate &result,
- const unsigned zoom_level = 18) const
+ const unsigned zoom_level = 18) final
{
- return m_static_rtree->LocateClosestEndPointForCoordinate(
+ if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+ {
+ LoadRTree();
+ }
+
+ return m_static_rtree->second->LocateClosestEndPointForCoordinate(
input_coordinate, result, zoom_level);
}
- bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
- PhantomNode &resulting_phantom_node,
- const unsigned zoom_level) const
+ bool
+ IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ PhantomNode &resulting_phantom_node) final
{
- return m_static_rtree->FindPhantomNodeForCoordinate(
- input_coordinate, resulting_phantom_node, zoom_level);
+ std::vector<PhantomNode> resulting_phantom_node_vector;
+ auto result = IncrementalFindPhantomNodeForCoordinate(input_coordinate,
+ 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 zoom_level,
- const unsigned number_of_results) const
+ const unsigned number_of_results) final
{
- return m_static_rtree->IncrementalFindPhantomNodeForCoordinate(
- input_coordinate, resulting_phantom_node_vector, zoom_level, number_of_results);
+ if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
+ {
+ LoadRTree();
+ }
+
+ return m_static_rtree->second->IncrementalFindPhantomNodeForCoordinate(
+ input_coordinate, resulting_phantom_node_vector, number_of_results);
}
- unsigned GetCheckSum() const { return m_check_sum; }
+ unsigned GetCheckSum() const final { return m_check_sum; }
- unsigned GetNameIndexFromEdgeID(const unsigned id) const
+ unsigned GetNameIndexFromEdgeID(const unsigned id) const final
{
return m_name_ID_list.at(id);
};
- void GetName(const unsigned name_id, std::string &result) const
+ void GetName(const unsigned name_id, std::string &result) const final
{
if (UINT_MAX == name_id)
{
@@ -392,7 +425,7 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
}
}
- std::string GetTimestamp() const { return m_timestamp; }
+ std::string GetTimestamp() const final { return m_timestamp; }
};
#endif // SHARED_DATA_FACADE_H
diff --git a/Server/DataStructures/SharedDataType.h b/Server/DataStructures/SharedDataType.h
index 98bdfd5..6357fd7 100644
--- a/Server/DataStructures/SharedDataType.h
+++ b/Server/DataStructures/SharedDataType.h
@@ -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,
@@ -28,15 +28,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SHARED_DATA_TYPE_H_
#define SHARED_DATA_TYPE_H_
-#include "../../Util/OSRMException.h"
-#include "../../Util/SimpleLogger.h"
+#include "../../Util/osrm_exception.hpp"
+#include "../../Util/simple_logger.hpp"
#include <cstdint>
#include <array>
// Added at the start and end of each block as sanity check
-constexpr char CANARY[] = "OSRM";
+static const char CANARY[] = "OSRM";
struct SharedDataLayout
{
@@ -50,6 +50,7 @@ struct SharedDataLayout
GRAPH_EDGE_LIST,
COORDINATE_LIST,
TURN_INSTRUCTION,
+ TRAVEL_MODE,
R_SEARCH_TREE,
GEOMETRIES_INDEX,
GEOMETRIES_LIST,
@@ -82,6 +83,7 @@ struct SharedDataLayout
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);
@@ -98,6 +100,7 @@ struct SharedDataLayout
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 );
@@ -159,11 +162,11 @@ struct SharedDataLayout
bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
if (!start_canary_alive)
{
- throw OSRMException("Start canary of block corrupted.");
+ throw osrm::exception("Start canary of block corrupted.");
}
if (!end_canary_alive)
{
- throw OSRMException("End canary of block corrupted.");
+ throw osrm::exception("End canary of block corrupted.");
}
}
diff --git a/Server/Http/CompressionType.h b/Server/Http/CompressionType.h
index 74d0b62..3836cd7 100644
--- a/Server/Http/CompressionType.h
+++ b/Server/Http/CompressionType.h
@@ -36,6 +36,6 @@ enum CompressionType
gzipRFC1952,
deflateRFC1951 };
-} // namespace http
+}
#endif // COMPRESSION_TYPE_H
diff --git a/Server/Http/Reply.cpp b/Server/Http/Reply.cpp
index b3247ec..e2cf0ae 100644
--- a/Server/Http/Reply.cpp
+++ b/Server/Http/Reply.cpp
@@ -27,7 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <osrm/Reply.h>
-#include "../../Util/StringUtil.h"
+#include "../../Util/cast.hpp"
namespace http
{
@@ -38,7 +38,7 @@ void Reply::SetSize(const unsigned size)
{
if ("Content-Length" == h.name)
{
- h.value = UintToString(size);
+ h.value = cast::integral_to_string(size);
}
}
}
@@ -87,8 +87,7 @@ Reply Reply::StockReply(Reply::status_type status)
const std::string status_string = reply.ToString(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",
- UintToString(static_cast<unsigned>(reply.content.size())));
+ reply.headers.emplace_back("Content-Length", cast::integral_to_string(reply.content.size()));
reply.headers.emplace_back("Content-Type", "text/html");
return reply;
}
diff --git a/Server/RequestHandler.cpp b/Server/RequestHandler.cpp
index 36a2808..b1178ba 100644
--- a/Server/RequestHandler.cpp
+++ b/Server/RequestHandler.cpp
@@ -25,14 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "APIGrammar.h"
#include "RequestHandler.h"
+
+#include "APIGrammar.h"
#include "Http/Request.h"
-#include "../DataStructures/JSONContainer.h"
+#include "../data_structures/json_container.hpp"
#include "../Library/OSRM.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/StringUtil.h"
+#include "../Util/json_renderer.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/string_util.hpp"
#include "../typedefs.h"
#include <osrm/Reply.h>
@@ -61,17 +63,17 @@ void RequestHandler::handle_request(const http::Request &req, http::Reply &reply
// req.agent << ( 0 == req.agent.length() ? "- " :" ") << request;
time_t ltime;
- struct tm *Tm;
+ struct tm *time_stamp;
ltime = time(nullptr);
- Tm = localtime(<ime);
+ time_stamp = localtime(<ime);
// log timestamp
- SimpleLogger().Write() << (Tm->tm_mday < 10 ? "0" : "") << Tm->tm_mday << "-"
- << (Tm->tm_mon + 1 < 10 ? "0" : "") << (Tm->tm_mon + 1) << "-"
- << 1900 + Tm->tm_year << " " << (Tm->tm_hour < 10 ? "0" : "")
- << Tm->tm_hour << ":" << (Tm->tm_min < 10 ? "0" : "") << Tm->tm_min
- << ":" << (Tm->tm_sec < 10 ? "0" : "") << Tm->tm_sec << " "
+ 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;
@@ -87,11 +89,11 @@ void RequestHandler::handle_request(const http::Request &req, http::Reply &reply
{
reply = http::Reply::StockReply(http::Reply::badRequest);
reply.content.clear();
- const unsigned position = static_cast<unsigned>(std::distance(request.begin(), iter));
+ 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 += UintToString(position);
+ message += cast::integral_to_string(position);
json_result.values["status_message"] = message;
JSON::render(reply.content, json_result);
return;
@@ -112,8 +114,7 @@ void RequestHandler::handle_request(const http::Request &req, http::Reply &reply
}
// set headers
- reply.headers.emplace_back("Content-Length",
- UintToString(static_cast<unsigned>(reply.content.size())));
+ 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");
diff --git a/Server/RequestHandler.h b/Server/RequestHandler.h
index 462c34f..7263dad 100644
--- a/Server/RequestHandler.h
+++ b/Server/RequestHandler.h
@@ -44,7 +44,7 @@ class RequestHandler
{
public:
- typedef APIGrammar<std::string::iterator, RouteParameters> APIGrammarParser;
+ using APIGrammarParser = APIGrammar<std::string::iterator, RouteParameters>;
RequestHandler();
RequestHandler(const RequestHandler &) = delete;
diff --git a/Server/RequestParser.cpp b/Server/RequestParser.cpp
index cad05b9..a599381 100644
--- a/Server/RequestParser.cpp
+++ b/Server/RequestParser.cpp
@@ -25,9 +25,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "Http/Request.h"
#include "RequestParser.h"
+#include "Http/Request.h"
+
namespace http
{
@@ -36,7 +37,7 @@ 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)
+RequestParser::Parse(Request &req, char *begin, char *end, http::CompressionType &compression_type)
{
while (begin != end)
{
@@ -51,7 +52,7 @@ RequestParser::Parse(Request &req, char *begin, char *end, http::CompressionType
}
boost::tribool
-RequestParser::consume(Request &req, char input, http::CompressionType *compression_type)
+RequestParser::consume(Request &req, char input, http::CompressionType &compression_type)
{
switch (state_)
{
@@ -177,11 +178,11 @@ RequestParser::consume(Request &req, char input, http::CompressionType *compress
/* giving gzip precedence over deflate */
if (header.value.find("deflate") != std::string::npos)
{
- *compression_type = deflateRFC1951;
+ compression_type = deflateRFC1951;
}
if (header.value.find("gzip") != std::string::npos)
{
- *compression_type = gzipRFC1952;
+ compression_type = gzipRFC1952;
}
}
@@ -264,18 +265,21 @@ RequestParser::consume(Request &req, char input, http::CompressionType *compress
return false;
default: // expecting_newline_3:
return (input == '\n');
- // default:
- // return false;
+ // default:
+ // return false;
}
}
-inline bool RequestParser::isChar(int c) { return c >= 0 && c <= 127; }
+inline bool RequestParser::isChar(int character) { return character >= 0 && character <= 127; }
-inline bool RequestParser::isCTL(int c) { return (c >= 0 && c <= 31) || (c == 127); }
+inline bool RequestParser::isCTL(int character)
+{
+ return (character >= 0 && character <= 31) || (character == 127);
+}
-inline bool RequestParser::isTSpecial(int c)
+inline bool RequestParser::isTSpecial(int character)
{
- switch (c)
+ switch (character)
{
case '(':
case ')':
@@ -302,5 +306,5 @@ inline bool RequestParser::isTSpecial(int c)
}
}
-inline bool RequestParser::isDigit(int c) { return c >= '0' && c <= '9'; }
+inline bool RequestParser::isDigit(int character) { return character >= '0' && character <= '9'; }
}
diff --git a/Server/RequestParser.h b/Server/RequestParser.h
index 4b74d83..7f302a2 100644
--- a/Server/RequestParser.h
+++ b/Server/RequestParser.h
@@ -46,10 +46,10 @@ class RequestParser
void Reset();
boost::tuple<boost::tribool, char *>
- Parse(Request &req, char *begin, char *end, CompressionType *compressionType);
+ Parse(Request &req, char *begin, char *end, CompressionType &compression_type);
private:
- boost::tribool consume(Request &req, char input, CompressionType *compressionType);
+ boost::tribool consume(Request &req, char input, CompressionType &compression_type);
inline bool isChar(int c);
diff --git a/Server/Server.h b/Server/Server.h
index be18c3b..8e0b101 100644
--- a/Server/Server.h
+++ b/Server/Server.h
@@ -28,14 +28,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SERVER_H
#define SERVER_H
-#include "../Util/StringUtil.h"
-
#include "Connection.h"
#include "RequestHandler.h"
+#include "../Util/cast.hpp"
+#include "../Util/make_unique.hpp"
+#include "../Util/simple_logger.hpp"
+
#include <boost/asio.hpp>
#include <boost/bind.hpp>
+#include <zlib.h>
+
#include <functional>
#include <memory>
#include <thread>
@@ -44,11 +48,21 @@ 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)
+ {
+ SimpleLogger().Write() << "http 1.1 compression handled by zlib version " << zlibVersion();
+ const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
+ const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
+ return std::make_shared<Server>(ip_address, ip_port, real_num_threads);
+ }
+
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(new http::Connection(io_service, request_handler)), request_handler()
+ new_connection(std::make_shared<http::Connection>(io_service, request_handler)), request_handler()
{
- const std::string port_string = IntToString(port);
+ const std::string port_string = cast::integral_to_string(port);
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query(address, port_string);
@@ -63,9 +77,6 @@ class Server
boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
}
- Server() = delete;
- Server(const Server &) = delete;
-
void Run()
{
std::vector<std::shared_ptr<std::thread>> threads;
@@ -75,9 +86,9 @@ class Server
boost::bind(&boost::asio::io_service::run, &io_service));
threads.push_back(thread);
}
- for (unsigned i = 0; i < threads.size(); ++i)
+ for (auto thread : threads)
{
- threads[i]->join();
+ thread->join();
}
}
@@ -91,7 +102,7 @@ class Server
if (!e)
{
new_connection->start();
- new_connection.reset(new http::Connection(io_service, request_handler));
+ new_connection = std::make_shared<http::Connection>(io_service, request_handler);
acceptor.async_accept(
new_connection->socket(),
boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
diff --git a/Server/ServerFactory.h b/Server/ServerFactory.h
deleted file mode 100644
index 5e037cf..0000000
--- a/Server/ServerFactory.h
+++ /dev/null
@@ -1,49 +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 SERVER_FACTORY_H
-#define SERVER_FACTORY_H
-
-#include "Server.h"
-#include "../Util/SimpleLogger.h"
-
-#include <zlib.h>
-
-struct ServerFactory
-{
- ServerFactory() = delete;
- ServerFactory(const ServerFactory &) = delete;
- static 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());
- const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
- return new Server(ip_address, ip_port, real_num_threads);
- }
-};
-
-#endif // SERVER_FACTORY_H
diff --git a/Tools/components.cpp b/Tools/components.cpp
deleted file mode 100644
index 945d94f..0000000
--- a/Tools/components.cpp
+++ /dev/null
@@ -1,136 +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 "../typedefs.h"
-#include "../Algorithms/StronglyConnectedComponents.h"
-#include "../DataStructures/DynamicGraph.h"
-#include "../DataStructures/QueryEdge.h"
-#include "../DataStructures/TurnInstructions.h"
-#include "../Util/GraphLoader.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/FingerPrint.h"
-
-#include <fstream>
-#include <memory>
-#include <string>
-#include <vector>
-
-typedef QueryEdge::EdgeData EdgeData;
-typedef DynamicGraph<EdgeData>::InputEdge InputEdge;
-
-std::vector<NodeInfo> internal_to_external_node_map;
-std::vector<TurnRestriction> restrictions_vector;
-std::vector<NodeID> bollard_node_IDs_vector;
-std::vector<NodeID> traffic_light_node_IDs_vector;
-
-int main(int argc, char *argv[])
-{
- LogPolicy::GetInstance().Unmute();
- if (argc < 3)
- {
- SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0] << " <osrm> <osrm.restrictions>";
- return -1;
- }
-
- try
- {
- 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((char *)&fingerprint_loaded, sizeof(FingerPrint));
-
- 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 OSRMException("Could not access <osrm-restrictions> files");
- }
- uint32_t usable_restriction_count = 0;
- restriction_ifstream.read((char *)&usable_restriction_count, sizeof(uint32_t));
- restrictions_vector.resize(usable_restriction_count);
-
- if (usable_restriction_count>0)
- {
- restriction_ifstream.read((char *)&(restrictions_vector[0]),
- usable_restriction_count * sizeof(TurnRestriction));
- }
- restriction_ifstream.close();
-
- std::ifstream input_stream;
- input_stream.open(argv[1], std::ifstream::in | std::ifstream::binary);
-
- if (!input_stream.is_open())
- {
- throw OSRMException("Cannot open osrm file");
- }
-
- std::vector<ImportEdge> edge_list;
- const NodeID number_of_nodes = readBinaryOSRMGraphFromStream(input_stream,
- edge_list,
- bollard_node_IDs_vector,
- traffic_light_node_IDs_vector,
- &internal_to_external_node_map,
- restrictions_vector);
- input_stream.close();
-
- BOOST_ASSERT_MSG(restrictions_vector.size() == usable_restriction_count,
- "size of restrictions_vector changed");
-
- SimpleLogger().Write() << restrictions_vector.size() << " restrictions, "
- << bollard_node_IDs_vector.size() << " bollard nodes, "
- << traffic_light_node_IDs_vector.size() << " traffic lights";
-
- /***
- * Building an edge-expanded graph from node-based input an turn
- * restrictions
- */
-
- SimpleLogger().Write() << "Starting SCC graph traversal";
- std::shared_ptr<TarjanSCC> tarjan =
- std::make_shared<TarjanSCC>(number_of_nodes,
- edge_list,
- bollard_node_IDs_vector,
- traffic_light_node_IDs_vector,
- restrictions_vector,
- internal_to_external_node_map);
- std::vector<ImportEdge>().swap(edge_list);
-
- tarjan->Run();
- SimpleLogger().Write() << "finished component analysis";
- }
- catch (const std::exception &e)
- {
- SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
- }
- return 0;
-}
diff --git a/UnitTests/Algorithms/DouglasPeuckerTest.cpp b/UnitTests/Algorithms/DouglasPeuckerTest.cpp
new file mode 100644
index 0000000..27818e5
--- /dev/null
+++ b/UnitTests/Algorithms/DouglasPeuckerTest.cpp
@@ -0,0 +1,109 @@
+/*
+
+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.
+
+*/
+
+#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 <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);
+}
+
+BOOST_AUTO_TEST_CASE(all_necessary_test)
+{
+ /*
+ * x
+ * / \
+ * x \
+ * / \
+ * x x
+ */
+ std::vector<SegmentInformation> info = {
+ getTestInfo(5, 5, true),
+ getTestInfo(6, 6, true),
+ getTestInfo(10, 10, true),
+ getTestInfo(5, 15, true)
+ };
+ DouglasPeucker dp;
+ for (unsigned z = 0; z < DOUGLAS_PEUCKER_THRESHOLDS.size(); z++)
+ {
+ dp.Run(info, z);
+ for (const auto& i : info)
+ {
+ BOOST_CHECK_EQUAL(i.necessary, true);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(remove_second_node_test)
+{
+ DouglasPeucker dp;
+ for (unsigned z = 0; z < DOUGLAS_PEUCKER_THRESHOLDS.size(); z++)
+ {
+ /*
+ * x--x
+ * | \
+ * x-x x
+ * |
+ * x
+ */
+ std::vector<SegmentInformation> info = {
+ getTestInfo(5 * COORDINATE_PRECISION,
+ 5 * COORDINATE_PRECISION, true),
+ getTestInfo(5 * COORDINATE_PRECISION,
+ 5 * COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z], false),
+ getTestInfo(10 * COORDINATE_PRECISION,
+ 10 * COORDINATE_PRECISION, false),
+ getTestInfo(10 * COORDINATE_PRECISION,
+ 10 + COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z] * 2, false),
+ getTestInfo(5 * COORDINATE_PRECISION,
+ 15 * COORDINATE_PRECISION, false),
+ getTestInfo(5 * COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z],
+ 15 * COORDINATE_PRECISION, true),
+ };
+ BOOST_TEST_MESSAGE("Threshold (" << z << "): " << DOUGLAS_PEUCKER_THRESHOLDS[z]);
+ dp.Run(info, z);
+ BOOST_CHECK_EQUAL(info[0].necessary, true);
+ BOOST_CHECK_EQUAL(info[1].necessary, false);
+ BOOST_CHECK_EQUAL(info[2].necessary, true);
+ BOOST_CHECK_EQUAL(info[3].necessary, true);
+ BOOST_CHECK_EQUAL(info[4].necessary, false);
+ BOOST_CHECK_EQUAL(info[5].necessary, true);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Util/GitDescription.h b/UnitTests/algorithm_tests.cpp
similarity index 85%
copy from Util/GitDescription.h
copy to UnitTests/algorithm_tests.cpp
index d3a00f4..216a713 100644
--- a/Util/GitDescription.h
+++ b/UnitTests/algorithm_tests.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,9 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef GIT_DESCRIPTION_H
-#define GIT_DESCRIPTION_H
+#define BOOST_TEST_MODULE algorithm tests
-extern char g_GIT_DESCRIPTION[];
+#include <boost/test/unit_test.hpp>
+
+/*
+ * This file will contain an automatically generated main function.
+ */
-#endif //GIT_DESCRIPTION_H
diff --git a/UnitTests/data_structures/BinaryHeapTest.cpp b/UnitTests/data_structures/BinaryHeapTest.cpp
new file mode 100644
index 0000000..9cfdae2
--- /dev/null
+++ b/UnitTests/data_structures/BinaryHeapTest.cpp
@@ -0,0 +1,178 @@
+/*
+
+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.
+
+*/
+
+#include "../../data_structures/binary_heap.hpp"
+#include "../../typedefs.h"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/mpl/list.hpp>
+
+#include <random>
+
+BOOST_AUTO_TEST_SUITE(binary_heap)
+
+struct TestData
+{
+ unsigned value;
+};
+
+typedef NodeID TestNodeID;
+typedef int TestKey;
+typedef int TestWeight;
+typedef boost::mpl::list<ArrayStorage<TestNodeID, TestKey>,
+ MapStorage<TestNodeID, TestKey>,
+ UnorderedMapStorage<TestNodeID, TestKey>> storage_types;
+
+template <unsigned NUM_ELEM> struct RandomDataFixture
+{
+ RandomDataFixture()
+ {
+ for (unsigned i = 0; i < NUM_ELEM; i++)
+ {
+ data.push_back(TestData{i * 3});
+ weights.push_back((i + 1) * 100);
+ ids.push_back(i);
+ order.push_back(i);
+ }
+
+ // Choosen by a fair W20 dice roll
+ std::mt19937 g(15);
+
+ std::shuffle(order.begin(), order.end(), g);
+ }
+
+ std::vector<TestData> data;
+ std::vector<TestWeight> weights;
+ std::vector<TestNodeID> ids;
+ std::vector<unsigned> order;
+};
+
+constexpr unsigned NUM_NODES = 100;
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(insert_test, T, storage_types, RandomDataFixture<NUM_NODES>)
+{
+ BinaryHeap<TestNodeID, TestKey, TestWeight, TestData, T> heap(NUM_NODES);
+
+ TestWeight min_weight = std::numeric_limits<TestWeight>::max();
+ TestNodeID min_id;
+
+ for (unsigned idx : order)
+ {
+ BOOST_CHECK(!heap.WasInserted(ids[idx]));
+
+ heap.Insert(ids[idx], weights[idx], data[idx]);
+
+ BOOST_CHECK(heap.WasInserted(ids[idx]));
+
+ if (weights[idx] < min_weight)
+ {
+ min_weight = weights[idx];
+ min_id = ids[idx];
+ }
+ BOOST_CHECK_EQUAL(min_id, heap.Min());
+ }
+
+ for (auto id : ids)
+ {
+ const auto &d = heap.GetData(id);
+ BOOST_CHECK_EQUAL(d.value, data[id].value);
+
+ const auto &w = heap.GetKey(id);
+ BOOST_CHECK_EQUAL(w, weights[id]);
+ }
+}
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(delete_min_test, T, storage_types, RandomDataFixture<NUM_NODES>)
+{
+ BinaryHeap<TestNodeID, TestKey, TestWeight, TestData, T> heap(NUM_NODES);
+
+ for (unsigned idx : order)
+ {
+ heap.Insert(ids[idx], weights[idx], data[idx]);
+ }
+
+ for (auto id : ids)
+ {
+ BOOST_CHECK(!heap.WasRemoved(id));
+
+ BOOST_CHECK_EQUAL(heap.Min(), id);
+ BOOST_CHECK_EQUAL(id, heap.DeleteMin());
+ if (id + 1 < NUM_NODES)
+ BOOST_CHECK_EQUAL(heap.Min(), id + 1);
+
+ BOOST_CHECK(heap.WasRemoved(id));
+ }
+}
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(delete_all_test, T, storage_types, RandomDataFixture<NUM_NODES>)
+{
+ BinaryHeap<TestNodeID, TestKey, TestWeight, TestData, T> heap(NUM_NODES);
+
+ for (unsigned idx : order)
+ {
+ heap.Insert(ids[idx], weights[idx], data[idx]);
+ }
+
+ heap.DeleteAll();
+
+ BOOST_CHECK(heap.Empty());
+}
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(decrease_key_test, T, storage_types, RandomDataFixture<10>)
+{
+ BinaryHeap<TestNodeID, TestKey, TestWeight, TestData, T> heap(10);
+
+ for (unsigned idx : order)
+ {
+ heap.Insert(ids[idx], weights[idx], data[idx]);
+ }
+
+ std::vector<TestNodeID> rids(ids);
+ std::reverse(rids.begin(), rids.end());
+
+ for (auto id : rids)
+ {
+ TestNodeID min_id = heap.Min();
+ TestWeight min_weight = heap.GetKey(min_id);
+
+ // decrease weight until we reach min weight
+ while (weights[id] > min_weight)
+ {
+ heap.DecreaseKey(id, weights[id]);
+ BOOST_CHECK_EQUAL(heap.Min(), min_id);
+ weights[id]--;
+ }
+
+ // make weight smaller than min
+ weights[id] -= 2;
+ heap.DecreaseKey(id, weights[id]);
+ BOOST_CHECK_EQUAL(heap.Min(), id);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/UnitTests/data_structures/RangeTableTest.cpp b/UnitTests/data_structures/RangeTableTest.cpp
new file mode 100644
index 0000000..9c92532
--- /dev/null
+++ b/UnitTests/data_structures/RangeTableTest.cpp
@@ -0,0 +1,131 @@
+/*
+
+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.
+
+*/
+
+#include "../../data_structures/range_table.hpp"
+#include "../../typedefs.h"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+
+#include <numeric>
+
+constexpr unsigned BLOCK_SIZE = 16;
+typedef RangeTable<BLOCK_SIZE, false> TestRangeTable;
+
+BOOST_AUTO_TEST_SUITE(range_table)
+
+void ConstructionTest(std::vector<unsigned> lengths, std::vector<unsigned> offsets)
+{
+ BOOST_ASSERT(lengths.size() == offsets.size() - 1);
+
+ TestRangeTable table(lengths);
+
+ for (unsigned i = 0; i < lengths.size(); i++)
+ {
+ auto range = table.GetRange(i);
+ BOOST_CHECK_EQUAL(range.front(), offsets[i]);
+ BOOST_CHECK_EQUAL(range.back() + 1, offsets[i + 1]);
+ }
+}
+
+void
+ComputeLengthsOffsets(std::vector<unsigned> &lengths, std::vector<unsigned> &offsets, unsigned num)
+{
+ lengths.resize(num);
+ offsets.resize(num + 1);
+ std::iota(lengths.begin(), lengths.end(), 1);
+ offsets[0] = 0;
+ std::partial_sum(lengths.begin(), lengths.end(), offsets.begin() + 1);
+
+ std::stringstream l_ss;
+ l_ss << "Lengths: ";
+ for (auto l : lengths)
+ l_ss << l << ", ";
+ BOOST_TEST_MESSAGE(l_ss.str());
+ std::stringstream o_ss;
+ o_ss << "Offsets: ";
+ for (auto o : offsets)
+ o_ss << o << ", ";
+ BOOST_TEST_MESSAGE(o_ss.str());
+}
+
+BOOST_AUTO_TEST_CASE(serialization_test)
+{
+ std::vector<unsigned> lengths;
+ std::vector<unsigned> offsets;
+ ComputeLengthsOffsets(lengths, offsets, (BLOCK_SIZE + 1) * 10);
+
+ TestRangeTable in_table(lengths);
+ TestRangeTable out_table;
+
+ std::stringstream ss;
+ ss << in_table;
+ ss >> out_table;
+
+ for (unsigned i = 0; i < lengths.size(); i++)
+ {
+ auto range = out_table.GetRange(i);
+ BOOST_CHECK_EQUAL(range.front(), offsets[i]);
+ BOOST_CHECK_EQUAL(range.back() + 1, offsets[i + 1]);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(construction_test)
+{
+ // only offset empty block
+ ConstructionTest({1}, {0, 1});
+ // first block almost full => sentinel is last element of block
+ // [0] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, (16)}
+ std::vector<unsigned> almost_full_lengths;
+ std::vector<unsigned> almost_full_offsets;
+ ComputeLengthsOffsets(almost_full_lengths, almost_full_offsets, BLOCK_SIZE);
+ ConstructionTest(almost_full_lengths, almost_full_offsets);
+
+ // first block full => sentinel is offset of new block, next block empty
+ // [0] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
+ // [(153)] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ std::vector<unsigned> full_lengths;
+ std::vector<unsigned> full_offsets;
+ ComputeLengthsOffsets(full_lengths, full_offsets, BLOCK_SIZE + 1);
+ ConstructionTest(full_lengths, full_offsets);
+
+ // first block full and offset of next block not sentinel, but the first differential value
+ // [0] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
+ // [153] {(17), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ std::vector<unsigned> over_full_lengths;
+ std::vector<unsigned> over_full_offsets;
+ ComputeLengthsOffsets(over_full_lengths, over_full_offsets, BLOCK_SIZE + 2);
+ ConstructionTest(over_full_lengths, over_full_offsets);
+
+ // test multiple blocks
+ std::vector<unsigned> multiple_lengths;
+ std::vector<unsigned> multiple_offsets;
+ ComputeLengthsOffsets(multiple_lengths, multiple_offsets, (BLOCK_SIZE + 1) * 10);
+ ConstructionTest(multiple_lengths, multiple_offsets);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/UnitTests/data_structures/StaticGraphTest.cpp b/UnitTests/data_structures/StaticGraphTest.cpp
new file mode 100644
index 0000000..4f82f8e
--- /dev/null
+++ b/UnitTests/data_structures/StaticGraphTest.cpp
@@ -0,0 +1,191 @@
+/*
+
+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.
+
+*/
+
+#include "../../data_structures/static_graph.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(static_graph)
+
+struct TestData
+{
+ EdgeID id;
+ bool shortcut;
+ unsigned distance;
+};
+
+struct TestEdge
+{
+ unsigned source;
+ unsigned target;
+ unsigned distance;
+};
+
+typedef StaticGraph<TestData> TestStaticGraph;
+typedef TestStaticGraph::NodeArrayEntry TestNodeArrayEntry;
+typedef TestStaticGraph::EdgeArrayEntry TestEdgeArrayEntry;
+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)
+constexpr unsigned RANDOM_SEED = 15;
+
+template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomArrayEntryFixture
+{
+ RandomArrayEntryFixture()
+ {
+ std::mt19937 g(RANDOM_SEED);
+
+ std::uniform_int_distribution<> edge_udist(0, NUM_EDGES - 1);
+ std::vector<unsigned> offsets;
+ for (unsigned i = 0; i < NUM_NODES; i++)
+ {
+ offsets.push_back(edge_udist(g));
+ }
+ std::sort(offsets.begin(), offsets.end());
+ // add sentinel
+ offsets.push_back(offsets.back());
+
+ // extract interval lengths
+ for (unsigned i = 0; i < offsets.size() - 1; i++)
+ {
+ lengths.push_back(offsets[i + 1] - offsets[i]);
+ }
+ lengths.push_back(NUM_EDGES - offsets[NUM_NODES - 1]);
+
+ for (auto offset : offsets)
+ {
+ nodes.emplace_back(TestNodeArrayEntry{offset});
+ }
+
+ std::uniform_int_distribution<> lengths_udist(0, 100000);
+ std::uniform_int_distribution<> node_udist(0, NUM_NODES - 1);
+ 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))}});
+ }
+
+ for (unsigned i = 0; i < NUM_NODES; i++)
+ order.push_back(i);
+ std::shuffle(order.begin(), order.end(), g);
+ }
+
+ typename ShM<TestNodeArrayEntry, false>::vector nodes;
+ typename ShM<TestEdgeArrayEntry, false>::vector edges;
+ std::vector<unsigned> lengths;
+ std::vector<unsigned> order;
+};
+
+typedef RandomArrayEntryFixture<TEST_NUM_NODES, TEST_NUM_EDGES> TestRandomArrayEntryFixture;
+
+BOOST_FIXTURE_TEST_CASE(array_test, TestRandomArrayEntryFixture)
+{
+ auto nodes_copy = nodes;
+
+ TestStaticGraph graph(nodes, edges);
+
+ BOOST_CHECK_EQUAL(graph.GetNumberOfEdges(), TEST_NUM_EDGES);
+ BOOST_CHECK_EQUAL(graph.GetNumberOfNodes(), TEST_NUM_NODES);
+
+ for (auto idx : order)
+ {
+ BOOST_CHECK_EQUAL(graph.BeginEdges((NodeID)idx), nodes_copy[idx].first_edge);
+ BOOST_CHECK_EQUAL(graph.EndEdges((NodeID)idx), nodes_copy[idx + 1].first_edge);
+ BOOST_CHECK_EQUAL(graph.GetOutDegree((NodeID)idx), lengths[idx]);
+ }
+}
+
+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
+ * | |
+ * (3) -4-> (4)
+ * <-3-
+ */
+ TestStaticGraph simple_graph = GraphFromEdgeList({TestEdge{0, 1, 1},
+ TestEdge{3, 0, 2},
+ TestEdge{3, 4, 4},
+ TestEdge{4, 3, 3},
+ TestEdge{3, 0, 1}});
+
+ auto eit = simple_graph.FindEdge(0, 1);
+ BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 0);
+
+ 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);
+
+ bool reverse = false;
+ eit = simple_graph.FindEdgeIndicateIfReverse(1, 0, reverse);
+ BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 0);
+ 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, 2);
+ eit = simple_graph.FindEdgeInEitherDirection(3, 4);
+ // I think this is wrong behaviour! Should be 3.
+ BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 2);
+
+ eit = simple_graph.FindEdge(3, 0);
+ BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 4);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/UnitTests/data_structures/StaticRTreeTest.cpp b/UnitTests/data_structures/StaticRTreeTest.cpp
new file mode 100644
index 0000000..cf3dfd0
--- /dev/null
+++ b/UnitTests/data_structures/StaticRTreeTest.cpp
@@ -0,0 +1,488 @@
+/*
+
+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.
+
+*/
+
+#include "../../data_structures/static_rtree.hpp"
+#include "../../data_structures/query_node.hpp"
+#include "../../data_structures/edge_based_node.hpp"
+#include "../../Util/floating_point.hpp"
+#include "../../typedefs.h"
+
+#include <osrm/Coordinate.h>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/mpl/list.hpp>
+
+#include <random>
+#include <unordered_set>
+
+BOOST_AUTO_TEST_SUITE(static_rtree)
+
+constexpr uint32_t TEST_BRANCHING_FACTOR = 8;
+constexpr uint32_t TEST_LEAF_NODE_SIZE = 64;
+
+typedef EdgeBasedNode TestData;
+typedef StaticRTree<TestData,
+ std::vector<FixedPointCoordinate>,
+ false,
+ TEST_BRANCHING_FACTOR,
+ TEST_LEAF_NODE_SIZE> TestStaticRTree;
+
+// Choosen by a fair W20 dice roll (this value is completely arbitrary)
+constexpr unsigned RANDOM_SEED = 42;
+static const int32_t WORLD_MIN_LAT = -90 * COORDINATE_PRECISION;
+static const int32_t WORLD_MAX_LAT = 90 * COORDINATE_PRECISION;
+static const int32_t WORLD_MIN_LON = -180 * COORDINATE_PRECISION;
+static const int32_t WORLD_MAX_LON = 180 * COORDINATE_PRECISION;
+
+class LinearSearchNN
+{
+ public:
+ LinearSearchNN(const std::shared_ptr<std::vector<FixedPointCoordinate>> &coords,
+ const std::vector<TestData> &edges)
+ : coords(coords), edges(edges)
+ {
+ }
+
+ bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
+ FixedPointCoordinate &result_coordinate)
+ {
+ float min_dist = std::numeric_limits<float>::max();
+ FixedPointCoordinate min_coord;
+ for (const TestData &e : edges)
+ {
+ const FixedPointCoordinate &start = coords->at(e.u);
+ const FixedPointCoordinate &end = coords->at(e.v);
+ float distance = FixedPointCoordinate::ApproximateEuclideanDistance(
+ input_coordinate.lat, input_coordinate.lon, start.lat, start.lon);
+ if (distance < min_dist)
+ {
+ min_coord = start;
+ min_dist = distance;
+ }
+
+ distance = FixedPointCoordinate::ApproximateEuclideanDistance(
+ input_coordinate.lat, input_coordinate.lon, end.lat, end.lon);
+ if (distance < min_dist)
+ {
+ min_coord = end;
+ min_dist = distance;
+ }
+ }
+
+ result_coordinate = min_coord;
+ return result_coordinate.is_valid();
+ }
+
+ bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ PhantomNode &result_phantom_node,
+ const unsigned zoom_level)
+ {
+ float min_dist = std::numeric_limits<float>::max();
+ TestData nearest_edge;
+ for (const TestData &e : edges)
+ {
+ if (e.component_id != 0)
+ continue;
+
+ float current_ratio = 0.;
+ FixedPointCoordinate nearest;
+ const float current_perpendicular_distance =
+ FixedPointCoordinate::ComputePerpendicularDistance(
+ coords->at(e.u), coords->at(e.v), input_coordinate, nearest, current_ratio);
+
+ if ((current_perpendicular_distance < min_dist) &&
+ !osrm::epsilon_compare(current_perpendicular_distance, min_dist))
+ { // found a new minimum
+ min_dist = current_perpendicular_distance;
+ result_phantom_node = {e.forward_edge_based_node_id,
+ e.reverse_edge_based_node_id,
+ e.name_id,
+ e.forward_weight,
+ e.reverse_weight,
+ e.forward_offset,
+ e.reverse_offset,
+ e.packed_geometry_id,
+ e.component_id,
+ nearest,
+ e.fwd_segment_position,
+ e.forward_travel_mode,
+ e.backward_travel_mode};
+ nearest_edge = e;
+ }
+ }
+
+ if (result_phantom_node.location.is_valid())
+ {
+ // Hack to fix rounding errors and wandering via nodes.
+ 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;
+ }
+
+ const float distance_1 = FixedPointCoordinate::ApproximateEuclideanDistance(
+ coords->at(nearest_edge.u), result_phantom_node.location);
+ const float distance_2 = FixedPointCoordinate::ApproximateEuclideanDistance(
+ coords->at(nearest_edge.u), coords->at(nearest_edge.v));
+ const float ratio = std::min(1.f, distance_1 / distance_2);
+
+ if (SPECIAL_NODEID != result_phantom_node.forward_node_id)
+ {
+ result_phantom_node.forward_weight *= ratio;
+ }
+ if (SPECIAL_NODEID != result_phantom_node.reverse_node_id)
+ {
+ result_phantom_node.reverse_weight *= (1. - ratio);
+ }
+ }
+
+ return result_phantom_node.location.is_valid();
+ }
+
+ private:
+ const std::shared_ptr<std::vector<FixedPointCoordinate>> &coords;
+ const std::vector<TestData> &edges;
+};
+
+template <unsigned NUM_NODES, unsigned NUM_EDGES> struct RandomGraphFixture
+{
+ struct TupleHash
+ {
+ typedef std::pair<unsigned, unsigned> argument_type;
+ typedef std::size_t result_type;
+
+ result_type operator()(const argument_type &t) const
+ {
+ std::size_t val{0};
+ boost::hash_combine(val, t.first);
+ boost::hash_combine(val, t.second);
+ return val;
+ }
+ };
+
+ RandomGraphFixture() : coords(std::make_shared<std::vector<FixedPointCoordinate>>())
+ {
+ BOOST_TEST_MESSAGE("Constructing " << NUM_NODES << " nodes and " << NUM_EDGES << " edges.");
+
+ std::mt19937 g(RANDOM_SEED);
+
+ std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
+ std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
+
+ for (unsigned i = 0; i < NUM_NODES; i++)
+ {
+ int lat = lat_udist(g);
+ int lon = lon_udist(g);
+ nodes.emplace_back(QueryNode(lat, lon, i));
+ coords->emplace_back(FixedPointCoordinate(lat, lon));
+ }
+
+ std::uniform_int_distribution<> edge_udist(0, nodes.size() - 1);
+
+ std::unordered_set<std::pair<unsigned, unsigned>, TupleHash> used_edges;
+
+ while (edges.size() < NUM_EDGES)
+ {
+ TestData data;
+ data.u = edge_udist(g);
+ data.v = edge_udist(g);
+ if (used_edges.find(std::pair<unsigned, unsigned>(
+ std::min(data.u, data.v), std::max(data.u, data.v))) == used_edges.end())
+ {
+ data.component_id = 0;
+ edges.emplace_back(data);
+ used_edges.emplace(std::min(data.u, data.v), std::max(data.u, data.v));
+ }
+ }
+ }
+
+ std::vector<QueryNode> nodes;
+ std::shared_ptr<std::vector<FixedPointCoordinate>> coords;
+ std::vector<TestData> edges;
+};
+
+struct GraphFixture
+{
+ GraphFixture(const std::vector<std::pair<float, float>> &input_coords,
+ const std::vector<std::pair<unsigned, unsigned>> &input_edges)
+ : coords(std::make_shared<std::vector<FixedPointCoordinate>>())
+ {
+
+ for (unsigned i = 0; i < input_coords.size(); i++)
+ {
+ FixedPointCoordinate c(input_coords[i].first * COORDINATE_PRECISION,
+ input_coords[i].second * COORDINATE_PRECISION);
+ coords->emplace_back(c);
+ nodes.emplace_back(QueryNode(c.lat, c.lon, i));
+ }
+
+ for (const auto &pair : input_edges)
+ {
+ TestData d;
+ d.u = pair.first;
+ d.v = pair.second;
+ edges.emplace_back(d);
+ }
+ }
+
+ std::vector<QueryNode> nodes;
+ std::shared_ptr<std::vector<FixedPointCoordinate>> coords;
+ std::vector<TestData> edges;
+};
+
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 3, TEST_LEAF_NODE_SIZE / 2>
+TestRandomGraphFixture_LeafHalfFull;
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 5, TEST_LEAF_NODE_SIZE>
+TestRandomGraphFixture_LeafFull;
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * 10, TEST_LEAF_NODE_SIZE * 2>
+TestRandomGraphFixture_TwoLeaves;
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 3,
+ TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR>
+TestRandomGraphFixture_Branch;
+typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 3,
+ TEST_LEAF_NODE_SIZE * TEST_BRANCHING_FACTOR * 2>
+TestRandomGraphFixture_MultipleLevels;
+
+template <typename RTreeT>
+void simple_verify_rtree(RTreeT &rtree,
+ const std::shared_ptr<std::vector<FixedPointCoordinate>> &coords,
+ const std::vector<TestData> &edges)
+{
+ BOOST_TEST_MESSAGE("Verify end points");
+ for (const auto &e : edges)
+ {
+ FixedPointCoordinate result_u, result_v;
+ const FixedPointCoordinate &pu = coords->at(e.u);
+ const FixedPointCoordinate &pv = coords->at(e.v);
+ 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);
+ 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);
+ BOOST_CHECK_LE(dist_v, std::numeric_limits<float>::epsilon());
+ }
+}
+
+template <typename RTreeT>
+void sampling_verify_rtree(RTreeT &rtree, LinearSearchNN &lsnn, unsigned num_samples)
+{
+ std::mt19937 g(RANDOM_SEED);
+ std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
+ std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
+ std::vector<FixedPointCoordinate> queries;
+ for (unsigned i = 0; i < num_samples; i++)
+ {
+ queries.emplace_back(FixedPointCoordinate(lat_udist(g), lon_udist(g)));
+ }
+
+ BOOST_TEST_MESSAGE("Sampling queries");
+ for (const auto &q : queries)
+ {
+ FixedPointCoordinate result_rtree;
+ rtree.LocateClosestEndPointForCoordinate(q, result_rtree, 1);
+ FixedPointCoordinate result_ln;
+ lsnn.LocateClosestEndPointForCoordinate(q, result_ln);
+ BOOST_CHECK_EQUAL(result_ln, result_rtree);
+
+ PhantomNode phantom_rtree;
+ rtree.FindPhantomNodeForCoordinate(q, phantom_rtree, 1);
+ PhantomNode phantom_ln;
+ lsnn.FindPhantomNodeForCoordinate(q, phantom_ln, 1);
+ BOOST_CHECK_EQUAL(phantom_rtree, phantom_ln);
+ }
+}
+
+template <typename FixtureT, typename RTreeT = TestStaticRTree>
+void build_rtree(const std::string &prefix,
+ FixtureT *fixture,
+ std::string &leaves_path,
+ std::string &nodes_path)
+{
+ nodes_path = prefix + ".ramIndex";
+ leaves_path = prefix + ".fileIndex";
+ const std::string coords_path = prefix + ".nodes";
+
+ boost::filesystem::ofstream node_stream(coords_path, std::ios::binary);
+ const unsigned num_nodes = fixture->nodes.size();
+ node_stream.write((char *)&num_nodes, sizeof(unsigned));
+ node_stream.write((char *)&(fixture->nodes[0]), num_nodes * sizeof(QueryNode));
+ node_stream.close();
+
+ RTreeT r(fixture->edges, nodes_path, leaves_path, fixture->nodes);
+}
+
+template <typename FixtureT, typename RTreeT = TestStaticRTree>
+void construction_test(const std::string &prefix, FixtureT *fixture)
+{
+ std::string leaves_path;
+ std::string nodes_path;
+ build_rtree<FixtureT, RTreeT>(prefix, fixture, leaves_path, nodes_path);
+ RTreeT rtree(nodes_path, leaves_path, fixture->coords);
+ LinearSearchNN lsnn(fixture->coords, fixture->edges);
+
+ simple_verify_rtree(rtree, fixture->coords, fixture->edges);
+ sampling_verify_rtree(rtree, lsnn, 100);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_half_leaf_test, TestRandomGraphFixture_LeafHalfFull)
+{
+ construction_test("test_1", this);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_full_leaf_test, TestRandomGraphFixture_LeafFull)
+{
+ construction_test("test_2", this);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_two_leaves_test, TestRandomGraphFixture_TwoLeaves)
+{
+ construction_test("test_3", this);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_branch_test, TestRandomGraphFixture_Branch)
+{
+ construction_test("test_4", this);
+}
+
+BOOST_FIXTURE_TEST_CASE(construct_multiple_levels_test, TestRandomGraphFixture_MultipleLevels)
+{
+ construction_test("test_5", this);
+}
+
+/*
+ * Bug: If you querry a point that lies between two BBs that have a gap,
+ * one BB will be pruned, even if it could contain a nearer match.
+ */
+BOOST_AUTO_TEST_CASE(regression_test)
+{
+ typedef std::pair<float, float> Coord;
+ typedef std::pair<unsigned, unsigned> Edge;
+ GraphFixture fixture({
+ Coord(40.0, 0.0),
+ Coord(35.0, 5.0),
+
+ Coord(5.0, 5.0),
+ Coord(0.0, 10.0),
+
+ Coord(20.0, 10.0),
+ Coord(20.0, 5.0),
+
+ Coord(40.0, 100.0),
+ Coord(35.0, 105.0),
+
+ Coord(5.0, 105.0),
+ Coord(0.0, 110.0),
+ },
+ {Edge(0, 1), Edge(2, 3), Edge(4, 5), Edge(6, 7), Edge(8, 9)});
+
+ 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);
+ MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords);
+
+ // query a node just right of the center of the gap
+ FixedPointCoordinate input(20.0 * COORDINATE_PRECISION, 55.1 * COORDINATE_PRECISION);
+ FixedPointCoordinate result;
+ rtree.LocateClosestEndPointForCoordinate(input, result, 1);
+ FixedPointCoordinate result_ln;
+ LinearSearchNN lsnn(fixture.coords, fixture.edges);
+ lsnn.LocateClosestEndPointForCoordinate(input, result_ln);
+
+ // TODO: reactivate
+ // BOOST_CHECK_EQUAL(result_ln, result);
+}
+
+void TestRectangle(double width, double height, double center_lat, double center_lon)
+{
+ FixedPointCoordinate center(center_lat * COORDINATE_PRECISION,
+ center_lon * COORDINATE_PRECISION);
+
+ TestStaticRTree::RectangleT rect;
+ rect.min_lat = center.lat - height / 2.0 * COORDINATE_PRECISION;
+ rect.max_lat = center.lat + height / 2.0 * COORDINATE_PRECISION;
+ rect.min_lon = center.lon - width / 2.0 * COORDINATE_PRECISION;
+ rect.max_lon = center.lon + width / 2.0 * COORDINATE_PRECISION;
+
+ unsigned offset = 5 * COORDINATE_PRECISION;
+ FixedPointCoordinate north(rect.max_lat + offset, center.lon);
+ FixedPointCoordinate south(rect.min_lat - offset, center.lon);
+ FixedPointCoordinate west(center.lat, rect.min_lon - offset);
+ FixedPointCoordinate east(center.lat, rect.max_lon + offset);
+ FixedPointCoordinate north_east(rect.max_lat + offset, rect.max_lon + offset);
+ FixedPointCoordinate north_west(rect.max_lat + offset, rect.min_lon - offset);
+ FixedPointCoordinate south_east(rect.min_lat - offset, rect.max_lon + offset);
+ FixedPointCoordinate south_west(rect.min_lat - offset, rect.min_lon - offset);
+
+ /* Distance to line segments of rectangle */
+ BOOST_CHECK_EQUAL(rect.GetMinDist(north),
+ FixedPointCoordinate::ApproximateEuclideanDistance(
+ north, FixedPointCoordinate(rect.max_lat, north.lon)));
+ BOOST_CHECK_EQUAL(rect.GetMinDist(south),
+ FixedPointCoordinate::ApproximateEuclideanDistance(
+ south, FixedPointCoordinate(rect.min_lat, south.lon)));
+ BOOST_CHECK_EQUAL(rect.GetMinDist(west),
+ FixedPointCoordinate::ApproximateEuclideanDistance(
+ west, FixedPointCoordinate(west.lat, rect.min_lon)));
+ BOOST_CHECK_EQUAL(rect.GetMinDist(east),
+ FixedPointCoordinate::ApproximateEuclideanDistance(
+ east, FixedPointCoordinate(east.lat, rect.max_lon)));
+
+ /* Distance to corner points */
+ BOOST_CHECK_EQUAL(rect.GetMinDist(north_east),
+ FixedPointCoordinate::ApproximateEuclideanDistance(
+ north_east, FixedPointCoordinate(rect.max_lat, rect.max_lon)));
+ BOOST_CHECK_EQUAL(rect.GetMinDist(north_west),
+ FixedPointCoordinate::ApproximateEuclideanDistance(
+ north_west, FixedPointCoordinate(rect.max_lat, rect.min_lon)));
+ BOOST_CHECK_EQUAL(rect.GetMinDist(south_east),
+ FixedPointCoordinate::ApproximateEuclideanDistance(
+ south_east, FixedPointCoordinate(rect.min_lat, rect.max_lon)));
+ BOOST_CHECK_EQUAL(rect.GetMinDist(south_west),
+ FixedPointCoordinate::ApproximateEuclideanDistance(
+ south_west, FixedPointCoordinate(rect.min_lat, rect.min_lon)));
+}
+
+BOOST_AUTO_TEST_CASE(rectangle_test)
+{
+ TestRectangle(10, 10, 5, 5);
+ TestRectangle(10, 10, -5, 5);
+ TestRectangle(10, 10, 5, -5);
+ TestRectangle(10, 10, -5, -5);
+ TestRectangle(10, 10, 0, 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/Util/GitDescription.h b/UnitTests/datastructure_tests.cpp
similarity index 85%
copy from Util/GitDescription.h
copy to UnitTests/datastructure_tests.cpp
index d3a00f4..ab39d8d 100644
--- a/Util/GitDescription.h
+++ b/UnitTests/datastructure_tests.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,9 +25,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef GIT_DESCRIPTION_H
-#define GIT_DESCRIPTION_H
+#define BOOST_TEST_MODULE datastructure tests
-extern char g_GIT_DESCRIPTION[];
+#include <boost/test/unit_test.hpp>
-#endif //GIT_DESCRIPTION_H
+/*
+ * This file will contain an automatically generated main function.
+ */
diff --git a/Util/Azimuth.h b/Util/Azimuth.h
deleted file mode 100644
index c4bf815..0000000
--- a/Util/Azimuth.h
+++ /dev/null
@@ -1,73 +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 AZIMUTH_H
-#define AZIMUTH_H
-
-#include <string>
-
-struct Azimuth
-{
- static std::string Get(const double heading)
- {
- 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)
- {
- return "SW";
- }
- if (heading > 247.5 && heading <= 292.5)
- {
- return "W";
- }
- if (heading > 292.5 && heading <= 337.5)
- {
- return "NW";
- }
- return "N";
- }
-};
-
-#endif // AZIMUTH_H
diff --git a/Util/BoostFileSystemFix.h b/Util/BoostFileSystemFix.h
index 1e1e98e..aeab380 100644
--- a/Util/BoostFileSystemFix.h
+++ b/Util/BoostFileSystemFix.h
@@ -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,
@@ -28,12 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef BOOST_FILE_SYSTEM_FIX_H
#define BOOST_FILE_SYSTEM_FIX_H
-#include "OSRMException.h"
-#include "SimpleLogger.h"
+#include "osrm_exception.hpp"
-#include <boost/any.hpp>
+// #include <boost/any.hpp>
#include <boost/filesystem.hpp>
-#include <boost/program_options.hpp>
+// #include <boost/program_options.hpp>
// This is one big workaround for latest boost renaming woes.
@@ -60,12 +59,10 @@ namespace filesystem
// boost::program_options::validators::check_first_occurrence(v);
// const std::string & input_string =
// boost::program_options::validators::get_single_string(values);
-// // SimpleLogger().Write() << "validator called for " << input_string;
-// // SimpleLogger().Write() << "validator called for " << input_string;
// if(boost::filesystem::is_regular_file(input_string)) {
// v = boost::any(boost::filesystem::path(input_string));
// } else {
-// throw OSRMException(input_string + " not found");
+// throw osrm::exception(input_string + " not found");
// }
// }
@@ -121,7 +118,7 @@ portable_canonical(const boost::filesystem::path &relative_path,
inline path temp_directory_path()
{
char *buffer;
- buffer = tmpnam(NULL);
+ buffer = tmpnam(nullptr);
return path(buffer);
}
@@ -140,7 +137,7 @@ inline void AssertPathExists(const boost::filesystem::path &path)
{
if (!boost::filesystem::is_regular_file(path))
{
- throw OSRMException(path.string() + " not found.");
+ throw osrm::exception(path.string() + " not found.");
}
}
diff --git a/Util/DataStoreOptions.h b/Util/DataStoreOptions.h
index 7a76bfb..389c723 100644
--- a/Util/DataStoreOptions.h
+++ b/Util/DataStoreOptions.h
@@ -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,
@@ -29,10 +29,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define DATA_STORE_OPTIONS_H
#include "BoostFileSystemFix.h"
-#include "GitDescription.h"
+#include "git_sha.hpp"
#include "IniFileUtil.h"
-#include "OSRMException.h"
-#include "SimpleLogger.h"
+#include "osrm_exception.hpp"
+#include "simple_logger.hpp"
#include <osrm/ServerPaths.h>
@@ -43,7 +43,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
// generate boost::program_options object for the routing part
-inline bool GenerateDataStoreOptions(const int argc, const char *argv[], ServerPaths &paths, bool & springclean)
+bool GenerateDataStoreOptions(const int argc, const char *argv[], ServerPaths &paths)
{
// declare a group of options that will be allowed only on command line
boost::program_options::options_description generic_options("Options");
@@ -122,11 +122,6 @@ inline bool GenerateDataStoreOptions(const int argc, const char *argv[], ServerP
return false;
}
- if (option_variables.count("springclean"))
- {
- springclean = true;
- return true;
- }
boost::program_options::notify(option_variables);
const bool parameter_present = (paths.find("hsgrdata") != paths.end() &&
@@ -226,56 +221,56 @@ inline bool GenerateDataStoreOptions(const int argc, const char *argv[], ServerP
path_iterator = paths.find("hsgrdata");
if (path_iterator == paths.end() || path_iterator->second.string().empty())
{
- throw OSRMException(".hsgr file must be specified");
+ throw osrm::exception(".hsgr file must be specified");
}
AssertPathExists(path_iterator->second);
path_iterator = paths.find("nodesdata");
if (path_iterator == paths.end() || path_iterator->second.string().empty())
{
- throw OSRMException(".nodes file must be specified");
+ throw osrm::exception(".nodes file must be specified");
}
AssertPathExists(path_iterator->second);
path_iterator = paths.find("edgesdata");
if (path_iterator == paths.end() || path_iterator->second.string().empty())
{
- throw OSRMException(".edges file must be specified");
+ throw osrm::exception(".edges file must be specified");
}
AssertPathExists(path_iterator->second);
path_iterator = paths.find("geometry");
if (path_iterator == paths.end() || path_iterator->second.string().empty())
{
- throw OSRMException(".geometry file must be specified");
+ throw osrm::exception(".geometry file must be specified");
}
AssertPathExists(path_iterator->second);
path_iterator = paths.find("ramindex");
if (path_iterator == paths.end() || path_iterator->second.string().empty())
{
- throw OSRMException(".ramindex file must be specified");
+ throw osrm::exception(".ramindex file must be specified");
}
AssertPathExists(path_iterator->second);
path_iterator = paths.find("fileindex");
if (path_iterator == paths.end() || path_iterator->second.string().empty())
{
- throw OSRMException(".fileindex file must be specified");
+ throw osrm::exception(".fileindex file must be specified");
}
AssertPathExists(path_iterator->second);
path_iterator = paths.find("namesdata");
if (path_iterator == paths.end() || path_iterator->second.string().empty())
{
- throw OSRMException(".names file must be specified");
+ throw osrm::exception(".names file must be specified");
}
AssertPathExists(path_iterator->second);
path_iterator = paths.find("timestamp");
if (path_iterator == paths.end() || path_iterator->second.string().empty())
{
- throw OSRMException(".timestamp file must be specified");
+ throw osrm::exception(".timestamp file must be specified");
}
return true;
diff --git a/Util/FingerPrint.h b/Util/FingerPrint.h
index c61fe36..5fd04b6 100644
--- a/Util/FingerPrint.h
+++ b/Util/FingerPrint.h
@@ -42,7 +42,6 @@ class FingerPrint
bool TestGraphUtil(const FingerPrint &other) const;
bool TestPrepare(const FingerPrint &other) const;
bool TestRTree(const FingerPrint &other) const;
- bool TestNodeInfo(const FingerPrint &other) const;
bool TestQueryObjects(const FingerPrint &other) const;
private:
diff --git a/Util/MercatorUtil.h b/Util/MercatorUtil.h
index 31d1139..b4a15b7 100644
--- a/Util/MercatorUtil.h
+++ b/Util/MercatorUtil.h
@@ -30,14 +30,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <cmath>
-inline float y2lat(const float a)
+inline double y2lat(const double a)
{
- return 180.f * static_cast<float>(M_1_PI) * (2.f * std::atan(std::exp(a * static_cast<float>(M_PI) / 180.f)) - static_cast<float>(M_PI_2));
+ return 180. * M_1_PI * (2. * std::atan(std::exp(a * M_PI / 180.)) - M_PI_2);
}
-inline float lat2y(const float a)
+inline double lat2y(const double a)
{
- return 180.f * static_cast<float>(M_1_PI) * std::log(std::tan(static_cast<float>(M_PI_4) + a * (static_cast<float>(M_PI) / 180.f) / 2.f));
+ return 180. * M_1_PI * std::log(std::tan(M_PI_4 + a * (M_PI / 180.) / 2.));
}
#endif // MERCATOR_UTIL_H
diff --git a/Util/ProgramOptions.h b/Util/ProgramOptions.h
index c6e5448..3329b31 100644
--- a/Util/ProgramOptions.h
+++ b/Util/ProgramOptions.h
@@ -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,
@@ -28,10 +28,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef PROGAM_OPTIONS_H
#define PROGAM_OPTIONS_H
-#include "GitDescription.h"
+#include "git_sha.hpp"
#include "IniFileUtil.h"
-#include "OSRMException.h"
-#include "SimpleLogger.h"
+#include "osrm_exception.hpp"
+#include "simple_logger.hpp"
#include <osrm/ServerPaths.h>
@@ -45,6 +45,104 @@ const static unsigned INIT_OK_START_ENGINE = 0;
const static unsigned INIT_OK_DO_NOT_START_ENGINE = 1;
const static unsigned INIT_FAILED = -1;
+inline void populate_base_path(ServerPaths &server_paths)
+{
+ // populate the server_path object
+ auto path_iterator = server_paths.find("base");
+
+ // if a base path has been set, we populate it.
+ if (path_iterator != server_paths.end())
+ {
+ const std::string base_string = path_iterator->second.string();
+ SimpleLogger().Write() << "populating base path: " << base_string;
+
+ server_paths["hsgrdata"] = base_string + ".hsgr";
+ BOOST_ASSERT(server_paths.find("hsgrdata") != server_paths.end());
+ server_paths["nodesdata"] = base_string + ".nodes";
+ BOOST_ASSERT(server_paths.find("nodesdata") != server_paths.end());
+ server_paths["edgesdata"] = base_string + ".edges";
+ BOOST_ASSERT(server_paths.find("edgesdata") != server_paths.end());
+ server_paths["geometries"] = base_string + ".geometry";
+ BOOST_ASSERT(server_paths.find("geometries") != server_paths.end());
+ server_paths["ramindex"] = base_string + ".ramIndex";
+ BOOST_ASSERT(server_paths.find("ramindex") != server_paths.end());
+ server_paths["fileindex"] = base_string + ".fileIndex";
+ BOOST_ASSERT(server_paths.find("fileindex") != server_paths.end());
+ server_paths["namesdata"] = base_string + ".names";
+ BOOST_ASSERT(server_paths.find("namesdata") != server_paths.end());
+ server_paths["timestamp"] = base_string + ".timestamp";
+ BOOST_ASSERT(server_paths.find("timestamp") != server_paths.end());
+ }
+
+ // check if files are give and whether they exist at all
+ path_iterator = server_paths.find("hsgrdata");
+ if (path_iterator == server_paths.end() ||
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ if (path_iterator == server_paths.end())
+ {
+ SimpleLogger().Write() << "hsgrdata unset";
+ }
+ if (!boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ SimpleLogger().Write() << "not a regular file";
+ }
+
+ throw osrm::exception(".hsgr not found: " + path_iterator->second.string());
+ }
+
+ path_iterator = server_paths.find("nodesdata");
+ if (path_iterator == server_paths.end() ||
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ throw osrm::exception(".nodes not found");
+ }
+
+ path_iterator = server_paths.find("edgesdata");
+ if (path_iterator == server_paths.end() ||
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ throw osrm::exception(".edges not found");
+ }
+
+ path_iterator = server_paths.find("geometries");
+ if (path_iterator == server_paths.end() ||
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ throw osrm::exception(".geometry not found");
+ }
+
+ path_iterator = server_paths.find("ramindex");
+ if (path_iterator == server_paths.end() ||
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ throw osrm::exception(".ramIndex not found");
+ }
+
+ path_iterator = server_paths.find("fileindex");
+ if (path_iterator == server_paths.end() ||
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ throw osrm::exception(".fileIndex not found");
+ }
+
+ path_iterator = server_paths.find("namesdata");
+ if (path_iterator == server_paths.end() ||
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ throw osrm::exception(".namesIndex not found");
+ }
+
+ SimpleLogger().Write() << "HSGR file:\t" << server_paths["hsgrdata"];
+ SimpleLogger().Write(logDEBUG) << "Nodes file:\t" << server_paths["nodesdata"];
+ SimpleLogger().Write(logDEBUG) << "Edges file:\t" << server_paths["edgesdata"];
+ SimpleLogger().Write(logDEBUG) << "Geometry file:\t" << server_paths["geometries"];
+ SimpleLogger().Write(logDEBUG) << "RAM file:\t" << server_paths["ramindex"];
+ SimpleLogger().Write(logDEBUG) << "Index file:\t" << server_paths["fileindex"];
+ SimpleLogger().Write(logDEBUG) << "Names file:\t" << server_paths["namesdata"];
+ SimpleLogger().Write(logDEBUG) << "Timestamp file:\t" << server_paths["timestamp"];
+}
+
// generate boost::program_options object for the routing part
inline unsigned GenerateServerProgramOptions(const int argc,
const char *argv[],
@@ -55,7 +153,6 @@ inline unsigned GenerateServerProgramOptions(const int argc,
bool &use_shared_memory,
bool &trial)
{
-
// 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")(
@@ -164,99 +261,11 @@ inline unsigned GenerateServerProgramOptions(const int argc,
if (1 > requested_num_threads)
{
- throw OSRMException("Number of threads must be a positive number");
+ throw osrm::exception("Number of threads must be a positive number");
}
if (!use_shared_memory && option_variables.count("base"))
{
- path_iterator = paths.find("base");
- BOOST_ASSERT(paths.end() != path_iterator);
- std::string base_string = path_iterator->second.string();
-
- path_iterator = paths.find("hsgrdata");
- if (path_iterator != paths.end() &&
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- path_iterator->second = base_string + ".hsgr";
- }
- else
- {
- throw OSRMException(base_string + ".hsgr not found");
- }
-
- path_iterator = paths.find("nodesdata");
- if (path_iterator != paths.end() &&
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- path_iterator->second = base_string + ".nodes";
- }
- else
- {
- throw OSRMException(base_string + ".nodes not found");
- }
-
- path_iterator = paths.find("edgesdata");
- if (path_iterator != paths.end() &&
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- path_iterator->second = base_string + ".edges";
- }
- else
- {
- throw OSRMException(base_string + ".edges not found");
- }
-
- path_iterator = paths.find("geometries");
- if (path_iterator != paths.end() &&
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- path_iterator->second = base_string + ".geometry";
- }
- else
- {
- throw OSRMException(base_string + ".geometry not found");
- }
-
- path_iterator = paths.find("ramindex");
- if (path_iterator != paths.end() &&
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- path_iterator->second = base_string + ".ramIndex";
- }
- else
- {
- throw OSRMException(base_string + ".ramIndex not found");
- }
-
- path_iterator = paths.find("fileindex");
- if (path_iterator != paths.end() &&
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- path_iterator->second = base_string + ".fileIndex";
- }
- else
- {
- throw OSRMException(base_string + ".fileIndex not found");
- }
-
- path_iterator = paths.find("namesdata");
- if (path_iterator != paths.end() &&
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- path_iterator->second = base_string + ".names";
- }
- else
- {
- throw OSRMException(base_string + ".namesIndex not found");
- }
-
- path_iterator = paths.find("timestamp");
- if (path_iterator != paths.end() &&
- !boost::filesystem::is_regular_file(path_iterator->second))
- {
- path_iterator->second = base_string + ".timestamp";
- }
-
return INIT_OK_START_ENGINE;
}
if (use_shared_memory && !option_variables.count("base"))
diff --git a/Util/SimpleLogger.h b/Util/SimpleLogger.h
deleted file mode 100644
index a234c96..0000000
--- a/Util/SimpleLogger.h
+++ /dev/null
@@ -1,158 +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 SIMPLE_LOGGER_H
-#define SIMPLE_LOGGER_H
-
-#include <boost/assert.hpp>
-
-#include <cstdio>
-
-#ifdef _MSC_VER
-#include <io.h>
-#define isatty _isatty
-#define fileno _fileno
-#else
-#include <unistd.h>
-#endif
-
-#include <ostream>
-#include <iostream>
-#include <mutex>
-#include <sstream>
-
-enum LogLevel
-{ logINFO,
- logWARNING,
- logDEBUG };
-
-const char COL_RESET[] = "\x1b[0m";
-const char RED[] = "\x1b[31m";
-const char GREEN[] = "\x1b[32m";
-const char YELLOW[] = "\x1b[33m";
-const char BLUE[] = "\x1b[34m";
-const char MAGENTA[] = "\x1b[35m";
-const char CYAN[] = "\x1b[36m";
-
-class LogPolicy
-{
- public:
- void Unmute() { m_is_mute = false; }
-
- void Mute() { m_is_mute = true; }
-
- bool IsMute() const { return m_is_mute; }
-
- static LogPolicy &GetInstance()
- {
- static LogPolicy runningInstance;
- return runningInstance;
- }
-
- LogPolicy(const LogPolicy &) = delete;
-
- private:
- LogPolicy() : m_is_mute(true) {}
- bool m_is_mute;
-};
-
-class SimpleLogger
-{
- public:
- SimpleLogger() : level(logINFO) {}
-
- std::mutex& get_mutex()
- {
- static std::mutex m;
- return m;
- }
-
-
- std::ostringstream &Write(LogLevel l = logINFO)
- {
- std::lock_guard<std::mutex> lock(get_mutex());
- try
- {
- level = l;
- os << "[";
- switch (level)
- {
- case logINFO:
- os << "info";
- break;
- case logWARNING:
- os << "warn";
- break;
- case logDEBUG:
-#ifndef NDEBUG
- os << "debug";
-#endif
- break;
- default:
- BOOST_ASSERT_MSG(false, "should not happen");
- break;
- }
- os << "] ";
- }
- catch (...) {}
- return os;
- }
-
- virtual ~SimpleLogger()
- {
- std::lock_guard<std::mutex> lock(get_mutex());
- if (!LogPolicy::GetInstance().IsMute())
- {
- const bool is_terminal = ( 0 != isatty(fileno(stdout)) ? true : false);
- switch (level)
- {
- case logINFO:
- std::cout << os.str() << (is_terminal ? COL_RESET : "") << std::endl;
- break;
- case logWARNING:
- std::cerr << (is_terminal ? RED : "") << os.str() << (is_terminal ? COL_RESET : "")
- << std::endl;
- break;
- case logDEBUG:
-#ifndef NDEBUG
- std::cout << (is_terminal ? YELLOW : "") << os.str()
- << (is_terminal ? COL_RESET : "") << std::endl;
-#endif
- break;
- default:
- BOOST_ASSERT_MSG(false, "should not happen");
- break;
- }
- }
- }
-
- private:
- LogLevel level;
- std::ostringstream os;
-};
-
-#endif /* SIMPLE_LOGGER_H */
diff --git a/Util/StringUtil.h b/Util/StringUtil.h
deleted file mode 100644
index 68a9ac9..0000000
--- a/Util/StringUtil.h
+++ /dev/null
@@ -1,318 +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 STRINGUTIL_H
-#define STRINGUTIL_H
-
-#include <boost/algorithm/string.hpp>
-#include <boost/spirit/include/karma.hpp>
-#include <boost/spirit/include/qi.hpp>
-
-#include <cstdio>
-#include <cctype>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-// precision: position after decimal point
-// length: maximum number of digits including comma and decimals
-// work with negative values to prevent overflowing when taking -value
-template <int length, int precision> static inline char *printInt(char *buffer, int value)
-{
- bool minus = true;
- if (value > 0)
- {
- minus = false;
- value = -value;
- }
- buffer += length - 1;
- for (int i = 0; i < precision; i++)
- {
- *buffer = '0' - (value % 10);
- value /= 10;
- buffer--;
- }
- *buffer = '.';
- buffer--;
- for (int i = precision + 1; i < length; i++)
- {
- *buffer = '0' - (value % 10);
- value /= 10;
- if (value == 0)
- break;
- buffer--;
- }
- if (minus)
- {
- buffer--;
- *buffer = '-';
- }
- return buffer;
-}
-
-// convert scoped enums to integers
-template <typename Enumeration>
-auto as_integer(Enumeration const value)
- -> typename std::underlying_type<Enumeration>::type
-{
- return static_cast<typename std::underlying_type<Enumeration>::type>(value);
-}
-
-static inline std::string IntToString(const int value)
-{
- std::string output;
- std::back_insert_iterator<std::string> sink(output);
- boost::spirit::karma::generate(sink, boost::spirit::karma::int_, value);
- return output;
-}
-
-static inline std::string UintToString(const unsigned value)
-{
- std::string output;
- std::back_insert_iterator<std::string> sink(output);
- boost::spirit::karma::generate(sink, boost::spirit::karma::uint_, value);
- return output;
-}
-
-static inline void int64ToString(const int64_t value, std::string &output)
-{
- output.clear();
- std::back_insert_iterator<std::string> sink(output);
- boost::spirit::karma::generate(sink, boost::spirit::karma::long_long, value);
-}
-
-static inline int StringToInt(const std::string &input)
-{
- auto first_digit = input.begin();
- // Delete any trailing white-spaces
- while (first_digit != input.end() && std::isspace(*first_digit))
- {
- ++first_digit;
- }
- int value = 0;
- boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::int_, value);
- return value;
-}
-
-static inline unsigned StringToUint(const std::string &input)
-{
- auto first_digit = input.begin();
- // Delete any trailing white-spaces
- while (first_digit != input.end() && std::isspace(*first_digit))
- {
- ++first_digit;
- }
- unsigned value = 0;
- boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::uint_, value);
- return value;
-}
-
-static inline uint64_t StringToInt64(const std::string &input)
-{
- auto first_digit = input.begin();
- // Delete any trailing white-spaces
- while (first_digit != input.end() && std::isspace(*first_digit))
- {
- ++first_digit;
- }
- uint64_t value = 0;
- boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::long_long, value);
- return value;
-}
-
-// source: http://tinodidriksen.com/2011/05/28/cpp-convert-string-to-double-speed/
-static inline double StringToDouble(const char *p)
-{
- double r = 0.0;
- bool neg = false;
- if (*p == '-')
- {
- neg = true;
- ++p;
- }
- while (*p >= '0' && *p <= '9')
- {
- r = (r * 10.0) + (*p - '0');
- ++p;
- }
- if (*p == '.')
- {
- double f = 0.0;
- int n = 0;
- ++p;
- while (*p >= '0' && *p <= '9')
- {
- f = (f * 10.0) + (*p - '0');
- ++p;
- ++n;
- }
- r += f / std::pow(10.0, n);
- }
- if (neg)
- {
- r = -r;
- }
- return r;
-}
-
-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 n) { 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;
-
-static inline std::string FixedDoubleToString(const double value)
-{
- std::string output;
- std::back_insert_iterator<std::string> sink(output);
- boost::spirit::karma::generate(sink, science_type(), value);
- if (output.size() >= 2 && output[output.size()-2] == '.' && output[output.size()-1] == '0')
- {
- output.resize(output.size()-2);
- }
- return output;
-}
-
-static inline std::string DoubleToString(const double value)
-{
- std::string output;
- std::back_insert_iterator<std::string> sink(output);
- boost::spirit::karma::generate(sink, value);
- return output;
-}
-
-static inline void doubleToStringWithTwoDigitsBehindComma(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
- char buffer[12];
- sprintf(buffer, "%g", value);
- output = buffer;
-}
-
-inline void replaceAll(std::string &s, const std::string &sub, const std::string &other)
-{
- boost::replace_all(s, sub, other);
-}
-
-inline std::string EscapeJSONString(const std::string &input)
-{
- std::string output;
- output.reserve(input.size());
- for (auto iter = input.begin(); iter != input.end(); ++iter)
- {
- switch (iter[0])
- {
- case '\\':
- output += "\\\\";
- break;
- case '"':
- output += "\\\"";
- break;
- case '/':
- output += "\\/";
- break;
- case '\b':
- output += "\\b";
- break;
- case '\f':
- output += "\\f";
- break;
- case '\n':
- output += "\\n";
- break;
- case '\r':
- output += "\\r";
- break;
- case '\t':
- output += "\\t";
- break;
- default:
- output += *iter;
- 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();
- output.resize(input.size() + 1);
- std::size_t decoded_length = 0;
- for (decoded_length = 0; src_iter != input.end(); ++decoded_length)
- {
- if (src_iter[0] == '%' && src_iter[1] && src_iter[2] && isxdigit(src_iter[1]) &&
- isxdigit(src_iter[2]))
- {
- std::string::value_type a = src_iter[1];
- std::string::value_type b = src_iter[2];
- a -= src_iter[1] < 58 ? 48 : src_iter[1] < 71 ? 55 : 87;
- b -= src_iter[2] < 58 ? 48 : src_iter[2] < 71 ? 55 : 87;
- output[decoded_length] = 16 * a + b;
- src_iter += 3;
- continue;
- }
- output[decoded_length] = *src_iter++;
- }
- output.resize(decoded_length);
- return decoded_length;
-}
-
-inline std::size_t URIDecodeInPlace(std::string &URI) { return URIDecode(URI, URI); }
-
-inline bool StringStartsWith(const std::string &input, const std::string &prefix)
-{
- return boost::starts_with(input, prefix);
-}
-
-inline std::string GetRandomString()
-{
- std::string s;
- s.resize(128);
- static const char alphanum[] = "0123456789"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz";
-
- for (int i = 0; i < 127; ++i)
- {
- s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
- }
- s[127] = 0;
- return s;
-}
-
-#endif // STRINGUTIL_H
diff --git a/Util/TimingUtil.h b/Util/TimingUtil.h
deleted file mode 100644
index c1505ce..0000000
--- a/Util/TimingUtil.h
+++ /dev/null
@@ -1,39 +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 TIMINGUTIL_H
-#define TIMINGUTIL_H
-
-#include <chrono>
-
-#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_MSEC(_X) std::chrono::duration_cast<std::chrono::milliseconds>(_X##_stop - _X##_start).count()
-#define TIMER_SEC(_X) (0.001*std::chrono::duration_cast<std::chrono::milliseconds>(_X##_stop - _X##_start).count())
-#define TIMER_MIN(_X) std::chrono::duration_cast<std::chrono::minutes>(_X##_stop - _X##_start).count()
-
-#endif // TIMINGUTIL_H
diff --git a/Util/MachineInfo.h b/Util/bearing.cpp
similarity index 65%
rename from Util/MachineInfo.h
rename to Util/bearing.cpp
index c5cb052..1cdcf30 100644
--- a/Util/MachineInfo.h
+++ b/Util/bearing.cpp
@@ -25,33 +25,41 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MACHINE_INFO_H
-#define MACHINE_INFO_H
+#include "bearing.hpp"
-enum Endianness
-{ LittleEndian = 1,
- BigEndian = 2 };
-
-// Function is optimized to a single 'mov eax,1' on GCC, clang and icc using -O3
-inline Endianness GetMachineEndianness()
+std::string Bearing::Get(const double heading)
{
- int i(1);
- char *p = (char *)&i;
- if (1 == p[0])
+ if (heading <= 202.5)
{
- return LittleEndian;
+ 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";
}
- return BigEndian;
-}
-
-// Reverses Network Byte Order into something usable, compiles down to a bswap-mov combination
-inline unsigned SwapEndian(unsigned x)
-{
- if (GetMachineEndianness() == LittleEndian)
+ if (heading > 202.5 && heading <= 247.5)
{
- return ((x >> 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x << 24));
+ return "SW";
}
- return x;
+ if (heading > 247.5 && heading <= 292.5)
+ {
+ return "W";
+ }
+ if (heading > 292.5 && heading <= 337.5)
+ {
+ return "NW";
+ }
+ return "N";
}
-
-#endif // MACHINE_INFO_H
diff --git a/Util/GitDescription.h b/Util/bearing.hpp
similarity index 89%
copy from Util/GitDescription.h
copy to Util/bearing.hpp
index d3a00f4..a30ec2f 100644
--- a/Util/GitDescription.h
+++ b/Util/bearing.hpp
@@ -25,9 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef GIT_DESCRIPTION_H
-#define GIT_DESCRIPTION_H
+#ifndef BEARING_HPP_
+#define BEARING_HPP_
-extern char g_GIT_DESCRIPTION[];
+#include <string>
-#endif //GIT_DESCRIPTION_H
+struct Bearing
+{
+ static std::string Get(const double heading);
+};
+
+#endif // BEARING_HPP_
diff --git a/Util/cast.hpp b/Util/cast.hpp
new file mode 100644
index 0000000..9d09761
--- /dev/null
+++ b/Util/cast.hpp
@@ -0,0 +1,188 @@
+/*
+
+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 CAST_HPP
+#define CAST_HPP
+
+#include <boost/spirit/include/karma.hpp>
+#include <boost/spirit/include/qi.hpp>
+
+#include <string>
+#include <type_traits>
+
+struct cast
+{
+ // convert scoped enums to integers
+ template <typename Enumeration>
+ static auto enum_to_underlying(Enumeration const value) -> typename std::underlying_type<Enumeration>::type
+ {
+ return static_cast<typename std::underlying_type<Enumeration>::type>(value);
+ }
+
+ template <typename Number>
+ static typename std::enable_if<std::is_integral<Number>::value, std::string>::type
+ integral_to_string(const Number value)
+ {
+ std::string output;
+ std::back_insert_iterator<std::string> sink(output);
+
+ if (8 == sizeof(Number))
+ {
+ boost::spirit::karma::generate(sink, boost::spirit::karma::long_long, value);
+ }
+ else
+ {
+ if (std::is_signed<Number>::value)
+ {
+ boost::spirit::karma::generate(sink, boost::spirit::karma::int_, value);
+ }
+ else
+ {
+ boost::spirit::karma::generate(sink, boost::spirit::karma::uint_, value);
+ }
+ }
+ return output;
+ }
+
+ static int string_to_int(const std::string &input)
+ {
+ auto first_digit = input.begin();
+ // Delete any trailing white-spaces
+ while (first_digit != input.end() && std::isspace(*first_digit))
+ {
+ ++first_digit;
+ }
+ int value = 0;
+ boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::int_, value);
+ return value;
+ }
+
+ static unsigned string_to_uint(const std::string &input)
+ {
+ auto first_digit = input.begin();
+ // Delete any trailing white-spaces
+ while (first_digit != input.end() && (std::isspace(*first_digit) || '-' == *first_digit))
+ {
+ ++first_digit;
+ }
+ unsigned value = 0;
+ boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::uint_, value);
+ return value;
+ }
+
+ static uint64_t string_to_uint64(const std::string &input)
+ {
+ auto first_digit = input.begin();
+ // Delete any trailing white-spaces
+ while (first_digit != input.end() && std::isspace(*first_digit))
+ {
+ ++first_digit;
+ }
+ uint64_t value = 0;
+ boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::long_long, value);
+ return value;
+ }
+
+ // source: http://tinodidriksen.com/2011/05/28/cpp-convert-string-to-double-speed/
+ static double string_to_double(const char *p)
+ {
+ double r = 0.0;
+ bool neg = false;
+ if (*p == '-')
+ {
+ neg = true;
+ ++p;
+ }
+ while (*p >= '0' && *p <= '9')
+ {
+ r = (r * 10.0) + (*p - '0');
+ ++p;
+ }
+ if (*p == '.')
+ {
+ double f = 0.0;
+ int n = 0;
+ ++p;
+ while (*p >= '0' && *p <= '9')
+ {
+ f = (f * 10.0) + (*p - '0');
+ ++p;
+ ++n;
+ }
+ r += f / std::pow(10.0, n);
+ }
+ if (neg)
+ {
+ r = -r;
+ }
+ return r;
+ }
+
+ 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 unsigned int precision(T) { return 6; }
+ };
+ typedef boost::spirit::karma::real_generator<double, scientific_policy<double>> science_type;
+
+ static std::string double_fixed_to_string(const double value)
+ {
+ std::string output;
+ std::back_insert_iterator<std::string> sink(output);
+ boost::spirit::karma::generate(sink, science_type(), value);
+ if (output.size() >= 2 && output[output.size() - 2] == '.' &&
+ output[output.size() - 1] == '0')
+ {
+ output.resize(output.size() - 2);
+ }
+ return output;
+ }
+
+ static std::string double_to_string(const double value)
+ {
+ std::string output;
+ std::back_insert_iterator<std::string> sink(output);
+ boost::spirit::karma::generate(sink, value);
+ return 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
+ char buffer[12];
+ sprintf(buffer, "%g", value);
+ output = buffer;
+ }
+};
+
+#endif // CAST_HPP
diff --git a/Util/ComputeAngle.h b/Util/compute_angle.cpp
similarity index 77%
rename from Util/ComputeAngle.h
rename to Util/compute_angle.cpp
index 02f678a..b6350e4 100644
--- a/Util/ComputeAngle.h
+++ b/Util/compute_angle.cpp
@@ -25,33 +25,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef COMPUTE_ANGLE_H
-#define COMPUTE_ANGLE_H
+#include "compute_angle.hpp"
#include "TrigonometryTables.h"
#include "../Util/MercatorUtil.h"
#include <osrm/Coordinate.h>
-#include <boost/assert.hpp>
#include <cmath>
-/* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/
-template <class CoordinateT>
-inline static double GetAngleBetweenThreeFixedPointCoordinates(const CoordinateT &A,
- const CoordinateT &C,
- const CoordinateT &B)
+double ComputeAngle::OfThreeFixedPointCoordinates(const FixedPointCoordinate &A,
+ const FixedPointCoordinate &C,
+ const FixedPointCoordinate &B)
{
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);
- double angle = (atan2_lookup(v2y, v2x) - atan2_lookup(v1y, v1x)) * 180 / M_PI;
- while (angle < 0)
+ double angle = (atan2_lookup(v2y, v2x) - atan2_lookup(v1y, v1x)) * 180. / M_PI;
+ while (angle < 0.)
{
- angle += 360;
+ angle += 360.;
}
return angle;
}
-
-#endif // COMPUTE_ANGLE_H
diff --git a/Library/OSRM.h b/Util/compute_angle.hpp
similarity index 73%
copy from Library/OSRM.h
copy to Util/compute_angle.hpp
index 16b9977..72c861a 100644
--- a/Library/OSRM.h
+++ b/Util/compute_angle.hpp
@@ -25,28 +25,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef OSRM_H
-#define OSRM_H
+#ifndef COMPUTE_ANGLE_HPP
+#define COMPUTE_ANGLE_HPP
-#include <osrm/ServerPaths.h>
+struct FixedPointCoordinate;
+struct NodeInfo;
-class OSRM_impl;
-struct RouteParameters;
-
-namespace http
-{
-class Reply;
-}
-
-class OSRM
+struct ComputeAngle
{
- private:
- OSRM_impl *OSRM_pimpl_;
-
- public:
- explicit OSRM(const ServerPaths &paths, const bool use_shared_memory = false);
- ~OSRM();
- void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
+ /* 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);
};
-
-#endif // OSRM_H
+#endif // COMPUTE_ANGLE_HPP
diff --git a/Util/ContainerUtils.h b/Util/container.hpp
similarity index 57%
rename from Util/ContainerUtils.h
rename to Util/container.hpp
index 2517545..343ebe9 100644
--- a/Util/ContainerUtils.h
+++ b/Util/container.hpp
@@ -25,47 +25,58 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CONTAINERUTILS_H_
-#define CONTAINERUTILS_H_
+#ifndef CONTAINER_HPP_
+#define CONTAINER_HPP_
#include <algorithm>
+#include <iterator>
#include <vector>
-template <typename T> inline void sort_unique_resize(std::vector<T> &vector)
+namespace osrm
+{
+template <typename T> void sort_unique_resize(std::vector<T> &vector)
{
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);
}
-template <typename T> inline void sort_unique_resize_shrink_vector(std::vector<T> &vector)
-{
- sort_unique_resize(vector);
- std::vector<T>().swap(vector);
-}
+// template <typename T> inline void sort_unique_resize_shrink_vector(std::vector<T> &vector)
+// {
+// sort_unique_resize(vector);
+// vector.shrink_to_fit();
+// }
-template <typename T> inline void remove_consecutive_duplicates_from_vector(std::vector<T> &vector)
-{
- const auto number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin();
- vector.resize(number_of_unique_elements);
-}
+// template <typename T> inline void remove_consecutive_duplicates_from_vector(std::vector<T> &vector)
+// {
+// const auto number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin();
+// vector.resize(number_of_unique_elements);
+// }
-template <typename FwdIter, typename Func>
-Func for_each_pair(FwdIter iter_begin, FwdIter iter_end, Func func)
+template <typename ForwardIterator, typename Function>
+Function for_each_pair(ForwardIterator begin, ForwardIterator end, Function function)
{
- if (iter_begin == iter_end)
+ if (begin == end)
{
- return func;
+ return function;
}
- FwdIter iter_next = iter_begin;
- ++iter_next;
+ auto next = begin;
+ next = std::next(next);
- for (; iter_next != iter_end; ++iter_begin, ++iter_next)
+ while (next != end)
{
- func(*iter_begin, *iter_next);
+ function(*begin, *next);
+ begin = std::next(begin); next = std::next(next);
}
- return func;
+ return function;
}
-#endif /* CONTAINERUTILS_H_ */
+template <class ContainerT, typename Function>
+Function for_each_pair(ContainerT &container, Function function)
+{
+ return for_each_pair(std::begin(container), std::end(container), function);
+}
+
+}
+#endif /* CONTAINER_HPP_ */
diff --git a/Util/FingerPrint.cpp.in b/Util/finger_print.cpp.in
similarity index 87%
rename from Util/FingerPrint.cpp.in
rename to Util/finger_print.cpp.in
index d1ce4f0..c73756e 100644
--- a/Util/FingerPrint.cpp.in
+++ b/Util/finger_print.cpp.in
@@ -27,12 +27,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FingerPrint.h"
-#include "OSRMException.h"
+#include "osrm_exception.hpp"
#include <boost/uuid/name_generator.hpp>
-#include <cstring>
-
#include <algorithm>
#include <string>
@@ -47,8 +45,7 @@ FingerPrint::FingerPrint() : magic_number(1297240911)
md5_prepare[32] = md5_tree[32] = md5_graph[32] = md5_objects[32] = '\0';
boost::uuids::name_generator gen(named_uuid);
- std::string temp_string(__DATE__);
- temp_string += __TIME__;
+ std::string temp_string;
std::memcpy(md5_prepare, MD5PREPARE, strlen(MD5PREPARE));
temp_string += md5_prepare;
@@ -73,7 +70,7 @@ bool FingerPrint::TestGraphUtil(const FingerPrint &other) const
{
if (!other.IsMagicNumberOK())
{
- throw OSRMException("hsgr input file misses magic number. Check or reprocess the file");
+ throw osrm::exception("hsgr input file misses magic number. Check or reprocess the file");
}
return std::equal(md5_graph, md5_graph + 32, other.md5_graph);
}
@@ -82,7 +79,7 @@ bool FingerPrint::TestPrepare(const FingerPrint &other) const
{
if (!other.IsMagicNumberOK())
{
- throw OSRMException("osrm input file misses magic number. Check or reprocess the file");
+ throw osrm::exception("osrm input file misses magic number. Check or reprocess the file");
}
return std::equal(md5_prepare, md5_prepare + 32, other.md5_prepare);
}
@@ -91,7 +88,7 @@ bool FingerPrint::TestRTree(const FingerPrint &other) const
{
if (!other.IsMagicNumberOK())
{
- throw OSRMException("r-tree input file misses magic number. Check or reprocess the file");
+ throw osrm::exception("r-tree input file misses magic number. Check or reprocess the file");
}
return std::equal(md5_tree, md5_tree + 32, other.md5_tree);
}
@@ -100,7 +97,7 @@ bool FingerPrint::TestQueryObjects(const FingerPrint &other) const
{
if (!other.IsMagicNumberOK())
{
- throw OSRMException("missing magic number. Check or reprocess the file");
+ throw osrm::exception("missing magic number. Check or reprocess the file");
}
return std::equal(md5_objects, md5_objects + 32, other.md5_objects);
}
diff --git a/Library/OSRM.h b/Util/floating_point.hpp
similarity index 75%
copy from Library/OSRM.h
copy to Util/floating_point.hpp
index 16b9977..5c48102 100644
--- a/Library/OSRM.h
+++ b/Util/floating_point.hpp
@@ -1,5 +1,4 @@
/*
-
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved.
@@ -25,28 +24,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef OSRM_H
-#define OSRM_H
+#ifndef FLOATING_POINT_HPP
+#define FLOATING_POINT_HPP
-#include <osrm/ServerPaths.h>
+#include <cmath>
-class OSRM_impl;
-struct RouteParameters;
+#include <limits>
+#include <type_traits>
-namespace http
+namespace osrm
{
-class Reply;
-}
-
-class OSRM
+template <typename FloatT> bool epsilon_compare(const FloatT number1, const FloatT number2)
{
- private:
- OSRM_impl *OSRM_pimpl_;
-
- public:
- explicit OSRM(const ServerPaths &paths, const bool use_shared_memory = false);
- ~OSRM();
- void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
-};
+ static_assert(std::is_floating_point<FloatT>::value, "type must be floating point");
+ return (std::abs(number1 - number2) < std::numeric_limits<FloatT>::epsilon());
+}
+}
-#endif // OSRM_H
+#endif // FLOATING_POINT_HPP
diff --git a/Util/GitDescription.cpp.in b/Util/git_sha.cpp.in
similarity index 94%
rename from Util/GitDescription.cpp.in
rename to Util/git_sha.cpp.in
index 6f4ba7e..5b19337 100644
--- a/Util/GitDescription.cpp.in
+++ b/Util/git_sha.cpp.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,5 +25,7 @@ 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;
diff --git a/Util/GitDescription.h b/Util/git_sha.hpp
similarity index 90%
rename from Util/GitDescription.h
rename to Util/git_sha.hpp
index d3a00f4..d1f18a6 100644
--- a/Util/GitDescription.h
+++ b/Util/git_sha.hpp
@@ -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,9 +25,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef GIT_DESCRIPTION_H
-#define GIT_DESCRIPTION_H
+#ifndef GIT_SHA_HPP
+#define GIT_SHA_HPP
extern char g_GIT_DESCRIPTION[];
-#endif //GIT_DESCRIPTION_H
+#endif //GIT_SHA_HPP
diff --git a/Util/GraphLoader.h b/Util/graph_loader.hpp
similarity index 84%
rename from Util/GraphLoader.h
rename to Util/graph_loader.hpp
index 612332b..5ab8eba 100644
--- a/Util/GraphLoader.h
+++ b/Util/graph_loader.hpp
@@ -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,
@@ -28,12 +28,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GRAPHLOADER_H
#define GRAPHLOADER_H
-#include "OSRMException.h"
-#include "../DataStructures/ImportNode.h"
-#include "../DataStructures/ImportEdge.h"
-#include "../DataStructures/QueryNode.h"
-#include "../DataStructures/Restriction.h"
-#include "../Util/SimpleLogger.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"
@@ -57,7 +57,7 @@ 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<NodeInfo> *int_to_ext_node_id_map,
+ std::vector<QueryNode> *int_to_ext_node_id_map,
std::vector<TurnRestriction> &restriction_list)
{
const FingerPrint fingerprint_orig;
@@ -70,23 +70,23 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
"Reprocess to get rid of this warning.";
}
- NodeID n, source, target;
- EdgeID m;
- short dir; // direction (0 = open, 1 = forward, 2+ = open)
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.bollard)
+ if (current_node.barrier)
{
barrier_node_list.emplace_back(i);
}
- if (current_node.trafficLight)
+ if (current_node.traffic_lights)
{
traffic_light_node_list.emplace_back(i);
}
@@ -95,41 +95,47 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
// tighten vector sizes
barrier_node_list.shrink_to_fit();
traffic_light_node_list.shrink_to_fit();
- input_stream.read((char *)&m, sizeof(unsigned));
- SimpleLogger().Write() << " and " << m << " edges ";
+
+ // renumber nodes in turn restrictions
for (TurnRestriction ¤t_restriction : restriction_list)
{
- auto internal_id_iter = ext_to_int_id_map.find(current_restriction.fromNode);
+ 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.fromNode = internal_id_iter->second;
+ current_restriction.from.node = internal_id_iter->second;
- internal_id_iter = ext_to_int_id_map.find(current_restriction.viaNode);
+ 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.viaNode = internal_id_iter->second;
+ current_restriction.via.node = internal_id_iter->second;
- internal_id_iter = ext_to_int_id_map.find(current_restriction.toNode);
+ 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.toNode = internal_id_iter->second;
+ current_restriction.to.node = internal_id_iter->second;
}
- edge_list.reserve(m);
EdgeWeight weight;
- short type;
- NodeID nameID;
+ NodeID source, target;
+ unsigned nameID;
int length;
- bool is_roundabout, ignore_in_grid, is_access_restricted, is_contra_flow, is_split;
+ 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)
{
@@ -138,12 +144,11 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
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 *)&type, sizeof(short));
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 *)&is_contra_flow, 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");
@@ -161,8 +166,6 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
forward = false;
}
- BOOST_ASSERT(type >= 0);
-
// 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())
@@ -182,7 +185,8 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
continue;
}
target = internal_id_iter->second;
- BOOST_ASSERT_MSG(source != UINT_MAX && target != UINT_MAX, "nonexisting source or target");
+ BOOST_ASSERT_MSG(source != SPECIAL_NODEID && target != SPECIAL_NODEID,
+ "nonexisting source or target");
if (source > target)
{
@@ -196,15 +200,16 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
weight,
forward,
backward,
- type,
is_roundabout,
ignore_in_grid,
is_access_restricted,
- is_contra_flow,
+ 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) &&
@@ -215,22 +220,22 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
(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].backward != edge_list[i].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].backward != edge_list[i - 1].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 = UINT_MAX;
+ 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 = UINT_MAX;
+ edge_list[i].source = SPECIAL_NODEID;
}
else
{
@@ -252,16 +257,16 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
else
{
// edge i is smaller and goes in both direction. Throw away edge i-1
- edge_list[i - 1].source = UINT_MAX;
+ 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; });
- ext_to_int_id_map.clear();
+ 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";
@@ -276,11 +281,11 @@ unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
{
if (!boost::filesystem::exists(hsgr_file))
{
- throw OSRMException("hsgr file does not exist");
+ throw osrm::exception("hsgr file does not exist");
}
if (0 == boost::filesystem::file_size(hsgr_file))
{
- throw OSRMException("hsgr file is empty");
+ throw osrm::exception("hsgr file is empty");
}
boost::filesystem::ifstream hsgr_input_stream(hsgr_file, std::ios::binary);
@@ -304,7 +309,7 @@ unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
<< ", number_of_edges: " << number_of_edges;
// BOOST_ASSERT_MSG( 0 != number_of_edges, "number of edges is zero");
- node_list.resize(number_of_nodes + 1);
+ 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);
diff --git a/DataStructures/SearchEngine.h b/Util/integer_range.hpp
similarity index 54%
copy from DataStructures/SearchEngine.h
copy to Util/integer_range.hpp
index 58f5e77..030b2fa 100644
--- a/DataStructures/SearchEngine.h
+++ b/Util/integer_range.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2013,2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,36 +25,46 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SEARCHENGINE_H
-#define SEARCHENGINE_H
-
-#include "SearchEngineData.h"
-#include "../RoutingAlgorithms/AlternativePathRouting.h"
-#include "../RoutingAlgorithms/ManyToManyRouting.h"
-#include "../RoutingAlgorithms/ShortestPathRouting.h"
+#ifndef INTEGER_RANGE_HPP
+#define INTEGER_RANGE_HPP
#include <type_traits>
-template <class DataFacadeT> class SearchEngine
+namespace osrm
+{
+
+template <typename Integer> class range
{
private:
- DataFacadeT *facade;
- SearchEngineData engine_working_data;
+ Integer last;
+ Integer iter;
public:
- ShortestPathRouting<DataFacadeT> shortest_path;
- AlternativeRouting<DataFacadeT> alternative_path;
- ManyToManyRouting<DataFacadeT> distance_table;
-
- explicit SearchEngine(DataFacadeT *facade)
- : facade(facade), shortest_path(facade, engine_working_data),
- alternative_path(facade, engine_working_data), distance_table(facade, engine_working_data)
+ range(Integer start, Integer end) : last(end), iter(start)
{
- 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_integral<Integer>::value, "range type must be integral");
}
- ~SearchEngine() {}
+ // 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; }
+
+ // Iterator functions
+ bool operator!=(const range &) const { return iter < last; }
+ void operator++() { ++iter; }
+ Integer operator*() const { return iter; }
};
-#endif // SEARCHENGINE_H
+// 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
diff --git a/DataStructures/HashTable.h b/Util/iterator_range.hpp
similarity index 55%
rename from DataStructures/HashTable.h
rename to Util/iterator_range.hpp
index 199c6df..a057d7c 100644
--- a/DataStructures/HashTable.h
+++ b/Util/iterator_range.hpp
@@ -25,54 +25,48 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HASH_TABLE_H
-#define HASH_TABLE_H
+#ifndef RANGE_HPP_
+#define RANGE_HPP_
-#include <vector>
-
-template <typename Key, typename Value>
-class HashTable
+namespace osrm
+{
+namespace util
+{
+template <typename Iterator> class Range
{
- private:
- typedef std::pair<Key, Value> KeyValPair;
- std::vector<KeyValPair> table;
-
public:
- HashTable() {}
+ Range(Iterator begin, Iterator end) : begin_(begin), end_(end) {}
- inline void Add(Key const &key, Value const &value)
- {
- table.emplace_back(std::move(key), std::move(value));
- }
+ Iterator begin() const { return begin_; }
+ Iterator end() const { return end_; }
- inline void Clear()
- {
- table.clear();
- }
+ private:
+ Iterator begin_;
+ Iterator end_;
+};
- inline const Value Find(Key const &key) const
- {
- for (const auto &key_val_pair : table)
- {
- if (key_val_pair.first == key)
- {
- return key_val_pair.second;
- }
- }
- return Value();
- }
+// Convenience functions for template parameter inference,
+// akin to std::make_pair.
- inline const bool Holds(Key const &key) const
- {
- for (const auto &key_val_pair : table)
- {
- if (key_val_pair.first == key)
- {
- return true;
- }
- }
- return false;
- }
-};
+template <typename Iterator> Range<Iterator> range(Iterator begin, Iterator end)
+{
+ return Range<Iterator>(begin, end);
+}
+
+template <typename Reversable>
+Range<typename Reversable::reverse_iterator> reverse(Reversable *reversable)
+{
+ return Range<typename Reversable::reverse_iterator>(reversable->rbegin(), reversable->rend());
+}
+
+template <typename ConstReversable>
+Range<typename ConstReversable::const_reverse_iterator>
+const_reverse(const ConstReversable *const_reversable)
+{
+ return Range<typename ConstReversable::const_reverse_iterator>(const_reversable->crbegin(),
+ const_reversable->crend());
+}
+}
+}
-#endif /* HASH_TABLE_H */
+#endif // RANGE_HPP_
diff --git a/DataStructures/JSONContainer.h b/Util/json_renderer.hpp
similarity index 66%
rename from DataStructures/JSONContainer.h
rename to Util/json_renderer.hpp
index 47dc34b..dd6089c 100644
--- a/DataStructures/JSONContainer.h
+++ b/Util/json_renderer.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,79 +25,20 @@ 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
+// 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_RENDERER_HPP
+#define JSON_RENDERER_HPP
-#include "../Util/StringUtil.h"
+#include "../data_structures/json_container.hpp"
+#include "cast.hpp"
-#include <boost/variant.hpp>
+namespace JSON {
-#include <iostream>
-#include <vector>
-#include <string>
-#include <unordered_map>
-
-namespace JSON
-{
-
-struct String;
-struct Number;
-struct Object;
-struct Array;
-struct True;
-struct False;
-struct Null;
-
-typedef boost::variant<boost::recursive_wrapper<String>,
- boost::recursive_wrapper<Number>,
- boost::recursive_wrapper<Object>,
- boost::recursive_wrapper<Array>,
- boost::recursive_wrapper<True>,
- boost::recursive_wrapper<False>,
- boost::recursive_wrapper<Null> > Value;
-
-struct String
-{
- String() {}
- String(const char *value) : value(value) {}
- String(const std::string &value) : value(value) {}
- std::string value;
-};
-
-struct Number
-{
- Number() {}
- Number(double value) : value(value) {}
- double value;
-};
-
-struct Object
-{
- std::unordered_map<std::string, Value> values;
-};
-
-struct Array
-{
- std::vector<Value> values;
-};
-
-struct True
-{
-};
-
-struct False
-{
-};
-
-struct Null
+struct Renderer : mapbox::util::static_visitor<>
{
-};
-
-struct Renderer : boost::static_visitor<>
-{
- Renderer(std::ostream &_out) : out(_out) {}
+ explicit Renderer(std::ostream &_out) : out(_out) {}
void operator()(const String &string) const { out << "\"" << string.value << "\""; }
@@ -114,7 +55,7 @@ struct Renderer : boost::static_visitor<>
while (iterator != object.values.end())
{
out << "\"" << (*iterator).first << "\":";
- boost::apply_visitor(Renderer(out), (*iterator).second);
+ mapbox::util::apply_visitor(Renderer(out), (*iterator).second);
if (++iterator != object.values.end())
{
out << ",";
@@ -130,7 +71,7 @@ struct Renderer : boost::static_visitor<>
iterator = array.values.begin();
while (iterator != array.values.end())
{
- boost::apply_visitor(Renderer(out), *iterator);
+ mapbox::util::apply_visitor(Renderer(out), *iterator);
if (++iterator != array.values.end())
{
out << ",";
@@ -149,11 +90,12 @@ struct Renderer : boost::static_visitor<>
std::ostream &out;
};
-struct ArrayRenderer : boost::static_visitor<>
+struct ArrayRenderer : mapbox::util::static_visitor<>
{
- ArrayRenderer(std::vector<char> &_out) : out(_out) {}
+ explicit ArrayRenderer(std::vector<char> &_out) : out(_out) {}
- void operator()(const String &string) const {
+ void operator()(const String &string) const
+ {
out.push_back('\"');
out.insert(out.end(), string.value.begin(), string.value.end());
out.push_back('\"');
@@ -161,7 +103,7 @@ struct ArrayRenderer : boost::static_visitor<>
void operator()(const Number &number) const
{
- const std::string number_string = FixedDoubleToString(number.value);
+ const std::string number_string = cast::double_fixed_to_string(number.value);
out.insert(out.end(), number_string.begin(), number_string.end());
}
@@ -176,7 +118,7 @@ struct ArrayRenderer : boost::static_visitor<>
out.push_back('\"');
out.push_back(':');
- boost::apply_visitor(ArrayRenderer(out), (*iterator).second);
+ mapbox::util::apply_visitor(ArrayRenderer(out), (*iterator).second);
if (++iterator != object.values.end())
{
out.push_back(',');
@@ -192,7 +134,7 @@ struct ArrayRenderer : boost::static_visitor<>
iterator = array.values.begin();
while (iterator != array.values.end())
{
- boost::apply_visitor(ArrayRenderer(out), *iterator);
+ mapbox::util::apply_visitor(ArrayRenderer(out), *iterator);
if (++iterator != array.values.end())
{
out.push_back(',');
@@ -201,17 +143,20 @@ struct ArrayRenderer : boost::static_visitor<>
out.push_back(']');
}
- void operator()(const True &) const {
+ void operator()(const True &) const
+ {
const std::string temp("true");
out.insert(out.end(), temp.begin(), temp.end());
}
- void operator()(const False &) const {
+ void operator()(const False &) const
+ {
const std::string temp("false");
out.insert(out.end(), temp.begin(), temp.end());
}
- void operator()(const Null &) const {
+ void operator()(const Null &) const
+ {
const std::string temp("null");
out.insert(out.end(), temp.begin(), temp.end());
}
@@ -223,15 +168,15 @@ struct ArrayRenderer : boost::static_visitor<>
inline void render(std::ostream &out, const Object &object)
{
Value value = object;
- boost::apply_visitor(Renderer(out), value);
+ mapbox::util::apply_visitor(Renderer(out), value);
}
inline void render(std::vector<char> &out, const Object &object)
{
Value value = object;
- boost::apply_visitor(ArrayRenderer(out), value);
+ mapbox::util::apply_visitor(ArrayRenderer(out), value);
}
} // namespace JSON
-#endif // JSON_CONTAINER_H
+#endif // JSON_RENDERER_HPP
diff --git a/Util/LuaUtil.h b/Util/lua_util.hpp
similarity index 95%
rename from Util/LuaUtil.h
rename to Util/lua_util.hpp
index 5c502c9..f367949 100644
--- a/Util/LuaUtil.h
+++ b/Util/lua_util.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
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 LUA_UTIL_H
-#define LUA_UTIL_H
+#ifndef LUA_UTIL_HPP
+#define LUA_UTIL_HPP
extern "C" {
#include <lua.h>
@@ -63,4 +63,4 @@ inline void luaAddScriptFolderToLoadPath(lua_State *lua_state, const char *file_
luaL_dostring(lua_state, lua_code.c_str());
}
-#endif // LUA_UTIL_H
+#endif // LUA_UTIL_HPP
diff --git a/Extractor/ScriptingEnvironment.h b/Util/make_unique.hpp
similarity index 64%
copy from Extractor/ScriptingEnvironment.h
copy to Util/make_unique.hpp
index 2b1fffe..07786fe 100644
--- a/Extractor/ScriptingEnvironment.h
+++ b/Util/make_unique.hpp
@@ -25,28 +25,33 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SCRIPTINGENVIRONMENT_H_
-#define SCRIPTINGENVIRONMENT_H_
+#ifndef MAKE_UNIQUE_H_
+#define MAKE_UNIQUE_H_
-#include <string>
+#include <cstdlib>
#include <memory>
-#include <tbb/enumerable_thread_specific.h>
+#include <type_traits>
-struct lua_State;
-
-class ScriptingEnvironment
+namespace osrm
{
- public:
- ScriptingEnvironment();
- explicit ScriptingEnvironment(const char *file_name);
+// Taken from http://msdn.microsoft.com/en-us/library/dn439780.asp
+// Note, that the snippet was broken there and needed minor massaging
- lua_State *getLuaState();
+// make_unique<T>
+template <class T, class... Types> std::unique_ptr<T> make_unique(Types &&... Args)
+{
+ return (std::unique_ptr<T>(new T(std::forward<Types>(Args)...)));
+}
- private:
- void initLuaState(lua_State* lua_state);
+// make_unique<T[]>
+template <class T> std::unique_ptr<T[]> make_unique(std::size_t Size)
+{
+ return (std::unique_ptr<T>(new T[Size]()));
+}
- std::string file_name;
- tbb::enumerable_thread_specific<std::shared_ptr<lua_State>> script_contexts;
-};
+// 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;
+}
-#endif /* SCRIPTINGENVIRONMENT_H_ */
+#endif //MAKE_UNIQUE_H_
diff --git a/Include/osrm/Header.h b/Util/osrm_exception.cpp
similarity index 61%
copy from Include/osrm/Header.h
copy to Util/osrm_exception.cpp
index de0b2ab..ebdac6d 100644
--- a/Include/osrm/Header.h
+++ b/Util/osrm_exception.cpp
@@ -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,29 +25,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTTP_HEADER_H
-#define HTTP_HEADER_H
+#include "osrm_exception.hpp"
-#include <string>
-#include <algorithm>
-
-namespace http
-{
-struct Header
+namespace osrm
{
- Header& operator=(const Header& other) = default;
- Header(const std::string & name, const std::string & value) : name(name), value(value) {}
- Header(const Header && other) : name(std::move(other.name)), value(std::move(other.value)) {}
-
- void Clear()
- {
- name.clear();
- value.clear();
- }
-
- std::string name;
- std::string value;
-};
+ // 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 { }
}
-
-#endif // HTTP_HEADER_H
diff --git a/Util/OSRMException.h b/Util/osrm_exception.hpp
similarity index 67%
rename from Util/OSRMException.h
rename to Util/osrm_exception.hpp
index f4f4290..ac5044a 100644
--- a/Util/OSRMException.h
+++ b/Util/osrm_exception.hpp
@@ -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,22 +25,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef OSRM_EXCEPTION_H
-#define OSRM_EXCEPTION_H
+#ifndef OSRM_EXCEPTION_HPP
+#define OSRM_EXCEPTION_HPP
#include <exception>
#include <string>
-class OSRMException : public std::exception
+namespace osrm
+{
+class exception final : public std::exception
{
public:
- explicit OSRMException(const char *message) : message(message) {}
- explicit OSRMException(const std::string &message) : message(message) {}
- virtual ~OSRMException() throw() {}
+ explicit exception(const char *message) : message(message) {}
+ explicit exception(const std::string &message) : message(message) {}
private:
- virtual const char *what() const throw() { return message.c_str(); }
+ // This function exists to 'anchor' the class, and stop the compiler from
+ // copying vtable and RTTI info into every object file that includes
+ // this header. (Caught by -Wweak-vtables under Clang.)
+ virtual void anchor() const;
+ const char *what() const noexcept { return message.c_str(); }
const std::string message;
};
-
-#endif /* OSRM_EXCEPTION_H */
+}
+#endif /* OSRM_EXCEPTION_HPP */
diff --git a/Util/range_algorithms.hpp b/Util/range_algorithms.hpp
new file mode 100644
index 0000000..208236e
--- /dev/null
+++ b/Util/range_algorithms.hpp
@@ -0,0 +1,42 @@
+/*
+ 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/Util/simple_logger.cpp b/Util/simple_logger.cpp
new file mode 100644
index 0000000..dbbf348
--- /dev/null
+++ b/Util/simple_logger.cpp
@@ -0,0 +1,135 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "simple_logger.hpp"
+
+#include "osrm_exception.hpp"
+
+#include <boost/assert.hpp>
+
+#include <cstdio>
+
+#ifdef _MSC_VER
+#include <io.h>
+#define isatty _isatty
+#define fileno _fileno
+#else
+#include <unistd.h>
+#endif
+
+#include <ostream>
+#include <iostream>
+#include <mutex>
+
+namespace
+{
+static const char COL_RESET[] { "\x1b[0m"};
+static const char RED[] { "\x1b[31m"};
+#ifndef NDEBUG
+static const char YELLOW[] { "\x1b[33m"};
+#endif
+// static const char GREEN[] { "\x1b[32m"};
+// static const char BLUE[] { "\x1b[34m"};
+// static const char MAGENTA[] { "\x1b[35m"};
+// static const char CYAN[] { "\x1b[36m"};
+}
+
+void LogPolicy::Unmute() { m_is_mute = false; }
+
+void LogPolicy::Mute() { m_is_mute = true; }
+
+bool LogPolicy::IsMute() const { return m_is_mute; }
+
+LogPolicy &LogPolicy::GetInstance()
+{
+ static LogPolicy runningInstance;
+ return runningInstance;
+}
+
+SimpleLogger::SimpleLogger() : level(logINFO) {}
+
+std::mutex &SimpleLogger::get_mutex()
+{
+ static std::mutex mtx;
+ return mtx;
+}
+
+std::ostringstream &SimpleLogger::Write(LogLevel lvl)
+{
+ std::lock_guard<std::mutex> lock(get_mutex());
+ try
+ {
+ level = lvl;
+ os << "[";
+ switch (level)
+ {
+ case logWARNING:
+ os << "warn";
+ break;
+ case logDEBUG:
+#ifndef NDEBUG
+ 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");
+ }
+ return os;
+}
+
+SimpleLogger::~SimpleLogger()
+{
+ std::lock_guard<std::mutex> lock(get_mutex());
+ if (!LogPolicy::GetInstance().IsMute())
+ {
+ const bool is_terminal = static_cast<bool>(isatty(fileno(stdout)));
+ switch (level)
+ {
+ case logWARNING:
+ std::cerr << (is_terminal ? RED : "") << os.str() << (is_terminal ? COL_RESET : "")
+ << std::endl;
+ break;
+ case logDEBUG:
+#ifndef NDEBUG
+ std::cout << (is_terminal ? YELLOW : "") << os.str() << (is_terminal ? COL_RESET : "")
+ << std::endl;
+#endif
+ break;
+ default: //logINFO:
+ std::cout << os.str() << (is_terminal ? COL_RESET : "") << std::endl;
+ break;
+ }
+ }
+}
diff --git a/Server/RequestHandler.h b/Util/simple_logger.hpp
similarity index 67%
copy from Server/RequestHandler.h
copy to Util/simple_logger.hpp
index 462c34f..077fa2e 100644
--- a/Server/RequestHandler.h
+++ b/Util/simple_logger.hpp
@@ -25,35 +25,50 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef REQUEST_HANDLER_H
-#define REQUEST_HANDLER_H
+#ifndef SIMPLE_LOGGER_HPP
+#define SIMPLE_LOGGER_HPP
-#include <string>
+#include <atomic>
+#include <mutex>
+#include <sstream>
-template <typename Iterator, class HandlerT> struct APIGrammar;
-struct RouteParameters;
-class OSRM;
-
-namespace http
+enum LogLevel
{
-class Reply;
-struct Request;
-}
+ logINFO,
+ logWARNING,
+ logDEBUG
+};
-class RequestHandler
+class LogPolicy
{
-
public:
- typedef APIGrammar<std::string::iterator, RouteParameters> APIGrammarParser;
+ void Unmute();
+
+ void Mute();
+
+ bool IsMute() const;
+
+ static LogPolicy &GetInstance();
- RequestHandler();
- RequestHandler(const RequestHandler &) = delete;
+ LogPolicy(const LogPolicy &) = delete;
+
+ private:
+ LogPolicy() : m_is_mute(true) {}
+ std::atomic<bool> m_is_mute;
+};
+
+class SimpleLogger
+{
+ public:
+ SimpleLogger();
- void handle_request(const http::Request &req, http::Reply &rep);
- void RegisterRoutingMachine(OSRM *osrm);
+ virtual ~SimpleLogger();
+ std::mutex &get_mutex();
+ std::ostringstream &Write(LogLevel l = logINFO);
private:
- OSRM *routing_machine;
+ std::ostringstream os;
+ LogLevel level;
};
-#endif // REQUEST_HANDLER_H
+#endif /* SIMPLE_LOGGER_HPP */
diff --git a/Util/StdHashExtensions.h b/Util/std_hash.hpp
similarity index 86%
rename from Util/StdHashExtensions.h
rename to Util/std_hash.hpp
index 50cd337..59c4ad9 100644
--- a/Util/StdHashExtensions.h
+++ b/Util/std_hash.hpp
@@ -25,39 +25,43 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef STD_HASH_EXTENSIONS_H
-#define STD_HASH_EXTENSIONS_H
+#ifndef STD_HASH_HPP
+#define STD_HASH_HPP
#include <functional>
// this is largely inspired by boost's hash combine as can be found in
// "The C++ Standard Library" 2nd Edition. Nicolai M. Josuttis. 2012.
+
+namespace {
+
template<typename T>
-inline void hash_combine(std::size_t &seed, const T& val)
+void hash_combine(std::size_t &seed, const T& val)
{
seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
template<typename T>
-inline void hash_val(std::size_t &seed, const T& val)
+void hash_val(std::size_t &seed, const T& val)
{
hash_combine(seed, val);
}
template<typename T, typename ... Types>
-inline void hash_val(std::size_t &seed, const T& val, const Types& ... args)
+void hash_val(std::size_t &seed, const T& val, const Types& ... args)
{
hash_combine(seed, val);
hash_val(seed, args ...);
}
template<typename ... Types>
-inline std::size_t hash_val( const Types&... args)
+std::size_t hash_val(const Types&... args)
{
std::size_t seed = 0;
hash_val(seed, args...);
return seed;
}
+}
namespace std
{
@@ -70,4 +74,4 @@ template <typename T1, typename T2> struct hash<std::pair<T1, T2>>
};
}
-#endif // STD_HASH_EXTENSIONS_H
+#endif // STD_HASH_HPP
diff --git a/Util/string_util.hpp b/Util/string_util.hpp
new file mode 100644
index 0000000..08af554
--- /dev/null
+++ b/Util/string_util.hpp
@@ -0,0 +1,150 @@
+/*
+
+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 STRING_UTIL_HPP
+#define STRING_UTIL_HPP
+
+#include <boost/algorithm/string.hpp>
+
+#include <cctype>
+
+#include <random>
+#include <string>
+#include <vector>
+
+// precision: position after decimal point
+// length: maximum number of digits including comma and decimals
+// work with negative values to prevent overflowing when taking -value
+template <int length, int precision> static inline char *printInt(char *buffer, int value)
+{
+ bool minus = true;
+ if (value > 0)
+ {
+ minus = false;
+ value = -value;
+ }
+ buffer += length - 1;
+ for (int i = 0; i < precision; i++)
+ {
+ *buffer = '0' - (value % 10);
+ value /= 10;
+ buffer--;
+ }
+ *buffer = '.';
+ buffer--;
+ for (int i = precision + 1; i < length; i++)
+ {
+ *buffer = '0' - (value % 10);
+ value /= 10;
+ if (value == 0)
+ break;
+ buffer--;
+ }
+ if (minus)
+ {
+ buffer--;
+ *buffer = '-';
+ }
+ return buffer;
+}
+
+inline void replaceAll(std::string &s, const std::string &sub, const std::string &other)
+{
+ boost::replace_all(s, sub, other);
+}
+
+inline std::string EscapeJSONString(const std::string &input)
+{
+ std::string output;
+ output.reserve(input.size());
+ for (auto iter = input.begin(); iter != input.end(); ++iter)
+ {
+ switch (iter[0])
+ {
+ case '\\':
+ output += "\\\\";
+ break;
+ case '"':
+ output += "\\\"";
+ break;
+ case '/':
+ output += "\\/";
+ break;
+ case '\b':
+ output += "\\b";
+ break;
+ case '\f':
+ output += "\\f";
+ break;
+ case '\n':
+ output += "\\n";
+ break;
+ case '\r':
+ output += "\\r";
+ break;
+ case '\t':
+ output += "\\t";
+ break;
+ default:
+ output += *iter;
+ 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();
+ output.resize(input.size() + 1);
+ std::size_t decoded_length = 0;
+ for (decoded_length = 0; src_iter != input.end(); ++decoded_length)
+ {
+ if (src_iter[0] == '%' && src_iter[1] && src_iter[2] && isxdigit(src_iter[1]) &&
+ isxdigit(src_iter[2]))
+ {
+ std::string::value_type a = src_iter[1];
+ std::string::value_type b = src_iter[2];
+ a -= src_iter[1] < 58 ? 48 : src_iter[1] < 71 ? 55 : 87;
+ b -= src_iter[2] < 58 ? 48 : src_iter[2] < 71 ? 55 : 87;
+ output[decoded_length] = 16 * a + b;
+ src_iter += 3;
+ continue;
+ }
+ output[decoded_length] = *src_iter++;
+ }
+ output.resize(decoded_length);
+ return decoded_length;
+}
+
+inline std::size_t URIDecodeInPlace(std::string &URI) { return URIDecode(URI, URI); }
+
+#endif // STRING_UTIL_HPP
diff --git a/Util/timing_util.hpp b/Util/timing_util.hpp
new file mode 100644
index 0000000..1bbea47
--- /dev/null
+++ b/Util/timing_util.hpp
@@ -0,0 +1,80 @@
+/*
+
+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 TIMING_UTIL_HPP
+#define TIMING_UTIL_HPP
+
+#include <atomic>
+#include <chrono>
+#include <cstdint>
+#include <mutex>
+#include <unordered_map>
+
+struct GlobalTimer
+{
+ GlobalTimer() : time(0) {}
+ std::atomic<uint64_t> time;
+};
+
+class GlobalTimerFactory
+{
+public:
+ static GlobalTimerFactory& get()
+ {
+ static GlobalTimerFactory instance;
+ return instance;
+ }
+
+ GlobalTimer& getGlobalTimer(const std::string& name)
+ {
+ std::lock_guard<std::mutex> lock(map_mutex);
+ return timer_map[name];
+ }
+
+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_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_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 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()
+
+#endif // TIMING_UTIL_HPP
diff --git a/Util/xml_renderer.hpp b/Util/xml_renderer.hpp
new file mode 100644
index 0000000..46e0501
--- /dev/null
+++ b/Util/xml_renderer.hpp
@@ -0,0 +1,140 @@
+/*
+
+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 XML_RENDERER_HPP
+#define XML_RENDERER_HPP
+
+#include "../data_structures/json_container.hpp"
+#include "cast.hpp"
+
+namespace JSON {
+
+struct XMLToArrayRenderer : mapbox::util::static_visitor<>
+{
+ explicit XMLToArrayRenderer(std::vector<char> &_out) : out(_out) {}
+
+ void operator()(const String &string) const
+ {
+ out.push_back('\"');
+ out.insert(out.end(), string.value.begin(), string.value.end());
+ out.push_back('\"');
+ }
+
+ void operator()(const Number &number) const
+ {
+ const std::string number_string = cast::double_fixed_to_string(number.value);
+ out.insert(out.end(), number_string.begin(), number_string.end());
+ }
+
+ void operator()(const Object &object) const
+ {
+ auto iterator = object.values.begin();
+ while (iterator != object.values.end())
+ {
+ if (iterator->first.at(0) != '_')
+ {
+ out.push_back('<');
+ out.insert(out.end(), (*iterator).first.begin(), (*iterator).first.end());
+ }
+ else
+ {
+ 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) != '_')
+ {
+ out.push_back('/');
+ out.push_back('>');
+ }
+ ++iterator;
+ }
+ }
+
+ void operator()(const Array &array) const
+ {
+ std::vector<Value>::const_iterator iterator;
+ iterator = array.values.begin();
+ while (iterator != array.values.end())
+ {
+ mapbox::util::apply_visitor(XMLToArrayRenderer(out), *iterator);
+ ++iterator;
+ }
+ }
+
+ void operator()(const True &) const
+ {
+ const std::string temp("true");
+ out.insert(out.end(), temp.begin(), temp.end());
+ }
+
+ void operator()(const False &) const
+ {
+ const std::string temp("false");
+ out.insert(out.end(), temp.begin(), temp.end());
+ }
+
+ void operator()(const Null &) const
+ {
+ const std::string temp("null");
+ out.insert(out.end(), temp.begin(), temp.end());
+ }
+
+ private:
+ std::vector<char> &out;
+};
+
+template<class JSONObject>
+inline void xml_render(std::vector<char> &out, const JSONObject &object)
+{
+ Value value = object;
+ mapbox::util::apply_visitor(XMLToArrayRenderer(out), value);
+}
+
+template<class JSONObject>
+inline void gpx_render(std::vector<char> &out, const JSONObject &object)
+{
+ // add header
+
+ const std::string header {"<?xml version=\"1.0\" encoding=\"UTF-8\"?><gpx creator=\"OSRM Routing Engine\""
+ " version=\"1.1\" xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xsi=\"http:"
+ "//www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topogr"
+ "afix.com/GPX/1/1 gpx.xsd\"><metadata><copyright author=\"Project OSRM\"><lice"
+ "nse>Data (c) OpenStreetMap contributors (ODbL)</license></copyright></metadat"
+ "a><rte>"};
+ out.insert(out.end(), header.begin(), header.end());
+
+ xml_render(out, object);
+
+ const std::string footer {"</rte></gpx>"};
+ out.insert(out.end(), footer.begin(), footer.end());
+}
+} // namespace JSON
+
+#endif // XML_RENDERER_HPP
diff --git a/algorithms/bfs_components.hpp b/algorithms/bfs_components.hpp
new file mode 100644
index 0000000..57be635
--- /dev/null
+++ b/algorithms/bfs_components.hpp
@@ -0,0 +1,174 @@
+/*
+
+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 BFS_COMPONENTS_HPP_
+#define BFS_COMPONENTS_HPP_
+
+#include "../typedefs.h"
+#include "../data_structures/restriction_map.hpp"
+
+#include <queue>
+#include <unordered_set>
+
+// Explores the components of the given graph while respecting turn restrictions
+// and barriers.
+template <typename GraphT> class BFSComponentExplorer
+{
+ public:
+ BFSComponentExplorer(const GraphT &dynamic_graph,
+ const RestrictionMap &restrictions,
+ const std::unordered_set<NodeID> &barrier_nodes)
+ : m_graph(dynamic_graph), m_restriction_map(restrictions), m_barrier_nodes(barrier_nodes)
+ {
+ BOOST_ASSERT(m_graph.GetNumberOfNodes() > 0);
+ }
+
+ /*!
+ * Returns the size of the component that the node belongs to.
+ */
+ unsigned int GetComponentSize(const NodeID node) const
+ {
+ BOOST_ASSERT(node < m_component_index_list.size());
+
+ return m_component_index_size[m_component_index_list[node]];
+ }
+
+ unsigned int GetNumberOfComponents() { return m_component_index_size.size(); }
+
+ /*!
+ * Computes the component sizes.
+ */
+ void run()
+ {
+ std::queue<std::pair<NodeID, NodeID>> bfs_queue;
+ unsigned current_component = 0;
+
+ BOOST_ASSERT(m_component_index_list.empty());
+ BOOST_ASSERT(m_component_index_size.empty());
+
+ unsigned num_nodes = m_graph.GetNumberOfNodes();
+
+ m_component_index_list.resize(num_nodes, std::numeric_limits<unsigned>::max());
+
+ BOOST_ASSERT(num_nodes > 0);
+
+ // put unexplorered node with parent pointer into queue
+ for (NodeID node = 0; node < num_nodes; ++node)
+ {
+ if (std::numeric_limits<unsigned>::max() == m_component_index_list[node])
+ {
+ unsigned size = ExploreComponent(bfs_queue, node, current_component);
+
+ // push size into vector
+ m_component_index_size.emplace_back(size);
+ ++current_component;
+ }
+ }
+ }
+
+ private:
+ /*!
+ * Explores the current component that starts at node using BFS.
+ */
+ unsigned ExploreComponent(std::queue<std::pair<NodeID, NodeID>> &bfs_queue,
+ NodeID node,
+ unsigned current_component)
+ {
+ /*
+ Graphical representation of variables:
+
+ u v w
+ *---------->*---------->*
+ e2
+ */
+
+ bfs_queue.emplace(node, node);
+ // mark node as read
+ m_component_index_list[node] = current_component;
+
+ unsigned current_component_size = 1;
+
+ while (!bfs_queue.empty())
+ {
+ // fetch element from BFS queue
+ std::pair<NodeID, NodeID> current_queue_item = bfs_queue.front();
+ bfs_queue.pop();
+
+ const NodeID v = current_queue_item.first; // current node
+ const NodeID u = current_queue_item.second; // parent
+ // increment size counter of current component
+ ++current_component_size;
+ if (m_barrier_nodes.find(v) != m_barrier_nodes.end())
+ {
+ continue;
+ }
+ const NodeID to_node_of_only_restriction =
+ m_restriction_map.CheckForEmanatingIsOnlyTurn(u, v);
+
+ for (auto e2 : m_graph.GetAdjacentEdgeRange(v))
+ {
+ const NodeID w = m_graph.GetTarget(e2);
+
+ if (to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
+ w != to_node_of_only_restriction)
+ {
+ // At an only_-restriction but not at the right turn
+ continue;
+ }
+
+ if (u != w)
+ {
+ // only add an edge if turn is not a U-turn except
+ // when it is at the end of a dead-end street.
+ if (!m_restriction_map.CheckIfTurnIsRestricted(u, v, w))
+ {
+ // only add an edge if turn is not prohibited
+ if (std::numeric_limits<unsigned>::max() == m_component_index_list[w])
+ {
+ // insert next (node, parent) only if w has
+ // not yet been explored
+ // mark node as read
+ m_component_index_list[w] = current_component;
+ bfs_queue.emplace(w, v);
+ }
+ }
+ }
+ }
+ }
+
+ return current_component_size;
+ }
+
+ std::vector<unsigned> m_component_index_list;
+ std::vector<NodeID> m_component_index_size;
+
+ const GraphT &m_graph;
+ const RestrictionMap &m_restriction_map;
+ const std::unordered_set<NodeID> &m_barrier_nodes;
+};
+
+#endif // BFS_COMPONENTS_HPP_
diff --git a/Algorithms/IteratorBasedCRC32.h b/algorithms/crc32_processor.hpp
similarity index 64%
rename from Algorithms/IteratorBasedCRC32.h
rename to algorithms/crc32_processor.hpp
index 84a404a..a68514d 100644
--- a/Algorithms/IteratorBasedCRC32.h
+++ b/algorithms/crc32_processor.hpp
@@ -28,44 +28,59 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ITERATOR_BASED_CRC32_H
#define ITERATOR_BASED_CRC32_H
-#include "../Util/SimpleLogger.h"
-
-#include <iostream>
-
#if defined(__x86_64__) && !defined(__MINGW64__)
#include <cpuid.h>
-#else
+#endif
+
#include <boost/crc.hpp> // for boost::crc_32_type
-inline void __get_cpuid(int param, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
-{
- *ecx = 0;
-}
-#endif
+#include <iterator>
-template <class ContainerT> class IteratorbasedCRC32
+class IteratorbasedCRC32
{
- private:
- typedef typename ContainerT::iterator IteratorType;
- unsigned crc;
+ public:
+ bool using_hardware() const { return use_hardware_implementation; }
- bool use_SSE42_CRC_function;
+ IteratorbasedCRC32() : crc(0) { use_hardware_implementation = detect_hardware_support(); }
-#if !defined(__x86_64__)
- boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> CRC32_processor;
-#endif
- unsigned SoftwareBasedCRC32(char *str, unsigned len)
+ template <class Iterator> unsigned operator()(Iterator iter, const Iterator end)
{
-#if !defined(__x86_64__)
- CRC32_processor.process_bytes(str, len);
- return CRC32_processor.checksum();
-#else
- return 0;
-#endif
+ unsigned crc = 0;
+ while (iter != end)
+ {
+ using value_type = typename std::iterator_traits<Iterator>::value_type;
+ char *data = (char *)(&(*iter));
+
+ if (use_hardware_implementation)
+ {
+ crc = compute_in_hardware(data, sizeof(value_type));
+ }
+ else
+ {
+ crc = compute_in_software(data, sizeof(value_type));
+ }
+ ++iter;
+ }
+ return crc;
+ }
+
+ private:
+ bool detect_hardware_support() const
+ {
+ static const int sse42_bit = 0x00100000;
+ const unsigned ecx = cpuid();
+ const bool sse42_found = (ecx & sse42_bit) != 0;
+ return sse42_found;
+ }
+
+ unsigned compute_in_software(char *str, unsigned len)
+ {
+ crc_processor.process_bytes(str, len);
+ return crc_processor.checksum();
}
// adapted from http://byteworm.com/2010/10/13/crc32/
- unsigned SSE42BasedCRC32(char *str, unsigned len)
+ unsigned compute_in_hardware(char *str, unsigned len)
{
#if defined(__x86_64__)
unsigned q = len / sizeof(unsigned);
@@ -101,44 +116,31 @@ template <class ContainerT> class IteratorbasedCRC32
return ecx;
}
- bool DetectNativeCRC32Support()
+#if defined(__MINGW64__) || defined(_MSC_VER)
+ inline void
+ __get_cpuid(int param, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx) const
{
- static const int SSE42_BIT = 0x00100000;
- const unsigned ecx = cpuid();
- const bool has_SSE42 = (ecx & SSE42_BIT) != 0;
- if (has_SSE42)
- {
- SimpleLogger().Write() << "using hardware based CRC32 computation";
- }
- else
- {
- SimpleLogger().Write() << "using software based CRC32 computation";
- }
- return has_SSE42;
+ *ecx = 0;
}
+#endif
- public:
- IteratorbasedCRC32() : crc(0) { use_SSE42_CRC_function = DetectNativeCRC32Support(); }
+ boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> crc_processor;
+ unsigned crc;
+ bool use_hardware_implementation;
+};
- unsigned operator()(IteratorType iter, const IteratorType end)
+struct RangebasedCRC32
+{
+ template<typename Iteratable>
+ unsigned operator()(const Iteratable &iterable)
{
- unsigned crc = 0;
- while (iter != end)
- {
- char *data = reinterpret_cast<char *>(&(*iter));
-
- if (use_SSE42_CRC_function)
- {
- crc = SSE42BasedCRC32(data, sizeof(typename ContainerT::value_type));
- }
- else
- {
- crc = SoftwareBasedCRC32(data, sizeof(typename ContainerT::value_type));
- }
- ++iter;
- }
- return crc;
+ return crc32(std::begin(iterable), std::end(iterable));
}
+
+ bool using_hardware() const { return crc32.using_hardware(); }
+
+ private:
+ IteratorbasedCRC32 crc32;
};
#endif /* ITERATOR_BASED_CRC32_H */
diff --git a/Algorithms/DouglasPeucker.cpp b/algorithms/douglas_peucker.cpp
similarity index 60%
rename from Algorithms/DouglasPeucker.cpp
rename to algorithms/douglas_peucker.cpp
index 2e647fc..362f0a5 100644
--- a/Algorithms/DouglasPeucker.cpp
+++ b/algorithms/douglas_peucker.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,11 +25,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <osrm/Coordinate.h>
+#include "douglas_peucker.hpp"
+
+#include "../data_structures/segment_information.hpp"
+#include "../Util/integer_range.hpp"
-#include "DouglasPeucker.h"
-#include "../DataStructures/SegmentInformation.h"
-#include "../Util/SimpleLogger.h"
+#include <osrm/Coordinate.h>
#include <boost/assert.hpp>
@@ -37,6 +38,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <algorithm>
+namespace
+{
struct CoordinatePairCalculator
{
CoordinatePairCalculator() = delete;
@@ -78,62 +81,42 @@ struct CoordinatePairCalculator
float second_lat;
float second_lon;
};
-
-DouglasPeucker::DouglasPeucker()
- : douglas_peucker_thresholds({512440, // z0
- 256720, // z1
- 122560, // z2
- 56780, // z3
- 28800, // z4
- 14400, // z5
- 7200, // z6
- 3200, // z7
- 2400, // z8
- 1000, // z9
- 600, // z10
- 120, // z11
- 60, // z12
- 45, // z13
- 36, // z14
- 20, // z15
- 8, // z16
- 6, // z17
- 4 // z18
- })
-{
}
void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level)
{
- // check if input data is invalid
- BOOST_ASSERT_MSG(!input_geometry.empty(), "geometry invalid");
+ Run(std::begin(input_geometry), std::end(input_geometry), zoom_level);
+}
- if (input_geometry.size() < 2)
+void DouglasPeucker::Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level)
+{
+ unsigned size = std::distance(begin, end);
+ if (size < 2)
{
return;
}
- input_geometry.front().necessary = true;
- input_geometry.back().necessary = true;
+ begin->necessary = true;
+ std::prev(end)->necessary = true;
{
- BOOST_ASSERT_MSG(zoom_level < 19, "unsupported zoom level");
- unsigned left_border = 0;
- unsigned right_border = 1;
+ BOOST_ASSERT_MSG(zoom_level < DOUGLAS_PEUCKER_THRESHOLDS.size(), "unsupported zoom level");
+ RandomAccessIt left_border = begin;
+ RandomAccessIt right_border = std::next(begin);
// Sweep over array and identify those ranges that need to be checked
do
{
// traverse list until new border element found
- if (input_geometry[right_border].necessary)
+ if (right_border->necessary)
{
// sanity checks
- BOOST_ASSERT(input_geometry[left_border].necessary);
- BOOST_ASSERT(input_geometry[right_border].necessary);
+ BOOST_ASSERT(left_border->necessary);
+ BOOST_ASSERT(right_border->necessary);
recursion_stack.emplace(left_border, right_border);
left_border = right_border;
}
++right_border;
- } while (right_border < input_geometry.size());
+ } while (right_border != end);
}
// mark locations as 'necessary' by divide-and-conquer
@@ -143,40 +126,40 @@ void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const
const GeometryRange pair = recursion_stack.top();
recursion_stack.pop();
// sanity checks
- BOOST_ASSERT_MSG(input_geometry[pair.first].necessary, "left border mus be necessary");
- BOOST_ASSERT_MSG(input_geometry[pair.second].necessary, "right border must be necessary");
- BOOST_ASSERT_MSG(pair.second < input_geometry.size(), "right border outside of geometry");
- BOOST_ASSERT_MSG(pair.first < pair.second, "left border on the wrong side");
+ BOOST_ASSERT_MSG(pair.first->necessary, "left border must be necessary");
+ BOOST_ASSERT_MSG(pair.second->necessary, "right border must be necessary");
+ BOOST_ASSERT_MSG(std::distance(pair.second, end) > 0, "right border outside of geometry");
+ BOOST_ASSERT_MSG(std::distance(pair.first, pair.second) >= 0,
+ "left border on the wrong side");
int max_int_distance = 0;
- unsigned farthest_entry_index = pair.second;
- const CoordinatePairCalculator DistCalc(input_geometry[pair.first].location,
- input_geometry[pair.second].location);
+ auto farthest_entry_it = pair.second;
+ const CoordinatePairCalculator dist_calc(pair.first->location, pair.second->location);
// sweep over range to find the maximum
- for (unsigned i = pair.first + 1; i < pair.second; ++i)
+ for (auto it = std::next(pair.first); it != pair.second; ++it)
{
- const int distance = DistCalc(input_geometry[i].location);
+ const int distance = dist_calc(it->location);
// found new feasible maximum?
- if (distance > max_int_distance && distance > douglas_peucker_thresholds[zoom_level])
+ if (distance > max_int_distance && distance > DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
{
- farthest_entry_index = i;
+ farthest_entry_it = it;
max_int_distance = distance;
}
}
// check if maximum violates a zoom level dependent threshold
- if (max_int_distance > douglas_peucker_thresholds[zoom_level])
+ if (max_int_distance > DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
{
// mark idx as necessary
- input_geometry[farthest_entry_index].necessary = true;
- if (1 < (farthest_entry_index - pair.first))
+ farthest_entry_it->necessary = true;
+ if (1 < std::distance(pair.first, farthest_entry_it))
{
- recursion_stack.emplace(pair.first, farthest_entry_index);
+ recursion_stack.emplace(pair.first, farthest_entry_it);
}
- if (1 < (pair.second - farthest_entry_index))
+ if (1 < std::distance(farthest_entry_it, pair.second))
{
- recursion_stack.emplace(farthest_entry_index, pair.second);
+ recursion_stack.emplace(farthest_entry_it, pair.second);
}
}
}
diff --git a/Algorithms/DouglasPeucker.h b/algorithms/douglas_peucker.hpp
similarity index 71%
rename from Algorithms/DouglasPeucker.h
rename to algorithms/douglas_peucker.hpp
index d0f295c..417e80a 100644
--- a/Algorithms/DouglasPeucker.h
+++ b/algorithms/douglas_peucker.hpp
@@ -25,12 +25,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DOUGLASPEUCKER_H_
-#define DOUGLASPEUCKER_H_
+#ifndef DOUGLAS_PEUCKER_HPP_
+#define DOUGLAS_PEUCKER_HPP_
#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.
@@ -41,18 +41,40 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct SegmentInformation;
+static const std::array<int, 19> DOUGLAS_PEUCKER_THRESHOLDS {{
+ 512440, // z0
+ 256720, // z1
+ 122560, // z2
+ 56780, // z3
+ 28800, // z4
+ 14400, // z5
+ 7200, // z6
+ 3200, // z7
+ 2400, // z8
+ 1000, // z9
+ 600, // z10
+ 120, // z11
+ 60, // z12
+ 45, // z13
+ 36, // z14
+ 20, // z15
+ 8, // z16
+ 6, // z17
+ 4 // z18
+}};
+
class DouglasPeucker
{
- private:
- std::vector<int> douglas_peucker_thresholds;
+ public:
+ using RandomAccessIt = std::vector<SegmentInformation>::iterator;
- typedef std::pair<unsigned, unsigned> GeometryRange;
+ using GeometryRange = std::pair<RandomAccessIt, RandomAccessIt>;
// Stack to simulate the recursion
std::stack<GeometryRange> recursion_stack;
public:
- DouglasPeucker();
+ void Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level);
void Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level);
};
-#endif /* DOUGLASPEUCKER_H_ */
+#endif /* DOUGLAS_PEUCKER_HPP_ */
diff --git a/algorithms/object_encoder.hpp b/algorithms/object_encoder.hpp
new file mode 100644
index 0000000..af6e0d9
--- /dev/null
+++ b/algorithms/object_encoder.hpp
@@ -0,0 +1,94 @@
+/*
+
+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 OBJECT_ENCODER_HPP
+#define OBJECT_ENCODER_HPP
+
+#include "../Util/string_util.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/archive/iterators/base64_from_binary.hpp>
+#include <boost/archive/iterators/binary_from_base64.hpp>
+#include <boost/archive/iterators/transform_width.hpp>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+struct ObjectEncoder
+{
+ using base64_t = boost::archive::iterators::base64_from_binary<
+ boost::archive::iterators::transform_width<const char *, 6, 8>>;
+
+ using binary_t = boost::archive::iterators::transform_width<
+ boost::archive::iterators::binary_from_base64<std::string::const_iterator>,
+ 8,
+ 6>;
+
+ template <class ObjectT>
+ static void EncodeToBase64(const ObjectT &object, std::string &encoded)
+ {
+ const char *char_ptr_to_object = (const char *)&object;
+ std::vector<unsigned char> data(sizeof(object));
+ std::copy(char_ptr_to_object, char_ptr_to_object + sizeof(ObjectT), data.begin());
+
+ unsigned char number_of_padded_chars = 0; // is in {0,1,2};
+ while (data.size() % 3 != 0)
+ {
+ ++number_of_padded_chars;
+ data.push_back(0x00);
+ }
+
+ BOOST_ASSERT_MSG(0 == data.size() % 3, "base64 input data size is not a multiple of 3!");
+ encoded.resize(sizeof(ObjectT));
+ encoded.assign(base64_t(&data[0]),
+ base64_t(&data[0] + (data.size() - number_of_padded_chars)));
+ replaceAll(encoded, "+", "-");
+ replaceAll(encoded, "/", "_");
+ }
+
+ template <class ObjectT>
+ static void DecodeFromBase64(const std::string &input, ObjectT &object)
+ {
+ try
+ {
+ std::string encoded(input);
+ // replace "-" with "+" and "_" with "/"
+ replaceAll(encoded, "-", "+");
+ replaceAll(encoded, "_", "/");
+
+ std::copy(binary_t(encoded.begin()),
+ binary_t(encoded.begin() + encoded.length() - 1),
+ (char *)&object);
+ }
+ catch (...)
+ {
+ }
+ }
+};
+
+#endif /* OBJECT_ENCODER_HPP */
diff --git a/Algorithms/PolylineCompressor.cpp b/algorithms/polyline_compressor.cpp
similarity index 51%
rename from Algorithms/PolylineCompressor.cpp
rename to algorithms/polyline_compressor.cpp
index a34f8c7..2f2972b 100644
--- a/Algorithms/PolylineCompressor.cpp
+++ b/algorithms/polyline_compressor.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
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.
*/
-#include "PolylineCompressor.h"
-#include "../DataStructures/SegmentInformation.h"
+#include "polyline_compressor.hpp"
+#include "../data_structures/segment_information.hpp"
#include <osrm/Coordinate.h>
-void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output)
- const
+std::string PolylineCompressor::encode_vector(std::vector<int> &numbers) const
{
- const unsigned end = static_cast<unsigned>(numbers.size());
- for (unsigned i = 0; i < end; ++i)
+ std::string output;
+ const auto end = numbers.size();
+ for (std::size_t i = 0; i < end; ++i)
{
numbers[i] <<= 1;
if (numbers[i] < 0)
@@ -44,12 +44,14 @@ void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std
}
for (const int number : numbers)
{
- encodeNumber(number, output);
+ output += encode_number(number);
}
+ return output;
}
-void PolylineCompressor::encodeNumber(int number_to_encode, std::string &output) const
+std::string PolylineCompressor::encode_number(int number_to_encode) const
{
+ std::string output;
while (number_to_encode >= 0x20)
{
const int next_value = (0x20 | (number_to_encode & 0x1f)) + 63;
@@ -67,52 +69,30 @@ void PolylineCompressor::encodeNumber(int number_to_encode, std::string &output)
{
output += static_cast<char>(number_to_encode);
}
+ return output;
}
-JSON::String PolylineCompressor::printEncodedString(const std::vector<SegmentInformation> &polyline)
- const
+std::string
+PolylineCompressor::get_encoded_string(const std::vector<SegmentInformation> &polyline) const
{
- std::string output;
- std::vector<int> delta_numbers;
- if (!polyline.empty())
+ if (polyline.empty())
{
- FixedPointCoordinate last_coordinate = polyline[0].location;
- delta_numbers.emplace_back(last_coordinate.lat);
- delta_numbers.emplace_back(last_coordinate.lon);
- // iterate after skipping the first, already handled, segment
- for (auto it = ++polyline.cbegin(); it != polyline.cend(); ++it)
- {
- const auto &segment = *it;
- if (segment.necessary)
- {
- int lat_diff = segment.location.lat - last_coordinate.lat;
- int lon_diff = segment.location.lon - last_coordinate.lon;
- delta_numbers.emplace_back(lat_diff);
- delta_numbers.emplace_back(lon_diff);
- last_coordinate = segment.location;
- }
- }
- encodeVectorSignedNumber(delta_numbers, output);
+ return {};
}
- JSON::String return_value(output);
- return return_value;
-}
-JSON::Array
-PolylineCompressor::printUnencodedString(const std::vector<SegmentInformation> &polyline) const
-{
- JSON::Array json_geometry_array;
+ std::vector<int> delta_numbers;
+ delta_numbers.reserve((polyline.size() - 1) * 2);
+ FixedPointCoordinate previous_coordinate = {0, 0};
for (const auto &segment : polyline)
{
if (segment.necessary)
{
- std::string tmp, output;
- FixedPointCoordinate::convertInternalLatLonToString(segment.location.lat, tmp);
- output += (tmp + ",");
- FixedPointCoordinate::convertInternalLatLonToString(segment.location.lon, tmp);
- output += tmp;
- json_geometry_array.values.push_back(output);
+ const int lat_diff = segment.location.lat - previous_coordinate.lat;
+ const int lon_diff = segment.location.lon - previous_coordinate.lon;
+ delta_numbers.emplace_back(lat_diff);
+ delta_numbers.emplace_back(lon_diff);
+ previous_coordinate = segment.location;
}
}
- return json_geometry_array;
+ return encode_vector(delta_numbers);
}
diff --git a/Algorithms/PolylineCompressor.h b/algorithms/polyline_compressor.hpp
similarity index 79%
copy from Algorithms/PolylineCompressor.h
copy to algorithms/polyline_compressor.hpp
index 5472bd8..8bff4a0 100644
--- a/Algorithms/PolylineCompressor.h
+++ b/algorithms/polyline_compressor.hpp
@@ -30,22 +30,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct SegmentInformation;
-#include "../DataStructures/JSONContainer.h"
-
#include <string>
#include <vector>
class PolylineCompressor
{
private:
- void encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output) const;
+ std::string encode_vector(std::vector<int> &numbers) const;
- void encodeNumber(int number_to_encode, std::string &output) const;
+ std::string encode_number(const int number_to_encode) const;
public:
- JSON::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
-
- JSON::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
+ std::string get_encoded_string(const std::vector<SegmentInformation> &polyline) const;
};
#endif /* POLYLINECOMPRESSOR_H_ */
diff --git a/DataStructures/ImportNode.cpp b/algorithms/polyline_formatter.cpp
similarity index 59%
copy from DataStructures/ImportNode.cpp
copy to algorithms/polyline_formatter.cpp
index 8975d40..d72496a 100644
--- a/DataStructures/ImportNode.cpp
+++ b/algorithms/polyline_formatter.cpp
@@ -25,40 +25,32 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "ImportNode.h"
+#include "polyline_formatter.hpp"
-#include <limits>
+#include "polyline_compressor.hpp"
+#include "../data_structures/segment_information.hpp"
-ExternalMemoryNode::ExternalMemoryNode(
- int lat, int lon, unsigned int node_id, bool bollard, bool traffic_light)
- : NodeInfo(lat, lon, node_id), bollard(bollard), trafficLight(traffic_light)
-{
-}
-
-ExternalMemoryNode::ExternalMemoryNode() : bollard(false), trafficLight(false)
-{
-}
-
-ExternalMemoryNode ExternalMemoryNode::min_value()
-{
- return ExternalMemoryNode(0, 0, 0, false, false);
-}
+#include <osrm/Coordinate.h>
-ExternalMemoryNode ExternalMemoryNode::max_value()
+JSON::String
+PolylineFormatter::printEncodedString(const std::vector<SegmentInformation> &polyline) const
{
- return ExternalMemoryNode(std::numeric_limits<int>::max(),
- std::numeric_limits<int>::max(),
- std::numeric_limits<unsigned>::max(),
- false,
- false);
+ return JSON::String(PolylineCompressor().get_encoded_string(polyline));
}
-void ImportNode::Clear()
+JSON::Array
+PolylineFormatter::printUnencodedString(const std::vector<SegmentInformation> &polyline) const
{
- keyVals.Clear();
- lat = 0;
- lon = 0;
- node_id = 0;
- bollard = false;
- trafficLight = false;
+ JSON::Array json_geometry_array;
+ for (const auto &segment : polyline)
+ {
+ if (segment.necessary)
+ {
+ JSON::Array json_coordinate;
+ json_coordinate.values.push_back(segment.location.lat / COORDINATE_PRECISION);
+ json_coordinate.values.push_back(segment.location.lon / COORDINATE_PRECISION);
+ json_geometry_array.values.push_back(json_coordinate);
+ }
+ }
+ return json_geometry_array;
}
diff --git a/Algorithms/PolylineCompressor.h b/algorithms/polyline_formatter.hpp
similarity index 78%
copy from Algorithms/PolylineCompressor.h
copy to algorithms/polyline_formatter.hpp
index 5472bd8..1d4744d 100644
--- a/Algorithms/PolylineCompressor.h
+++ b/algorithms/polyline_formatter.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,27 +25,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef POLYLINECOMPRESSOR_H_
-#define POLYLINECOMPRESSOR_H_
+#ifndef POLYLINE_FORMATTER_HPP
+#define POLYLINE_FORMATTER_HPP
struct SegmentInformation;
-#include "../DataStructures/JSONContainer.h"
+#include "../data_structures/json_container.hpp"
#include <string>
#include <vector>
-class PolylineCompressor
+struct PolylineFormatter
{
- private:
- void encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output) const;
-
- void encodeNumber(int number_to_encode, std::string &output) const;
-
- public:
JSON::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
JSON::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
};
-#endif /* POLYLINECOMPRESSOR_H_ */
+#endif /* POLYLINE_FORMATTER_HPP */
diff --git a/Algorithms/ExtractRouteNames.h b/algorithms/route_name_extraction.hpp
similarity index 98%
rename from Algorithms/ExtractRouteNames.h
rename to algorithms/route_name_extraction.hpp
index 5c1b860..519452f 100644
--- a/Algorithms/ExtractRouteNames.h
+++ b/algorithms/route_name_extraction.hpp
@@ -54,7 +54,7 @@ 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)
+ if (segment.name_id != blocked_name_id && segment.length > result_segment.length && segment.name_id != 0)
{
result_segment = segment;
}
@@ -111,7 +111,7 @@ template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
shortest_path_set_difference.end(),
length_comperator);
shortest_segment_2 =
- PickNextLongestSegment(shortest_path_set_difference, shortest_path_segments[0].name_id);
+ PickNextLongestSegment(shortest_path_set_difference, shortest_segment_1.name_id);
// compute the set difference (for alternative path) depending on names between shortest and
// alternative
@@ -138,7 +138,7 @@ template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
if (!alternative_path_segments.empty())
{
alternative_segment_2 = PickNextLongestSegment(alternative_path_set_difference,
- alternative_path_segments[0].name_id);
+ alternative_segment_1.name_id);
}
// move the segments into the order in which they occur.
diff --git a/algorithms/tiny_components.hpp b/algorithms/tiny_components.hpp
new file mode 100644
index 0000000..5cf5a75
--- /dev/null
+++ b/algorithms/tiny_components.hpp
@@ -0,0 +1,253 @@
+/*
+
+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 TINY_COMPONENTS_HPP
+#define TINY_COMPONENTS_HPP
+
+#include "../typedefs.h"
+#include "../data_structures/deallocating_vector.hpp"
+#include "../data_structures/import_edge.hpp"
+#include "../data_structures/query_node.hpp"
+#include "../data_structures/percent.hpp"
+#include "../data_structures/restriction.hpp"
+#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 <osrm/Coordinate.h>
+
+#include <boost/assert.hpp>
+
+#include <tbb/parallel_sort.h>
+
+
+#include <cstdint>
+
+#include <memory>
+#include <stack>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+template <typename GraphT>
+class TarjanSCC
+{
+ struct TarjanStackFrame
+ {
+ explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {}
+ NodeID v;
+ NodeID parent;
+ };
+
+ struct TarjanNode
+ {
+ TarjanNode() : index(SPECIAL_NODEID), low_link(SPECIAL_NODEID), on_stack(false) {}
+ unsigned index;
+ unsigned low_link;
+ bool on_stack;
+ };
+
+ std::vector<unsigned> components_index;
+ std::vector<NodeID> component_size_vector;
+ std::shared_ptr<GraphT> m_node_based_graph;
+ std::unordered_set<NodeID> barrier_node_set;
+ RestrictionMap m_restriction_map;
+ unsigned size_one_counter;
+
+ public:
+ 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)
+ {
+ barrier_node_set.insert(std::begin(barrier_node_list), std::end(barrier_node_list));
+ BOOST_ASSERT(m_node_based_graph->GetNumberOfNodes() > 0);
+ }
+
+ void run()
+ {
+ TIMER_START(SCC_RUN);
+ // 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());
+ 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))
+ {
+ if (SPECIAL_NODEID == components_index[node])
+ {
+ recursion_stack.emplace(TarjanStackFrame(node, node));
+ }
+
+ while (!recursion_stack.empty())
+ {
+ TarjanStackFrame currentFrame = recursion_stack.top();
+ const NodeID u = currentFrame.parent;
+ const NodeID v = currentFrame.v;
+ recursion_stack.pop();
+
+ const bool before_recursion = processing_node_before_recursion[v];
+
+ if (before_recursion && tarjan_node_list[v].index != UINT_MAX)
+ {
+ continue;
+ }
+
+ if (before_recursion)
+ {
+ // Mark frame to handle tail of recursion
+ recursion_stack.emplace(currentFrame);
+ processing_node_before_recursion[v] = false;
+
+ // Mark essential information for SCC
+ tarjan_node_list[v].index = index;
+ tarjan_node_list[v].low_link = index;
+ tarjan_stack.push(v);
+ tarjan_node_list[v].on_stack = true;
+ ++index;
+
+ const NodeID to_node_of_only_restriction =
+ m_restriction_map.CheckForEmanatingIsOnlyTurn(u, v);
+
+ for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(v))
+ {
+ 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)
+ {
+ // continue;
+ }
+
+
+ if (to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
+ vprime == to_node_of_only_restriction)
+ {
+ // At an only_-restriction but not at the right turn
+ // continue;
+ }
+
+ if (m_restriction_map.CheckIfTurnIsRestricted(u, v, vprime))
+ {
+ // continue;
+ }
+
+ if (SPECIAL_NODEID == tarjan_node_list[vprime].index)
+ {
+ recursion_stack.emplace(TarjanStackFrame(vprime, v));
+ }
+ else
+ {
+ if (tarjan_node_list[vprime].on_stack &&
+ tarjan_node_list[vprime].index < tarjan_node_list[v].low_link)
+ {
+ tarjan_node_list[v].low_link = tarjan_node_list[vprime].index;
+ }
+ }
+ }
+ }
+ else
+ {
+ processing_node_before_recursion[v] = true;
+ tarjan_node_list[currentFrame.parent].low_link =
+ std::min(tarjan_node_list[currentFrame.parent].low_link,
+ tarjan_node_list[v].low_link);
+ // after recursion, lets do cycle checking
+ // Check if we found a cycle. This is the bottom part of the recursion
+ if (tarjan_node_list[v].low_link == tarjan_node_list[v].index)
+ {
+ NodeID vprime;
+ do
+ {
+ vprime = tarjan_stack.top();
+ tarjan_stack.pop();
+ tarjan_node_list[vprime].on_stack = false;
+ components_index[vprime] = component_index;
+ ++size_of_current_component;
+ } while (v != vprime);
+
+ component_size_vector.emplace_back(size_of_current_component);
+
+ if (size_of_current_component > 1000)
+ {
+ SimpleLogger().Write() << "large component [" << component_index
+ << "]=" << size_of_current_component;
+ }
+
+ ++component_index;
+ size_of_current_component = 0;
+ }
+ }
+ }
+ }
+
+ TIMER_STOP(SCC_RUN);
+ SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN)/1000. << "s";
+
+ size_one_counter = std::count_if(component_size_vector.begin(),
+ component_size_vector.end(),
+ [](unsigned value)
+ {
+ return 1 == value;
+ });
+ }
+
+ std::size_t get_number_of_components() const
+ {
+ return component_size_vector.size();
+ }
+
+ unsigned 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];
+ }
+};
+
+#endif /* TINY_COMPONENTS_HPP */
diff --git a/appveyor.yml b/appveyor.yml
index 7d6f835..e650e1a 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -23,6 +23,7 @@ platform: x64
install:
# by default, all script lines are interpreted as batch
+ - nuget install protobuf
- cd c:\projects\osrm
- curl -O http://build.project-osrm.org/libs_osrm_%Configuration%.7z
- 7z x libs_osrm_%Configuration%.7z | find ":"
@@ -33,12 +34,22 @@ build_script:
- cd build
- echo Running cmake...
- call "%VS120COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64
+ - SET PATH=C:\Program Files (x86)\MSBuild\12.0\bin\;%PATH%
- SET P=c:/projects/osrm
- set TBB_INSTALL_DIR=%P%/tbb
- set TBB_ARCH_PLATFORM=intel64/vc12
- - cmake .. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=%Configuration% -DBZIP2_INCLUDE_DIR=%P%/libs/include -DBZIP2_LIBRARIES=%P%/libs/lib/libbz2.lib -DCMAKE_INSTALL_PREFIX=%P%/libs -DBOOST_ROOT=%P%/boost_min -DBoost_USE_STATIC_LIBS=ON
- - nmake
+ - cmake .. -G "Visual Studio 12 Win64" -DCMAKE_BUILD_TYPE=%Configuration% -DCMAKE_INSTALL_PREFIX=%P%/libs -DBOOST_ROOT=%P%/boost_min -DBoost_ADDITIONAL_VERSIONS=1.57 -DBoost_USE_STATIC_LIBS=ON -T CTP_Nov2013
+ - msbuild /clp:Verbosity=minimal /nologo OSRM.sln
+ - msbuild /clp:Verbosity=minimal /nologo tests.vcxproj
+ - cd %Configuration%
- if "%APPVEYOR_REPO_BRANCH%"=="develop" (7z a %P%/osrm_%Configuration%.zip *.exe *.pdb %P%/libs/bin/*.dll -tzip)
+ - cd ..\..\profiles
+ - echo disk=c:\temp\stxxl,10000,wincall > .stxxl.txt
+ - if "%APPVEYOR_REPO_BRANCH%"=="develop" (7z a %P%/osrm_%Configuration%.zip * -tzip)
+ - set PATH=%PATH%;c:/projects/osrm/libs/bin
+ - cd c:/projects/osrm/build/%Configuration%
+ - datastructure-tests.exe
+ - algorithm-tests.exe
test: off
diff --git a/benchmarks/static_rtree.cpp b/benchmarks/static_rtree.cpp
new file mode 100644
index 0000000..7a24cfc
--- /dev/null
+++ b/benchmarks/static_rtree.cpp
@@ -0,0 +1,189 @@
+/*
+
+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.
+
+*/
+
+#include "../data_structures/original_edge_data.hpp"
+#include "../data_structures/query_node.hpp"
+#include "../data_structures/shared_memory_vector_wrapper.hpp"
+#include "../data_structures/static_rtree.hpp"
+#include "../data_structures/edge_based_node.hpp"
+#include "../Util/BoostFileSystemFix.h"
+
+#include <osrm/Coordinate.h>
+
+#include <random>
+
+// Choosen by a fair W20 dice roll (this value is completely arbitrary)
+constexpr unsigned RANDOM_SEED = 13;
+constexpr int32_t WORLD_MIN_LAT = -90 * COORDINATE_PRECISION;
+constexpr int32_t WORLD_MAX_LAT = 90 * COORDINATE_PRECISION;
+constexpr int32_t WORLD_MIN_LON = -180 * COORDINATE_PRECISION;
+constexpr int32_t WORLD_MAX_LON = 180 * COORDINATE_PRECISION;
+
+using RTreeLeaf = EdgeBasedNode;
+using FixedPointCoordinateListPtr = std::shared_ptr<std::vector<FixedPointCoordinate>>;
+using BenchStaticRTree = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>;
+
+FixedPointCoordinateListPtr LoadCoordinates(const boost::filesystem::path &nodes_file)
+{
+ boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
+
+ QueryNode current_node;
+ unsigned coordinate_count = 0;
+ nodes_input_stream.read((char *)&coordinate_count, sizeof(unsigned));
+ auto coords = std::make_shared<std::vector<FixedPointCoordinate>>(coordinate_count);
+ for (unsigned i = 0; i < coordinate_count; ++i)
+ {
+ nodes_input_stream.read((char *)¤t_node, sizeof(QueryNode));
+ coords->at(i) = FixedPointCoordinate(current_node.lat, current_node.lon);
+ BOOST_ASSERT((std::abs(coords->at(i).lat) >> 30) == 0);
+ BOOST_ASSERT((std::abs(coords->at(i).lon) >> 30) == 0);
+ }
+ nodes_input_stream.close();
+ return coords;
+}
+
+void Benchmark(BenchStaticRTree &rtree, unsigned num_queries)
+{
+ std::mt19937 mt_rand(RANDOM_SEED);
+ std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
+ std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
+ std::vector<FixedPointCoordinate> queries;
+ for (unsigned i = 0; i < num_queries; i++)
+ {
+ queries.emplace_back(FixedPointCoordinate(lat_udist(mt_rand), lon_udist(mt_rand)));
+ }
+
+ {
+ const unsigned num_results = 5;
+ std::cout << "#### IncrementalFindPhantomNodeForCoordinate : " << num_results
+ << " phantom nodes"
+ << "\n";
+
+ TIMER_START(query_phantom);
+ std::vector<PhantomNode> phantom_node_vector;
+ for (const auto &q : queries)
+ {
+ phantom_node_vector.clear();
+ rtree.IncrementalFindPhantomNodeForCoordinate(
+ q, phantom_node_vector, 3, num_results);
+ phantom_node_vector.clear();
+ rtree.IncrementalFindPhantomNodeForCoordinate(
+ q, phantom_node_vector, 17, num_results);
+ }
+ TIMER_STOP(query_phantom);
+
+ std::cout << "Took " << TIMER_MSEC(query_phantom) << " msec for " << num_queries
+ << " queries."
+ << "\n";
+ std::cout << TIMER_MSEC(query_phantom) / ((double)num_queries) << " msec/query."
+ << "\n";
+
+ std::cout << "#### LocateClosestEndPointForCoordinate"
+ << "\n";
+ }
+
+ TIMER_START(query_endpoint);
+ FixedPointCoordinate result;
+ for (const auto &q : queries)
+ {
+ rtree.LocateClosestEndPointForCoordinate(q, result, 3);
+ }
+ TIMER_STOP(query_endpoint);
+
+ std::cout << "Took " << TIMER_MSEC(query_endpoint) << " msec for " << num_queries << " queries."
+ << "\n";
+ std::cout << TIMER_MSEC(query_endpoint) / ((double)num_queries) << " msec/query."
+ << "\n";
+
+ std::cout << "#### FindPhantomNodeForCoordinate"
+ << "\n";
+
+ TIMER_START(query_node);
+ for (const auto &q : queries)
+ {
+ PhantomNode phantom;
+ rtree.FindPhantomNodeForCoordinate(q, phantom, 3);
+ }
+ TIMER_STOP(query_node);
+
+ 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";
+
+ {
+ const unsigned num_results = 1;
+ std::cout << "#### IncrementalFindPhantomNodeForCoordinate : " << num_results
+ << " phantom nodes"
+ << "\n";
+
+ TIMER_START(query_phantom);
+ std::vector<PhantomNode> phantom_node_vector;
+ for (const auto &q : queries)
+ {
+ phantom_node_vector.clear();
+ rtree.IncrementalFindPhantomNodeForCoordinate(
+ q, phantom_node_vector, 3, num_results);
+ phantom_node_vector.clear();
+ rtree.IncrementalFindPhantomNodeForCoordinate(
+ q, phantom_node_vector, 17, num_results);
+ }
+ TIMER_STOP(query_phantom);
+
+ std::cout << "Took " << TIMER_MSEC(query_phantom) << " msec for " << num_queries
+ << " queries."
+ << "\n";
+ std::cout << TIMER_MSEC(query_phantom) / ((double)num_queries) << " msec/query."
+ << "\n";
+
+ std::cout << "#### LocateClosestEndPointForCoordinate"
+ << "\n";
+ }
+}
+
+int main(int argc, char **argv)
+{
+ if (argc < 4)
+ {
+ std::cout << "./rtree-bench file.ramIndex file.fileIndx file.nodes"
+ << "\n";
+ return 1;
+ }
+
+ const char *ramPath = argv[1];
+ const char *filePath = argv[2];
+ const char *nodesPath = argv[3];
+
+ auto coords = LoadCoordinates(nodesPath);
+
+ BenchStaticRTree rtree(ramPath, filePath, coords);
+
+ Benchmark(rtree, 10000);
+
+ return 0;
+}
diff --git a/cmake/CPackDebianConfig.cmake b/cmake/CPackDebianConfig.cmake
new file mode 100644
index 0000000..065c429
--- /dev/null
+++ b/cmake/CPackDebianConfig.cmake
@@ -0,0 +1,44 @@
+IF(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ MESSAGE(FATAL_ERROR "Cannot configure CPack to generate Debian packages on non-linux systems.")
+ENDIF()
+
+INCLUDE(FindDebArch)
+
+SET(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md")
+SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENCE.TXT")
+SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CPACK_RESOURCE_FILE_README}")
+SET(CPACK_PACKAGE_VERSION_MAJOR "0")
+SET(CPACK_PACKAGE_VERSION_MINOR "4")
+SET(CPACK_PACKAGE_VERSION_PATCH "3")
+
+SET(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+
+string(TOLOWER "${CMAKE_PROJECT_NAME}" LOWER_PROJECT_NAME)
+SET(CPACK_PACKAGE_FILE_NAME "${LOWER_PROJECT_NAME}_${CPACK_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
+SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${LOWER_PROJECT_NAME}_${CPACK_PACKAGE_VERSION}_orig")
+SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Open Source Routing Machine (OSRM).")
+SET(CPACK_PACKAGE_DESCRIPTION "Open Source Routing Machine (OSRM) is a routing engine.")
+
+# To create a proper Debian/Ubuntu package, the following CMake
+# options should be used:
+
+SET(CPACK_STRIP_FILES "TRUE")
+SET(CPACK_INCLUDE_TOPLEVEL_DIRECTORY "FALSE")
+SET(CPACK_GENERATOR "DEB")
+
+SET(CPACK_DEBIAN_PACKAGE_NAME "${CPACK_PACKAGE_NAME}${VERSION_SUFFIX}")
+SET(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}${CPACK_PACKAGE_REVISION}")
+SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Dennis Luxen <info at project-osrm.org>")
+SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
+SET(CPACK_DEBIAN_PACKAGE_SECTION "devel")
+SET(CPACK_DEBIAN_PACKAGE_DESCRIPTION "Open Source Routing Machine (OSRM) is a high-performance routing engine.
+ It combines sophisticated routing algorithms with the open and free data of the OpenStreetMap."
+)
+SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6-dev, libprotobuf-dev, libosmpbf-dev, libbz2-1.0, libstxxl1, libxml2, libzip2, liblua5.1-0, libtbb2, libboost-all-dev")
+
+file(GLOB_RECURSE ProfileGlob ${CMAKE_SOURCE_DIR}/profiles/*)
+install(FILES ${ProfileGlob} DESTINATION "share/doc/${LOWER_PROJECT_NAME}/profiles")
+CONFIGURE_FILE (${CMAKE_SOURCE_DIR}/cmake/postinst.in postinst)
+set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_BINARY_DIR}/postinst;${CMAKE_CURRENT_BINARY_DIR}/copyright;")
+
+MESSAGE(STATUS "Debian Package: ${CPACK_DEBIAN_PACKAGE_NAME} (${CPACK_DEBIAN_PACKAGE_VERSION}) [${CPACK_PACKAGE_FILE_NAME}.deb]")
diff --git a/cmake/FindDebArch.cmake b/cmake/FindDebArch.cmake
new file mode 100644
index 0000000..5b405bc
--- /dev/null
+++ b/cmake/FindDebArch.cmake
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2013 Emmanuel Roullit <emmanuel.roullit at gmail.com>
+#
+
+IF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
+ FIND_PROGRAM(DPKG_CMD dpkg)
+ IF(NOT DPKG_CMD)
+ EXECUTE_PROCESS(COMMAND uname -p
+ OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ MESSAGE(STATUS "Can not find dpkg in your path, default to uname -p: ${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.")
+ ELSE(NOT DPKG_CMD)
+ EXECUTE_PROCESS(COMMAND "${DPKG_CMD}" --print-architecture
+ OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ ENDIF(NOT DPKG_CMD)
+ENDIF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
diff --git a/cmake/FingerPrint-Config.cmake b/cmake/FingerPrint-Config.cmake
index 7b45d5c..710368d 100644
--- a/cmake/FingerPrint-Config.cmake
+++ b/cmake/FingerPrint-Config.cmake
@@ -3,8 +3,8 @@ if (EXISTS ${OLDFILE})
file(REMOVE_RECURSE ${OLDFILE})
endif()
file(MD5 ${SOURCE_DIR}/prepare.cpp MD5PREPARE)
-file(MD5 ${SOURCE_DIR}/DataStructures/StaticRTree.h MD5RTREE)
-file(MD5 ${SOURCE_DIR}/Util/GraphLoader.h MD5GRAPH)
+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)
-CONFIGURE_FILE( ${SOURCE_DIR}/Util/FingerPrint.cpp.in ${SOURCE_DIR}/Util/FingerPrint.cpp )
+CONFIGURE_FILE( ${SOURCE_DIR}/Util/finger_print.cpp.in ${SOURCE_DIR}/Util/finger_print.cpp )
diff --git a/cmake/check_luabind.cmake b/cmake/check_luabind.cmake
new file mode 100644
index 0000000..18f0656
--- /dev/null
+++ b/cmake/check_luabind.cmake
@@ -0,0 +1,40 @@
+INCLUDE (CheckCXXSourceCompiles)
+unset(LUABIND_WORKS CACHE)
+unset(LUABIND51_WORKS CACHE)
+set (LUABIND_CHECK_SRC "#include \"lua.h\"\n#include <luabind/luabind.hpp>\n int main() { lua_State *myLuaState = luaL_newstate(); luabind::open(myLuaState); return 0;}")
+set (CMAKE_TRY_COMPILE_CONFIGURATION ${CMAKE_BUILD_TYPE})
+set (CMAKE_REQUIRED_INCLUDES "${Boost_INCLUDE_DIR};${LUABIND_INCLUDE_DIR};${LUA_INCLUDE_DIR}")
+set (CMAKE_REQUIRED_LIBRARIES "${LUABIND_LIBRARY};${LUA_LIBRARY}")
+
+find_package(Lua52)
+if(NOT APPLE)
+ find_package(LuaJIT 5.2)
+endif()
+if(LUA52_FOUND)
+ set (CMAKE_REQUIRED_INCLUDES "${Boost_INCLUDE_DIR};${LUABIND_INCLUDE_DIR};${LUA_INCLUDE_DIR}")
+ set (CMAKE_REQUIRED_LIBRARIES "${LUABIND_LIBRARY};${LUA_LIBRARY}")
+ CHECK_CXX_SOURCE_COMPILES("${LUABIND_CHECK_SRC}" LUABIND_WORKS)
+endif()
+
+if(LUABIND_WORKS)
+ message(STATUS "Luabind/Lua5.2 combination working with ${LUA_LIBRARY}")
+else()
+ message(STATUS "Luabind/Lua5.2 not feasible, falling back to Lua 5.1.")
+ unset(LUA_FOUND CACHE)
+ unset(LUA_INCLUDE_DIR CACHE)
+ unset(LUA_LIBRARY CACHE)
+ find_package(Lua51 REQUIRED)
+ if(NOT APPLE)
+ find_package(LuaJIT 5.1)
+ endif()
+ set (CMAKE_REQUIRED_INCLUDES "${Boost_INCLUDE_DIR};${LUABIND_INCLUDE_DIR};${LUA_INCLUDE_DIR}")
+ set (CMAKE_REQUIRED_LIBRARIES "${LUABIND_LIBRARY};${LUA_LIBRARY}")
+
+ CHECK_CXX_SOURCE_COMPILES("${LUABIND_CHECK_SRC}" LUABIND51_WORKS)
+
+ if(LUABIND51_WORKS)
+ message(STATUS "Luabind works with Lua 5.1 at ${LUA_LIBRARY}")
+ else()
+ message(FATAL_ERROR "Luabind does not work with Lua 5.1 at ${LUA_LIBRARY}, no working Luabind found")
+ endif()
+endif()
diff --git a/cmake/postinst.in b/cmake/postinst.in
new file mode 100644
index 0000000..92f2fde
--- /dev/null
+++ b/cmake/postinst.in
@@ -0,0 +1,2 @@
+#/usr/bin/env bash
+ln -s /usr/share/doc/@CMAKE_PROJECT_NAME@/profiles/car.lua @CMAKE_INSTALL_PREFIX@/profile.lua
diff --git a/Contractor/Contractor.h b/contractor/contractor.hpp
similarity index 83%
rename from Contractor/Contractor.h
rename to contractor/contractor.hpp
index a879607..c8c107c 100644
--- a/Contractor/Contractor.h
+++ b/contractor/contractor.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,22 +25,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CONTRACTOR_H
-#define CONTRACTOR_H
-
-#include "TemporaryStorage.h"
-#include "../DataStructures/BinaryHeap.h"
-#include "../DataStructures/DeallocatingVector.h"
-#include "../DataStructures/DynamicGraph.h"
-#include "../DataStructures/Percent.h"
-#include "../DataStructures/XORFastHash.h"
-#include "../DataStructures/XORFastHashStorage.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/StringUtil.h"
-#include "../Util/TimingUtil.h"
+#ifndef CONTRACTOR_HPP
+#define CONTRACTOR_HPP
+
+#include "../data_structures/binary_heap.hpp"
+#include "../data_structures/deallocating_vector.hpp"
+#include "../data_structures/dynamic_graph.hpp"
+#include "../data_structures/percent.hpp"
+#include "../data_structures/query_edge.hpp"
+#include "../data_structures/xor_fast_hash.hpp"
+#include "../data_structures/xor_fast_hash_storage.hpp"
+#include "../Util/integer_range.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/timing_util.hpp"
+#include "../typedefs.h"
#include <boost/assert.hpp>
+#include <stxxl/vector>
+
#include <tbb/enumerable_thread_specific.h>
#include <tbb/parallel_for.h>
#include <tbb/parallel_sort.h>
@@ -60,15 +63,15 @@ class Contractor
is_original_via_node_ID(false)
{
}
- ContractorEdgeData(unsigned _distance,
- unsigned _originalEdges,
- unsigned _id,
- bool _shortcut,
- bool _forward,
- bool _backward)
- : distance(_distance), id(_id),
- originalEdges(std::min((unsigned)1 << 28, _originalEdges)), shortcut(_shortcut),
- forward(_forward), backward(_backward), is_original_via_node_ID(false)
+ ContractorEdgeData(unsigned distance,
+ unsigned original_edges,
+ unsigned id,
+ bool shortcut,
+ bool forward,
+ bool backward)
+ : distance(distance), id(id),
+ originalEdges(std::min((unsigned)1 << 28, original_edges)), shortcut(shortcut),
+ forward(forward), backward(backward), is_original_via_node_ID(false)
{
}
unsigned distance;
@@ -88,19 +91,18 @@ class Contractor
ContractorHeapData(short h, bool t) : hop(h), target(t) {}
};
- typedef DynamicGraph<ContractorEdgeData> ContractorGraph;
- // typedef BinaryHeap< NodeID, NodeID, int, ContractorHeapData, ArrayStorage<NodeID, NodeID>
- // > ContractorHeap;
- typedef BinaryHeap<NodeID, NodeID, int, ContractorHeapData, XORFastHashStorage<NodeID, NodeID>>
- ContractorHeap;
- typedef ContractorGraph::InputEdge ContractorEdge;
+ using ContractorGraph = DynamicGraph<ContractorEdgeData>;
+ // using ContractorHeap = BinaryHeap<NodeID, NodeID, int, ContractorHeapData, ArrayStorage<NodeID, NodeID>
+ // >;
+ using ContractorHeap = BinaryHeap<NodeID, NodeID, int, ContractorHeapData, XORFastHashStorage<NodeID, NodeID>>;
+ using ContractorEdge = ContractorGraph::InputEdge;
struct ContractorThreadData
{
ContractorHeap heap;
std::vector<ContractorEdge> inserted_edges;
std::vector<NodeID> neighbours;
- ContractorThreadData(NodeID nodes) : heap(nodes) {}
+ explicit ContractorThreadData(NodeID nodes) : heap(nodes) {}
};
struct NodePriorityData
@@ -132,7 +134,7 @@ class Contractor
struct ThreadDataContainer
{
- 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()
{
@@ -147,7 +149,7 @@ class Contractor
}
int number_of_nodes;
- typedef tbb::enumerable_thread_specific<std::shared_ptr<ContractorThreadData>> EnumerableThreadData;
+ using EnumerableThreadData = tbb::enumerable_thread_specific<std::shared_ptr<ContractorThreadData>>;
EnumerableThreadData data;
};
@@ -156,41 +158,38 @@ class Contractor
{
std::vector<ContractorEdge> edges;
edges.reserve(input_edge_list.size() * 2);
- temp_edge_counter = 0;
- auto diter = input_edge_list.dbegin();
- auto dend = input_edge_list.dend();
-
- ContractorEdge new_edge;
- while (diter != dend)
+ const auto dend = input_edge_list.dend();
+ for (auto diter = input_edge_list.dbegin(); diter != dend; ++diter)
{
- new_edge.source = diter->source;
- new_edge.target = diter->target;
- new_edge.data = { static_cast<unsigned int>(std::max(diter->weight, 1)),
- 1,
- diter->edge_id,
- false,
- diter->forward,
- diter->backward};
-
- BOOST_ASSERT_MSG(new_edge.data.distance > 0, "edge distance < 1");
+ BOOST_ASSERT_MSG(static_cast<unsigned int>(std::max(diter->weight, 1)) > 0, "edge distance < 1");
#ifndef NDEBUG
- if (new_edge.data.distance > 24 * 60 * 60 * 10)
+ if (static_cast<unsigned int>(std::max(diter->weight, 1)) > 24 * 60 * 60 * 10)
{
SimpleLogger().Write(logWARNING) << "Edge weight large -> "
- << new_edge.data.distance;
+ << static_cast<unsigned int>(std::max(diter->weight, 1));
}
#endif
- edges.push_back(new_edge);
- std::swap(new_edge.source, new_edge.target);
- new_edge.data.forward = diter->backward;
- new_edge.data.backward = diter->forward;
- edges.push_back(new_edge);
- ++diter;
+ 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);
+
+ 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);
}
// clear input vector
- edges.shrink_to_fit();
input_edge_list.clear();
+ edges.shrink_to_fit();
+
tbb::parallel_sort(edges.begin(), edges.end());
NodeID edge = 0;
for (NodeID i = 0; i < edges.size();)
@@ -201,7 +200,7 @@ class Contractor
// remove eigenloops
if (source == target)
{
- i++;
+ ++i;
continue;
}
ContractorEdge forward_edge;
@@ -280,13 +279,10 @@ class Contractor
// << "); via: " << contractor_graph->GetEdgeData(i).via;
// }
- // Create temporary file
-
- edge_storage_slot = TemporaryStorage::GetInstance().AllocateSlot();
std::cout << "contractor finished initalization" << std::endl;
}
- ~Contractor() { TemporaryStorage::GetInstance().DeallocateSlot(edge_storage_slot); }
+ ~Contractor() { }
void Run()
{
@@ -362,7 +358,7 @@ class Contractor
// build forward and backward renumbering map and remap ids in remaining_nodes and
// Priorities.
- for (unsigned new_node_id = 0; new_node_id < remaining_nodes.size(); ++new_node_id)
+ for (const auto new_node_id : osrm::irange<std::size_t>(0, remaining_nodes.size()))
{
// create renumbering maps in both directions
orig_node_id_to_new_id_map[new_node_id] = remaining_nodes[new_node_id].id;
@@ -371,9 +367,8 @@ class Contractor
node_priorities[remaining_nodes[new_node_id].id];
remaining_nodes[new_node_id].id = new_node_id;
}
- TemporaryStorage &temporary_storage = TemporaryStorage::GetInstance();
// walk over all nodes
- for (unsigned i = 0; i < contractor_graph->GetNumberOfNodes(); ++i)
+ 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))
@@ -381,26 +376,20 @@ class Contractor
ContractorGraph::EdgeData &data =
contractor_graph->GetEdgeData(current_edge);
const NodeID target = contractor_graph->GetTarget(current_edge);
- if (UINT_MAX == new_node_id_from_orig_id_map[i])
+ if (SPECIAL_NODEID == new_node_id_from_orig_id_map[i])
{
- // Save edges of this node w/o renumbering.
- temporary_storage.WriteToSlot(
- edge_storage_slot, (char *)&source, sizeof(NodeID));
- temporary_storage.WriteToSlot(
- edge_storage_slot, (char *)&target, sizeof(NodeID));
- temporary_storage.WriteToSlot(edge_storage_slot,
- (char *)&data,
- sizeof(ContractorGraph::EdgeData));
- ++temp_edge_counter;
+ external_edge_list.push_back({source, target, data});
}
else
{
// node is not yet contracted.
// add (renumbered) outgoing edges to new DynamicGraph.
- ContractorEdge new_edge;
- new_edge.source = new_node_id_from_orig_id_map[source];
- new_edge.target = new_node_id_from_orig_id_map[target];
- new_edge.data = 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],
"new source id not resolveable");
@@ -569,7 +558,7 @@ class Contractor
if (contractor_graph->GetNumberOfNodes())
{
Edge new_edge;
- for (NodeID node = 0; node < number_of_nodes; ++node)
+ for (const auto node : osrm::irange(0u, number_of_nodes))
{
p.printStatus(node);
for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
@@ -611,29 +600,9 @@ class Contractor
orig_node_id_to_new_id_map.shrink_to_fit();
BOOST_ASSERT(0 == orig_node_id_to_new_id_map.capacity());
- TemporaryStorage &temporary_storage = TemporaryStorage::GetInstance();
- // loads edges of graph before renumbering, no need for further numbering action.
- NodeID source;
- NodeID target;
- ContractorGraph::EdgeData data;
-
- Edge restored_edge;
- for (unsigned i = 0; i < temp_edge_counter; ++i)
- {
- temporary_storage.ReadFromSlot(edge_storage_slot, (char *)&source, sizeof(NodeID));
- temporary_storage.ReadFromSlot(edge_storage_slot, (char *)&target, sizeof(NodeID));
- temporary_storage.ReadFromSlot(
- edge_storage_slot, (char *)&data, sizeof(ContractorGraph::EdgeData));
- restored_edge.source = source;
- restored_edge.target = target;
- restored_edge.data.distance = data.distance;
- restored_edge.data.shortcut = data.shortcut;
- restored_edge.data.id = data.id;
- restored_edge.data.forward = data.forward;
- restored_edge.data.backward = data.backward;
- edges.push_back(restored_edge);
- }
- temporary_storage.DeallocateSlot(edge_storage_slot);
+
+ edges.append(external_edge_list.begin(), external_edge_list.end());
+ external_edge_list.clear();
}
private:
@@ -648,7 +617,7 @@ class Contractor
int nodes = 0;
unsigned number_of_targets_found = 0;
- while (heap.Size() > 0)
+ while (!heap.Empty())
{
const NodeID node = heap.DeleteMin();
const int distance = heap.GetKey(node);
@@ -658,12 +627,12 @@ class Contractor
{
return;
}
- // Destination settled?
if (distance > max_distance)
{
return;
}
+ // Destination settled?
if (heap.GetData(node).target)
{
++number_of_targets_found;
@@ -731,7 +700,7 @@ class Contractor
template <bool RUNSIMULATION>
inline bool
- ContractNode(ContractorThreadData *data, NodeID node, ContractionStats *stats = nullptr)
+ ContractNode(ContractorThreadData *data, const NodeID node, ContractionStats *stats = nullptr)
{
ContractorHeap &heap = data->heap;
int inserted_edges_size = data->inserted_edges.size();
@@ -803,21 +772,19 @@ class Contractor
}
else
{
- ContractorEdge new_edge;
- new_edge.source = source;
- new_edge.target = target;
- new_edge.data =
- ContractorEdgeData(path_distance,
- out_data.originalEdges + in_data.originalEdges,
- node /*, 0, in_data.turnInstruction*/,
- true,
- true,
- false);
- inserted_edges.push_back(new_edge);
- std::swap(new_edge.source, new_edge.target);
- new_edge.data.forward = false;
- new_edge.data.backward = true;
- inserted_edges.push_back(new_edge);
+ inserted_edges.emplace_back(source, target, path_distance,
+ out_data.originalEdges + in_data.originalEdges,
+ node,
+ true,
+ true,
+ false);
+
+ inserted_edges.emplace_back(target, source, path_distance,
+ out_data.originalEdges + in_data.originalEdges,
+ node,
+ true,
+ false,
+ true);
}
}
}
@@ -879,7 +846,7 @@ class Contractor
std::sort(neighbours.begin(), neighbours.end());
neighbours.resize(std::unique(neighbours.begin(), neighbours.end()) - neighbours.begin());
- for (int i = 0, e = (int)neighbours.size(); i < e; ++i)
+ for (const auto i : osrm::irange<std::size_t>(0, neighbours.size()))
{
contractor_graph->DeleteEdgesTo(neighbours[i], node);
}
@@ -917,7 +884,7 @@ class Contractor
}
inline bool IsNodeIndependent(
- const std::vector<float> &priorities /*, const std::vector< NodePriorityData >& node_data*/,
+ const std::vector<float> &priorities,
ContractorThreadData *const data,
NodeID node) const
{
@@ -963,7 +930,7 @@ class Contractor
continue;
}
const float target_priority = priorities[target];
- assert(target_priority >= 0);
+ BOOST_ASSERT(target_priority >= 0);
// found a neighbour with lower priority?
if (priority > target_priority)
{
@@ -983,8 +950,8 @@ class Contractor
// This bias function takes up 22 assembly instructions in total on X86
inline bool bias(const NodeID a, const NodeID b) const
{
- unsigned short hasha = fast_hash(a);
- unsigned short hashb = fast_hash(b);
+ const unsigned short hasha = fast_hash(a);
+ const unsigned short hashb = fast_hash(b);
// The compiler optimizes that to conditional register flags but without branching
// statements!
@@ -997,10 +964,9 @@ class Contractor
std::shared_ptr<ContractorGraph> contractor_graph;
std::vector<ContractorGraph::InputEdge> contracted_edge_list;
- unsigned edge_storage_slot;
- uint64_t temp_edge_counter;
+ stxxl::vector<QueryEdge> external_edge_list;
std::vector<NodeID> orig_node_id_to_new_id_map;
XORFastHash fast_hash;
};
-#endif // CONTRACTOR_H
+#endif // CONTRACTOR_HPP
diff --git a/Contractor/EdgeBasedGraphFactory.cpp b/contractor/edge_based_graph_factory.cpp
similarity index 72%
rename from Contractor/EdgeBasedGraphFactory.cpp
rename to contractor/edge_based_graph_factory.cpp
index 1e4e381..144b1fa 100644
--- a/Contractor/EdgeBasedGraphFactory.cpp
+++ b/contractor/edge_based_graph_factory.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,17 +25,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "EdgeBasedGraphFactory.h"
-#include "../Algorithms/BFSComponentExplorer.h"
-#include "../DataStructures/Percent.h"
-#include "../Util/ComputeAngle.h"
-#include "../Util/LuaUtil.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/TimingUtil.h"
+#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 <boost/assert.hpp>
#include <fstream>
+#include <iomanip>
#include <limits>
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
@@ -43,14 +45,13 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(
std::unique_ptr<RestrictionMap> restriction_map,
std::vector<NodeID> &barrier_node_list,
std::vector<NodeID> &traffic_light_node_list,
- std::vector<NodeInfo> &m_node_info_list,
+ std::vector<QueryNode> &node_info_list,
SpeedProfileProperties &speed_profile)
: speed_profile(speed_profile),
m_number_of_edge_based_nodes(std::numeric_limits<unsigned>::max()),
- m_node_info_list(m_node_info_list), m_node_based_graph(node_based_graph),
- m_restriction_map(std::move(restriction_map)), max_id(0)
+ m_node_info_list(node_info_list), m_node_based_graph(node_based_graph),
+ m_restriction_map(std::move(restriction_map)), max_id(0), removed_node_count(0)
{
-
// insert into unordered sets for fast lookup
m_barrier_nodes.insert(barrier_node_list.begin(), barrier_node_list.end());
m_traffic_lights.insert(traffic_light_node_list.begin(), traffic_light_node_list.end());
@@ -77,33 +78,31 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes)
}
void
-EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool belongs_to_tiny_cc)
+EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
+ const NodeID node_v,
+ const unsigned component_id)
{
// merge edges together into one EdgeBasedNode
- BOOST_ASSERT(u != SPECIAL_NODEID);
- BOOST_ASSERT(v != SPECIAL_NODEID);
- BOOST_ASSERT(e1 != SPECIAL_EDGEID);
+ BOOST_ASSERT(node_u != SPECIAL_NODEID);
+ BOOST_ASSERT(node_v != SPECIAL_NODEID);
-#ifndef NDEBUG
// find forward edge id and
- const EdgeID e1b = m_node_based_graph->FindEdge(u, v);
- BOOST_ASSERT(e1 == e1b);
-#endif
-
+ const EdgeID e1 = m_node_based_graph->FindEdge(node_u, node_v);
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
+
const EdgeData &forward_data = m_node_based_graph->GetEdgeData(e1);
// find reverse edge id and
- const EdgeID e2 = m_node_based_graph->FindEdge(v, u);
+ const EdgeID e2 = m_node_based_graph->FindEdge(node_v, node_u);
#ifndef NDEBUG
- if (e2 == m_node_based_graph->EndEdges(v))
+ if (e2 == m_node_based_graph->EndEdges(node_v))
{
- SimpleLogger().Write(logWARNING) << "Did not find edge (" << v << "," << u << ")";
+ 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(v));
+ BOOST_ASSERT(e2 < m_node_based_graph->EndEdges(node_v));
const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(e2);
if (forward_data.edgeBasedNodeID == SPECIAL_NODEID &&
@@ -125,6 +124,8 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
m_geometry_compressor.GetBucketReference(e2);
BOOST_ASSERT(forward_geometry.size() == reverse_geometry.size());
BOOST_ASSERT(0 != forward_geometry.size());
+ const unsigned geometry_size = static_cast<unsigned>(forward_geometry.size());
+ BOOST_ASSERT(geometry_size > 1);
// reconstruct bidirectional edge with individual weights and put each into the NN index
@@ -135,7 +136,7 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
// TODO: move to lambda function with C++11
int temp_sum = 0;
- for (unsigned i = 0; i < forward_geometry.size(); ++i)
+ for (const auto i : osrm::irange(0u, geometry_size))
{
forward_dist_prefix_sum[i] = temp_sum;
temp_sum += forward_geometry[i].second;
@@ -144,20 +145,16 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
}
temp_sum = 0;
- for (unsigned i = 0; i < reverse_geometry.size(); ++i)
+ for (const auto i : osrm::irange(0u, geometry_size))
{
temp_sum += reverse_geometry[reverse_geometry.size() - 1 - i].second;
reverse_dist_prefix_sum[i] = reverse_data.distance - temp_sum;
- BOOST_ASSERT(reverse_data.distance >= temp_sum);
+ // BOOST_ASSERT(reverse_data.distance >= temp_sum);
}
- BOOST_ASSERT(forward_geometry.size() == reverse_geometry.size());
-
- const unsigned geometry_size = forward_geometry.size();
- BOOST_ASSERT(geometry_size > 1);
- NodeID current_edge_source_coordinate_id = u;
+ NodeID current_edge_source_coordinate_id = node_u;
- if (forward_data.edgeBasedNodeID != SPECIAL_NODEID)
+ if (SPECIAL_NODEID != forward_data.edgeBasedNodeID)
{
max_id = std::max(forward_data.edgeBasedNodeID, max_id);
}
@@ -167,7 +164,7 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
}
// traverse arrays from start and end respectively
- for (unsigned i = 0; i < geometry_size; ++i)
+ for (const auto i : osrm::irange(0u, geometry_size))
{
BOOST_ASSERT(current_edge_source_coordinate_id ==
reverse_geometry[geometry_size - 1 - i].first);
@@ -181,24 +178,26 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
current_edge_target_coordinate_id,
forward_data.nameID,
forward_geometry[i].second,
- reverse_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,
- belongs_to_tiny_cc);
+ 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());
- BOOST_ASSERT(u != m_edge_based_node_list.back().u ||
- v != m_edge_based_node_list.back().v);
+ BOOST_ASSERT(node_u != m_edge_based_node_list.back().u ||
+ node_v != m_edge_based_node_list.back().v);
- BOOST_ASSERT(u != m_edge_based_node_list.back().v ||
- v != m_edge_based_node_list.back().u);
+ BOOST_ASSERT(node_u != m_edge_based_node_list.back().v ||
+ node_v != m_edge_based_node_list.back().u);
}
- BOOST_ASSERT(current_edge_source_coordinate_id == v);
+ BOOST_ASSERT(current_edge_source_coordinate_id == node_v);
BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
}
else
@@ -225,18 +224,20 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
BOOST_ASSERT(forward_data.edgeBasedNodeID != SPECIAL_NODEID ||
reverse_data.edgeBasedNodeID != SPECIAL_NODEID);
- m_edge_based_node_list.emplace_back(EdgeBasedNode(forward_data.edgeBasedNodeID,
- reverse_data.edgeBasedNodeID,
- u,
- v,
- forward_data.nameID,
- forward_data.distance,
- reverse_data.distance,
- 0,
- 0,
- SPECIAL_EDGEID,
- 0,
- belongs_to_tiny_cc));
+ 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());
}
}
@@ -289,61 +290,60 @@ void EdgeBasedGraphFactory::CompressGeometry()
const unsigned original_number_of_nodes = m_node_based_graph->GetNumberOfNodes();
const unsigned original_number_of_edges = m_node_based_graph->GetNumberOfEdges();
- Percent p(original_number_of_nodes);
- unsigned removed_node_count = 0;
+ Percent progress(original_number_of_nodes);
- for (NodeID v = 0; v < original_number_of_nodes; ++v)
+ for (const NodeID node_v : osrm::irange(0u, original_number_of_nodes))
{
- p.printStatus(v);
+ progress.printStatus(node_v);
// only contract degree 2 vertices
- if (2 != m_node_based_graph->GetOutDegree(v))
+ if (2 != m_node_based_graph->GetOutDegree(node_v))
{
continue;
}
// don't contract barrier node
- if (m_barrier_nodes.end() != m_barrier_nodes.find(v))
+ if (m_barrier_nodes.end() != m_barrier_nodes.find(node_v))
{
continue;
}
// check if v is a via node for a turn restriction, i.e. a 'directed' barrier node
- if (m_restriction_map->IsViaNode(v))
+ if (m_restriction_map->IsViaNode(node_v))
{
continue;
}
const bool reverse_edge_order =
- !(m_node_based_graph->GetEdgeData(m_node_based_graph->BeginEdges(v)).forward);
- const EdgeID forward_e2 = m_node_based_graph->BeginEdges(v) + reverse_edge_order;
+ !(m_node_based_graph->GetEdgeData(m_node_based_graph->BeginEdges(node_v)).forward);
+ const EdgeID forward_e2 = m_node_based_graph->BeginEdges(node_v) + reverse_edge_order;
BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
- const EdgeID reverse_e2 = m_node_based_graph->BeginEdges(v) + 1 - reverse_edge_order;
+ const EdgeID reverse_e2 = m_node_based_graph->BeginEdges(node_v) + 1 - reverse_edge_order;
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
const EdgeData &fwd_edge_data2 = m_node_based_graph->GetEdgeData(forward_e2);
const EdgeData &rev_edge_data2 = m_node_based_graph->GetEdgeData(reverse_e2);
- const NodeID w = m_node_based_graph->GetTarget(forward_e2);
- BOOST_ASSERT(SPECIAL_NODEID != w);
- BOOST_ASSERT(v != w);
- const NodeID u = m_node_based_graph->GetTarget(reverse_e2);
- BOOST_ASSERT(SPECIAL_NODEID != u);
- BOOST_ASSERT(u != v);
+ const NodeID node_w = m_node_based_graph->GetTarget(forward_e2);
+ BOOST_ASSERT(SPECIAL_NODEID != node_w);
+ BOOST_ASSERT(node_v != node_w);
+ const NodeID node_u = m_node_based_graph->GetTarget(reverse_e2);
+ BOOST_ASSERT(SPECIAL_NODEID != node_u);
+ BOOST_ASSERT(node_u != node_v);
- const EdgeID forward_e1 = m_node_based_graph->FindEdge(u, v);
- BOOST_ASSERT(m_node_based_graph->EndEdges(u) != forward_e1);
+ 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(v == m_node_based_graph->GetTarget(forward_e1));
- const EdgeID reverse_e1 = m_node_based_graph->FindEdge(w, v);
+ BOOST_ASSERT(node_v == m_node_based_graph->GetTarget(forward_e1));
+ const EdgeID reverse_e1 = m_node_based_graph->FindEdge(node_w, node_v);
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e1);
- BOOST_ASSERT(v == m_node_based_graph->GetTarget(reverse_e1));
+ BOOST_ASSERT(node_v == m_node_based_graph->GetTarget(reverse_e1));
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(u, w) != m_node_based_graph->EndEdges(u)) ||
- (m_node_based_graph->FindEdge(w, u) != m_node_based_graph->EndEdges(w)))
+ 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)))
{
continue;
}
@@ -366,7 +366,7 @@ void EdgeBasedGraphFactory::CompressGeometry()
BOOST_ASSERT(0 != forward_weight2);
const bool add_traffic_signal_penalty =
- (m_traffic_lights.find(v) != m_traffic_lights.end());
+ (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;
@@ -374,43 +374,47 @@ void EdgeBasedGraphFactory::CompressGeometry()
if (add_traffic_signal_penalty)
{
m_node_based_graph->GetEdgeData(forward_e1).distance +=
- speed_profile.trafficSignalPenalty;
+ speed_profile.traffic_signal_penalty;
m_node_based_graph->GetEdgeData(reverse_e1).distance +=
- speed_profile.trafficSignalPenalty;
+ speed_profile.traffic_signal_penalty;
}
// extend e1's to targets of e2's
- m_node_based_graph->SetTarget(forward_e1, w);
- m_node_based_graph->SetTarget(reverse_e1, u);
+ m_node_based_graph->SetTarget(forward_e1, node_w);
+ m_node_based_graph->SetTarget(reverse_e1, node_u);
// remove e2's (if bidir, otherwise only one)
- m_node_based_graph->DeleteEdge(v, forward_e2);
- m_node_based_graph->DeleteEdge(v, reverse_e2);
+ m_node_based_graph->DeleteEdge(node_v, forward_e2);
+ m_node_based_graph->DeleteEdge(node_v, reverse_e2);
// update any involved turn restrictions
- m_restriction_map->FixupStartingTurnRestriction(u, v, w);
- m_restriction_map->FixupArrivingTurnRestriction(u, v, w);
+ m_restriction_map->FixupStartingTurnRestriction(node_u, node_v, node_w);
+ m_restriction_map->FixupArrivingTurnRestriction(node_u, node_v,
+ node_w,
+ m_node_based_graph);
- m_restriction_map->FixupStartingTurnRestriction(w, v, u);
- m_restriction_map->FixupArrivingTurnRestriction(w, v, u);
+ m_restriction_map->FixupStartingTurnRestriction(node_w, node_v, node_u);
+ 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,
- v,
- w,
+ node_v,
+ node_w,
forward_weight1 +
- (add_traffic_signal_penalty ? speed_profile.trafficSignalPenalty : 0),
+ (add_traffic_signal_penalty ? speed_profile.traffic_signal_penalty : 0),
forward_weight2);
m_geometry_compressor.CompressEdge(
reverse_e1,
reverse_e2,
- v,
- u,
+ node_v,
+ node_u,
reverse_weight1,
reverse_weight2 +
- (add_traffic_signal_penalty ? speed_profile.trafficSignalPenalty : 0));
+ (add_traffic_signal_penalty ? speed_profile.traffic_signal_penalty : 0));
++removed_node_count;
BOOST_ASSERT(m_node_based_graph->GetEdgeData(forward_e1).nameID ==
@@ -422,7 +426,8 @@ void EdgeBasedGraphFactory::CompressGeometry()
unsigned new_node_count = 0;
unsigned new_edge_count = 0;
- for (unsigned i = 0; i < m_node_based_graph->GetNumberOfNodes(); ++i)
+
+ for(const auto i : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
if (m_node_based_graph->GetOutDegree(i) > 0)
{
@@ -438,16 +443,15 @@ void EdgeBasedGraphFactory::CompressGeometry()
}
/**
- * Writes the id of the edge in the edge expanded graph (into the egde in the node based graph)
+ * Writes the id of the edge in the edge expanded graph (into the edge in the node based graph)
*/
void EdgeBasedGraphFactory::RenumberEdges()
{
// renumber edge based node IDs
unsigned numbered_edges_count = 0;
- for (NodeID current_node = 0; current_node < m_node_based_graph->GetNumberOfNodes();
- ++current_node)
+ for (const auto current_node : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
- for (EdgeID current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
+ for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
{
EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
if (!edge_data.forward)
@@ -470,33 +474,31 @@ void EdgeBasedGraphFactory::RenumberEdges()
*/
void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
{
- SimpleLogger().Write() << "Identifying components of the road network";
+ SimpleLogger().Write() << "Identifying components of the (compressed) road network";
// Run a BFS on the undirected graph and identify small components
- BFSComponentExplorer<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.GetNumberOfComponents()
- << " many components";
+ 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
+ << " (compressed) SCCs of size 1";
SimpleLogger().Write() << "generating edge-expanded nodes";
- Percent p(m_node_based_graph->GetNumberOfNodes());
+ Percent progress(m_node_based_graph->GetNumberOfNodes());
// loop over all edges and generate new set of nodes
- for (NodeID u = 0, end = m_node_based_graph->GetNumberOfNodes(); u < end; ++u)
+ for (const auto u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
BOOST_ASSERT(u != SPECIAL_NODEID);
BOOST_ASSERT(u < m_node_based_graph->GetNumberOfNodes());
- p.printIncrement();
+ progress.printStatus(u);
for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
{
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
- if (edge_data.edgeBasedNodeID == SPECIAL_NODEID)
- {
- // continue;
- }
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
const NodeID v = m_node_based_graph->GetTarget(e1);
@@ -508,15 +510,30 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
}
BOOST_ASSERT(u < v);
- BOOST_ASSERT(edge_data.type != SHRT_MAX);
// 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.GetComponentSize(u),
- component_explorer.GetComponentSize(v));
+ const unsigned size_of_component = std::min(component_explorer.get_component_size(u),
+ component_explorer.get_component_size(v));
+
+ const unsigned id_of_smaller_component = [u,v,&component_explorer] {
+ if (component_explorer.get_component_size(u) < component_explorer.get_component_size(v))
+ {
+ return component_explorer.get_component_id(u);
+ }
+ return component_explorer.get_component_id(v);
+ }();
const bool component_is_tiny = (size_of_component < 1000);
- InsertEdgeBasedNode(u, v, e1, component_is_tiny);
+
+ if (edge_data.edgeBasedNodeID == SPECIAL_NODEID)
+ {
+ InsertEdgeBasedNode(v, u, (component_is_tiny ? id_of_smaller_component + 1 : 0));
+ }
+ else
+ {
+ InsertEdgeBasedNode(u, v, (component_is_tiny ? id_of_smaller_component + 1 : 0));
+ }
}
}
@@ -552,11 +569,12 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
unsigned skipped_barrier_turns_counter = 0;
unsigned compressed = 0;
- Percent p(m_node_based_graph->GetNumberOfNodes());
+ Percent progress(m_node_based_graph->GetNumberOfNodes());
- for (NodeID u = 0, end = m_node_based_graph->GetNumberOfNodes(); u < end; ++u)
+ for (const auto u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
- for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
+ progress.printStatus(u);
+ for (const EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
{
if (!m_node_based_graph->GetEdgeData(e1).forward)
{
@@ -569,7 +587,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
m_restriction_map->CheckForEmanatingIsOnlyTurn(u, v);
const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end());
- for (EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(v))
+ for (const EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(v))
{
if (!m_node_based_graph->GetEdgeData(e2).forward)
{
@@ -625,15 +643,27 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
unsigned distance = edge_data1.distance;
if (m_traffic_lights.find(v) != m_traffic_lights.end())
{
- distance += speed_profile.trafficSignalPenalty;
+ distance += speed_profile.traffic_signal_penalty;
}
- const double angle = GetAngleBetweenThreeFixedPointCoordinates(
- m_node_info_list[u], m_node_info_list[v], m_node_info_list[w]);
- const int turn_penalty = GetTurnPenalty(angle, lua_state);
- TurnInstruction turn_instruction = AnalyzeTurn(u, v, w, angle);
+
+ // 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)];
+
+ // 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 double turn_angle = ComputeAngle::OfThreeFixedPointCoordinates(
+ first_coordinate, m_node_info_list[v], third_coordinate);
+
+ const int turn_penalty = GetTurnPenalty(turn_angle, lua_state);
+ TurnInstruction turn_instruction = AnalyzeTurn(u, v, w, turn_angle);
if (turn_instruction == TurnInstruction::UTurn)
{
- distance += speed_profile.uTurnPenalty;
+ distance += speed_profile.u_turn_penalty;
}
distance += turn_penalty;
@@ -648,7 +678,8 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
(edge_is_compressed ? m_geometry_compressor.GetPositionForID(e1) : v),
edge_data1.nameID,
turn_instruction,
- edge_is_compressed);
+ edge_is_compressed,
+ edge_data2.travel_mode);
++original_edges_counter;
@@ -668,7 +699,6 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
false));
}
}
- p.printIncrement();
}
FlushVectorToStream(edge_data_file, original_edge_data_vector);
@@ -702,37 +732,28 @@ int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) co
return 0;
}
-TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u,
- const NodeID v,
- const NodeID w,
- double angle)
+TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID node_u,
+ const NodeID node_v,
+ const NodeID node_w,
+ const double angle)
const
{
- if (u == w)
+ if (node_u == node_w)
{
return TurnInstruction::UTurn;
}
- const EdgeID edge1 = m_node_based_graph->FindEdge(u, v);
- const EdgeID edge2 = m_node_based_graph->FindEdge(v, w);
+ const EdgeID edge1 = m_node_based_graph->FindEdge(node_u, node_v);
+ const EdgeID edge2 = m_node_based_graph->FindEdge(node_v, node_w);
const EdgeData &data1 = m_node_based_graph->GetEdgeData(edge1);
const EdgeData &data2 = m_node_based_graph->GetEdgeData(edge2);
- if (!data1.contraFlow && data2.contraFlow)
- {
- return TurnInstruction::EnterAgainstAllowedDirection;
- }
- if (data1.contraFlow && !data2.contraFlow)
- {
- return TurnInstruction::LeaveAgainstAllowedDirection;
- }
-
// roundabouts need to be handled explicitely
if (data1.roundabout && data2.roundabout)
{
// Is a turn possible? If yes, we stay on the roundabout!
- if (1 == m_node_based_graph->GetDirectedOutDegree(v))
+ if (1 == m_node_based_graph->GetDirectedOutDegree(node_v))
{
// No turn possible.
return TurnInstruction::NoTurn;
@@ -760,11 +781,7 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u,
{
// TODO: Here we should also do a small graph exploration to check for
// more complex situations
- if (0 != data1.nameID)
- {
- return TurnInstruction::NoTurn;
- }
- else if (m_node_based_graph->GetOutDegree(v) <= 2)
+ if (0 != data1.nameID || m_node_based_graph->GetOutDegree(node_v) <= 2)
{
return TurnInstruction::NoTurn;
}
diff --git a/Contractor/EdgeBasedGraphFactory.h b/contractor/edge_based_graph_factory.hpp
similarity index 76%
rename from Contractor/EdgeBasedGraphFactory.h
rename to contractor/edge_based_graph_factory.hpp
index cf489c5..95b65ba 100644
--- a/Contractor/EdgeBasedGraphFactory.h
+++ b/contractor/edge_based_graph_factory.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -27,18 +27,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This class constructs the edge-expanded routing graph
-#ifndef EDGEBASEDGRAPHFACTORY_H_
-#define EDGEBASEDGRAPHFACTORY_H_
+#ifndef EDGE_BASED_GRAPH_FACTORY_HPP_
+#define EDGE_BASED_GRAPH_FACTORY_HPP_
+#include "geometry_compressor.hpp"
#include "../typedefs.h"
-#include "../DataStructures/DeallocatingVector.h"
-#include "../DataStructures/EdgeBasedNode.h"
-#include "../DataStructures/OriginalEdgeData.h"
-#include "../DataStructures/QueryNode.h"
-#include "../DataStructures/TurnInstructions.h"
-#include "../DataStructures/NodeBasedGraph.h"
-#include "../DataStructures/RestrictionMap.h"
-#include "GeometryCompressor.h"
+#include "../data_structures/deallocating_vector.hpp"
+#include "../data_structures/edge_based_node.hpp"
+#include "../data_structures/original_edge_data.hpp"
+#include "../data_structures/query_node.hpp"
+#include "../data_structures/turn_instructions.hpp"
+#include "../data_structures/node_based_graph.hpp"
+#include "../data_structures/restriction_map.hpp"
#include <algorithm>
#include <iosfwd>
@@ -63,7 +63,7 @@ class EdgeBasedGraphFactory
std::unique_ptr<RestrictionMap> restricion_map,
std::vector<NodeID> &barrier_node_list,
std::vector<NodeID> &traffic_light_node_list,
- std::vector<NodeInfo> &m_node_info_list,
+ std::vector<QueryNode> &node_info_list,
SpeedProfileProperties &speed_profile);
void Run(const std::string &original_edge_data_filename,
@@ -74,7 +74,7 @@ class EdgeBasedGraphFactory
void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes);
- TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, double angle) const;
+ TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, const double angle) const;
int GetTurnPenalty(double angle, lua_State *lua_state) const;
@@ -83,21 +83,21 @@ class EdgeBasedGraphFactory
struct SpeedProfileProperties
{
SpeedProfileProperties()
- : trafficSignalPenalty(0), uTurnPenalty(0), has_turn_penalty_function(false)
+ : traffic_signal_penalty(0), u_turn_penalty(0), has_turn_penalty_function(false)
{
}
- int trafficSignalPenalty;
- int uTurnPenalty;
+ int traffic_signal_penalty;
+ int u_turn_penalty;
bool has_turn_penalty_function;
} speed_profile;
private:
- typedef NodeBasedDynamicGraph::EdgeData EdgeData;
+ using EdgeData = NodeBasedDynamicGraph::EdgeData;
unsigned m_number_of_edge_based_nodes;
- std::vector<NodeInfo> m_node_info_list;
+ std::vector<QueryNode> m_node_info_list;
std::vector<EdgeBasedNode> m_edge_based_node_list;
DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
@@ -115,12 +115,14 @@ class EdgeBasedGraphFactory
void GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
lua_State *lua_state);
- void InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool belongsToTinyComponent);
+ void InsertEdgeBasedNode(const NodeID u, const NodeID v, const unsigned component_id);
void FlushVectorToStream(std::ofstream &edge_data_file,
std::vector<OriginalEdgeData> &original_edge_data_vector) const;
- unsigned max_id;
+ NodeID max_id;
+ std::size_t removed_node_count;
+
};
-#endif /* EDGEBASEDGRAPHFACTORY_H_ */
+#endif /* EDGE_BASED_GRAPH_FACTORY_HPP_ */
diff --git a/Contractor/GeometryCompressor.cpp b/contractor/geometry_compressor.cpp
similarity index 93%
rename from Contractor/GeometryCompressor.cpp
rename to contractor/geometry_compressor.cpp
index 7c51910..9458c44 100644
--- a/Contractor/GeometryCompressor.cpp
+++ b/contractor/geometry_compressor.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
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.
*/
-#include "GeometryCompressor.h"
-#include "../Util/SimpleLogger.h"
+#include "geometry_compressor.hpp"
+#include "../Util/simple_logger.hpp"
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
@@ -225,3 +225,17 @@ GeometryCompressor::GetBucketReference(const EdgeID edge_id) const
const unsigned index = m_edge_id_to_list_index_map.at(edge_id);
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;
+ }
+
diff --git a/Contractor/GeometryCompressor.h b/contractor/geometry_compressor.hpp
similarity index 86%
copy from Contractor/GeometryCompressor.h
copy to contractor/geometry_compressor.hpp
index 7c4fba4..dd5748d 100644
--- a/Contractor/GeometryCompressor.h
+++ b/contractor/geometry_compressor.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,6 +25,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifndef GEOMETRY_COMPRESSOR_HPP_
+#define GEOMETRY_COMPRESSOR_HPP_
+
#include "../typedefs.h"
#include <unordered_map>
@@ -32,13 +35,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
#include <vector>
-#ifndef GEOMETRY_COMPRESSOR_H
-#define GEOMETRY_COMPRESSOR_H
-
class GeometryCompressor
{
public:
- typedef std::pair<NodeID, EdgeWeight> CompressedNode;
+ using CompressedNode = std::pair<NodeID, EdgeWeight>;
GeometryCompressor();
void CompressEdge(const EdgeID surviving_edge_id,
@@ -54,6 +54,8 @@ class GeometryCompressor
unsigned GetPositionForID(const EdgeID edge_id) const;
const std::vector<GeometryCompressor::CompressedNode> &
GetBucketReference(const EdgeID edge_id) const;
+ NodeID GetFirstNodeIDOfBucket(const EdgeID edge_id) const;
+ NodeID GetLastNodeIDOfBucket(const EdgeID edge_id) const;
private:
void IncreaseFreeList();
@@ -62,4 +64,4 @@ class GeometryCompressor
std::unordered_map<EdgeID, unsigned> m_edge_id_to_list_index_map;
};
-#endif // GEOMETRY_COMPRESSOR_H
+#endif // GEOMETRY_COMPRESSOR_HPP_
diff --git a/contractor/processing_chain.cpp b/contractor/processing_chain.cpp
new file mode 100644
index 0000000..23d406b
--- /dev/null
+++ b/contractor/processing_chain.cpp
@@ -0,0 +1,581 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "processing_chain.hpp"
+
+#include "contractor.hpp"
+
+#include "../algorithms/crc32_processor.hpp"
+#include "../data_structures/deallocating_vector.hpp"
+#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 "../typedefs.h"
+
+#include <boost/filesystem/fstream.hpp>
+#include <boost/program_options.hpp>
+
+#include <tbb/task_scheduler_init.h>
+#include <tbb/parallel_sort.h>
+
+#include <chrono>
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+Prepare::Prepare() : requested_num_threads(1) {}
+
+Prepare::~Prepare() {}
+
+int Prepare::Process(int argc, char *argv[])
+{
+ LogPolicy::GetInstance().Unmute();
+ TIMER_START(preparing);
+ TIMER_START(expansion);
+
+ if (!ParseArguments(argc, argv))
+ {
+ return 0;
+ }
+ if (!boost::filesystem::is_regular_file(input_path))
+ {
+ SimpleLogger().Write(logWARNING) << "Input file " << input_path.string() << " not found!";
+ return 1;
+ }
+
+ if (!boost::filesystem::is_regular_file(profile_path))
+ {
+ SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string() << " not found!";
+ return 1;
+ }
+
+ if (1 > requested_num_threads)
+ {
+ SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
+ return 1;
+ }
+
+ const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
+
+ SimpleLogger().Write() << "Input file: " << input_path.filename().string();
+ SimpleLogger().Write() << "Restrictions file: " << restrictions_path.filename().string();
+ SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
+ SimpleLogger().Write() << "Threads: " << requested_num_threads;
+ if (recommended_num_threads != requested_num_threads)
+ {
+ SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
+ << recommended_num_threads
+ << "! This setting may have performance side-effects.";
+ }
+
+ tbb::task_scheduler_init init(requested_num_threads);
+
+ LogPolicy::GetInstance().Unmute();
+
+ FingerPrint fingerprint_orig;
+ CheckRestrictionsFile(fingerprint_orig);
+
+ boost::filesystem::ifstream input_stream(input_path, std::ios::in | std::ios::binary);
+
+ node_filename = input_path.string() + ".nodes";
+ edge_out = input_path.string() + ".edges";
+ geometry_filename = input_path.string() + ".geometry";
+ graph_out = input_path.string() + ".hsgr";
+ rtree_nodes_path = input_path.string() + ".ramIndex";
+ rtree_leafs_path = input_path.string() + ".fileIndex";
+
+ /*** Setup Scripting Environment ***/
+ // Create a new lua state
+ lua_State *lua_state = luaL_newstate();
+
+ // Connect LuaBind to this lua state
+ luabind::open(lua_state);
+
+ EdgeBasedGraphFactory::SpeedProfileProperties speed_profile;
+
+ if (!SetupScriptingEnvironment(lua_state, speed_profile))
+ {
+ return 1;
+ }
+
+#ifdef WIN32
+#pragma message("Memory consumption on Windows can be higher due to different bit packing")
+#else
+ 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);
+ input_stream.close();
+
+ if (edge_list.empty())
+ {
+ SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
+ return 1;
+ }
+
+ SimpleLogger().Write() << restriction_list.size() << " restrictions, "
+ << barrier_node_list.size() << " bollard nodes, "
+ << traffic_light_list.size() << " traffic lights";
+
+ std::vector<EdgeBasedNode> node_based_edge_list;
+ unsigned number_of_edge_based_nodes = 0;
+ 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);
+ lua_close(lua_state);
+
+ TIMER_STOP(expansion);
+
+ BuildRTree(node_based_edge_list);
+
+ RangebasedCRC32 crc32;
+ if (crc32.using_hardware())
+ {
+ SimpleLogger().Write() << "using hardware based CRC32 computation";
+ }
+ else
+ {
+ SimpleLogger().Write() << "using software based CRC32 computation";
+ }
+
+ const unsigned crc32_value = crc32(node_based_edge_list);
+ node_based_edge_list.clear();
+ node_based_edge_list.shrink_to_fit();
+ SimpleLogger().Write() << "CRC32: " << crc32_value;
+
+ WriteNodeMapping();
+
+ /***
+ * Contracting the edge-expanded graph
+ */
+
+ SimpleLogger().Write() << "initializing contractor";
+ auto contractor =
+ osrm::make_unique<Contractor>(number_of_edge_based_nodes, edge_based_edge_list);
+
+ TIMER_START(contraction);
+ contractor->Run();
+ TIMER_STOP(contraction);
+
+ SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
+
+ DeallocatingVector<QueryEdge> contracted_edge_list;
+ contractor->GetEdges(contracted_edge_list);
+ contractor.reset();
+
+ /***
+ * Sorting contracted edges in a way that the static query graph can read some in in-place.
+ */
+
+ tbb::parallel_sort(contracted_edge_list.begin(), contracted_edge_list.end());
+ const unsigned contracted_edge_count = contracted_edge_list.size();
+ SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
+ << " edges";
+
+ boost::filesystem::ofstream hsgr_output_stream(graph_out, std::ios::binary);
+ hsgr_output_stream.write((char *)&fingerprint_orig, sizeof(FingerPrint));
+ const unsigned max_used_node_id = 1 + [&contracted_edge_list]
+ {
+ unsigned tmp_max = 0;
+ for (const QueryEdge &edge : contracted_edge_list)
+ {
+ BOOST_ASSERT(SPECIAL_NODEID != edge.source);
+ BOOST_ASSERT(SPECIAL_NODEID != edge.target);
+ tmp_max = std::max(tmp_max, edge.source);
+ tmp_max = std::max(tmp_max, edge.target);
+ }
+ return tmp_max;
+ }();
+
+ SimpleLogger().Write(logDEBUG) << "input graph has " << number_of_edge_based_nodes << " nodes";
+ SimpleLogger().Write(logDEBUG) << "contracted graph has " << max_used_node_id << " nodes";
+
+ std::vector<StaticGraph<EdgeData>::NodeArrayEntry> node_array;
+ node_array.resize(number_of_edge_based_nodes + 1);
+
+ SimpleLogger().Write() << "Building node array";
+ StaticGraph<EdgeData>::EdgeIterator edge = 0;
+ StaticGraph<EdgeData>::EdgeIterator position = 0;
+ StaticGraph<EdgeData>::EdgeIterator last_edge = edge;
+
+ // initializing 'first_edge'-field of nodes:
+ for (const auto node : osrm::irange(0u, max_used_node_id))
+ {
+ last_edge = edge;
+ while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node))
+ {
+ ++edge;
+ }
+ node_array[node].first_edge = position; //=edge
+ position += edge - last_edge; // remove
+ }
+
+ for (const auto sentinel_counter : osrm::irange<unsigned>(max_used_node_id, node_array.size()))
+ {
+ // sentinel element, guarded against underflow
+ node_array[sentinel_counter].first_edge = contracted_edge_count;
+ }
+
+ SimpleLogger().Write() << "Serializing node array";
+
+ const unsigned node_array_size = node_array.size();
+ // serialize crc32, aka checksum
+ hsgr_output_stream.write((char *)&crc32_value, sizeof(unsigned));
+ // serialize number of nodes
+ hsgr_output_stream.write((char *)&node_array_size, sizeof(unsigned));
+ // serialize number of edges
+ hsgr_output_stream.write((char *)&contracted_edge_count, sizeof(unsigned));
+ // serialize all nodes
+ if (node_array_size > 0)
+ {
+ hsgr_output_stream.write((char *)&node_array[0],
+ sizeof(StaticGraph<EdgeData>::NodeArrayEntry) * node_array_size);
+ }
+ // serialize all edges
+
+ SimpleLogger().Write() << "Building edge array";
+ edge = 0;
+ int number_of_used_edges = 0;
+
+ StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
+ for (const auto edge : osrm::irange<std::size_t>(0, contracted_edge_list.size()))
+ {
+ // no eigen loops
+ BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target);
+ current_edge.target = contracted_edge_list[edge].target;
+ current_edge.data = contracted_edge_list[edge].data;
+
+ // every target needs to be valid
+ BOOST_ASSERT(current_edge.target < max_used_node_id);
+#ifndef NDEBUG
+ if (current_edge.data.distance <= 0)
+ {
+ SimpleLogger().Write(logWARNING) << "Edge: " << edge
+ << ",source: " << contracted_edge_list[edge].source
+ << ", target: " << contracted_edge_list[edge].target
+ << ", dist: " << current_edge.data.distance;
+
+ SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node "
+ << contracted_edge_list[edge].source << "/"
+ << node_array.size() - 1;
+ return 1;
+ }
+#endif
+ hsgr_output_stream.write((char *)¤t_edge,
+ sizeof(StaticGraph<EdgeData>::EdgeArrayEntry));
+
+ ++number_of_used_edges;
+ }
+ hsgr_output_stream.close();
+
+ TIMER_STOP(preparing);
+
+ SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
+ SimpleLogger().Write() << "Expansion : " << (number_of_node_based_nodes / TIMER_SEC(expansion))
+ << " nodes/sec and "
+ << (number_of_edge_based_nodes / TIMER_SEC(expansion)) << " edges/sec";
+
+ SimpleLogger().Write() << "Contraction: "
+ << (number_of_edge_based_nodes / TIMER_SEC(contraction))
+ << " nodes/sec and " << number_of_used_edges / TIMER_SEC(contraction)
+ << " edges/sec";
+
+ node_array.clear();
+ SimpleLogger().Write() << "finished preprocessing";
+
+ return 0;
+}
+
+/**
+ \brief Parses command line arguments
+ \param argc count of arguments
+ \param argv array of arguments
+ \param result [out] value for exit return value
+ \return true if everything is ok, false if need to terminate execution
+*/
+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"),
+ "Path to a configuration file.");
+
+ // declare a group of options that will be allowed both on command line and in config file
+ boost::program_options::options_description config_options("Configuration");
+ config_options.add_options()(
+ "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"),
+ "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()),
+ "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 file in .osm, .osm.bz2 or .osm.pbf format");
+
+ // positional option
+ boost::program_options::positional_options_description positional_options;
+ positional_options.add("input", 1);
+
+ // combine above options for parsing
+ boost::program_options::options_description cmdline_options;
+ cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+
+ boost::program_options::options_description config_file_options;
+ config_file_options.add(config_options).add(hidden_options);
+
+ boost::program_options::options_description visible_options(
+ "Usage: " + boost::filesystem::basename(argv[0]) + " <input.osrm> [options]");
+ visible_options.add(generic_options).add(config_options);
+
+ // parse command line options
+ boost::program_options::variables_map option_variables;
+ boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
+ .options(cmdline_options)
+ .positional(positional_options)
+ .run(),
+ option_variables);
+
+ const auto& temp_config_path = option_variables["config"].as<boost::filesystem::path>();
+ if (boost::filesystem::is_regular_file(temp_config_path))
+ {
+ boost::program_options::store(boost::program_options::parse_config_file<char>(temp_config_path.string().c_str(), cmdline_options, true),
+ option_variables);
+ }
+
+ if (option_variables.count("version"))
+ {
+ SimpleLogger().Write() << g_GIT_DESCRIPTION;
+ return false;
+ }
+
+ if (option_variables.count("help"))
+ {
+ SimpleLogger().Write() << "\n" << visible_options;
+ return false;
+ }
+
+ boost::program_options::notify(option_variables);
+
+ if (!option_variables.count("restrictions"))
+ {
+ restrictions_path = std::string(input_path.string() + ".restrictions");
+ }
+
+ if (!option_variables.count("input"))
+ {
+ SimpleLogger().Write() << "\n" << visible_options;
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ \brief Loads and checks file UUIDs
+*/
+void Prepare::CheckRestrictionsFile(FingerPrint &fingerprint_orig)
+{
+ boost::filesystem::ifstream restriction_stream(restrictions_path, std::ios::binary);
+ FingerPrint fingerprint_loaded;
+ unsigned number_of_usable_restrictions = 0;
+ restriction_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
+ if (!fingerprint_loaded.TestPrepare(fingerprint_orig))
+ {
+ SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n"
+ "Reprocess to get rid of this warning.";
+ }
+
+ restriction_stream.read((char *)&number_of_usable_restrictions, sizeof(unsigned));
+ restriction_list.resize(number_of_usable_restrictions);
+ if (number_of_usable_restrictions > 0)
+ {
+ restriction_stream.read((char *)&(restriction_list[0]),
+ number_of_usable_restrictions * sizeof(TurnRestriction));
+ }
+ restriction_stream.close();
+}
+
+/**
+ \brief Setups scripting environment (lua-scripting)
+ Also initializes speed profile.
+*/
+bool
+Prepare::SetupScriptingEnvironment(lua_State *lua_state,
+ EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile)
+{
+ // open utility libraries string library;
+ luaL_openlibs(lua_state);
+
+ // adjust lua load path
+ luaAddScriptFolderToLoadPath(lua_state, profile_path.string().c_str());
+
+ // Now call our function in a lua script
+ if (0 != luaL_dofile(lua_state, profile_path.string().c_str()))
+ {
+ std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
+ return false;
+ }
+
+ if (0 != luaL_dostring(lua_state, "return traffic_signal_penalty\n"))
+ {
+ std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
+ return false;
+ }
+ speed_profile.traffic_signal_penalty = 10 * lua_tointeger(lua_state, -1);
+ SimpleLogger().Write(logDEBUG)
+ << "traffic_signal_penalty: " << speed_profile.traffic_signal_penalty;
+
+ if (0 != luaL_dostring(lua_state, "return u_turn_penalty\n"))
+ {
+ std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
+ return false;
+ }
+
+ speed_profile.u_turn_penalty = 10 * lua_tointeger(lua_state, -1);
+ speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function");
+
+ return true;
+}
+
+/**
+ \brief Building an edge-expanded graph from node-based input and turn restrictions
+*/
+std::size_t
+Prepare::BuildEdgeExpandedGraph(lua_State *lua_state,
+ NodeID number_of_node_based_nodes,
+ std::vector<EdgeBasedNode> &node_based_edge_list,
+ DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
+ EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile)
+{
+ 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::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);
+ edge_list.clear();
+ edge_list.shrink_to_fit();
+
+ edge_based_graph_factory->Run(edge_out, geometry_filename, lua_state);
+
+ restriction_list.clear();
+ restriction_list.shrink_to_fit();
+ barrier_node_list.clear();
+ barrier_node_list.shrink_to_fit();
+ traffic_light_list.clear();
+ traffic_light_list.shrink_to_fit();
+
+ const std::size_t number_of_edge_based_nodes =
+ edge_based_graph_factory->GetNumberOfEdgeBasedNodes();
+
+ BOOST_ASSERT(number_of_edge_based_nodes != std::numeric_limits<unsigned>::max());
+#ifndef WIN32
+ static_assert(sizeof(EdgeBasedEdge) == 16,
+ "changing ImportEdge type has influence on memory consumption!");
+#endif
+
+ edge_based_graph_factory->GetEdgeBasedEdges(edge_based_edge_list);
+ edge_based_graph_factory->GetEdgeBasedNodes(node_based_edge_list);
+
+ edge_based_graph_factory.reset();
+ node_based_graph.reset();
+
+ return number_of_edge_based_nodes;
+}
+
+/**
+ \brief Writing info on original (node-based) nodes
+ */
+void Prepare::WriteNodeMapping()
+{
+ SimpleLogger().Write() << "writing node map ...";
+ boost::filesystem::ofstream node_stream(node_filename, std::ios::binary);
+ const unsigned size_of_mapping = internal_to_external_node_map.size();
+ node_stream.write((char *)&size_of_mapping, sizeof(unsigned));
+ if (size_of_mapping > 0)
+ {
+ node_stream.write((char *)&(internal_to_external_node_map[0]),
+ size_of_mapping * sizeof(QueryNode));
+ }
+ node_stream.close();
+ internal_to_external_node_map.clear();
+ internal_to_external_node_map.shrink_to_fit();
+}
+
+/**
+ \brief Building rtree-based nearest-neighbor data structure
+
+ Saves info to files: '.ramIndex' and '.fileIndex'.
+ */
+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);
+}
diff --git a/contractor/processing_chain.hpp b/contractor/processing_chain.hpp
new file mode 100644
index 0000000..933213a
--- /dev/null
+++ b/contractor/processing_chain.hpp
@@ -0,0 +1,95 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef PROCESSING_CHAIN_HPP
+#define PROCESSING_CHAIN_HPP
+
+#include "edge_based_graph_factory.hpp"
+#include "../data_structures/query_edge.hpp"
+#include "../data_structures/static_graph.hpp"
+
+class FingerPrint;
+struct EdgeBasedNode;
+struct lua_State;
+
+#include <boost/filesystem.hpp>
+
+#include <vector>
+
+/**
+ \brief class of 'prepare' utility.
+ */
+class Prepare
+{
+ public:
+ using EdgeData = QueryEdge::EdgeData;
+ using InputEdge = DynamicGraph<EdgeData>::InputEdge;
+ using StaticEdge = StaticGraph<EdgeData>::InputEdge;
+
+ explicit Prepare();
+ Prepare(const Prepare &) = delete;
+ ~Prepare();
+
+ int Process(int argc, char *argv[]);
+
+ protected:
+ bool ParseArguments(int argc, char *argv[]);
+ void CheckRestrictionsFile(FingerPrint &fingerprint_orig);
+ bool SetupScriptingEnvironment(lua_State *myLuaState,
+ EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile);
+ std::size_t BuildEdgeExpandedGraph(lua_State *myLuaState,
+ NodeID nodeBasedNodeNumber,
+ std::vector<EdgeBasedNode> &nodeBasedEdgeList,
+ DeallocatingVector<EdgeBasedEdge> &edgeBasedEdgeList,
+ EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile);
+ void WriteNodeMapping();
+ void BuildRTree(std::vector<EdgeBasedNode> &node_based_edge_list);
+
+ private:
+ std::vector<QueryNode> internal_to_external_node_map;
+ std::vector<TurnRestriction> restriction_list;
+ std::vector<NodeID> barrier_node_list;
+ std::vector<NodeID> traffic_light_list;
+ std::vector<ImportEdge> edge_list;
+
+ unsigned requested_num_threads;
+ boost::filesystem::path config_file_path;
+ boost::filesystem::path input_path;
+ boost::filesystem::path restrictions_path;
+ boost::filesystem::path preinfo_path;
+ boost::filesystem::path profile_path;
+
+ std::string node_filename;
+ std::string edge_out;
+ std::string info_out;
+ std::string geometry_filename;
+ std::string graph_out;
+ std::string rtree_nodes_path;
+ std::string rtree_leafs_path;
+};
+
+#endif // PROCESSING_CHAIN_HPP
diff --git a/DataStructures/Coordinate.cpp b/data_structures/Coordinate.cpp
similarity index 80%
rename from DataStructures/Coordinate.cpp
rename to data_structures/Coordinate.cpp
index 9c453e7..4305256 100644
--- a/DataStructures/Coordinate.cpp
+++ b/data_structures/Coordinate.cpp
@@ -27,8 +27,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <osrm/Coordinate.h>
#include "../Util/MercatorUtil.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/StringUtil.h"
+#ifndef NDEBUG
+#include "../Util/simple_logger.hpp"
+#endif
+#include "../Util/string_util.hpp"
#include <boost/assert.hpp>
@@ -70,7 +72,7 @@ bool FixedPointCoordinate::isSet() const
{
return (std::numeric_limits<int>::min() != lat) && (std::numeric_limits<int>::min() != lon);
}
-bool FixedPointCoordinate::isValid() const
+bool FixedPointCoordinate::is_valid() const
{
if (lat > 90 * COORDINATE_PRECISION || lat < -90 * COORDINATE_PRECISION ||
lon > 180 * COORDINATE_PRECISION || lon < -180 * COORDINATE_PRECISION)
@@ -157,12 +159,12 @@ FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &s
const FixedPointCoordinate &point)
{
// initialize values
- const float x_value = lat2y(point.lat / COORDINATE_PRECISION);
+ const float x_value = static_cast<float>(lat2y(point.lat / COORDINATE_PRECISION));
const float y_value = point.lon / COORDINATE_PRECISION;
- const float a = lat2y(source_coordinate.lat / COORDINATE_PRECISION);
- const float b = source_coordinate.lon / COORDINATE_PRECISION;
- const float c = lat2y(target_coordinate.lat / COORDINATE_PRECISION);
- const float d = target_coordinate.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())
{
@@ -178,15 +180,36 @@ FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &s
q = y_value;
}
- 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))
+ 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())
{
- nY = 0.f;
+ 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;
}
- // compute ratio
- float ratio = (p - nY * a) / c;
if (std::isnan(ratio))
{
ratio = (target_coordinate == point ? 1.f : 0.f);
@@ -200,7 +223,13 @@ FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &s
ratio = 1.f;
}
- //compute the nearest location
+ // 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)
@@ -216,7 +245,8 @@ FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &s
nearest_location.lat = static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
}
- BOOST_ASSERT(nearest_location.isValid());
+
+ BOOST_ASSERT(nearest_location.is_valid());
return FixedPointCoordinate::ApproximateEuclideanDistance(point, nearest_location);
}
@@ -226,19 +256,19 @@ float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordin
FixedPointCoordinate &nearest_location,
float &ratio)
{
- BOOST_ASSERT(query_location.isValid());
+ BOOST_ASSERT(query_location.is_valid());
// initialize values
- const float x = lat2y(query_location.lat / COORDINATE_PRECISION);
- const float y = query_location.lon / COORDINATE_PRECISION;
- const float a = lat2y(segment_source.lat / COORDINATE_PRECISION);
- const float b = segment_source.lon / COORDINATE_PRECISION;
- const float c = lat2y(segment_target.lat / COORDINATE_PRECISION);
- const float d = segment_target.lon / COORDINATE_PRECISION;
- float p, q /*,mX*/, nY;
- if (std::abs(a - c) > std::numeric_limits<float>::epsilon())
+ 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 float m = (d - b) / (c - a); // slope
+ 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);
@@ -264,11 +294,11 @@ float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordin
{
ratio = (segment_target == query_location ? 1.f : 0.f);
}
- else if (std::abs(ratio) <= std::numeric_limits<float>::epsilon())
+ else if (std::abs(ratio) <= std::numeric_limits<double>::epsilon())
{
- ratio = 0.;
+ ratio = 0.f;
}
- else if (std::abs(ratio - 1.f) <= std::numeric_limits<float>::epsilon())
+ else if (std::abs(ratio - 1.f) <= std::numeric_limits<double>::epsilon())
{
ratio = 1.f;
}
@@ -279,7 +309,7 @@ float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordin
{
nearest_location = segment_source;
}
- else if (ratio >= 1.)
+ else if (ratio >= 1.f)
{
nearest_location = segment_target;
}
@@ -289,7 +319,7 @@ float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordin
nearest_location.lat = static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
}
- BOOST_ASSERT(nearest_location.isValid());
+ BOOST_ASSERT(nearest_location.is_valid());
const float approximate_distance =
FixedPointCoordinate::ApproximateEuclideanDistance(query_location, nearest_location);
@@ -337,7 +367,8 @@ void FixedPointCoordinate::Output(std::ostream &out) const
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_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);
@@ -379,9 +410,15 @@ float FixedPointCoordinate::GetBearing(const FixedPointCoordinate &other) const
return result;
}
-float FixedPointCoordinate::DegreeToRadian(const float degree) { return degree * (static_cast<float>(M_PI) / 180.f); }
+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)); }
+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).
@@ -392,11 +429,11 @@ int FixedPointCoordinate::OrderedPerpendicularDistanceApproximation(
const FixedPointCoordinate &segment_target)
{
// initialize values
- const float x = lat2y(input_point.lat / COORDINATE_PRECISION);
+ const float x = static_cast<float>(lat2y(input_point.lat / COORDINATE_PRECISION));
const float y = input_point.lon / COORDINATE_PRECISION;
- const float a = lat2y(segment_source.lat / 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 = lat2y(segment_target.lat / 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;
diff --git a/DataStructures/InputReaderFactory.h b/data_structures/InputReaderFactory.h
similarity index 100%
rename from DataStructures/InputReaderFactory.h
rename to data_structures/InputReaderFactory.h
diff --git a/DataStructures/BinaryHeap.h b/data_structures/binary_heap.hpp
similarity index 98%
rename from DataStructures/BinaryHeap.h
rename to data_structures/binary_heap.hpp
index 00d3782..049f12f 100644
--- a/DataStructures/BinaryHeap.h
+++ b/data_structures/binary_heap.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -36,6 +36,7 @@ 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
{
@@ -99,8 +100,8 @@ class BinaryHeap
void operator=(const BinaryHeap &right);
public:
- typedef Weight WeightType;
- typedef Data DataType;
+ using WeightType = Weight;
+ using DataType = Data;
explicit BinaryHeap(size_t maxID) : node_index(maxID) { Clear(); }
diff --git a/DataStructures/ConcurrentQueue.h b/data_structures/concurrent_queue.hpp
similarity index 94%
rename from DataStructures/ConcurrentQueue.h
rename to data_structures/concurrent_queue.hpp
index 9d5b366..b3d4e1a 100644
--- a/DataStructures/ConcurrentQueue.h
+++ b/data_structures/concurrent_queue.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,10 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CONCURRENT_QUEUE_H
-#define CONCURRENT_QUEUE_H
-
-#include "../typedefs.h"
+#ifndef CONCURRENT_QUEUE_HPP
+#define CONCURRENT_QUEUE_HPP
#include <boost/circular_buffer.hpp>
#include <condition_variable>
@@ -82,4 +80,4 @@ template <typename Data> class ConcurrentQueue
std::condition_variable m_not_full;
};
-#endif // CONCURRENT_QUEUE_H
+#endif // CONCURRENT_QUEUE_HPP
diff --git a/data_structures/deallocating_vector.hpp b/data_structures/deallocating_vector.hpp
new file mode 100644
index 0000000..415fa69
--- /dev/null
+++ b/data_structures/deallocating_vector.hpp
@@ -0,0 +1,313 @@
+/*
+
+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 DEALLOCATINGVECTOR_H_
+#define DEALLOCATINGVECTOR_H_
+
+#include "../Util/integer_range.hpp"
+
+#include <boost/iterator/iterator_facade.hpp>
+
+#include <utility>
+#include <vector>
+
+template <typename ElementT> struct DeallocatingVectorIteratorState
+{
+ DeallocatingVectorIteratorState() : index(-1), bucket_list(nullptr) {}
+ explicit DeallocatingVectorIteratorState(const DeallocatingVectorIteratorState &r)
+ : index(r.index), bucket_list(r.bucket_list)
+ {
+ }
+ explicit DeallocatingVectorIteratorState(const std::size_t idx,
+ std::vector<ElementT *> *input_list)
+ : index(idx), bucket_list(input_list)
+ {
+ }
+ std::size_t index;
+ std::vector<ElementT *> *bucket_list;
+
+ inline DeallocatingVectorIteratorState &operator=(const DeallocatingVectorIteratorState &other)
+ {
+ index = other.index;
+ bucket_list = other.bucket_list;
+ return *this;
+ }
+};
+
+template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK>
+class DeallocatingVectorIterator
+ : public boost::iterator_facade<DeallocatingVectorIterator<ElementT, ELEMENTS_PER_BLOCK>,
+ ElementT,
+ std::random_access_iterator_tag>
+{
+ DeallocatingVectorIteratorState<ElementT> current_state;
+
+ public:
+ DeallocatingVectorIterator() {}
+ DeallocatingVectorIterator(std::size_t idx, std::vector<ElementT *> *input_list)
+ : current_state(idx, input_list)
+ {
+ }
+
+ friend class boost::iterator_core_access;
+
+ void advance(std::size_t n) { current_state.index += n; }
+
+ void increment() { advance(1); }
+
+ void decrement() { advance(-1); }
+
+ bool equal(DeallocatingVectorIterator const &other) const
+ {
+ return current_state.index == other.current_state.index;
+ }
+
+ std::ptrdiff_t distance_to(DeallocatingVectorIterator const &other) const
+ {
+ // it is important to implement it 'other minus this'. otherwise sorting breaks
+ return other.current_state.index - current_state.index;
+ }
+
+ ElementT &dereference() const
+ {
+ const std::size_t current_bucket = current_state.index / ELEMENTS_PER_BLOCK;
+ const std::size_t current_index = current_state.index % ELEMENTS_PER_BLOCK;
+ return (current_state.bucket_list->at(current_bucket)[current_index]);
+ }
+
+ ElementT &operator[](const std::size_t index) const
+ {
+ const std::size_t current_bucket = (index + current_state.index) / ELEMENTS_PER_BLOCK;
+ const std::size_t current_index = (index + current_state.index) % ELEMENTS_PER_BLOCK;
+ return (current_state.bucket_list->at(current_bucket)[current_index]);
+ }
+};
+
+template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK>
+class DeallocatingVectorRemoveIterator
+ : public boost::iterator_facade<DeallocatingVectorRemoveIterator<ElementT, ELEMENTS_PER_BLOCK>,
+ ElementT,
+ boost::forward_traversal_tag>
+{
+ DeallocatingVectorIteratorState<ElementT> current_state;
+
+ public:
+ DeallocatingVectorRemoveIterator(std::size_t idx, std::vector<ElementT *> *input_list)
+ : current_state(idx, input_list)
+ {
+ }
+
+ friend class boost::iterator_core_access;
+
+ void increment()
+ {
+ const std::size_t old_bucket = current_state.index / ELEMENTS_PER_BLOCK;
+
+ ++current_state.index;
+ const std::size_t new_bucket = current_state.index / ELEMENTS_PER_BLOCK;
+ if (old_bucket != new_bucket)
+ {
+ // delete old bucket entry
+ if (nullptr != current_state.bucket_list->at(old_bucket))
+ {
+ delete[] current_state.bucket_list->at(old_bucket);
+ current_state.bucket_list->at(old_bucket) = nullptr;
+ }
+ }
+ }
+
+ bool equal(DeallocatingVectorRemoveIterator const &other) const
+ {
+ return current_state.index == other.current_state.index;
+ }
+
+ std::ptrdiff_t distance_to(DeallocatingVectorRemoveIterator const &other) const
+ {
+ return other.current_state.index - current_state.index;
+ }
+
+ ElementT &dereference() const
+ {
+ const std::size_t current_bucket = current_state.index / ELEMENTS_PER_BLOCK;
+ const std::size_t current_index = current_state.index % ELEMENTS_PER_BLOCK;
+ return (current_state.bucket_list->at(current_bucket)[current_index]);
+ }
+};
+
+template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK = 8388608 / sizeof(ElementT)>
+class DeallocatingVector
+{
+ std::size_t current_size;
+ std::vector<ElementT *> bucket_list;
+
+ public:
+ using iterator = DeallocatingVectorIterator<ElementT, ELEMENTS_PER_BLOCK>;
+ using const_iterator = DeallocatingVectorIterator<ElementT, ELEMENTS_PER_BLOCK>;
+
+ // 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() { clear(); }
+
+ inline void swap(DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK> &other)
+ {
+ std::swap(current_size, other.current_size);
+ bucket_list.swap(other.bucket_list);
+ }
+
+ inline void clear()
+ {
+ // Delete[]'ing ptr's to all Buckets
+ for (auto bucket : bucket_list)
+ {
+ if (nullptr != bucket)
+ {
+ delete[] bucket;
+ bucket = nullptr;
+ }
+ }
+ bucket_list.clear(); bucket_list.shrink_to_fit();
+ current_size = 0;
+ }
+
+ inline void push_back(const ElementT &element)
+ {
+ const std::size_t current_capacity = capacity();
+ if (current_size == current_capacity)
+ {
+ bucket_list.push_back(new ElementT[ELEMENTS_PER_BLOCK]);
+ }
+
+ std::size_t current_index = size() % ELEMENTS_PER_BLOCK;
+ bucket_list.back()[current_index] = element;
+ ++current_size;
+ }
+
+ template <typename... Ts> inline void emplace_back(Ts &&... element)
+ {
+ const std::size_t current_capacity = capacity();
+ if (current_size == current_capacity)
+ {
+ bucket_list.push_back(new ElementT[ELEMENTS_PER_BLOCK]);
+ }
+
+ const std::size_t current_index = size() % ELEMENTS_PER_BLOCK;
+ bucket_list.back()[current_index] = ElementT(std::forward<Ts>(element)...);
+ ++current_size;
+ }
+
+ inline void reserve(const std::size_t) const { /* don't do anything */ }
+
+ inline void resize(const std::size_t new_size)
+ {
+ if (new_size >= current_size)
+ {
+ while (capacity() < new_size)
+ {
+ bucket_list.push_back(new ElementT[ELEMENTS_PER_BLOCK]);
+ }
+ }
+ else
+ { // down-size
+ const std::size_t number_of_necessary_buckets = 1 + (new_size / ELEMENTS_PER_BLOCK);
+ for (const auto bucket_index : osrm::irange(number_of_necessary_buckets, bucket_list.size()))
+ {
+ if (nullptr != bucket_list[bucket_index])
+ {
+ delete[] bucket_list[bucket_index];
+ }
+ }
+ bucket_list.resize(number_of_necessary_buckets);
+ }
+ current_size = new_size;
+ }
+
+ inline std::size_t size() const { return current_size; }
+
+ inline 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); }
+
+ inline iterator end() { return iterator(size(), &bucket_list); }
+
+ inline deallocation_iterator dbegin()
+ {
+ return deallocation_iterator(static_cast<std::size_t>(0), &bucket_list);
+ }
+
+ inline deallocation_iterator dend() { return deallocation_iterator(size(), &bucket_list); }
+
+ inline 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); }
+
+ inline 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
+ {
+ 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
+ {
+ 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)
+ {
+ InputIterator position = first;
+ while (position != last)
+ {
+ push_back(*position);
+ ++position;
+ }
+ }
+};
+
+#endif /* DEALLOCATINGVECTOR_H_ */
diff --git a/DataStructures/DynamicGraph.h b/data_structures/dynamic_graph.hpp
similarity index 53%
rename from DataStructures/DynamicGraph.h
rename to data_structures/dynamic_graph.hpp
index 3dc48b6..7244d1e 100644
--- a/DataStructures/DynamicGraph.h
+++ b/data_structures/dynamic_graph.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,13 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DYNAMICGRAPH_H
-#define DYNAMICGRAPH_H
+#ifndef DYNAMICGRAPH_HPP
+#define DYNAMICGRAPH_HPP
-#include "../DataStructures/DeallocatingVector.h"
+#include "deallocating_vector.hpp"
+#include "../Util/integer_range.hpp"
#include <boost/assert.hpp>
-#include <boost/range/irange.hpp>
#include <cstdint>
@@ -43,10 +43,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
template <typename EdgeDataT> class DynamicGraph
{
public:
- typedef decltype(boost::irange(0u,0u)) EdgeRange;
- typedef EdgeDataT EdgeData;
- typedef unsigned NodeIterator;
- typedef unsigned EdgeIterator;
+ using EdgeData = EdgeDataT;
+ using NodeIterator = unsigned;
+ using EdgeIterator = unsigned;
+ using EdgeRange = osrm::range<EdgeIterator>;
class InputEdge
{
@@ -54,57 +54,62 @@ template <typename EdgeDataT> class DynamicGraph
NodeIterator source;
NodeIterator target;
EdgeDataT data;
+
+ 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)...) { }
+
bool operator<(const InputEdge &right) const
{
if (source != right.source)
+ {
return source < right.source;
+ }
return target < right.target;
}
};
// Constructs an empty graph with a given number of nodes.
- explicit DynamicGraph(int32_t nodes) : m_numNodes(nodes), m_numEdges(0)
+ explicit DynamicGraph(NodeIterator nodes) : number_of_nodes(nodes), number_of_edges(0)
{
- m_nodes.reserve(m_numNodes);
- m_nodes.resize(m_numNodes);
+ node_list.reserve(number_of_nodes);
+ node_list.resize(number_of_nodes);
- m_edges.reserve(m_numNodes * 1.1);
- m_edges.resize(m_numNodes);
+ edge_list.reserve(number_of_nodes * 1.1);
+ edge_list.resize(number_of_nodes);
}
- template <class ContainerT> DynamicGraph(const int32_t nodes, const ContainerT &graph)
+ template <class ContainerT> DynamicGraph(const NodeIterator nodes, const ContainerT &graph)
{
- m_numNodes = nodes;
- m_numEdges = (EdgeIterator)graph.size();
- m_nodes.reserve(m_numNodes + 1);
- m_nodes.resize(m_numNodes + 1);
+ number_of_nodes = nodes;
+ number_of_edges = (EdgeIterator)graph.size();
+ node_list.reserve(number_of_nodes + 1);
+ node_list.resize(number_of_nodes + 1);
EdgeIterator edge = 0;
EdgeIterator position = 0;
- for (NodeIterator node = 0; node < m_numNodes; ++node)
+ for (const auto node : osrm::irange(0u, number_of_nodes))
{
EdgeIterator lastEdge = edge;
- while (edge < m_numEdges && graph[edge].source == node)
+ while (edge < number_of_edges && graph[edge].source == node)
{
++edge;
}
- m_nodes[node].firstEdge = position;
- m_nodes[node].edges = edge - lastEdge;
- position += m_nodes[node].edges;
+ node_list[node].firstEdge = position;
+ node_list[node].edges = edge - lastEdge;
+ position += node_list[node].edges;
}
- m_nodes.back().firstEdge = position;
- m_edges.reserve(static_cast<std::size_t>(position * 1.1));
- m_edges.resize(position);
+ node_list.back().firstEdge = position;
+ edge_list.reserve(static_cast<std::size_t>(edge_list.size() * 1.1));
+ edge_list.resize(position);
edge = 0;
- for (NodeIterator node = 0; node < m_numNodes; ++node)
+ for (const auto node : osrm::irange(0u, number_of_nodes))
{
- for (EdgeIterator i = m_nodes[node].firstEdge,
- e = m_nodes[node].firstEdge + m_nodes[node].edges;
- i != e;
- ++i)
+ for (const auto i : osrm::irange(node_list[node].firstEdge,
+ node_list[node].firstEdge + node_list[node].edges))
{
- m_edges[i].target = graph[edge].target;
- m_edges[i].data = graph[edge].data;
- BOOST_ASSERT_MSG(graph[edge].data.distance > 0, "edge distance invalid");
+ edge_list[i].target = graph[edge].target;
+ edge_list[i].data = graph[edge].data;
++edge;
}
}
@@ -112,16 +117,16 @@ template <typename EdgeDataT> class DynamicGraph
~DynamicGraph() {}
- unsigned GetNumberOfNodes() const { return m_numNodes; }
+ unsigned GetNumberOfNodes() const { return number_of_nodes; }
- unsigned GetNumberOfEdges() const { return m_numEdges; }
+ unsigned GetNumberOfEdges() const { return number_of_edges; }
- unsigned GetOutDegree(const NodeIterator n) const { return m_nodes[n].edges; }
+ unsigned GetOutDegree(const NodeIterator n) const { return node_list[n].edges; }
unsigned GetDirectedOutDegree(const NodeIterator n) const
{
unsigned degree = 0;
- for(EdgeIterator edge = BeginEdges(n); edge < EndEdges(n); ++edge)
+ for (const auto edge : osrm::irange(BeginEdges(n), EndEdges(n)))
{
if (GetEdgeData(edge).forward)
{
@@ -131,66 +136,76 @@ template <typename EdgeDataT> class DynamicGraph
return degree;
}
- NodeIterator GetTarget(const EdgeIterator e) const { return NodeIterator(m_edges[e].target); }
+ NodeIterator GetTarget(const EdgeIterator e) const { return NodeIterator(edge_list[e].target); }
- void SetTarget(const EdgeIterator e, const NodeIterator n) { m_edges[e].target = n; }
+ void SetTarget(const EdgeIterator e, const NodeIterator n) { edge_list[e].target = n; }
- EdgeDataT &GetEdgeData(const EdgeIterator e) { return m_edges[e].data; }
+ EdgeDataT &GetEdgeData(const EdgeIterator e) { return edge_list[e].data; }
- const EdgeDataT &GetEdgeData(const EdgeIterator e) const { return m_edges[e].data; }
+ const EdgeDataT &GetEdgeData(const EdgeIterator e) const { return edge_list[e].data; }
EdgeIterator BeginEdges(const NodeIterator n) const
{
- return EdgeIterator(m_nodes[n].firstEdge);
+ return EdgeIterator(node_list[n].firstEdge);
}
EdgeIterator EndEdges(const NodeIterator n) const
{
- return EdgeIterator(m_nodes[n].firstEdge + m_nodes[n].edges);
+ return EdgeIterator(node_list[n].firstEdge + node_list[n].edges);
}
EdgeRange GetAdjacentEdgeRange(const NodeIterator node) const
{
- return boost::irange(BeginEdges(node), EndEdges(node));
+ return osrm::irange(BeginEdges(node), EndEdges(node));
+ }
+
+ NodeIterator InsertNode()
+ {
+ node_list.emplace_back(node_list.back());
+ number_of_nodes += 1;
+
+ return number_of_nodes;
}
// adds an edge. Invalidates edge iterators for the source node
EdgeIterator InsertEdge(const NodeIterator from, const NodeIterator to, const EdgeDataT &data)
{
- Node &node = m_nodes[from];
+ Node &node = node_list[from];
EdgeIterator newFirstEdge = node.edges + node.firstEdge;
- if (newFirstEdge >= m_edges.size() || !isDummy(newFirstEdge))
+ if (newFirstEdge >= edge_list.size() || !isDummy(newFirstEdge))
{
if (node.firstEdge != 0 && isDummy(node.firstEdge - 1))
{
node.firstEdge--;
- m_edges[node.firstEdge] = m_edges[node.firstEdge + node.edges];
+ edge_list[node.firstEdge] = edge_list[node.firstEdge + node.edges];
}
else
{
- EdgeIterator newFirstEdge = (EdgeIterator)m_edges.size();
+ EdgeIterator newFirstEdge = (EdgeIterator)edge_list.size();
unsigned newSize = node.edges * 1.1 + 2;
- EdgeIterator requiredCapacity = newSize + m_edges.size();
- EdgeIterator oldCapacity = m_edges.capacity();
+ EdgeIterator requiredCapacity = newSize + edge_list.size();
+ EdgeIterator oldCapacity = edge_list.capacity();
if (requiredCapacity >= oldCapacity)
{
- m_edges.reserve(requiredCapacity * 1.1);
+ edge_list.reserve(requiredCapacity * 1.1);
}
- m_edges.resize(m_edges.size() + newSize);
- for (EdgeIterator i = 0; i < node.edges; ++i)
+ edge_list.resize(edge_list.size() + newSize);
+ for (const auto i : osrm::irange(0u, node.edges))
{
- m_edges[newFirstEdge + i] = m_edges[node.firstEdge + i];
+ edge_list[newFirstEdge + i] = edge_list[node.firstEdge + i];
makeDummy(node.firstEdge + i);
}
- for (EdgeIterator i = node.edges + 1; i < newSize; ++i)
+ for (const auto i : osrm::irange(node.edges + 1, newSize))
+ {
makeDummy(newFirstEdge + i);
+ }
node.firstEdge = newFirstEdge;
}
}
- Edge &edge = m_edges[node.firstEdge + node.edges];
+ Edge &edge = edge_list[node.firstEdge + node.edges];
edge.target = to;
edge.data = data;
- ++m_numEdges;
+ ++number_of_edges;
++node.edges;
return EdgeIterator(node.firstEdge + node.edges);
}
@@ -198,14 +213,14 @@ template <typename EdgeDataT> class DynamicGraph
// removes an edge. Invalidates edge iterators for the source node
void DeleteEdge(const NodeIterator source, const EdgeIterator e)
{
- Node &node = m_nodes[source];
- --m_numEdges;
+ Node &node = node_list[source];
+ --number_of_edges;
--node.edges;
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != node.edges);
const unsigned last = node.firstEdge + node.edges;
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != last);
// swap with last edge
- m_edges[e] = m_edges[last];
+ edge_list[e] = edge_list[last];
makeDummy(last);
}
@@ -215,19 +230,19 @@ template <typename EdgeDataT> class DynamicGraph
int32_t deleted = 0;
for (EdgeIterator i = BeginEdges(source), iend = EndEdges(source); i < iend - deleted; ++i)
{
- if (m_edges[i].target == target)
+ if (edge_list[i].target == target)
{
do
{
deleted++;
- m_edges[i] = m_edges[iend - deleted];
+ edge_list[i] = edge_list[iend - deleted];
makeDummy(iend - deleted);
- } while (i < iend - deleted && m_edges[i].target == target);
+ } while (i < iend - deleted && edge_list[i].target == target);
}
}
- m_numEdges -= deleted;
- m_nodes[source].edges -= deleted;
+ number_of_edges -= deleted;
+ node_list[source].edges -= deleted;
return deleted;
}
@@ -235,9 +250,9 @@ template <typename EdgeDataT> class DynamicGraph
// searches for a specific edge
EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
{
- for (EdgeIterator i = BeginEdges(from), iend = EndEdges(from); i != iend; ++i)
+ for (const auto i : osrm::irange(BeginEdges(from), EndEdges(from)))
{
- if (to == m_edges[i].target)
+ if (to == edge_list[i].target)
{
return i;
}
@@ -248,12 +263,12 @@ template <typename EdgeDataT> class DynamicGraph
protected:
bool isDummy(const EdgeIterator edge) const
{
- return m_edges[edge].target == (std::numeric_limits<NodeIterator>::max)();
+ return edge_list[edge].target == (std::numeric_limits<NodeIterator>::max)();
}
void makeDummy(const EdgeIterator edge)
{
- m_edges[edge].target = (std::numeric_limits<NodeIterator>::max)();
+ edge_list[edge].target = (std::numeric_limits<NodeIterator>::max)();
}
struct Node
@@ -270,11 +285,11 @@ template <typename EdgeDataT> class DynamicGraph
EdgeDataT data;
};
- NodeIterator m_numNodes;
- std::atomic_uint m_numEdges;
+ NodeIterator number_of_nodes;
+ std::atomic_uint number_of_edges;
- std::vector<Node> m_nodes;
- DeallocatingVector<Edge> m_edges;
+ std::vector<Node> node_list;
+ DeallocatingVector<Edge> edge_list;
};
-#endif // DYNAMICGRAPH_H
+#endif // DYNAMICGRAPH_HPP
diff --git a/DataStructures/EdgeBasedNode.h b/data_structures/edge_based_node.hpp
similarity index 58%
rename from DataStructures/EdgeBasedNode.h
rename to data_structures/edge_based_node.hpp
index 90f8b7c..98746d9 100644
--- a/DataStructures/EdgeBasedNode.h
+++ b/data_structures/edge_based_node.hpp
@@ -1,7 +1,34 @@
-#ifndef EDGE_BASED_NODE_H
-#define EDGE_BASED_NODE_H
+/*
-#include "../Util/SimpleLogger.h"
+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 EDGE_BASED_NODE_HPP
+#define EDGE_BASED_NODE_HPP
+
+#include "../data_structures/travel_mode.hpp"
#include "../typedefs.h"
#include <osrm/Coordinate.h>
@@ -12,7 +39,6 @@
struct EdgeBasedNode
{
-
EdgeBasedNode() :
forward_edge_based_node_id(SPECIAL_NODEID),
reverse_edge_based_node_id(SPECIAL_NODEID),
@@ -24,8 +50,10 @@ struct EdgeBasedNode
forward_offset(0),
reverse_offset(0),
packed_geometry_id(SPECIAL_EDGEID),
+ component_id(-1),
fwd_segment_position( std::numeric_limits<unsigned short>::max() ),
- is_in_tiny_cc(false)
+ forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
+ backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
{ }
explicit EdgeBasedNode(
@@ -39,8 +67,10 @@ struct EdgeBasedNode
int forward_offset,
int reverse_offset,
unsigned packed_geometry_id,
+ unsigned component_id,
unsigned short fwd_segment_position,
- bool belongs_to_tiny_component
+ 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),
@@ -52,8 +82,10 @@ struct EdgeBasedNode
forward_offset(forward_offset),
reverse_offset(reverse_offset),
packed_geometry_id(packed_geometry_id),
+ component_id(component_id),
fwd_segment_position(fwd_segment_position),
- is_in_tiny_cc(belongs_to_tiny_component)
+ 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));
@@ -73,6 +105,11 @@ struct EdgeBasedNode
return packed_geometry_id != SPECIAL_EDGEID;
}
+ 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
@@ -83,8 +120,10 @@ struct EdgeBasedNode
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
- bool is_in_tiny_cc;
+ TravelMode forward_travel_mode : 4;
+ TravelMode backward_travel_mode : 4;
};
-#endif //EDGE_BASED_NODE_H
+#endif //EDGE_BASED_NODE_HPP
diff --git a/DataStructures/ImportNode.cpp b/data_structures/external_memory_node.cpp
similarity index 70%
rename from DataStructures/ImportNode.cpp
rename to data_structures/external_memory_node.cpp
index 8975d40..cd6271b 100644
--- a/DataStructures/ImportNode.cpp
+++ b/data_structures/external_memory_node.cpp
@@ -25,19 +25,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "ImportNode.h"
+#include "external_memory_node.hpp"
#include <limits>
ExternalMemoryNode::ExternalMemoryNode(
- int lat, int lon, unsigned int node_id, bool bollard, bool traffic_light)
- : NodeInfo(lat, lon, node_id), bollard(bollard), trafficLight(traffic_light)
+ int lat, int lon, unsigned int node_id, bool barrier, bool traffic_lights)
+ : QueryNode(lat, lon, node_id), barrier(barrier), traffic_lights(traffic_lights)
{
}
-ExternalMemoryNode::ExternalMemoryNode() : bollard(false), trafficLight(false)
-{
-}
+ExternalMemoryNode::ExternalMemoryNode() : barrier(false), traffic_lights(false) {}
ExternalMemoryNode ExternalMemoryNode::min_value()
{
@@ -53,12 +51,18 @@ ExternalMemoryNode ExternalMemoryNode::max_value()
false);
}
-void ImportNode::Clear()
+bool ExternalMemoryNodeSTXXLCompare::operator()(const ExternalMemoryNode &left,
+ const ExternalMemoryNode &right) const
+{
+ return left.node_id < right.node_id;
+}
+
+ExternalMemoryNodeSTXXLCompare::value_type ExternalMemoryNodeSTXXLCompare::max_value()
+{
+ return ExternalMemoryNode::max_value();
+}
+
+ExternalMemoryNodeSTXXLCompare::value_type ExternalMemoryNodeSTXXLCompare::min_value()
{
- keyVals.Clear();
- lat = 0;
- lon = 0;
- node_id = 0;
- bollard = false;
- trafficLight = false;
+ return ExternalMemoryNode::min_value();
}
diff --git a/DataStructures/ImportNode.h b/data_structures/external_memory_node.hpp
similarity index 70%
copy from DataStructures/ImportNode.h
copy to data_structures/external_memory_node.hpp
index b8a9451..f88a23e 100644
--- a/DataStructures/ImportNode.h
+++ b/data_structures/external_memory_node.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,17 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef IMPORTNODE_H_
-#define IMPORTNODE_H_
+#ifndef EXTERNAL_MEMORY_NODE_HPP_
+#define EXTERNAL_MEMORY_NODE_HPP_
-#include "QueryNode.h"
-#include "../DataStructures/HashTable.h"
+#include "query_node.hpp"
#include <string>
-struct ExternalMemoryNode : NodeInfo
+struct ExternalMemoryNode : QueryNode
{
- ExternalMemoryNode(int lat, int lon, unsigned int id, bool bollard, bool traffic_light);
+ ExternalMemoryNode(int lat, int lon, NodeID id, bool barrier, bool traffic_light);
ExternalMemoryNode();
@@ -43,15 +42,16 @@ struct ExternalMemoryNode : NodeInfo
static ExternalMemoryNode max_value();
- bool bollard;
- bool trafficLight;
+ bool barrier;
+ bool traffic_lights;
};
-struct ImportNode : public ExternalMemoryNode
+struct ExternalMemoryNodeSTXXLCompare
{
- HashTable<std::string, std::string> keyVals;
-
- inline void Clear();
+ using value_type = ExternalMemoryNode;
+ bool operator()(const ExternalMemoryNode &left, const ExternalMemoryNode &right) const;
+ value_type max_value();
+ value_type min_value();
};
-#endif /* IMPORTNODE_H_ */
+#endif /* EXTERNAL_MEMORY_NODE_HPP_ */
diff --git a/data_structures/fixed_point_number.hpp b/data_structures/fixed_point_number.hpp
new file mode 100644
index 0000000..eab6850
--- /dev/null
+++ b/data_structures/fixed_point_number.hpp
@@ -0,0 +1,216 @@
+/*
+
+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 FIXED_POINT_NUMBER_HPP
+#define FIXED_POINT_NUMBER_HPP
+
+#include <cmath>
+#include <cstdint>
+
+#include <iostream>
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+namespace osrm
+{
+
+// implements an binary based fixed point number type
+template <unsigned FractionalBitSize,
+ bool use_64_bits = false,
+ bool is_unsigned = false,
+ bool truncate_results = false>
+class FixedPointNumber
+{
+ static_assert(FractionalBitSize > 0, "FractionalBitSize must be greater than 0");
+ static_assert(FractionalBitSize <= 32, "FractionalBitSize must at most 32");
+
+ typename std::conditional<use_64_bits, int64_t, int32_t>::type m_fixed_point_state;
+ constexpr static const decltype(m_fixed_point_state) PRECISION = 1 << FractionalBitSize;
+
+ // state signage encapsulates whether the state should either represent a
+ // signed or an unsigned floating point number
+ using state_signage =
+ typename std::conditional<is_unsigned,
+ typename std::make_unsigned<decltype(m_fixed_point_state)>::type,
+ decltype(m_fixed_point_state)>::type;
+
+ public:
+ FixedPointNumber() : m_fixed_point_state(0) {}
+
+ // the type is either initialized with a floating point value or an
+ // integral state. Anything else will throw at compile-time.
+ template <class T>
+ constexpr FixedPointNumber(const T &&input) noexcept
+ : m_fixed_point_state(static_cast<decltype(m_fixed_point_state)>(
+ std::round(std::forward<const T>(input) * PRECISION)))
+ {
+ static_assert(
+ std::is_floating_point<T>::value || std::is_integral<T>::value,
+ "FixedPointNumber needs to be initialized with floating point or integral value");
+ }
+
+ // get max value
+ template <typename T,
+ typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
+ constexpr static auto max() noexcept -> T
+ {
+ return static_cast<T>(std::numeric_limits<state_signage>::max()) / PRECISION;
+ }
+
+ // get min value
+ template <typename T,
+ typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
+ constexpr static auto min() noexcept -> T
+ {
+ return static_cast<T>(1) / PRECISION;
+ }
+
+ // get lowest value
+ template <typename T,
+ typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
+ constexpr static auto lowest() noexcept -> T
+ {
+ return static_cast<T>(std::numeric_limits<state_signage>::min()) / PRECISION;
+ }
+
+ // cast to floating point type T, return value
+ template <typename T,
+ typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
+ explicit operator const T() const noexcept
+ {
+ // casts to external type (signed or unsigned) and then to float
+ return static_cast<T>(static_cast<state_signage>(m_fixed_point_state)) / PRECISION;
+ }
+
+ // warn about cast to integral type T, its disabled for good reason
+ template <typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
+ explicit operator T() const
+ {
+ static_assert(std::is_integral<T>::value,
+ "casts to integral types have been disabled on purpose");
+ }
+
+ // compare, ie. sort fixed-point numbers
+ bool operator<(const FixedPointNumber &other) const noexcept
+ {
+ return m_fixed_point_state < other.m_fixed_point_state;
+ }
+
+ // equality, ie. sort fixed-point numbers
+ bool operator==(const FixedPointNumber &other) const noexcept
+ {
+ return m_fixed_point_state == other.m_fixed_point_state;
+ }
+
+ bool operator!=(const FixedPointNumber &other) const { return !(*this == other); }
+ bool operator>(const FixedPointNumber &other) const { return other < *this; }
+ bool operator<=(const FixedPointNumber &other) const { return !(other < *this); }
+ bool operator>=(const FixedPointNumber &other) const { return !(*this < other); }
+
+ // arithmetic operators
+ FixedPointNumber operator+(const FixedPointNumber &other) const noexcept
+ {
+ FixedPointNumber tmp = *this;
+ tmp.m_fixed_point_state += other.m_fixed_point_state;
+ return tmp;
+ }
+
+ FixedPointNumber &operator+=(const FixedPointNumber &other) noexcept
+ {
+ this->m_fixed_point_state += other.m_fixed_point_state;
+ return *this;
+ }
+
+ FixedPointNumber operator-(const FixedPointNumber &other) const noexcept
+ {
+ FixedPointNumber tmp = *this;
+ tmp.m_fixed_point_state -= other.m_fixed_point_state;
+ return tmp;
+ }
+
+ FixedPointNumber &operator-=(const FixedPointNumber &other) noexcept
+ {
+ this->m_fixed_point_state -= other.m_fixed_point_state;
+ return *this;
+ }
+
+ FixedPointNumber operator*(const FixedPointNumber &other) const noexcept
+ {
+ int64_t temp = this->m_fixed_point_state;
+ temp *= other.m_fixed_point_state;
+
+ // rounding!
+ if (!truncate_results)
+ {
+ temp = temp + ((temp & 1 << (FractionalBitSize - 1)) << 1);
+ }
+ temp >>= FractionalBitSize;
+ FixedPointNumber tmp;
+ tmp.m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
+ return tmp;
+ }
+
+ FixedPointNumber &operator*=(const FixedPointNumber &other) noexcept
+ {
+ int64_t temp = this->m_fixed_point_state;
+ temp *= other.m_fixed_point_state;
+
+ // rounding!
+ if (!truncate_results)
+ {
+ temp = temp + ((temp & 1 << (FractionalBitSize - 1)) << 1);
+ }
+ temp >>= FractionalBitSize;
+ this->m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
+ return *this;
+ }
+
+ FixedPointNumber operator/(const FixedPointNumber &other) const noexcept
+ {
+ int64_t temp = this->m_fixed_point_state;
+ temp <<= FractionalBitSize;
+ temp /= static_cast<int64_t>(other.m_fixed_point_state);
+ FixedPointNumber tmp;
+ tmp.m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
+ return tmp;
+ }
+
+ FixedPointNumber &operator/=(const FixedPointNumber &other) noexcept
+ {
+ int64_t temp = this->m_fixed_point_state;
+ temp <<= FractionalBitSize;
+ temp /= static_cast<int64_t>(other.m_fixed_point_state);
+ FixedPointNumber tmp;
+ this->m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
+ return *this;
+ }
+};
+
+static_assert(4 == sizeof(FixedPointNumber<1>), "FP19 has wrong size != 4");
+}
+#endif // FIXED_POINT_NUMBER_HPP
diff --git a/DataStructures/HilbertValue.cpp b/data_structures/hilbert_value.cpp
similarity index 97%
rename from DataStructures/HilbertValue.cpp
rename to data_structures/hilbert_value.cpp
index 9cb88c7..216b7c5 100644
--- a/DataStructures/HilbertValue.cpp
+++ b/data_structures/hilbert_value.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,7 +25,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "HilbertValue.h"
+#include "hilbert_value.hpp"
#include <osrm/Coordinate.h>
diff --git a/DataStructures/HilbertValue.h b/data_structures/hilbert_value.hpp
similarity index 92%
rename from DataStructures/HilbertValue.h
rename to data_structures/hilbert_value.hpp
index 9de2372..e194029 100644
--- a/DataStructures/HilbertValue.h
+++ b/data_structures/hilbert_value.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
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 HILBERTVALUE_H_
-#define HILBERTVALUE_H_
+#ifndef HILBERT_VALUE_HPP
+#define HILBERT_VALUE_HPP
#include <cstdint>
@@ -46,4 +46,4 @@ class HilbertCode
inline void TransposeCoordinate(uint32_t *X) const;
};
-#endif /* HILBERTVALUE_H_ */
+#endif /* HILBERT_VALUE_HPP */
diff --git a/DataStructures/ImportEdge.cpp b/data_structures/import_edge.cpp
similarity index 93%
rename from DataStructures/ImportEdge.cpp
rename to data_structures/import_edge.cpp
index 0d04b9f..55f5f16 100644
--- a/DataStructures/ImportEdge.cpp
+++ b/data_structures/import_edge.cpp
@@ -25,7 +25,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "ImportEdge.h"
+#include "import_edge.hpp"
#include <boost/assert.hpp>
@@ -52,17 +52,15 @@ NodeBasedEdge::NodeBasedEdge(NodeID source,
EdgeWeight weight,
bool forward,
bool backward,
- short type,
bool roundabout,
bool in_tiny_cc,
bool access_restricted,
- bool contra_flow,
+ TravelMode travel_mode,
bool is_split)
- : source(source), target(target), name_id(name_id), weight(weight), type(type),
+ : 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), contra_flow(contra_flow), is_split(is_split)
+ access_restricted(access_restricted), is_split(is_split), travel_mode(travel_mode)
{
- BOOST_ASSERT_MSG(type > 0, "negative edge type");
}
bool EdgeBasedEdge::operator<(const EdgeBasedEdge &other) const
diff --git a/DataStructures/ImportEdge.h b/data_structures/import_edge.hpp
similarity index 91%
rename from DataStructures/ImportEdge.h
rename to data_structures/import_edge.hpp
index f79a484..f9004d4 100644
--- a/DataStructures/ImportEdge.h
+++ b/data_structures/import_edge.hpp
@@ -25,9 +25,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef IMPORT_EDGE_H
-#define IMPORT_EDGE_H
+#ifndef IMPORT_EDGE_HPP
+#define IMPORT_EDGE_HPP
+#include "../data_structures/travel_mode.hpp"
#include "../typedefs.h"
struct NodeBasedEdge
@@ -40,25 +41,23 @@ struct NodeBasedEdge
EdgeWeight weight,
bool forward,
bool backward,
- short type,
bool roundabout,
bool in_tiny_cc,
bool access_restricted,
- bool contra_flow,
+ TravelMode travel_mode,
bool is_split);
NodeID source;
NodeID target;
NodeID name_id;
EdgeWeight weight;
- short type;
bool forward : 1;
bool backward : 1;
bool roundabout : 1;
bool in_tiny_cc : 1;
bool access_restricted : 1;
- bool contra_flow : 1;
bool is_split : 1;
+ TravelMode travel_mode : 4;
NodeBasedEdge() = delete;
};
@@ -87,6 +86,6 @@ struct EdgeBasedEdge
bool backward : 1;
};
-typedef NodeBasedEdge ImportEdge;
+using ImportEdge = NodeBasedEdge;
-#endif /* IMPORT_EDGE_H */
+#endif /* IMPORT_EDGE_HPP */
diff --git a/Contractor/GeometryCompressor.h b/data_structures/json_container.hpp
similarity index 55%
rename from Contractor/GeometryCompressor.h
rename to data_structures/json_container.hpp
index 7c4fba4..9bbbec4 100644
--- a/Contractor/GeometryCompressor.h
+++ b/data_structures/json_container.hpp
@@ -25,41 +25,70 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "../typedefs.h"
+// based on
+// https://svn.apache.org/repos/asf/mesos/tags/release-0.9.0-incubating-RC0/src/common/json.hpp
-#include <unordered_map>
+#ifndef JSON_CONTAINER_H
+#define JSON_CONTAINER_H
-#include <string>
+#include <variant/variant.hpp>
+
+#include <iostream>
#include <vector>
+#include <string>
+#include <unordered_map>
+
+namespace JSON
+{
-#ifndef GEOMETRY_COMPRESSOR_H
-#define GEOMETRY_COMPRESSOR_H
+struct Object;
+struct Array;
-class GeometryCompressor
+struct String
{
- public:
- typedef std::pair<NodeID, EdgeWeight> CompressedNode;
-
- GeometryCompressor();
- void CompressEdge(const EdgeID surviving_edge_id,
- const EdgeID removed_edge_id,
- const NodeID via_node_id,
- const NodeID target_node,
- const EdgeWeight weight1,
- const EdgeWeight weight2);
-
- bool HasEntryForID(const EdgeID edge_id) const;
- void PrintStatistics() const;
- void SerializeInternalVector(const std::string &path) const;
- unsigned GetPositionForID(const EdgeID edge_id) const;
- const std::vector<GeometryCompressor::CompressedNode> &
- GetBucketReference(const EdgeID edge_id) const;
-
- private:
- void IncreaseFreeList();
- std::vector<std::vector<CompressedNode>> m_compressed_geometries;
- std::vector<unsigned> m_free_list;
- std::unordered_map<EdgeID, unsigned> m_edge_id_to_list_index_map;
+ String() {}
+ String(const char *value) : value(value) {}
+ String(const std::string &value) : value(value) {}
+ std::string value;
};
-#endif // GEOMETRY_COMPRESSOR_H
+struct Number
+{
+ Number() {}
+ Number(double value) : value(static_cast<double>(value)) {}
+ double value;
+};
+
+struct True
+{
+};
+
+struct False
+{
+};
+
+struct Null
+{
+};
+
+using Value = mapbox::util::variant<String,
+ Number,
+ mapbox::util::recursive_wrapper<Object>,
+ mapbox::util::recursive_wrapper<Array>,
+ True,
+ False,
+ Null>;
+
+struct Object
+{
+ std::unordered_map<std::string, Value> values;
+};
+
+struct Array
+{
+ std::vector<Value> values;
+};
+
+} // namespace JSON
+
+#endif // JSON_CONTAINER_H
diff --git a/DataStructures/LRUCache.h b/data_structures/lru_cache.hpp
similarity index 96%
rename from DataStructures/LRUCache.h
rename to data_structures/lru_cache.hpp
index 75b9139..cdbeb38 100644
--- a/DataStructures/LRUCache.h
+++ b/data_structures/lru_cache.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
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 LRUCACHE_H
-#define LRUCACHE_H
+#ifndef LRUCACHE_HPP
+#define LRUCACHE_HPP
#include <list>
#include <unordered_map>
@@ -94,4 +94,4 @@ template <typename KeyT, typename ValueT> class LRUCache
}
unsigned Size() const { return itemsInCache.size(); }
};
-#endif // LRUCACHE_H
+#endif // LRUCACHE_HPP
diff --git a/data_structures/node_based_graph.hpp b/data_structures/node_based_graph.hpp
new file mode 100644
index 0000000..8fe7b75
--- /dev/null
+++ b/data_structures/node_based_graph.hpp
@@ -0,0 +1,271 @@
+/*
+
+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 NODE_BASED_GRAPH_HPP
+#define NODE_BASED_GRAPH_HPP
+
+#include "dynamic_graph.hpp"
+#include "import_edge.hpp"
+#include "../Util/simple_logger.hpp"
+
+#include <tbb/parallel_sort.h>
+
+#include <memory>
+
+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)
+ {
+ }
+
+ int distance;
+ unsigned edgeBasedNodeID;
+ unsigned nameID;
+ bool isAccessRestricted : 1;
+ bool shortcut : 1;
+ bool forward : 1;
+ bool backward : 1;
+ bool roundabout : 1;
+ bool ignore_in_grid : 1;
+ TravelMode travel_mode : 4;
+
+ void SwapDirectionFlags()
+ {
+ bool temp_flag = forward;
+ forward = backward;
+ backward = temp_flag;
+ }
+
+ bool IsEqualTo(const NodeBasedEdgeData &other) const
+ {
+ return (forward == other.forward) && (backward == other.backward) &&
+ (nameID == other.nameID) && (ignore_in_grid == other.ignore_in_grid) &&
+ (travel_mode == other.travel_mode);
+ }
+};
+
+struct SimpleEdgeData
+{
+ SimpleEdgeData() : capacity(0) {}
+ EdgeWeight capacity;
+};
+
+using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
+using SimpleNodeBasedDynamicGraph = DynamicGraph<SimpleEdgeData>;
+
+// Factory method to create NodeBasedDynamicGraph from ImportEdges
+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");
+
+ DeallocatingVector<NodeBasedDynamicGraph::InputEdge> edges_list;
+ NodeBasedDynamicGraph::InputEdge edge;
+ for (const ImportEdge &import_edge : input_edge_list)
+ {
+ if (import_edge.forward)
+ {
+ edge.source = import_edge.source;
+ edge.target = import_edge.target;
+ edge.data.forward = import_edge.forward;
+ edge.data.backward = import_edge.backward;
+ }
+ else
+ {
+ edge.source = import_edge.target;
+ edge.target = import_edge.source;
+ edge.data.backward = import_edge.forward;
+ edge.data.forward = import_edge.backward;
+ }
+
+ if (edge.source == edge.target)
+ {
+ continue;
+ }
+
+ edge.data.distance = (std::max)((int)import_edge.weight, 1);
+ BOOST_ASSERT(edge.data.distance > 0);
+ edge.data.shortcut = false;
+ edge.data.roundabout = import_edge.roundabout;
+ edge.data.ignore_in_grid = import_edge.in_tiny_cc;
+ edge.data.nameID = import_edge.name_id;
+ edge.data.isAccessRestricted = import_edge.access_restricted;
+ edge.data.travel_mode = import_edge.travel_mode;
+
+ edges_list.push_back(edge);
+
+ if (!import_edge.is_split)
+ {
+ using std::swap; // enable ADL
+ swap(edge.source, edge.target);
+ edge.data.SwapDirectionFlags();
+ edges_list.push_back(edge);
+ }
+ }
+
+ // remove duplicate edges
+ tbb::parallel_sort(edges_list.begin(), edges_list.end());
+ NodeID edge_count = 0;
+ for (NodeID i = 0; i < edges_list.size(); )
+ {
+ const NodeID source = edges_list[i].source;
+ const NodeID target = edges_list[i].target;
+ // remove eigenloops
+ if (source == target)
+ {
+ i++;
+ continue;
+ }
+ NodeBasedDynamicGraph::InputEdge forward_edge;
+ NodeBasedDynamicGraph::InputEdge reverse_edge;
+ forward_edge = reverse_edge = edges_list[i];
+ 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();
+ // remove parallel edges
+ while (i < edges_list.size() && edges_list[i].source == source && edges_list[i].target == target)
+ {
+ if (edges_list[i].data.forward)
+ {
+ forward_edge.data.distance =
+ std::min(edges_list[i].data.distance, forward_edge.data.distance);
+ }
+ if (edges_list[i].data.backward)
+ {
+ reverse_edge.data.distance =
+ std::min(edges_list[i].data.distance, reverse_edge.data.distance);
+ }
+ ++i;
+ }
+ // 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())
+ {
+ forward_edge.data.backward = true;
+ edges_list[edge_count++] = forward_edge;
+ }
+ }
+ else
+ { // insert seperate edges
+ if (((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())
+ {
+ 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();
+
+ auto graph = std::make_shared<NodeBasedDynamicGraph>(static_cast<NodeBasedDynamicGraph::NodeIterator>(number_of_nodes), edges_list);
+ return graph;
+}
+
+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");
+ tbb::parallel_sort(input_edge_list.begin(), input_edge_list.end());
+
+ DeallocatingVector<SimpleNodeBasedDynamicGraph::InputEdge> edges_list;
+ SimpleNodeBasedDynamicGraph::InputEdge edge;
+ edge.data.capacity = 1;
+ for (const SimpleEdgeT &import_edge : input_edge_list)
+ {
+ if (import_edge.source == import_edge.target)
+ {
+ continue;
+ }
+ edge.source = import_edge.source;
+ edge.target = import_edge.target;
+ edges_list.push_back(edge);
+ std::swap(edge.source, edge.target);
+ edges_list.push_back(edge);
+ }
+
+ // remove duplicate edges
+ tbb::parallel_sort(edges_list.begin(), edges_list.end());
+ NodeID edge_count = 0;
+ for (NodeID i = 0; i < edges_list.size(); )
+ {
+ const NodeID source = edges_list[i].source;
+ const NodeID target = edges_list[i].target;
+ // remove eigenloops
+ if (source == target)
+ {
+ i++;
+ continue;
+ }
+ SimpleNodeBasedDynamicGraph::InputEdge forward_edge;
+ SimpleNodeBasedDynamicGraph::InputEdge reverse_edge;
+ 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)
+ {
+ 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)
+ {
+ edges_list[edge_count++] = forward_edge;
+ }
+ }
+ else
+ { // insert seperate edges
+ if (((int)forward_edge.data.capacity) != INVALID_EDGE_WEIGHT)
+ {
+ edges_list[edge_count++] = forward_edge;
+ }
+ if ((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();
+
+ auto graph = std::make_shared<SimpleNodeBasedDynamicGraph>(number_of_nodes, edges_list);
+ return graph;
+}
+
+#endif // NODE_BASED_GRAPH_HPP
diff --git a/Server/Http/CompressionType.h b/data_structures/node_id.hpp
similarity index 77%
copy from Server/Http/CompressionType.h
copy to data_structures/node_id.hpp
index 74d0b62..4f07809 100644
--- a/Server/Http/CompressionType.h
+++ b/data_structures/node_id.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
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 COMPRESSION_TYPE_H
-#define COMPRESSION_TYPE_H
+#ifndef NODE_ID_HPP
+#define NODE_ID_HPP
-namespace http
-{
-
-enum CompressionType
-{ noCompression,
- gzipRFC1952,
- deflateRFC1951 };
+#include "../typedefs.h"
-} // namespace http
+struct Cmp
+{
+ using value_type = NodeID;
+ bool operator()(const NodeID left, const NodeID right) const { return left < right; }
+ value_type max_value() { return 0xffffffff; }
+ value_type min_value() { return 0x0; }
+};
-#endif // COMPRESSION_TYPE_H
+#endif // NODE_ID_HPP
diff --git a/DataStructures/OriginalEdgeData.h b/data_structures/original_edge_data.hpp
similarity index 79%
rename from DataStructures/OriginalEdgeData.h
rename to data_structures/original_edge_data.hpp
index f75aeda..b4fdfd9 100644
--- a/DataStructures/OriginalEdgeData.h
+++ b/data_structures/original_edge_data.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,10 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ORIGINAL_EDGE_DATA_H
-#define ORIGINAL_EDGE_DATA_H
+#ifndef ORIGINAL_EDGE_DATA_HPP
+#define ORIGINAL_EDGE_DATA_HPP
-#include "TurnInstructions.h"
+#include "travel_mode.hpp"
+#include "turn_instructions.hpp"
#include "../typedefs.h"
#include <limits>
@@ -38,16 +39,18 @@ struct OriginalEdgeData
explicit OriginalEdgeData(NodeID via_node,
unsigned name_id,
TurnInstruction turn_instruction,
- bool compressed_geometry)
+ bool compressed_geometry,
+ TravelMode travel_mode)
: via_node(via_node), name_id(name_id), turn_instruction(turn_instruction),
- compressed_geometry(compressed_geometry)
+ compressed_geometry(compressed_geometry), travel_mode(travel_mode)
{
}
OriginalEdgeData()
: via_node(std::numeric_limits<unsigned>::max()),
name_id(std::numeric_limits<unsigned>::max()),
- turn_instruction(TurnInstruction::NoTurn), compressed_geometry(false)
+ turn_instruction(TurnInstruction::NoTurn), compressed_geometry(false),
+ travel_mode(TRAVEL_MODE_INACCESSIBLE)
{
}
@@ -55,6 +58,7 @@ struct OriginalEdgeData
unsigned name_id;
TurnInstruction turn_instruction;
bool compressed_geometry;
+ TravelMode travel_mode;
};
-#endif // ORIGINAL_EDGE_DATA_H
+#endif // ORIGINAL_EDGE_DATA_HPP
diff --git a/DataStructures/Percent.h b/data_structures/percent.hpp
similarity index 93%
rename from DataStructures/Percent.h
rename to data_structures/percent.hpp
index f201fc8..0c4e152 100644
--- a/DataStructures/Percent.h
+++ b/data_structures/percent.hpp
@@ -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,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef PERCENT_H
-#define PERCENT_H
+#ifndef PERCENT_HPP
+#define PERCENT_HPP
#include <iostream>
#include <atomic>
@@ -53,7 +53,7 @@ class Percent
if (current_value >= m_next_threshold)
{
m_next_threshold += m_percent_interval;
- printPercent(current_value / (double)m_max_value * 100);
+ printPercent(current_value / static_cast<double>(m_max_value) * 100.);
}
if (current_value + 1 == m_max_value)
std::cout << " 100%" << std::endl;
@@ -98,4 +98,4 @@ class Percent
}
};
-#endif // PERCENT_H
+#endif // PERCENT_HPP
diff --git a/data_structures/phantom_node.cpp b/data_structures/phantom_node.cpp
new file mode 100644
index 0000000..413c0d7
--- /dev/null
+++ b/data_structures/phantom_node.cpp
@@ -0,0 +1,124 @@
+/*
+
+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 "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)
+{ }
+
+int PhantomNode::GetForwardWeightPlusOffset() const
+{
+ if (SPECIAL_NODEID == forward_node_id)
+ {
+ return 0;
+ }
+ return forward_offset + forward_weight;
+}
+
+int PhantomNode::GetReverseWeightPlusOffset() const
+{
+ if (SPECIAL_NODEID == reverse_node_id)
+ {
+ return 0;
+ }
+ return reverse_offset + reverse_weight;
+}
+
+bool PhantomNode::is_bidirected() const
+{
+ return (forward_node_id != SPECIAL_NODEID) &&
+ (reverse_node_id != SPECIAL_NODEID);
+}
+
+bool PhantomNode::is_compressed() const
+{
+ return (forward_offset != 0) || (reverse_offset != 0);
+}
+
+bool PhantomNode::is_valid(const unsigned number_of_nodes) const
+{
+ return
+ location.is_valid() &&
+ (
+ (forward_node_id < number_of_nodes) ||
+ (reverse_node_id < number_of_nodes)
+ ) &&
+ (
+ (forward_weight != INVALID_EDGE_WEIGHT) ||
+ (reverse_weight != INVALID_EDGE_WEIGHT)
+ ) &&
+ (name_id != INVALID_NAMEID
+ );
+}
+
+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
new file mode 100644
index 0000000..9286fb9
--- /dev/null
+++ b/data_structures/phantom_node.hpp
@@ -0,0 +1,129 @@
+/*
+
+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 PHANTOM_NODES_H
+#define PHANTOM_NODES_H
+
+#include <osrm/Coordinate.h>
+#include "../data_structures/travel_mode.hpp"
+#include "../typedefs.h"
+
+#include <iostream>
+#include <vector>
+
+struct PhantomNode
+{
+ PhantomNode(NodeID forward_node_id,
+ NodeID reverse_node_id,
+ unsigned name_id,
+ int forward_weight,
+ int reverse_weight,
+ int forward_offset,
+ int reverse_offset,
+ unsigned packed_geometry_id,
+ unsigned component_id,
+ FixedPointCoordinate &location,
+ unsigned short fwd_segment_position,
+ TravelMode forward_travel_mode,
+ TravelMode backward_travel_mode);
+
+ 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 : 4;
+ TravelMode backward_travel_mode : 4;
+
+ int GetForwardWeightPlusOffset() const;
+
+ int GetReverseWeightPlusOffset() const;
+
+ bool is_bidirected() const;
+
+ bool is_compressed() const;
+
+ bool is_valid(const unsigned numberOfNodes) const;
+
+ bool is_valid() const;
+
+ bool is_in_tiny_component() 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
+{
+ std::vector<PhantomNode> source_phantom_list;
+ std::vector<PhantomNode> target_phantom_list;
+};
+
+struct PhantomNodes
+{
+ PhantomNode source_phantom;
+ PhantomNode target_phantom;
+};
+
+inline std::ostream& operator<<(std::ostream &out, const PhantomNodes & pn)
+{
+ out << "source_coord: " << pn.source_phantom.location << "\n";
+ out << "target_coord: " << pn.target_phantom.location << std::endl;
+ return out;
+}
+
+inline std::ostream& operator<<(std::ostream &out, const PhantomNode & pn)
+{
+ out << "node1: " << pn.forward_node_id << ", " <<
+ "node2: " << pn.reverse_node_id << ", " <<
+ "name: " << pn.name_id << ", " <<
+ "fwd-w: " << pn.forward_weight << ", " <<
+ "rev-w: " << pn.reverse_weight << ", " <<
+ "fwd-o: " << pn.forward_offset << ", " <<
+ "rev-o: " << pn.reverse_offset << ", " <<
+ "geom: " << pn.packed_geometry_id << ", " <<
+ "comp: " << pn.component_id << ", " <<
+ "pos: " << pn.fwd_segment_position << ", " <<
+ "loc: " << pn.location;
+ return out;
+}
+
+#endif // PHANTOM_NODES_H
diff --git a/DataStructures/QueryEdge.h b/data_structures/query_edge.hpp
similarity index 75%
rename from DataStructures/QueryEdge.h
rename to data_structures/query_edge.hpp
index b84c180..84a7f15 100644
--- a/DataStructures/QueryEdge.h
+++ b/data_structures/query_edge.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
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 QUERYEDGE_H_
-#define QUERYEDGE_H_
+#ifndef QUERYEDGE_HPP_
+#define QUERYEDGE_HPP_
#include "../typedefs.h"
@@ -36,6 +36,16 @@ struct QueryEdge
NodeID target;
struct EdgeData
{
+ EdgeData() : id(0), shortcut(false), distance(0), forward(false), backward(false) {}
+
+ template <class OtherT> EdgeData(const OtherT &other)
+ {
+ distance = other.distance;
+ shortcut = other.shortcut;
+ id = other.id;
+ forward = other.forward;
+ backward = other.backward;
+ }
NodeID id : 31;
bool shortcut : 1;
int distance : 30;
@@ -43,6 +53,13 @@ struct QueryEdge
bool backward : 1;
} data;
+ QueryEdge() : source(SPECIAL_NODEID), target(SPECIAL_NODEID) {}
+
+ QueryEdge(NodeID source, NodeID target, EdgeData data)
+ : source(source), target(target), data(data)
+ {
+ }
+
bool operator<(const QueryEdge &right) const
{
if (source != right.source)
@@ -61,4 +78,4 @@ struct QueryEdge
}
};
-#endif /* QUERYEDGE_H_ */
+#endif /* QUERYEDGE_HPP_ */
diff --git a/DataStructures/QueryNode.h b/data_structures/query_node.hpp
similarity index 68%
rename from DataStructures/QueryNode.h
rename to data_structures/query_node.hpp
index ee6b278..7705df0 100644
--- a/DataStructures/QueryNode.h
+++ b/data_structures/query_node.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
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 QUERY_NODE_H
-#define QUERY_NODE_H
+#ifndef QUERY_NODE_HPP
+#define QUERY_NODE_HPP
#include "../typedefs.h"
@@ -36,13 +36,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <limits>
-struct NodeInfo
+struct QueryNode
{
- typedef NodeID key_type; // type of NodeID
- typedef int value_type; // type of lat,lons
+ using key_type = NodeID; // type of NodeID
+ using value_type = int; // type of lat,lons
- explicit NodeInfo(int lat, int lon, NodeID node_id) : lat(lat), lon(lon), node_id(node_id) {}
- NodeInfo()
+ explicit QueryNode(int lat, int lon, NodeID node_id) : lat(lat), lon(lon), node_id(node_id) {}
+ QueryNode()
: lat(std::numeric_limits<int>::max()), lon(std::numeric_limits<int>::max()),
node_id(std::numeric_limits<unsigned>::max())
{
@@ -52,18 +52,18 @@ struct NodeInfo
int lon;
NodeID node_id;
- static NodeInfo min_value()
+ static QueryNode min_value()
{
- return NodeInfo(static_cast<int>(-90 * COORDINATE_PRECISION),
- static_cast<int>(-180 * COORDINATE_PRECISION),
- std::numeric_limits<NodeID>::min());
+ return QueryNode(static_cast<int>(-90 * COORDINATE_PRECISION),
+ static_cast<int>(-180 * COORDINATE_PRECISION),
+ std::numeric_limits<NodeID>::min());
}
- static NodeInfo max_value()
+ static QueryNode max_value()
{
- return NodeInfo(static_cast<int>(90 * COORDINATE_PRECISION),
- static_cast<int>(180 * COORDINATE_PRECISION),
- std::numeric_limits<NodeID>::max());
+ return QueryNode(static_cast<int>(90 * COORDINATE_PRECISION),
+ static_cast<int>(180 * COORDINATE_PRECISION),
+ std::numeric_limits<NodeID>::max());
}
value_type operator[](const std::size_t n) const
@@ -78,8 +78,8 @@ struct NodeInfo
break;
}
BOOST_ASSERT_MSG(false, "should not happen");
- return std::numeric_limits<unsigned>::max();
+ return std::numeric_limits<int>::lowest();
}
};
-#endif // QUERY_NODE_H
+#endif // QUERY_NODE_HPP
diff --git a/DataStructures/RangeTable.h b/data_structures/range_table.hpp
similarity index 79%
rename from DataStructures/RangeTable.h
rename to data_structures/range_table.hpp
index f9ec254..eef268b 100644
--- a/DataStructures/RangeTable.h
+++ b/data_structures/range_table.hpp
@@ -1,10 +1,36 @@
-#ifndef __RANGE_TABLE_H__
-#define __RANGE_TABLE_H__
+/*
+
+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.
-#include "SharedMemoryFactory.h"
-#include "SharedMemoryVectorWrapper.h"
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <boost/range/irange.hpp>
+*/
+
+#ifndef RANGE_TABLE_HPP
+#define RANGE_TABLE_HPP
+
+#include "../Util/integer_range.hpp"
+#include "shared_memory_factory.hpp"
+#include "shared_memory_vector_wrapper.hpp"
#include <fstream>
#include <vector>
@@ -37,10 +63,10 @@ class RangeTable
{
public:
- typedef std::array<unsigned char, BLOCK_SIZE> BlockT;
- typedef typename ShM<BlockT, USE_SHARED_MEMORY>::vector BlockContainerT;
- typedef typename ShM<unsigned, USE_SHARED_MEMORY>::vector OffsetContainerT;
- typedef decltype(boost::irange(0u,0u)) RangeT;
+ 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);
@@ -117,7 +143,8 @@ public:
{
// the last value is used as sentinel
block_offsets.push_back(lengths_prefix_sum);
- block_idx = (block_idx + 1) % BLOCK_SIZE;
+ block_idx = 1;
+ last_length = 0;
}
while (0 != block_idx)
@@ -166,7 +193,7 @@ public:
BOOST_ASSERT(begin_idx < sum_lengths && end_idx <= sum_lengths);
BOOST_ASSERT(begin_idx <= end_idx);
- return boost::irange(begin_idx, end_idx);
+ return osrm::irange(begin_idx, end_idx);
}
private:
@@ -228,4 +255,4 @@ std::istream& operator>>(std::istream &in, RangeTable<BLOCK_SIZE, USE_SHARED_MEM
return in;
}
-#endif
+#endif //RANGE_TABLE_HPP
diff --git a/DataStructures/RawRouteData.h b/data_structures/raw_route_data.hpp
similarity index 73%
rename from DataStructures/RawRouteData.h
rename to data_structures/raw_route_data.hpp
index e034b43..f9242cf 100644
--- a/DataStructures/RawRouteData.h
+++ b/data_structures/raw_route_data.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,11 +25,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef RAW_ROUTE_DATA_H
-#define RAW_ROUTE_DATA_H
+#ifndef RAW_ROUTE_DATA_HPP
+#define RAW_ROUTE_DATA_HPP
-#include "../DataStructures/PhantomNodes.h"
-#include "../DataStructures/TurnInstructions.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>
@@ -41,18 +42,25 @@ struct PathData
PathData()
: node(SPECIAL_NODEID), name_id(INVALID_EDGE_WEIGHT),
segment_duration(INVALID_EDGE_WEIGHT),
- turn_instruction(TurnInstruction::NoTurn)
+ turn_instruction(TurnInstruction::NoTurn),
+ travel_mode(TRAVEL_MODE_INACCESSIBLE)
{
}
- PathData(NodeID node, unsigned name_id, TurnInstruction turn_instruction, EdgeWeight segment_duration)
- : node(node), name_id(name_id), segment_duration(segment_duration), turn_instruction(turn_instruction)
+ PathData(NodeID node,
+ unsigned name_id,
+ TurnInstruction turn_instruction,
+ EdgeWeight segment_duration,
+ TravelMode travel_mode)
+ : node(node), name_id(name_id), segment_duration(segment_duration), turn_instruction(turn_instruction),
+ travel_mode(travel_mode)
{
}
NodeID node;
unsigned name_id;
EdgeWeight segment_duration;
TurnInstruction turn_instruction;
+ TravelMode travel_mode : 4;
};
struct RawRouteData
@@ -60,21 +68,23 @@ struct RawRouteData
std::vector<std::vector<PathData>> unpacked_path_segments;
std::vector<PathData> unpacked_alternative;
std::vector<PhantomNodes> segment_end_coordinates;
- std::vector<FixedPointCoordinate> raw_via_node_coordinates;
std::vector<bool> source_traversed_in_reverse;
std::vector<bool> target_traversed_in_reverse;
std::vector<bool> alt_source_traversed_in_reverse;
std::vector<bool> alt_target_traversed_in_reverse;
- unsigned check_sum;
int shortest_path_length;
int alternative_path_length;
- RawRouteData()
- : check_sum(SPECIAL_NODEID),
+ bool is_via_leg(const std::size_t leg) const
+ {
+ return (leg != unpacked_path_segments.size() - 1);
+ }
+
+ RawRouteData() :
shortest_path_length(INVALID_EDGE_WEIGHT),
alternative_path_length(INVALID_EDGE_WEIGHT)
{
}
};
-#endif // RAW_ROUTE_DATA_H
+#endif // RAW_ROUTE_DATA_HPP
diff --git a/data_structures/rectangle.hpp b/data_structures/rectangle.hpp
new file mode 100644
index 0000000..2f6815c
--- /dev/null
+++ b/data_structures/rectangle.hpp
@@ -0,0 +1,199 @@
+/*
+
+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 RECTANGLE_HPP
+#define RECTANGLE_HPP
+
+#include <boost/assert.hpp>
+
+#include <algorithm>
+#include <cstdint>
+#include <limits>
+
+// TODO: Make template type, add tests
+struct RectangleInt2D
+{
+ RectangleInt2D() : min_lon(std::numeric_limits<int32_t>::max()),
+ max_lon(std::numeric_limits<int32_t>::min()),
+ min_lat(std::numeric_limits<int32_t>::max()),
+ max_lat(std::numeric_limits<int32_t>::min()) {}
+
+ int32_t min_lon, max_lon;
+ int32_t min_lat, max_lat;
+
+ inline void MergeBoundingBoxes(const RectangleInt2D &other)
+ {
+ min_lon = std::min(min_lon, other.min_lon);
+ max_lon = std::max(max_lon, other.max_lon);
+ min_lat = std::min(min_lat, other.min_lat);
+ max_lat = std::max(max_lat, other.max_lat);
+ BOOST_ASSERT(min_lat != std::numeric_limits<int32_t>::min());
+ BOOST_ASSERT(min_lon != std::numeric_limits<int32_t>::min());
+ BOOST_ASSERT(max_lat != std::numeric_limits<int32_t>::min());
+ BOOST_ASSERT(max_lon != std::numeric_limits<int32_t>::min());
+ }
+
+ inline FixedPointCoordinate Centroid() const
+ {
+ FixedPointCoordinate centroid;
+ // The coordinates of the midpoints are given by:
+ // x = (x1 + x2) /2 and y = (y1 + y2) /2.
+ centroid.lon = (min_lon + max_lon) / 2;
+ centroid.lat = (min_lat + max_lat) / 2;
+ return centroid;
+ }
+
+ inline bool Intersects(const RectangleInt2D &other) const
+ {
+ FixedPointCoordinate upper_left(other.max_lat, other.min_lon);
+ FixedPointCoordinate upper_right(other.max_lat, other.max_lon);
+ FixedPointCoordinate lower_right(other.min_lat, other.max_lon);
+ FixedPointCoordinate lower_left(other.min_lat, other.min_lon);
+
+ return (Contains(upper_left) || Contains(upper_right) || Contains(lower_right) ||
+ Contains(lower_left));
+ }
+
+ inline float GetMinDist(const FixedPointCoordinate &location) const
+ {
+ const bool is_contained = Contains(location);
+ if (is_contained)
+ {
+ return 0.0f;
+ }
+
+ enum Direction
+ {
+ INVALID = 0,
+ NORTH = 1,
+ SOUTH = 2,
+ EAST = 4,
+ NORTH_EAST = 5,
+ SOUTH_EAST = 6,
+ WEST = 8,
+ NORTH_WEST = 9,
+ SOUTH_WEST = 10
+ };
+
+ Direction d = INVALID;
+ if (location.lat > max_lat)
+ d = (Direction) (d | NORTH);
+ else if (location.lat < min_lat)
+ d = (Direction) (d | SOUTH);
+ if (location.lon > max_lon)
+ d = (Direction) (d | EAST);
+ else if (location.lon < min_lon)
+ d = (Direction) (d | WEST);
+
+ BOOST_ASSERT(d != INVALID);
+
+ float min_dist = std::numeric_limits<float>::max();
+ switch (d)
+ {
+ case NORTH:
+ min_dist = 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;
+ }
+
+ BOOST_ASSERT(min_dist != std::numeric_limits<float>::max());
+
+ return min_dist;
+ }
+
+ inline float GetMinMaxDist(const FixedPointCoordinate &location) const
+ {
+ float min_max_dist = std::numeric_limits<float>::max();
+ // Get minmax distance to each of the four sides
+ const FixedPointCoordinate upper_left(max_lat, min_lon);
+ const FixedPointCoordinate upper_right(max_lat, max_lon);
+ const FixedPointCoordinate lower_right(min_lat, max_lon);
+ const FixedPointCoordinate lower_left(min_lat, min_lon);
+
+ min_max_dist = std::min(
+ min_max_dist,
+ std::max(
+ 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)));
+ return min_max_dist;
+ }
+
+ inline 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)
+ {
+ out << rect.min_lat / COORDINATE_PRECISION << "," << rect.min_lon / COORDINATE_PRECISION
+ << " " << rect.max_lat / COORDINATE_PRECISION << ","
+ << rect.max_lon / COORDINATE_PRECISION;
+ return out;
+ }
+};
+
+#endif
diff --git a/DataStructures/Restriction.h b/data_structures/restriction.hpp
similarity index 56%
rename from DataStructures/Restriction.h
rename to data_structures/restriction.hpp
index 2b166f5..5f6e9b0 100644
--- a/DataStructures/Restriction.h
+++ b/data_structures/restriction.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
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 RESTRICTION_H
-#define RESTRICTION_H
+#ifndef RESTRICTION_HPP
+#define RESTRICTION_HPP
#include "../typedefs.h"
@@ -34,19 +34,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct TurnRestriction
{
- NodeID viaNode;
- NodeID fromNode;
- NodeID toNode;
+ union WayOrNode
+ {
+ NodeID node;
+ EdgeID way;
+ };
+ WayOrNode via;
+ WayOrNode from;
+ WayOrNode to;
+
struct Bits
{ // mostly unused
Bits()
- : isOnly(false), unused1(false), unused2(false), unused3(false), unused4(false),
+ : is_only(false), uses_via_way(false), unused2(false), unused3(false), unused4(false),
unused5(false), unused6(false), unused7(false)
{
}
- bool isOnly : 1;
- bool unused1 : 1;
+ bool is_only : 1;
+ bool uses_via_way : 1;
bool unused2 : 1;
bool unused3 : 1;
bool unused4 : 1;
@@ -55,57 +61,57 @@ struct TurnRestriction
bool unused7 : 1;
} flags;
- explicit TurnRestriction(NodeID viaNode)
- : viaNode(viaNode), fromNode(std::numeric_limits<unsigned>::max()),
- toNode(std::numeric_limits<unsigned>::max())
+ explicit TurnRestriction(NodeID node)
{
+ via.node = node;
+ from.node = SPECIAL_NODEID;
+ to.node = SPECIAL_NODEID;
}
- explicit TurnRestriction(const bool isOnly = false)
- : viaNode(std::numeric_limits<unsigned>::max()),
- fromNode(std::numeric_limits<unsigned>::max()),
- toNode(std::numeric_limits<unsigned>::max())
+ explicit TurnRestriction(const bool is_only = false)
{
- flags.isOnly = isOnly;
+ via.node = SPECIAL_NODEID;
+ from.node = SPECIAL_NODEID;
+ to.node = SPECIAL_NODEID;
+ flags.is_only = is_only;
}
};
struct InputRestrictionContainer
{
- EdgeID fromWay;
- EdgeID toWay;
- unsigned viaNode;
+ // EdgeID fromWay;
+ // EdgeID toWay;
+ // NodeID via_node;
TurnRestriction restriction;
- InputRestrictionContainer(EdgeID fromWay, EdgeID toWay, NodeID vn, unsigned vw)
- : fromWay(fromWay), toWay(toWay), viaNode(vw)
+ InputRestrictionContainer(EdgeID fromWay, EdgeID toWay, EdgeID vw)
{
- restriction.viaNode = vn;
+ restriction.from.way = fromWay;
+ restriction.to.way = toWay;
+ restriction.via.way = vw;
}
- explicit InputRestrictionContainer(bool isOnly = false)
- : fromWay(std::numeric_limits<unsigned>::max()),
- toWay(std::numeric_limits<unsigned>::max()), viaNode(std::numeric_limits<unsigned>::max())
+ explicit InputRestrictionContainer(bool is_only = false)
{
- restriction.flags.isOnly = isOnly;
+ restriction.from.way = SPECIAL_EDGEID;
+ restriction.to.way = SPECIAL_EDGEID;
+ restriction.via.node = SPECIAL_NODEID;
+ restriction.flags.is_only = is_only;
}
- static InputRestrictionContainer min_value() { return InputRestrictionContainer(0, 0, 0, 0); }
+ static InputRestrictionContainer min_value() { return InputRestrictionContainer(0, 0, 0); }
static InputRestrictionContainer max_value()
{
- return InputRestrictionContainer(std::numeric_limits<unsigned>::max(),
- std::numeric_limits<unsigned>::max(),
- std::numeric_limits<unsigned>::max(),
- std::numeric_limits<unsigned>::max());
+ return InputRestrictionContainer(SPECIAL_EDGEID, SPECIAL_EDGEID, SPECIAL_EDGEID);
}
};
struct CmpRestrictionContainerByFrom
{
typedef InputRestrictionContainer value_type;
- inline bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b)
- const
+ inline bool operator()(const InputRestrictionContainer &a,
+ const InputRestrictionContainer &b) const
{
- return a.fromWay < b.fromWay;
+ 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(); }
@@ -114,13 +120,13 @@ struct CmpRestrictionContainerByFrom
struct CmpRestrictionContainerByTo
{
typedef InputRestrictionContainer value_type;
- inline bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b)
- const
+ inline bool operator()(const InputRestrictionContainer &a,
+ const InputRestrictionContainer &b) const
{
- return a.toWay < b.toWay;
+ return a.restriction.to.way < b.restriction.to.way;
}
value_type max_value() const { return InputRestrictionContainer::max_value(); }
value_type min_value() const { return InputRestrictionContainer::min_value(); }
};
-#endif // RESTRICTION_H
+#endif // RESTRICTION_HPP
diff --git a/DataStructures/RestrictionMap.cpp b/data_structures/restriction_map.cpp
similarity index 56%
rename from DataStructures/RestrictionMap.cpp
rename to data_structures/restriction_map.cpp
index 1859b82..3c13d73 100644
--- a/DataStructures/RestrictionMap.cpp
+++ b/data_structures/restriction_map.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,105 +25,56 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "RestrictionMap.h"
-#include "NodeBasedGraph.h"
+#include "restriction_map.hpp"
-#include "../Util/SimpleLogger.h"
-
-bool RestrictionMap::IsViaNode(const NodeID node) const
-{
- return m_no_turn_via_node_set.find(node) != m_no_turn_via_node_set.end();
-}
-
-RestrictionMap::RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &graph,
- const std::vector<TurnRestriction> &restriction_list)
- : m_count(0), m_graph(graph)
-{
- // 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)
+RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_list)
+ : m_count(0)
{
- m_restriction_start_nodes.insert(restriction.fromNode);
- m_no_turn_via_node_set.insert(restriction.viaNode);
+ // 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);
- RestrictionSource restriction_source = {restriction.fromNode, restriction.viaNode};
+ RestrictionSource restriction_source = {restriction.from.node, restriction.via.node};
- unsigned 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)
+ std::size_t index;
+ auto restriction_iter = m_restriction_map.find(restriction_source);
+ if (restriction_iter == m_restriction_map.end())
{
- continue;
+ index = m_restriction_bucket_list.size();
+ m_restriction_bucket_list.resize(index + 1);
+ m_restriction_map.emplace(restriction_source, index);
}
- else if (restriction.flags.isOnly)
+ else
{
- // 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();
+ 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();
+ }
}
+ ++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.toNode, restriction.flags.isOnly);
}
-}
-// Replace end v with w in each turn restriction containing u as via node
-void RestrictionMap::FixupArrivingTurnRestriction(const NodeID node_u,
- const NodeID node_v,
- const NodeID node_w)
-{
- BOOST_ASSERT(node_u != SPECIAL_NODEID);
- BOOST_ASSERT(node_v != SPECIAL_NODEID);
- BOOST_ASSERT(node_w != SPECIAL_NODEID);
-
- if (!IsViaNode(node_u))
- {
- return;
- }
- // find all potential start edges. It is more efficent to get a (small) list
- // of potential start edges than iterating over all buckets
- std::vector<NodeID> predecessors;
- for (const EdgeID current_edge_id : m_graph->GetAdjacentEdgeRange(node_u))
- {
- const EdgeData &edge_data = m_graph->GetEdgeData(current_edge_id);
- const NodeID target = m_graph->GetTarget(current_edge_id);
- if (edge_data.backward && (node_v != target))
- {
- predecessors.push_back(target);
- }
- }
-
- for (const NodeID node_x : predecessors)
- {
- const auto restriction_iterator = m_restriction_map.find({node_x, node_u});
- if (restriction_iterator == m_restriction_map.end())
- {
- continue;
- }
-
- 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)
- {
- restriction_target.target_node = node_w;
- }
- }
- }
+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,
@@ -163,11 +114,11 @@ NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID node_u, const No
return SPECIAL_NODEID;
}
- auto restriction_iter = m_restriction_map.find({node_u, node_v});
+ const auto restriction_iter = m_restriction_map.find({node_u, node_v});
if (restriction_iter != m_restriction_map.end())
{
const unsigned index = restriction_iter->second;
- auto &bucket = m_restriction_bucket_list.at(index);
+ const auto &bucket = m_restriction_bucket_list.at(index);
for (const RestrictionTarget &restriction_target : bucket)
{
if (restriction_target.is_only)
@@ -184,8 +135,6 @@ bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
const NodeID node_v,
const NodeID node_w) const
{
- // return false;
-
BOOST_ASSERT(node_u != SPECIAL_NODEID);
BOOST_ASSERT(node_v != SPECIAL_NODEID);
BOOST_ASSERT(node_w != SPECIAL_NODEID);
@@ -195,7 +144,7 @@ bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
return false;
}
- auto restriction_iter = m_restriction_map.find({node_u, node_v});
+ const auto restriction_iter = m_restriction_map.find({node_u, node_v});
if (restriction_iter != m_restriction_map.end())
{
const unsigned index = restriction_iter->second;
diff --git a/DataStructures/RestrictionMap.h b/data_structures/restriction_map.hpp
similarity index 52%
rename from DataStructures/RestrictionMap.h
rename to data_structures/restriction_map.hpp
index 8207b80..7633faf 100644
--- a/DataStructures/RestrictionMap.h
+++ b/data_structures/restriction_map.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,19 +25,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef __RESTRICTION_MAP_H__
-#define __RESTRICTION_MAP_H__
+#ifndef RESTRICTION_MAP_HPP
+#define RESTRICTION_MAP_HPP
#include <memory>
-#include "DynamicGraph.h"
-#include "Restriction.h"
-#include "NodeBasedGraph.h"
-#include "../Util/StdHashExtensions.h"
+#include "restriction.hpp"
+#include "../Util/std_hash.hpp"
#include "../typedefs.h"
+#include <boost/assert.hpp>
+
#include <unordered_map>
#include <unordered_set>
+#include <vector>
struct RestrictionSource
{
@@ -95,26 +96,84 @@ template <> struct hash<RestrictionTarget>
class RestrictionMap
{
public:
- RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &graph,
- const std::vector<TurnRestriction> &input_restrictions_list);
+ RestrictionMap(const std::vector<TurnRestriction> &restriction_list);
+
+ // Replace end v with w in each turn restriction containing u as via node
+ template<class GraphT>
+ void FixupArrivingTurnRestriction(const NodeID node_u,
+ const NodeID node_v,
+ const NodeID node_w,
+ const std::shared_ptr<GraphT> &graph)
+ {
+ BOOST_ASSERT(node_u != SPECIAL_NODEID);
+ BOOST_ASSERT(node_v != SPECIAL_NODEID);
+ BOOST_ASSERT(node_w != SPECIAL_NODEID);
+
+ if (!IsViaNode(node_u))
+ {
+ return;
+ }
+
+ // find all potential start edges. It is more efficent to get a (small) list
+ // of potential start edges than iterating over all buckets
+ std::vector<NodeID> predecessors;
+ for (const EdgeID current_edge_id : graph->GetAdjacentEdgeRange(node_u))
+ {
+ const NodeID target = graph->GetTarget(current_edge_id);
+ if (node_v != target)
+ {
+ predecessors.push_back(target);
+ }
+ }
+
+ for (const NodeID node_x : predecessors)
+ {
+ const auto restriction_iterator = m_restriction_map.find({node_x, node_u});
+ if (restriction_iterator == m_restriction_map.end())
+ {
+ continue;
+ }
+
+ 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)
+ {
+ restriction_target.target_node = node_w;
+ }
+ }
+ }
+ }
- void FixupArrivingTurnRestriction(const NodeID u, const NodeID v, const NodeID w);
- void FixupStartingTurnRestriction(const NodeID u, const NodeID v, const NodeID w);
- NodeID CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const;
- bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const;
bool IsViaNode(const NodeID node) const;
- unsigned size()
+
+
+ // 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);
+
+ // 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;
+
+ std::size_t size()
{
return m_count;
}
private:
+ // check of node is the start of any restriction
bool IsSourceNode(const NodeID node) const;
- typedef std::vector<RestrictionTarget> EmanatingRestrictionsVector;
- typedef NodeBasedDynamicGraph::EdgeData EdgeData;
- unsigned m_count;
- std::shared_ptr<NodeBasedDynamicGraph> m_graph;
+ using EmanatingRestrictionsVector = std::vector<RestrictionTarget>;
+
+ std::size_t m_count;
//! index -> list of (target, isOnly)
std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
//! maps (start, via) -> bucket index
@@ -123,4 +182,4 @@ class RestrictionMap
std::unordered_set<NodeID> m_no_turn_via_node_set;
};
-#endif
+#endif //RESTRICTION_MAP_HPP
diff --git a/DataStructures/RouteParameters.cpp b/data_structures/route_parameters.cpp
similarity index 82%
rename from DataStructures/RouteParameters.cpp
rename to data_structures/route_parameters.cpp
index edc7311..1019a91 100644
--- a/DataStructures/RouteParameters.cpp
+++ b/data_structures/route_parameters.cpp
@@ -33,7 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
RouteParameters::RouteParameters()
: zoom_level(18), print_instructions(false), alternate_route(true), geometry(true),
- compression(true), deprecatedAPI(false), check_sum(-1)
+ compression(true), deprecatedAPI(false), uturn_default(false), check_sum(-1), num_results(1)
{
}
@@ -45,8 +45,36 @@ void RouteParameters::setZoomLevel(const short level)
}
}
+void RouteParameters::setNumberOfResults(const short number)
+{
+ if (number > 0 && number <= 100)
+ {
+ num_results = number;
+ }
+}
+
void RouteParameters::setAlternateRouteFlag(const bool flag) { alternate_route = flag; }
+void RouteParameters::setUTurn(const bool flag)
+{
+ uturns.resize(coordinates.size(), uturn_default);
+ if (!uturns.empty())
+ {
+ uturns.back() = flag;
+ }
+}
+
+void RouteParameters::setAllUTurns(const bool flag)
+{
+ // if the flag flips the default, then we erase everything.
+ if (flag)
+ {
+ uturn_default = flag;
+ uturns.clear();
+ uturns.resize(coordinates.size(), uturn_default);
+ }
+}
+
void RouteParameters::setDeprecatedAPIFlag(const std::string &) { deprecatedAPI = true; }
void RouteParameters::setChecksum(const unsigned sum) { check_sum = sum; }
diff --git a/DataStructures/SearchEngine.h b/data_structures/search_engine.hpp
similarity index 86%
rename from DataStructures/SearchEngine.h
rename to data_structures/search_engine.hpp
index 58f5e77..0b2b888 100644
--- a/DataStructures/SearchEngine.h
+++ b/data_structures/search_engine.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,13 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SEARCHENGINE_H
-#define SEARCHENGINE_H
+#ifndef SEARCH_ENGINE_HPP
+#define SEARCH_ENGINE_HPP
-#include "SearchEngineData.h"
-#include "../RoutingAlgorithms/AlternativePathRouting.h"
-#include "../RoutingAlgorithms/ManyToManyRouting.h"
-#include "../RoutingAlgorithms/ShortestPathRouting.h"
+#include "search_engine_data.hpp"
+#include "../routing_algorithms/alternative_path.hpp"
+#include "../routing_algorithms/many_to_many.hpp"
+#include "../routing_algorithms/shortest_path.hpp"
#include <type_traits>
@@ -57,4 +57,4 @@ template <class DataFacadeT> class SearchEngine
~SearchEngine() {}
};
-#endif // SEARCHENGINE_H
+#endif // SEARCH_ENGINE_HPP
diff --git a/DataStructures/SearchEngineData.cpp b/data_structures/search_engine_data.cpp
similarity index 97%
rename from DataStructures/SearchEngineData.cpp
rename to data_structures/search_engine_data.cpp
index a5e4bfc..810762a 100644
--- a/DataStructures/SearchEngineData.cpp
+++ b/data_structures/search_engine_data.cpp
@@ -25,9 +25,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "SearchEngineData.h"
+#include "search_engine_data.hpp"
-#include "BinaryHeap.h"
+#include "binary_heap.hpp"
void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes)
{
diff --git a/DataStructures/SearchEngineData.h b/data_structures/search_engine_data.hpp
similarity index 85%
rename from DataStructures/SearchEngineData.h
rename to data_structures/search_engine_data.hpp
index f0621e6..6c2efb1 100644
--- a/DataStructures/SearchEngineData.h
+++ b/data_structures/search_engine_data.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,13 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SEARCH_ENGINE_DATA_H
-#define SEARCH_ENGINE_DATA_H
+#ifndef SEARCH_ENGINE_DATA_HPP
+#define SEARCH_ENGINE_DATA_HPP
#include <boost/thread/tss.hpp>
#include "../typedefs.h"
-#include "BinaryHeap.h"
+#include "binary_heap.hpp"
struct HeapData
{
@@ -41,8 +41,8 @@ struct HeapData
struct SearchEngineData
{
- typedef BinaryHeap<NodeID, NodeID, int, HeapData, UnorderedMapStorage<NodeID, int>> QueryHeap;
- typedef boost::thread_specific_ptr<QueryHeap> SearchEngineHeapPtr;
+ using QueryHeap = BinaryHeap<NodeID, NodeID, int, HeapData, UnorderedMapStorage<NodeID, int>>;
+ using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
static SearchEngineHeapPtr forwardHeap;
static SearchEngineHeapPtr backwardHeap;
@@ -58,4 +58,4 @@ struct SearchEngineData
void InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes);
};
-#endif // SEARCH_ENGINE_DATA_H
+#endif // SEARCH_ENGINE_DATA_HPP
diff --git a/DataStructures/SegmentInformation.h b/data_structures/segment_information.hpp
similarity index 78%
rename from DataStructures/SegmentInformation.h
rename to data_structures/segment_information.hpp
index f145804..dd1fc57 100644
--- a/DataStructures/SegmentInformation.h
+++ b/data_structures/segment_information.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,8 +28,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SEGMENT_INFORMATION_H
#define SEGMENT_INFORMATION_H
-#include "TurnInstructions.h"
+#include "turn_instructions.hpp"
+#include "../data_structures/travel_mode.hpp"
#include "../typedefs.h"
#include <osrm/Coordinate.h>
@@ -43,8 +44,9 @@ struct SegmentInformation
float length;
short bearing; // more than enough [0..3600] fits into 12 bits
TurnInstruction turn_instruction;
- bool necessary:1;
- bool is_via_location:1;
+ TravelMode travel_mode;
+ bool necessary;
+ bool is_via_location;
explicit SegmentInformation(const FixedPointCoordinate &location,
const NodeID name_id,
@@ -52,9 +54,11 @@ struct SegmentInformation
const float length,
const TurnInstruction turn_instruction,
const bool necessary,
- const bool is_via_location)
+ const bool is_via_location,
+ const TravelMode travel_mode)
: location(location), name_id(name_id), duration(duration), length(length), bearing(0),
- turn_instruction(turn_instruction), necessary(necessary), is_via_location(is_via_location)
+ turn_instruction(turn_instruction), travel_mode(travel_mode), necessary(necessary),
+ is_via_location(is_via_location)
{
}
@@ -62,9 +66,11 @@ struct SegmentInformation
const NodeID name_id,
const EdgeWeight duration,
const float length,
- const TurnInstruction turn_instruction)
+ const TurnInstruction turn_instruction,
+ const TravelMode travel_mode)
: location(location), name_id(name_id), duration(duration), length(length), bearing(0),
- turn_instruction(turn_instruction), necessary(turn_instruction != TurnInstruction::NoTurn), is_via_location(false)
+ turn_instruction(turn_instruction), travel_mode(travel_mode),
+ necessary(turn_instruction != TurnInstruction::NoTurn), is_via_location(false)
{
}
};
diff --git a/DataStructures/SharedMemoryFactory.h b/data_structures/shared_memory_factory.hpp
similarity index 95%
rename from DataStructures/SharedMemoryFactory.h
rename to data_structures/shared_memory_factory.hpp
index a07e125..dc714a6 100644
--- a/DataStructures/SharedMemoryFactory.h
+++ b/data_structures/shared_memory_factory.hpp
@@ -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,11 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SHARED_MEMORY_FACTORY_H
-#define SHARED_MEMORY_FACTORY_H
+#ifndef SHARED_MEMORY_FACTORY_HPP
+#define SHARED_MEMORY_FACTORY_HPP
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
+#include "../Util/osrm_exception.hpp"
+#include "../Util/simple_logger.hpp"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@@ -196,12 +196,14 @@ class SharedMemory
};
#else
// Windows - specific code
-class SharedMemory : boost::noncopyable
+class SharedMemory
{
+ SharedMemory(const SharedMemory&) = delete;
// Remove shared memory on destruction
- class shm_remove : boost::noncopyable
+ class shm_remove
{
private:
+ shm_remove(const shm_remove&) = delete;
char *m_shmid;
bool m_initialized;
@@ -286,7 +288,6 @@ class SharedMemory : boost::noncopyable
private:
static void build_key(int id, char *key)
{
- OSRMLockFile lock_file;
sprintf(key, "%s.%d", "osrm.lock", id);
}
@@ -343,7 +344,7 @@ template <class LockFileT = OSRMLockFile> class SharedMemoryFactory_tmpl
{
if (0 == size)
{
- throw OSRMException("lock file does not exist, exiting");
+ throw osrm::exception("lock file does not exist, exiting");
}
else
{
@@ -357,7 +358,7 @@ template <class LockFileT = OSRMLockFile> class SharedMemoryFactory_tmpl
{
SimpleLogger().Write(logWARNING) << "caught exception: " << e.what() << ", code "
<< e.get_error_code();
- throw OSRMException(e.what());
+ throw osrm::exception(e.what());
}
}
@@ -365,6 +366,6 @@ template <class LockFileT = OSRMLockFile> class SharedMemoryFactory_tmpl
SharedMemoryFactory_tmpl(const SharedMemoryFactory_tmpl &) = delete;
};
-typedef SharedMemoryFactory_tmpl<> SharedMemoryFactory;
+using SharedMemoryFactory = SharedMemoryFactory_tmpl<>;
-#endif /* SHARED_MEMORY_POINTER_FACTORY_H */
+#endif // SHARED_MEMORY_FACTORY_HPP
diff --git a/DataStructures/SharedMemoryVectorWrapper.h b/data_structures/shared_memory_vector_wrapper.hpp
similarity index 89%
rename from DataStructures/SharedMemoryVectorWrapper.h
rename to data_structures/shared_memory_vector_wrapper.hpp
index fe4baf3..d508e5f 100644
--- a/DataStructures/SharedMemoryVectorWrapper.h
+++ b/data_structures/shared_memory_vector_wrapper.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,10 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SHARED_MEMORY_VECTOR_WRAPPER_H
-#define SHARED_MEMORY_VECTOR_WRAPPER_H
-
-#include "../Util/SimpleLogger.h"
+#ifndef SHARED_MEMORY_VECTOR_WRAPPER_HPP
+#define SHARED_MEMORY_VECTOR_WRAPPER_HPP
#include <boost/assert.hpp>
@@ -78,7 +76,7 @@ template <typename DataT> class SharedMemoryWrapper
void swap(SharedMemoryWrapper<DataT> &other)
{
- BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
+ // BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
std::swap(m_size, other.m_size);
std::swap(m_ptr, other.m_ptr);
}
@@ -121,7 +119,7 @@ template <> class SharedMemoryWrapper<bool>
void swap(SharedMemoryWrapper<bool> &other)
{
- BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
+ // BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
std::swap(m_size, other.m_size);
std::swap(m_ptr, other.m_ptr);
}
@@ -148,9 +146,9 @@ template <> class SharedMemoryWrapper<bool>
template <typename DataT, bool UseSharedMemory> struct ShM
{
- typedef typename std::conditional<UseSharedMemory,
+ using vector = typename std::conditional<UseSharedMemory,
SharedMemoryWrapper<DataT>,
- std::vector<DataT>>::type vector;
+ std::vector<DataT>>::type;
};
-#endif // SHARED_MEMORY_VECTOR_WRAPPER_H
+#endif // SHARED_MEMORY_VECTOR_WRAPPER_HPP
diff --git a/DataStructures/StaticGraph.h b/data_structures/static_graph.hpp
similarity index 70%
rename from DataStructures/StaticGraph.h
rename to data_structures/static_graph.hpp
index 9210c87..05d65ee 100644
--- a/DataStructures/StaticGraph.h
+++ b/data_structures/static_graph.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,36 +25,40 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef STATIC_GRAPH_H
-#define STATIC_GRAPH_H
+#ifndef STATIC_GRAPH_HPP
+#define STATIC_GRAPH_HPP
-#include "../DataStructures/Percent.h"
-#include "../DataStructures/SharedMemoryVectorWrapper.h"
-#include "../Util/SimpleLogger.h"
+#include "percent.hpp"
+#include "shared_memory_vector_wrapper.hpp"
+#include "../Util/integer_range.hpp"
#include "../typedefs.h"
#include <boost/assert.hpp>
-#include <boost/range/irange.hpp>
#include <tbb/parallel_sort.h>
#include <algorithm>
#include <limits>
+#include <utility>
#include <vector>
template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
{
public:
- typedef decltype(boost::irange(0u,0u)) EdgeRange;
- typedef NodeID NodeIterator;
- typedef NodeID EdgeIterator;
- typedef EdgeDataT EdgeData;
+ using NodeIterator = NodeID;
+ using EdgeIterator = NodeID;
+ using EdgeData = EdgeDataT;
+ using EdgeRange = osrm::range<EdgeIterator>;
+
class InputEdge
{
public:
- EdgeDataT data;
NodeIterator source;
NodeIterator target;
+ EdgeDataT 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)
@@ -79,18 +83,18 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
EdgeRange GetAdjacentEdgeRange(const NodeID node) const
{
- return boost::irange(BeginEdges(node), EndEdges(node));
+ return osrm::irange(BeginEdges(node), EndEdges(node));
}
StaticGraph(const int nodes, std::vector<InputEdge> &graph)
{
tbb::parallel_sort(graph.begin(), graph.end());
number_of_nodes = nodes;
- number_of_edges = (EdgeIterator)graph.size();
+ number_of_edges = static_cast<EdgeIterator>(graph.size());
node_array.resize(number_of_nodes + 1);
EdgeIterator edge = 0;
EdgeIterator position = 0;
- for (NodeIterator node = 0; node <= number_of_nodes; ++node)
+ for (const auto node : osrm::irange(0u, number_of_nodes+1))
{
EdgeIterator last_edge = edge;
while (edge < number_of_edges && graph[edge].source == node)
@@ -102,7 +106,7 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
}
edge_array.resize(position); //(edge)
edge = 0;
- for (NodeIterator node = 0; node < number_of_nodes; ++node)
+ 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)
@@ -118,51 +122,18 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
StaticGraph(typename ShM<NodeArrayEntry, UseSharedMemory>::vector &nodes,
typename ShM<EdgeArrayEntry, UseSharedMemory>::vector &edges)
{
- number_of_nodes = nodes.size() - 1;
- number_of_edges = edges.size();
+ number_of_nodes = static_cast<decltype(number_of_nodes)>(nodes.size() - 1);
+ number_of_edges = static_cast<decltype(number_of_edges)>(edges.size());
node_array.swap(nodes);
edge_array.swap(edges);
-
-#ifndef NDEBUG
- Percent p(GetNumberOfNodes());
- for (unsigned u = 0; u < GetNumberOfNodes(); ++u)
- {
- for (auto eid : GetAdjacentEdgeRange(u))
- {
- const EdgeData &data = GetEdgeData(eid);
- if (!data.shortcut)
- {
- continue;
- }
- const unsigned v = GetTarget(eid);
- const EdgeID first_edge_id = FindEdgeInEitherDirection(u, data.id);
- if (SPECIAL_EDGEID == first_edge_id)
- {
- SimpleLogger().Write(logWARNING) << "cannot find first segment of edge ("
- << u << "," << data.id << "," << v
- << "), eid: " << eid;
- BOOST_ASSERT(false);
- }
- const EdgeID second_edge_id = FindEdgeInEitherDirection(data.id, v);
- if (SPECIAL_EDGEID == second_edge_id)
- {
- SimpleLogger().Write(logWARNING) << "cannot find second segment of edge ("
- << u << "," << data.id << "," << v
- << "), eid: " << eid;
- BOOST_ASSERT(false);
- }
- }
- p.printIncrement();
- }
-#endif
}
- unsigned GetNumberOfNodes() const { return number_of_nodes -1; }
+ unsigned GetNumberOfNodes() const { return number_of_nodes; }
unsigned GetNumberOfEdges() const { return number_of_edges; }
- unsigned GetOutDegree(const NodeIterator n) const { return BeginEdges(n) - EndEdges(n) - 1; }
+ unsigned GetOutDegree(const NodeIterator n) const { return EndEdges(n) - BeginEdges(n); }
inline NodeIterator GetTarget(const EdgeIterator e) const
{
@@ -230,4 +201,4 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
typename ShM<EdgeArrayEntry, UseSharedMemory>::vector edge_array;
};
-#endif // STATIC_GRAPH_H
+#endif // STATIC_GRAPH_HPP
diff --git a/DataStructures/StaticKDTree.h b/data_structures/static_kdtree.hpp
similarity index 98%
rename from DataStructures/StaticKDTree.h
rename to data_structures/static_kdtree.hpp
index e36eee9..b173d3a 100644
--- a/DataStructures/StaticKDTree.h
+++ b/data_structures/static_kdtree.hpp
@@ -27,8 +27,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// KD Tree coded by Christian Vetter, Monav Project
-#ifndef STATICKDTREE_H_INCLUDED
-#define STATICKDTREE_H_INCLUDED
+#ifndef STATICKDTREE_HPP
+#define STATICKDTREE_HPP
#include <boost/assert.hpp>
#include <vector>
@@ -211,7 +211,7 @@ class StaticKDTree
}
private:
- typedef unsigned Iterator;
+ using Iterator = unsigned;
struct Tree
{
Iterator left;
@@ -257,4 +257,4 @@ class StaticKDTree
};
}
-#endif // STATICKDTREE_H_INCLUDED
+#endif // STATICKDTREE_HPP
diff --git a/DataStructures/StaticRTree.h b/data_structures/static_rtree.hpp
similarity index 69%
rename from DataStructures/StaticRTree.h
rename to data_structures/static_rtree.hpp
index ce306ad..f670ca3 100644
--- a/DataStructures/StaticRTree.h
+++ b/data_structures/static_rtree.hpp
@@ -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,20 +25,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef STATICRTREE_H
-#define STATICRTREE_H
+#ifndef STATIC_RTREE_HPP
+#define STATIC_RTREE_HPP
-#include "DeallocatingVector.h"
-#include "HilbertValue.h"
-#include "PhantomNodes.h"
-#include "QueryNode.h"
-#include "SharedMemoryFactory.h"
-#include "SharedMemoryVectorWrapper.h"
+#include "deallocating_vector.hpp"
+#include "hilbert_value.hpp"
+#include "phantom_node.hpp"
+#include "query_node.hpp"
+#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/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/TimingUtil.h"
+#include "../Util/osrm_exception.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/timing_util.hpp"
#include "../typedefs.h"
#include <osrm/Coordinate.h>
@@ -47,11 +50,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/thread.hpp>
-#include <boost/variant.hpp>
#include <tbb/parallel_for.h>
#include <tbb/parallel_sort.h>
+#include <variant/variant.hpp>
+
#include <algorithm>
#include <array>
#include <limits>
@@ -60,16 +64,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
#include <vector>
-// tuning parameters
-const static uint32_t RTREE_BRANCHING_FACTOR = 64;
-const static uint32_t RTREE_LEAF_NODE_SIZE = 1024;
-
-static boost::thread_specific_ptr<boost::filesystem::ifstream> thread_local_rtree_stream;
-
// Implements a static, i.e. packed, R-tree
template <class EdgeDataT,
class CoordinateListT = std::vector<FixedPointCoordinate>,
- bool UseSharedMemory = false>
+ bool UseSharedMemory = false,
+ uint32_t BRANCHING_FACTOR=64,
+ uint32_t LEAF_NODE_SIZE=1024>
class StaticRTree
{
public:
@@ -80,9 +80,9 @@ class StaticRTree
int32_t min_lon, max_lon;
int32_t min_lat, max_lat;
- inline void InitializeMBRectangle(const std::array<EdgeDataT, RTREE_LEAF_NODE_SIZE> &objects,
+ inline void InitializeMBRectangle(const std::array<EdgeDataT, LEAF_NODE_SIZE> &objects,
const uint32_t element_count,
- const std::vector<NodeInfo> &coordinate_list)
+ const std::vector<QueryNode> &coordinate_list)
{
for (uint32_t i = 0; i < element_count; ++i)
{
@@ -147,19 +147,64 @@ class StaticRTree
return 0.;
}
+ enum Direction
+ {
+ INVALID = 0,
+ NORTH = 1,
+ SOUTH = 2,
+ EAST = 4,
+ NORTH_EAST = 5,
+ SOUTH_EAST = 6,
+ WEST = 8,
+ NORTH_WEST = 9,
+ SOUTH_WEST = 10
+ };
+
+ Direction d = INVALID;
+ if (location.lat > max_lat)
+ d = (Direction) (d | NORTH);
+ else if (location.lat < min_lat)
+ d = (Direction) (d | SOUTH);
+ if (location.lon > max_lon)
+ d = (Direction) (d | EAST);
+ else if (location.lon < min_lon)
+ d = (Direction) (d | WEST);
+
+ BOOST_ASSERT(d != INVALID);
+
float min_dist = std::numeric_limits<float>::max();
- min_dist = std::min(min_dist,
- FixedPointCoordinate::ApproximateEuclideanDistance(
- location.lat, location.lon, max_lat, min_lon));
- min_dist = std::min(min_dist,
- FixedPointCoordinate::ApproximateEuclideanDistance(
- location.lat, location.lon, max_lat, max_lon));
- min_dist = std::min(min_dist,
- FixedPointCoordinate::ApproximateEuclideanDistance(
- location.lat, location.lon, min_lat, max_lon));
- min_dist = std::min(min_dist,
- FixedPointCoordinate::ApproximateEuclideanDistance(
- location.lat, location.lon, min_lat, min_lon));
+ 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;
+ }
+
+ BOOST_ASSERT(min_dist != std::numeric_limits<float>::max());
+
return min_dist;
}
@@ -167,10 +212,10 @@ class StaticRTree
{
float min_max_dist = std::numeric_limits<float>::max();
// Get minmax distance to each of the four sides
- FixedPointCoordinate upper_left(max_lat, min_lon);
- FixedPointCoordinate upper_right(max_lat, max_lon);
- FixedPointCoordinate lower_right(min_lat, max_lon);
- FixedPointCoordinate lower_left(min_lat, min_lon);
+ const FixedPointCoordinate upper_left(max_lat, min_lon);
+ const FixedPointCoordinate upper_right(max_lat, max_lon);
+ const FixedPointCoordinate lower_right(min_lat, max_lon);
+ const FixedPointCoordinate lower_left(min_lat, min_lon);
min_max_dist = std::min(
min_max_dist,
@@ -198,8 +243,8 @@ class StaticRTree
inline 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);
+ 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;
}
@@ -212,7 +257,7 @@ class StaticRTree
}
};
- typedef RectangleInt2D RectangleT;
+ using RectangleT = RectangleInt2D;
struct TreeNode
{
@@ -220,7 +265,7 @@ class StaticRTree
RectangleT minimum_bounding_rectangle;
uint32_t child_count : 31;
bool child_is_on_disk : 1;
- uint32_t children[RTREE_BRANCHING_FACTOR];
+ uint32_t children[BRANCHING_FACTOR];
};
private:
@@ -244,9 +289,9 @@ class StaticRTree
struct LeafNode
{
- LeafNode() : object_count(0) {}
+ LeafNode() : object_count(0), objects() {}
uint32_t object_count;
- std::array<EdgeDataT, RTREE_LEAF_NODE_SIZE> objects;
+ std::array<EdgeDataT, LEAF_NODE_SIZE> objects;
};
struct QueryCandidate
@@ -265,7 +310,7 @@ class StaticRTree
}
};
- typedef boost::variant<TreeNode, EdgeDataT> IncrementalQueryNodeType;
+ using IncrementalQueryNodeType = mapbox::util::variant<TreeNode, EdgeDataT>;
struct IncrementalQueryCandidate
{
explicit IncrementalQueryCandidate(const float dist, const IncrementalQueryNodeType &node)
@@ -281,29 +326,15 @@ class StaticRTree
return other.min_dist < min_dist;
}
- inline bool RepresentsTreeNode() const
- {
- return boost::apply_visitor(decide_type_visitor(), node);
- }
-
float min_dist;
IncrementalQueryNodeType node;
-
- private:
- class decide_type_visitor : public boost::static_visitor<bool>
- {
- public:
- bool operator()(const TreeNode &) const { return true; }
-
- template<typename AnotherType>
- bool operator()(const AnotherType &) const { return false; }
- };
};
typename ShM<TreeNode, UseSharedMemory>::vector m_search_tree;
uint64_t m_element_count;
const std::string m_leaf_node_filename;
std::shared_ptr<CoordinateListT> m_coordinate_list;
+ boost::filesystem::ifstream leaves_stream;
public:
StaticRTree() = delete;
@@ -313,7 +344,7 @@ class StaticRTree
explicit StaticRTree(std::vector<EdgeDataT> &input_data_vector,
const std::string tree_node_filename,
const std::string leaf_node_filename,
- const std::vector<NodeInfo> &coordinate_list)
+ const std::vector<QueryNode> &coordinate_list)
: m_element_count(input_data_vector.size()), m_leaf_node_filename(leaf_node_filename)
{
SimpleLogger().Write() << "constructing r-tree of " << m_element_count
@@ -369,7 +400,7 @@ class StaticRTree
TreeNode current_node;
// SimpleLogger().Write() << "reading " << tree_size << " tree nodes in " <<
// (sizeof(TreeNode)*tree_size) << " bytes";
- for (uint32_t current_element_index = 0; RTREE_LEAF_NODE_SIZE > current_element_index;
+ for (uint32_t current_element_index = 0; LEAF_NODE_SIZE > current_element_index;
++current_element_index)
{
if (m_element_count > (processed_objects_count + current_element_index))
@@ -384,7 +415,7 @@ class StaticRTree
}
// generate tree node that resemble the objects in leaf and store it for next level
- current_node.minimum_bounding_rectangle.InitializeMBRectangle(
+ 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();
@@ -406,9 +437,9 @@ class StaticRTree
while (processed_tree_nodes_in_level < tree_nodes_in_level.size())
{
TreeNode parent_node;
- // pack RTREE_BRANCHING_FACTOR elements into tree_nodes each
+ // pack BRANCHING_FACTOR elements into tree_nodes each
for (uint32_t current_child_node_index = 0;
- RTREE_BRANCHING_FACTOR > 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())
@@ -480,11 +511,11 @@ class StaticRTree
if (!boost::filesystem::exists(node_file))
{
- throw OSRMException("ram index file does not exist");
+ throw osrm::exception("ram index file does not exist");
}
if (0 == boost::filesystem::file_size(node_file))
{
- throw OSRMException("ram index file is empty");
+ throw osrm::exception("ram index file is empty");
}
boost::filesystem::ifstream tree_node_file(node_file, std::ios::binary);
@@ -500,23 +531,22 @@ class StaticRTree
// open leaf node file and store thread specific pointer
if (!boost::filesystem::exists(leaf_file))
{
- throw OSRMException("mem index file does not exist");
+ throw osrm::exception("mem index file does not exist");
}
if (0 == boost::filesystem::file_size(leaf_file))
{
- throw OSRMException("mem index file is empty");
+ throw osrm::exception("mem index file is empty");
}
- boost::filesystem::ifstream leaf_node_file(leaf_file, std::ios::binary);
- leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
- leaf_node_file.close();
+ leaves_stream.open(leaf_file, std::ios::binary);
+ leaves_stream.read((char *)&m_element_count, sizeof(uint64_t));
// SimpleLogger().Write() << tree_size << " nodes in search tree";
// SimpleLogger().Write() << m_element_count << " elements in leafs";
}
explicit StaticRTree(TreeNode *tree_node_ptr,
- const uint32_t number_of_nodes,
+ const uint64_t number_of_nodes,
const boost::filesystem::path &leaf_file,
std::shared_ptr<CoordinateListT> coordinate_list)
: m_search_tree(tree_node_ptr, number_of_nodes), m_leaf_node_filename(leaf_file.string()),
@@ -525,21 +555,15 @@ class StaticRTree
// open leaf node file and store thread specific pointer
if (!boost::filesystem::exists(leaf_file))
{
- throw OSRMException("mem index file does not exist");
+ throw osrm::exception("mem index file does not exist");
}
if (0 == boost::filesystem::file_size(leaf_file))
{
- throw OSRMException("mem index file is empty");
+ throw osrm::exception("mem index file is empty");
}
- boost::filesystem::ifstream leaf_node_file(leaf_file, std::ios::binary);
- leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
- leaf_node_file.close();
-
- if (thread_local_rtree_stream.get())
- {
- thread_local_rtree_stream->close();
- }
+ leaves_stream.open(leaf_file, std::ios::binary);
+ leaves_stream.read((char *)&m_element_count, sizeof(uint64_t));
// SimpleLogger().Write() << tree_size << " nodes in search tree";
// SimpleLogger().Write() << m_element_count << " elements in leafs";
@@ -576,7 +600,7 @@ class StaticRTree
for (uint32_t i = 0; i < current_leaf_node.object_count; ++i)
{
EdgeDataT const ¤t_edge = current_leaf_node.objects[i];
- if (ignore_tiny_components && current_edge.is_in_tiny_cc)
+ if (ignore_tiny_components && current_edge.component_id != 0)
{
continue;
}
@@ -619,32 +643,163 @@ class StaticRTree
}
}
}
- return result_coordinate.isValid();
+ 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 zoom_level,
- const unsigned number_of_results,
- const unsigned max_checked_segments = 4*RTREE_LEAF_NODE_SIZE)
+ const unsigned max_number_of_phantom_nodes,
+ const unsigned max_checked_elements = 4*LEAF_NODE_SIZE)
{
- // TIMER_START(samet);
- // SimpleLogger().Write(logDEBUG) << "searching for " << number_of_results << " results";
- 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 dequeues = 0;
- unsigned inspected_mbrs = 0;
- unsigned loaded_leafs = 0;
- unsigned inspected_segments = 0;
- unsigned pruned_elements = 0;
- unsigned ignored_segments = 0;
- unsigned ignored_mbrs = 0;
+ // initialize queue with root element
+ std::priority_queue<IncrementalQueryCandidate> traversal_queue;
+ traversal_queue.emplace(0.f, m_search_tree[0]);
+
+ while (!traversal_queue.empty())
+ {
+ const IncrementalQueryCandidate current_query_node = traversal_queue.top();
+ traversal_queue.pop();
+
+ 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>();
+ if (current_tree_node.child_is_on_disk)
+ {
+ LeafNode current_leaf_node;
+ LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
+
+ // 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(
+ m_coordinate_list->at(current_edge.u),
+ m_coordinate_list->at(current_edge.v),
+ input_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);
+ }
+ }
+ else
+ {
+ // 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);
+ BOOST_ASSERT(0.f <= lower_bound_to_element);
+
+ traversal_queue.emplace(lower_bound_to_element, child_tree_node);
+ }
+ }
+ }
+ else
+ { // current object is a leaf node
+ ++inspected_elements;
+ // inspecting an actual road segment
+ const EdgeDataT & current_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 &&
+ number_of_elements_from_tiny_cc >= max_number_of_phantom_nodes &&
+ current_segment.is_in_tiny_cc())
+ {
+ continue;
+ }
+
+ // 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);
+
+ // 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);
+
+ // 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());
+
+ // 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;
+ }
+
+ // 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) ||
+ inspected_elements >= max_checked_elements)
+ {
+ traversal_queue = std::priority_queue<IncrementalQueryCandidate>{};
+ }
+ }
+ // SimpleLogger().Write() << "inspected_elements: " << inspected_elements;
+ 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)
+ {
+ std::vector<float> min_found_distances(number_of_results, std::numeric_limits<float>::max());
unsigned number_of_results_found_in_big_cc = 0;
unsigned number_of_results_found_in_tiny_cc = 0;
+ unsigned inspected_segments = 0;
+
// initialize queue with root element
std::priority_queue<IncrementalQueryCandidate> traversal_queue;
traversal_queue.emplace(0.f, m_search_tree[0]);
@@ -654,28 +809,18 @@ class StaticRTree
const IncrementalQueryCandidate current_query_node = traversal_queue.top();
traversal_queue.pop();
- ++dequeues;
-
const float current_min_dist = min_found_distances[number_of_results-1];
if (current_query_node.min_dist > current_min_dist)
{
- ++pruned_elements;
continue;
}
if (current_query_node.RepresentsTreeNode())
{
- const TreeNode & current_tree_node = boost::get<TreeNode>(current_query_node.node);
+ const TreeNode & current_tree_node = current_query_node.node.template get<TreeNode>();
if (current_tree_node.child_is_on_disk)
{
- ++loaded_leafs;
- // SimpleLogger().Write(logDEBUG) << "loading leaf: " << current_tree_node.children[0] << " w/ mbr [" <<
- // current_tree_node.minimum_bounding_rectangle.min_lat/COORDINATE_PRECISION << "," <<
- // current_tree_node.minimum_bounding_rectangle.min_lon/COORDINATE_PRECISION << "," <<
- // current_tree_node.minimum_bounding_rectangle.max_lat/COORDINATE_PRECISION << "-" <<
- // current_tree_node.minimum_bounding_rectangle.max_lon/COORDINATE_PRECISION << "]";
-
LeafNode current_leaf_node;
LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
// Add all objects from leaf into queue
@@ -694,23 +839,10 @@ class StaticRTree
{
traversal_queue.emplace(current_perpendicular_distance, current_edge);
}
- else
- {
- ++ignored_segments;
- }
}
- // SimpleLogger().Write(logDEBUG) << "added " << current_leaf_node.object_count << " roads into queue of " << traversal_queue.size();
}
else
{
- ++inspected_mbrs;
- // explore inner node
- // SimpleLogger().Write(logDEBUG) << "explore inner node w/ mbr [" <<
- // current_tree_node.minimum_bounding_rectangle.min_lat/COORDINATE_PRECISION << "," <<
- // current_tree_node.minimum_bounding_rectangle.min_lon/COORDINATE_PRECISION << "," <<
- // current_tree_node.minimum_bounding_rectangle.max_lat/COORDINATE_PRECISION << "-" <<
- // current_tree_node.minimum_bounding_rectangle.max_lon/COORDINATE_PRECISION << "," << "]";
-
// for each child mbr
for (uint32_t i = 0; i < current_tree_node.child_count; ++i)
{
@@ -727,10 +859,6 @@ class StaticRTree
{
traversal_queue.emplace(lower_bound_to_element, child_tree_node);
}
- else
- {
- ++ignored_mbrs;
- }
}
// SimpleLogger().Write(logDEBUG) << "added " << current_tree_node.child_count << " mbrs into queue of " << traversal_queue.size();
}
@@ -739,7 +867,7 @@ class StaticRTree
{
++inspected_segments;
// inspecting an actual road segment
- const EdgeDataT & current_segment = boost::get<EdgeDataT>(current_query_node.node);
+ 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)
@@ -767,20 +895,21 @@ class StaticRTree
BOOST_ASSERT(0. <= current_perpendicular_distance);
if ((current_perpendicular_distance < current_min_dist) &&
- !EpsilonCompare(current_perpendicular_distance, current_min_dist))
+ !osrm::epsilon_compare(current_perpendicular_distance, current_min_dist))
{
// 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,
- foot_point_coordinate_on_segment,
- current_segment.fwd_segment_position);
+ 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());
@@ -813,40 +942,15 @@ class StaticRTree
}
}
- // for (const PhantomNode& result_node : result_phantom_node_vector)
- // {
- // SimpleLogger().Write(logDEBUG) << std::setprecision(8) << "found location " << result_node.forward_node_id << " at " << result_node.location;
- // }
- // SimpleLogger().Write(logDEBUG) << "dequeues: " << dequeues;
- // SimpleLogger().Write(logDEBUG) << "inspected_mbrs: " << inspected_mbrs;
- // SimpleLogger().Write(logDEBUG) << "loaded_leafs: " << loaded_leafs;
- // SimpleLogger().Write(logDEBUG) << "inspected_segments: " << inspected_segments;
- // SimpleLogger().Write(logDEBUG) << "pruned_elements: " << pruned_elements;
- // SimpleLogger().Write(logDEBUG) << "ignored_segments: " << ignored_segments;
- // SimpleLogger().Write(logDEBUG) << "ignored_mbrs: " << ignored_mbrs;
-
- // SimpleLogger().Write(logDEBUG) << "number_of_results_found_in_big_cc: " << number_of_results_found_in_big_cc;
- // SimpleLogger().Write(logDEBUG) << "number_of_results_found_in_tiny_cc: " << number_of_results_found_in_tiny_cc;
- // TIMER_STOP(samet);
- // SimpleLogger().Write() << "query took " << TIMER_MSEC(samet) << "ms";
-
- // if we found an element in either category, then we are good
return !result_phantom_node_vector.empty();
}
+
+
bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
PhantomNode &result_phantom_node,
const unsigned zoom_level)
{
-
- std::vector<PhantomNode> result_phantom_node_vector;
- IncrementalFindPhantomNodeForCoordinate(input_coordinate, result_phantom_node_vector, zoom_level, 2);
- // if (!result_phantom_node_vector.empty())
- // {
- // result_phantom_node = result_phantom_node_vector.front();
- // }
- // return !result_phantom_node_vector.empty();
-
const bool ignore_tiny_components = (zoom_level <= 14);
EdgeDataT nearest_edge;
@@ -873,7 +977,7 @@ class StaticRTree
for (uint32_t i = 0; i < current_leaf_node.object_count; ++i)
{
const EdgeDataT ¤t_edge = current_leaf_node.objects[i];
- if (ignore_tiny_components && current_edge.is_in_tiny_cc)
+ if (ignore_tiny_components && current_edge.component_id != 0)
{
continue;
}
@@ -891,7 +995,7 @@ class StaticRTree
BOOST_ASSERT(0. <= current_perpendicular_distance);
if ((current_perpendicular_distance < min_dist) &&
- !EpsilonCompare(current_perpendicular_distance, min_dist))
+ !osrm::epsilon_compare(current_perpendicular_distance, min_dist))
{ // found a new minimum
min_dist = current_perpendicular_distance;
result_phantom_node = {current_edge.forward_edge_based_node_id,
@@ -902,8 +1006,11 @@ class StaticRTree
current_edge.forward_offset,
current_edge.reverse_offset,
current_edge.packed_geometry_id,
+ current_edge.component_id,
nearest,
- current_edge.fwd_segment_position};
+ current_edge.fwd_segment_position,
+ current_edge.forward_travel_mode,
+ current_edge.backward_travel_mode};
nearest_edge = current_edge;
}
}
@@ -919,7 +1026,7 @@ class StaticRTree
}
}
- if (result_phantom_node.location.isValid())
+ if (result_phantom_node.location.is_valid())
{
// Hack to fix rounding errors and wandering via nodes.
FixUpRoundingIssue(input_coordinate, result_phantom_node);
@@ -927,7 +1034,7 @@ class StaticRTree
// set forward and reverse weights on the phantom node
SetForwardAndReverseWeightsOnPhantomNode(nearest_edge, result_phantom_node);
}
- return result_phantom_node.location.isValid();
+ return result_phantom_node.location.is_valid();
}
private:
@@ -941,13 +1048,20 @@ class StaticRTree
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");
+
if (SPECIAL_NODEID != result_phantom_node.forward_node_id)
{
- 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)
{
- 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;
}
}
@@ -997,22 +1111,21 @@ class StaticRTree
inline void LoadLeafFromDisk(const uint32_t leaf_id, LeafNode &result_node)
{
- if (!thread_local_rtree_stream.get() || !thread_local_rtree_stream->is_open())
+ if (!leaves_stream.is_open())
{
- thread_local_rtree_stream.reset(new boost::filesystem::ifstream(
- m_leaf_node_filename, std::ios::in | std::ios::binary));
+ leaves_stream.open(m_leaf_node_filename, std::ios::in | std::ios::binary);
}
- if (!thread_local_rtree_stream->good())
+ if (!leaves_stream.good())
{
- thread_local_rtree_stream->clear(std::ios::goodbit);
+ leaves_stream.clear(std::ios::goodbit);
SimpleLogger().Write(logDEBUG) << "Resetting stale filestream";
}
const uint64_t seek_pos = sizeof(uint64_t) + leaf_id * sizeof(LeafNode);
- thread_local_rtree_stream->seekg(seek_pos);
- BOOST_ASSERT_MSG(thread_local_rtree_stream->good(),
+ leaves_stream.seekg(seek_pos);
+ BOOST_ASSERT_MSG(leaves_stream.good(),
"Seeking to position in leaf file failed.");
- thread_local_rtree_stream->read((char *)&result_node, sizeof(LeafNode));
- BOOST_ASSERT_MSG(thread_local_rtree_stream->good(), "Reading from leaf file failed.");
+ leaves_stream.read((char *)&result_node, sizeof(LeafNode));
+ BOOST_ASSERT_MSG(leaves_stream.good(), "Reading from leaf file failed.");
}
inline bool EdgesAreEquivalent(const FixedPointCoordinate &a,
@@ -1023,9 +1136,31 @@ class StaticRTree
return (a == b && c == d) || (a == c && b == d) || (a == d && b == c);
}
- template <typename FloatT> inline bool EpsilonCompare(const FloatT d1, const FloatT d2) const
+ inline void InitializeMBRectangle(RectangleT& rectangle,
+ const std::array<EdgeDataT, LEAF_NODE_SIZE> &objects,
+ const uint32_t element_count,
+ const std::vector<QueryNode> &coordinate_list)
{
- return (std::abs(d1 - d2) < std::numeric_limits<FloatT>::epsilon());
+ 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));
+ }
+ BOOST_ASSERT(rectangle.min_lat != std::numeric_limits<int>::min());
+ BOOST_ASSERT(rectangle.min_lon != std::numeric_limits<int>::min());
+ BOOST_ASSERT(rectangle.max_lat != std::numeric_limits<int>::min());
+ BOOST_ASSERT(rectangle.max_lon != std::numeric_limits<int>::min());
}
};
@@ -1033,4 +1168,4 @@ class StaticRTree
//[2] "Nearest Neighbor Queries", N. Roussopulos et al; 1995; DOI: 10.1145/223784.223794
//[3] "Distance Browsing in Spatial Databases"; G. Hjaltason, H. Samet; 1999; ACM Trans. DB Sys
// Vol.24 No.2, pp.265-318
-#endif // STATICRTREE_H
+#endif // STATIC_RTREE_HPP
diff --git a/Server/Http/CompressionType.h b/data_structures/travel_mode.hpp
similarity index 81%
copy from Server/Http/CompressionType.h
copy to data_structures/travel_mode.hpp
index 74d0b62..345ec90 100644
--- a/Server/Http/CompressionType.h
+++ b/data_structures/travel_mode.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,17 +25,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef COMPRESSION_TYPE_H
-#define COMPRESSION_TYPE_H
+#ifndef TRAVEL_MODE_HPP
+#define TRAVEL_MODE_HPP
-namespace http
-{
-
-enum CompressionType
-{ noCompression,
- gzipRFC1952,
- deflateRFC1951 };
-
-} // namespace http
-
-#endif // COMPRESSION_TYPE_H
+namespace {
+using TravelMode = unsigned char;
+static const TravelMode TRAVEL_MODE_INACCESSIBLE = 0;
+static const TravelMode TRAVEL_MODE_DEFAULT = 1;
+}
+#endif /* TRAVEL_MODE_HPP */
diff --git a/DataStructures/TurnInstructions.h b/data_structures/turn_instructions.hpp
similarity index 92%
rename from DataStructures/TurnInstructions.h
rename to data_structures/turn_instructions.hpp
index 61de3b1..4b36658 100644
--- a/DataStructures/TurnInstructions.h
+++ b/data_structures/turn_instructions.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,13 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TURN_INSTRUCTIONS_H
-#define TURN_INSTRUCTIONS_H
+#ifndef TURN_INSTRUCTIONS_HPP
+#define TURN_INSTRUCTIONS_HPP
enum class TurnInstruction : unsigned char
{
NoTurn = 0, GoStraight, TurnSlightRight, TurnRight, TurnSharpRight, UTurn,
- TurnSharpLeft, TurnLeft, TurnSlightLeft, ReachViaPoint, HeadOn, EnterRoundAbout,
+ TurnSharpLeft, TurnLeft, TurnSlightLeft, ReachViaLocation, HeadOn, EnterRoundAbout,
LeaveRoundAbout, StayOnRoundAbout, StartAtEndOfStreet, ReachedYourDestination,
EnterAgainstAllowedDirection, LeaveAgainstAllowedDirection,
InverseAccessRestrictionFlag = 127,
@@ -87,4 +87,4 @@ struct TurnInstructionsClass
}
};
-#endif /* TURN_INSTRUCTIONS_H */
+#endif /* TURN_INSTRUCTIONS_HPP */
diff --git a/DataStructures/XORFastHash.h b/data_structures/xor_fast_hash.hpp
similarity index 95%
rename from DataStructures/XORFastHash.h
rename to data_structures/xor_fast_hash.hpp
index ee36830..1f6dc29 100644
--- a/DataStructures/XORFastHash.h
+++ b/data_structures/xor_fast_hash.hpp
@@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef XOR_FAST_HASH_H
-#define XOR_FAST_HASH_H
+#ifndef XOR_FAST_HASH_HPP
+#define XOR_FAST_HASH_HPP
#include <algorithm>
#include <vector>
@@ -70,7 +70,7 @@ class XORFastHash
inline unsigned short operator()(const unsigned originalValue) const
{
- unsigned short lsb = ((originalValue) & 0xffff);
+ unsigned short lsb = ((originalValue)&0xffff);
unsigned short msb = (((originalValue) >> 16) & 0xffff);
return table1[lsb] ^ table2[msb];
}
@@ -104,7 +104,7 @@ class XORMiniHash
}
unsigned char operator()(const unsigned originalValue) const
{
- unsigned char byte1 = ((originalValue) & 0xff);
+ unsigned char byte1 = ((originalValue)&0xff);
unsigned char byte2 = ((originalValue >> 8) & 0xff);
unsigned char byte3 = ((originalValue >> 16) & 0xff);
unsigned char byte4 = ((originalValue >> 24) & 0xff);
@@ -112,4 +112,4 @@ class XORMiniHash
}
};
-#endif // XOR_FAST_HASH_H
+#endif // XOR_FAST_HASH_HPP
diff --git a/DataStructures/XORFastHashStorage.h b/data_structures/xor_fast_hash_storage.hpp
similarity index 88%
rename from DataStructures/XORFastHashStorage.h
rename to data_structures/xor_fast_hash_storage.hpp
index abdb9ac..1d84260 100644
--- a/DataStructures/XORFastHashStorage.h
+++ b/data_structures/xor_fast_hash_storage.hpp
@@ -25,10 +25,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef XOR_FAST_HASH_STORAGE_H
-#define XOR_FAST_HASH_STORAGE_H
+#ifndef XOR_FAST_HASH_STORAGE_HPP
+#define XOR_FAST_HASH_STORAGE_HPP
-#include "XORFastHash.h"
+#include "xor_fast_hash.hpp"
#include <limits>
#include <vector>
@@ -49,14 +49,14 @@ template <typename NodeID, typename Key> class XORFastHashStorage
HashCell(const HashCell &other) : key(other.key), id(other.id), time(other.time) {}
- inline operator Key() const { return key; }
+ operator Key() const { return key; }
- inline void operator=(const Key &key_to_insert) { key = key_to_insert; }
+ void operator=(const Key &key_to_insert) { key = key_to_insert; }
};
explicit XORFastHashStorage(size_t) : positions(2 << 16), current_timestamp(0) {}
- inline HashCell &operator[](const NodeID node)
+ HashCell &operator[](const NodeID node)
{
unsigned short position = fast_hasher(node);
while ((positions[position].time == current_timestamp) && (positions[position].id != node))
@@ -69,7 +69,7 @@ template <typename NodeID, typename Key> class XORFastHashStorage
return positions[position];
}
- inline void Clear()
+ void Clear()
{
++current_timestamp;
if (std::numeric_limits<unsigned>::max() == current_timestamp)
@@ -86,4 +86,4 @@ template <typename NodeID, typename Key> class XORFastHashStorage
unsigned current_timestamp;
};
-#endif // XOR_FAST_HASH_STORAGE_H
+#endif // XOR_FAST_HASH_STORAGE_HPP
diff --git a/datastore.cpp b/datastore.cpp
index 10d5bf5..d292004 100644
--- a/datastore.cpp
+++ b/datastore.cpp
@@ -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,28 +25,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "DataStructures/OriginalEdgeData.h"
-#include "DataStructures/RangeTable.h"
-#include "DataStructures/QueryEdge.h"
-#include "DataStructures/SharedMemoryFactory.h"
-#include "DataStructures/SharedMemoryVectorWrapper.h"
-#include "DataStructures/StaticGraph.h"
-#include "DataStructures/StaticRTree.h"
-#include "DataStructures/TurnInstructions.h"
+#include "data_structures/original_edge_data.hpp"
+#include "data_structures/range_table.hpp"
+#include "data_structures/query_edge.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/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/SimpleLogger.h"
+#include "Util/simple_logger.hpp"
+#include "Util/osrm_exception.hpp"
#include "Util/FingerPrint.h"
#include "typedefs.h"
#include <osrm/Coordinate.h>
-typedef BaseDataFacade<QueryEdge::EdgeData>::RTreeLeaf RTreeLeaf;
-typedef StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode RTreeNode;
-typedef StaticGraph<QueryEdge::EdgeData> QueryGraph;
+using RTreeLeaf = BaseDataFacade<QueryEdge::EdgeData>::RTreeLeaf;
+using RTreeNode = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode;
+using QueryGraph = StaticGraph<QueryEdge::EdgeData>;
#ifdef __linux__
#include <sys/mman.h>
@@ -60,21 +61,51 @@ typedef StaticGraph<QueryEdge::EdgeData> QueryGraph;
#include <fstream>
#include <string>
+// delete a shared memory region. report warning if it could not be deleted
+void delete_region(const SharedDataType region)
+{
+ if (SharedMemory::RegionExists(region) && !SharedMemory::Remove(region))
+ {
+ const std::string name = [&]
+ {
+ switch (region)
+ {
+ case CURRENT_REGIONS:
+ return "CURRENT_REGIONS";
+ case LAYOUT_1:
+ return "LAYOUT_1";
+ case DATA_1:
+ return "DATA_1";
+ case LAYOUT_2:
+ return "LAYOUT_2";
+ case DATA_2:
+ return "DATA_2";
+ case LAYOUT_NONE:
+ return "LAYOUT_NONE";
+ default: // DATA_NONE:
+ return "DATA_NONE";
+ }
+ }();
+
+ SimpleLogger().Write(logWARNING) << "could not delete shared memory region " << name;
+ }
+}
+
int main(const int argc, const char *argv[])
{
LogPolicy::GetInstance().Unmute();
SharedBarriers barrier;
-#ifdef __linux__
- const bool lock_flags = MCL_CURRENT | MCL_FUTURE;
- if (-1 == mlockall(lock_flags))
- {
- SimpleLogger().Write(logWARNING) << "Process " << argv[0] << " could not request RAM lock";
- }
-#endif
-
try
{
+#ifdef __linux__
+ // try to disable swapping on Linux
+ const bool lock_flags = MCL_CURRENT | MCL_FUTURE;
+ if (-1 == mlockall(lock_flags))
+ {
+ SimpleLogger().Write(logWARNING) << "Process " << argv[0] << " could not request RAM lock";
+ }
+#endif
try
{
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
@@ -96,66 +127,38 @@ int main(const int argc, const char *argv[])
SimpleLogger().Write(logDEBUG) << "Checking input parameters";
ServerPaths server_paths;
- bool springclean = false;
- if (!GenerateDataStoreOptions(argc, argv, server_paths, springclean))
+ if (!GenerateDataStoreOptions(argc, argv, server_paths))
{
return 0;
}
- if (springclean)
- {
- SimpleLogger().Write() << "spring-cleaning all shared memory regions";
- // find all existing shmem regions and remove them.
- if (SharedMemory::RegionExists(DATA_1) && !SharedMemory::Remove(DATA_1))
- {
- SimpleLogger().Write(logWARNING) << "could not delete DATA_1";
- }
- if (SharedMemory::RegionExists(LAYOUT_1) && !SharedMemory::Remove(LAYOUT_1))
- {
- SimpleLogger().Write(logWARNING) << "could not delete LAYOUT_1";
- }
- if (SharedMemory::RegionExists(DATA_2) && !SharedMemory::Remove(DATA_2))
- {
- SimpleLogger().Write(logWARNING) << "could not delete DATA_2";
- }
- if (SharedMemory::RegionExists(LAYOUT_2) && !SharedMemory::Remove(LAYOUT_2))
- {
- SimpleLogger().Write(logWARNING) << "could not delete LAYOUT_2";
- }
- if (SharedMemory::RegionExists(CURRENT_REGIONS) &&
- !SharedMemory::Remove(CURRENT_REGIONS))
- {
- SimpleLogger().Write(logWARNING) << "could not delete CURRENT_REGIONS";
- }
- return 0;
- }
if (server_paths.find("hsgrdata") == server_paths.end())
{
- throw OSRMException("no hsgr file found");
+ throw osrm::exception("no hsgr file found");
}
if (server_paths.find("ramindex") == server_paths.end())
{
- throw OSRMException("no ram index file found");
+ throw osrm::exception("no ram index file found");
}
if (server_paths.find("fileindex") == server_paths.end())
{
- throw OSRMException("no leaf index file found");
+ throw osrm::exception("no leaf index file found");
}
if (server_paths.find("nodesdata") == server_paths.end())
{
- throw OSRMException("no nodes file found");
+ throw osrm::exception("no nodes file found");
}
if (server_paths.find("edgesdata") == server_paths.end())
{
- throw OSRMException("no edges file found");
+ throw osrm::exception("no edges file found");
}
if (server_paths.find("namesdata") == server_paths.end())
{
- throw OSRMException("no names file found");
+ throw osrm::exception("no names file found");
}
if (server_paths.find("geometry") == server_paths.end())
{
- throw OSRMException("no geometry file found");
+ throw osrm::exception("no geometry file found");
}
ServerPaths::const_iterator paths_iterator = server_paths.find("hsgrdata");
@@ -193,27 +196,28 @@ int main(const int argc, const char *argv[])
BOOST_ASSERT(!paths_iterator->second.empty());
const boost::filesystem::path &geometries_data_path = paths_iterator->second;
- // get the shared memory segment to use
- bool use_first_segment = SharedMemory::RegionExists(LAYOUT_2);
- const SharedDataType LAYOUT = [&]
+ // determine segment to use
+ bool segment2_in_use = SharedMemory::RegionExists(LAYOUT_2);
+ const SharedDataType layout_region = [&]
{
- if (use_first_segment)
- {
- return LAYOUT_1;
- }
- return LAYOUT_2;
+ return segment2_in_use ? LAYOUT_1 : LAYOUT_2;
}();
- const SharedDataType DATA = [&]
+ const SharedDataType data_region = [&]
{
- if (use_first_segment)
- {
- return DATA_1;
- }
- return DATA_2;
+ return segment2_in_use ? DATA_1 : DATA_2;
+ }();
+ const SharedDataType previous_layout_region = [&]
+ {
+ return segment2_in_use ? LAYOUT_2 : LAYOUT_1;
+ }();
+ const SharedDataType previous_data_region = [&]
+ {
+ return segment2_in_use ? DATA_2 : DATA_1;
}();
// Allocate a memory layout in shared memory, deallocate previous
- SharedMemory *layout_memory = SharedMemoryFactory::Get(LAYOUT, sizeof(SharedDataLayout));
+ SharedMemory *layout_memory =
+ SharedMemoryFactory::Get(layout_region, sizeof(SharedDataLayout));
SharedDataLayout *shared_layout_ptr = static_cast<SharedDataLayout *>(layout_memory->Ptr());
shared_layout_ptr = new (layout_memory->Ptr()) SharedDataLayout();
@@ -246,6 +250,8 @@ int main(const int argc, const char *argv[])
number_of_original_edges);
shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::NAME_ID_LIST,
number_of_original_edges);
+ shared_layout_ptr->SetBlockSize<TravelMode>(SharedDataLayout::TRAVEL_MODE,
+ number_of_original_edges);
shared_layout_ptr->SetBlockSize<TurnInstruction>(SharedDataLayout::TURN_INSTRUCTION,
number_of_original_edges);
// note: there are 32 geometry indicators in one unsigned block
@@ -281,7 +287,7 @@ int main(const int argc, const char *argv[])
// load graph edge size
unsigned number_of_graph_edges = 0;
hsgr_input_stream.read((char *)&number_of_graph_edges, sizeof(unsigned));
- BOOST_ASSERT_MSG(0 != number_of_graph_edges, "number of graph edges is zero");
+ // BOOST_ASSERT_MSG(0 != number_of_graph_edges, "number of graph edges is zero");
shared_layout_ptr->SetBlockSize<QueryGraph::EdgeArrayEntry>(
SharedDataLayout::GRAPH_EDGE_LIST, number_of_graph_edges);
@@ -339,12 +345,11 @@ int main(const int argc, const char *argv[])
geometry_input_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::GEOMETRIES_LIST,
number_of_compressed_geometries);
-
// allocate shared memory block
SimpleLogger().Write() << "allocating shared memory of "
<< shared_layout_ptr->GetSizeOfLayout() << " bytes";
SharedMemory *shared_memory =
- SharedMemoryFactory::Get(DATA, shared_layout_ptr->GetSizeOfLayout());
+ SharedMemoryFactory::Get(data_region, shared_layout_ptr->GetSizeOfLayout());
char *shared_memory_ptr = static_cast<char *>(shared_memory->Ptr());
// read actual data into shared memory object //
@@ -405,6 +410,10 @@ 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);
+
TurnInstruction *turn_instructions_ptr =
shared_layout_ptr->GetBlockPtr<TurnInstruction, true>(
shared_memory_ptr, SharedDataLayout::TURN_INSTRUCTION);
@@ -418,6 +427,7 @@ int main(const int argc, const char *argv[])
edges_input_stream.read((char *)&(current_edge_data), sizeof(OriginalEdgeData));
via_node_ptr[i] = current_edge_data.via_node;
name_id_ptr[i] = current_edge_data.name_id;
+ travel_mode_ptr[i] = current_edge_data.travel_mode;
turn_instructions_ptr[i] = current_edge_data.turn_instruction;
const unsigned bucket = i / 32;
@@ -472,10 +482,10 @@ int main(const int argc, const char *argv[])
shared_layout_ptr->GetBlockPtr<FixedPointCoordinate, true>(
shared_memory_ptr, SharedDataLayout::COORDINATE_LIST);
- NodeInfo current_node;
+ QueryNode current_node;
for (unsigned i = 0; i < coordinate_list_size; ++i)
{
- nodes_input_stream.read((char *)¤t_node, sizeof(NodeInfo));
+ nodes_input_stream.read((char *)¤t_node, sizeof(QueryNode));
coordinates_ptr[i] = FixedPointCoordinate(current_node.lat, current_node.lon);
}
nodes_input_stream.close();
@@ -533,35 +543,11 @@ int main(const int argc, const char *argv[])
barrier.no_running_queries_condition.wait(query_lock);
}
- data_timestamp_ptr->layout = LAYOUT;
- data_timestamp_ptr->data = DATA;
+ data_timestamp_ptr->layout = layout_region;
+ data_timestamp_ptr->data = data_region;
data_timestamp_ptr->timestamp += 1;
- if (use_first_segment)
- {
- BOOST_ASSERT(DATA == DATA_1);
- BOOST_ASSERT(LAYOUT == LAYOUT_1);
- if (!SharedMemory::Remove(DATA_2))
- {
- SimpleLogger().Write(logWARNING) << "could not delete DATA_2";
- }
- if (!SharedMemory::Remove(LAYOUT_2))
- {
- SimpleLogger().Write(logWARNING) << "could not delete LAYOUT_2";
- }
- }
- else
- {
- BOOST_ASSERT(DATA == DATA_2);
- BOOST_ASSERT(LAYOUT == LAYOUT_2);
- if (!SharedMemory::Remove(DATA_1))
- {
- SimpleLogger().Write(logWARNING) << "could not delete DATA_1";
- }
- if (!SharedMemory::Remove(LAYOUT_1))
- {
- SimpleLogger().Write(logWARNING) << "could not delete LAYOUT_1";
- }
- }
+ delete_region(previous_data_region);
+ delete_region(previous_layout_region);
SimpleLogger().Write() << "all data loaded";
shared_layout_ptr->PrintInformation();
diff --git a/Descriptors/DescriptionFactory.cpp b/descriptors/description_factory.cpp
similarity index 50%
rename from Descriptors/DescriptionFactory.cpp
rename to descriptors/description_factory.cpp
index 5c9cbef..075eff0 100644
--- a/Descriptors/DescriptionFactory.cpp
+++ b/descriptors/description_factory.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,18 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "DescriptionFactory.h"
+#include "description_factory.hpp"
#include <osrm/Coordinate.h>
#include "../typedefs.h"
-#include "../Algorithms/PolylineCompressor.h"
-#include "../DataStructures/PhantomNodes.h"
-#include "../DataStructures/RawRouteData.h"
-#include "../DataStructures/SegmentInformation.h"
-#include "../DataStructures/TurnInstructions.h"
+#include "../algorithms/polyline_formatter.hpp"
+#include "../data_structures/raw_route_data.hpp"
+#include "../data_structures/turn_instructions.hpp"
-DescriptionFactory::DescriptionFactory() : entireLength(0) { via_indices.push_back(0); }
+DescriptionFactory::DescriptionFactory() : entire_length(0) { via_indices.push_back(0); }
std::vector<unsigned> const &DescriptionFactory::GetViaIndices() const { return via_indices; }
@@ -45,44 +43,77 @@ void DescriptionFactory::SetStartSegment(const PhantomNode &source, const bool t
start_phantom = source;
const EdgeWeight segment_duration =
(traversed_in_reverse ? source.reverse_weight : source.forward_weight);
- AppendSegment(source.location,
- PathData(0, source.name_id, TurnInstruction::HeadOn, segment_duration));
+ const TravelMode travel_mode =
+ (traversed_in_reverse ? source.backward_travel_mode : source.forward_travel_mode);
+ AppendSegment(
+ source.location,
+ PathData(0, source.name_id, TurnInstruction::HeadOn, segment_duration, travel_mode));
BOOST_ASSERT(path_description.back().duration == segment_duration);
}
-void DescriptionFactory::SetEndSegment(const PhantomNode &target, const bool traversed_in_reverse)
+void DescriptionFactory::SetEndSegment(const PhantomNode &target,
+ const bool traversed_in_reverse,
+ const bool is_via_location)
{
target_phantom = target;
const EdgeWeight segment_duration =
(traversed_in_reverse ? target.reverse_weight : target.forward_weight);
- path_description.emplace_back(
- target.location, target.name_id, segment_duration, 0.f, TurnInstruction::NoTurn, true, true);
+ const TravelMode travel_mode =
+ (traversed_in_reverse ? target.backward_travel_mode : target.forward_travel_mode);
+ path_description.emplace_back(target.location,
+ target.name_id,
+ segment_duration,
+ 0.f,
+ is_via_location ? TurnInstruction::ReachViaLocation
+ : TurnInstruction::NoTurn,
+ true,
+ true,
+ travel_mode);
BOOST_ASSERT(path_description.back().duration == segment_duration);
}
void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
const PathData &path_point)
{
- if ((1 == path_description.size()) && (path_description.back().location == coordinate))
+ // if the start location is on top of a node, the first movement might be zero-length,
+ // in which case we dont' add a new description, but instead update the existing one
+ if ((1 == path_description.size()) && (path_description.front().location == coordinate))
{
- path_description.back().name_id = path_point.name_id;
+ if (path_point.segment_duration > 0)
+ {
+ path_description.front().name_id = path_point.name_id;
+ path_description.front().travel_mode = path_point.travel_mode;
+ }
return;
}
+ // make sure mode changes are announced, even when there otherwise is no turn
+ const TurnInstruction turn = [&]() -> TurnInstruction
+ {
+ if (TurnInstruction::NoTurn == path_point.turn_instruction &&
+ path_description.front().travel_mode != path_point.travel_mode &&
+ path_point.segment_duration > 0)
+ {
+ return TurnInstruction::GoStraight;
+ }
+ return path_point.turn_instruction;
+ }();
+
path_description.emplace_back(coordinate,
path_point.name_id,
path_point.segment_duration,
- 0,
- path_point.turn_instruction);
+ 0.f,
+ turn,
+ path_point.travel_mode);
}
-JSON::Value DescriptionFactory::AppendEncodedPolylineString(const bool return_encoded)
+JSON::Value DescriptionFactory::AppendGeometryString(const bool return_encoded)
{
if (return_encoded)
{
- return polyline_compressor.printEncodedString(path_description);
+ return PolylineFormatter().printEncodedString(path_description);
}
- return polyline_compressor.printUnencodedString(path_description);
+ return PolylineFormatter().printUnencodedString(path_description);
}
void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
diff --git a/Descriptors/DescriptionFactory.h b/descriptors/description_factory.hpp
similarity index 85%
rename from Descriptors/DescriptionFactory.h
rename to descriptors/description_factory.hpp
index d081bae..9b96dd2 100644
--- a/Descriptors/DescriptionFactory.h
+++ b/descriptors/description_factory.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,18 +25,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef DESCRIPTIONFACTORY_H_
-#define DESCRIPTIONFACTORY_H_
+#ifndef DESCRIPTION_FACTORY_HPP
+#define DESCRIPTION_FACTORY_HPP
-#include "../Algorithms/DouglasPeucker.h"
-#include "../Algorithms/PolylineCompressor.h"
-#include "../DataStructures/PhantomNodes.h"
-#include "../DataStructures/SegmentInformation.h"
-#include "../DataStructures/TurnInstructions.h"
+#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 <cmath>
+
#include <limits>
#include <vector>
@@ -47,7 +51,6 @@ struct PathData;
class DescriptionFactory
{
DouglasPeucker polyline_generalizer;
- PolylineCompressor polyline_compressor;
PhantomNode start_phantom, target_phantom;
double DegreeToRadian(const double degree) const;
@@ -55,6 +58,8 @@ class DescriptionFactory
std::vector<unsigned> via_indices;
+ double entire_length;
+
public:
struct RouteSummary
{
@@ -67,22 +72,27 @@ class DescriptionFactory
void BuildDurationAndLengthStrings(const double raw_distance, const unsigned raw_duration)
{
// compute distance/duration for route summary
- distance = static_cast<unsigned>(round(raw_distance));
- duration = static_cast<unsigned>(round(raw_duration / 10.));
+ distance = static_cast<unsigned>(std::round(raw_distance));
+ duration = static_cast<unsigned>(std::round(raw_duration / 10.));
}
} summary;
- double entireLength;
-
// I know, declaring this public is considered bad. I'm lazy
std::vector<SegmentInformation> path_description;
DescriptionFactory();
void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data);
void BuildRouteSummary(const double distance, const unsigned time);
void SetStartSegment(const PhantomNode &start_phantom, const bool traversed_in_reverse);
- void SetEndSegment(const PhantomNode &start_phantom, const bool traversed_in_reverse);
- JSON::Value AppendEncodedPolylineString(const bool return_encoded);
- std::vector<unsigned> const & GetViaIndices() const;
+ void SetEndSegment(const PhantomNode &start_phantom,
+ const bool traversed_in_reverse,
+ const bool is_via_location = false);
+ 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)
{
@@ -150,7 +160,7 @@ class DescriptionFactory
for (unsigned i = 1; i < path_description.size(); ++i)
{
- entireLength += path_description[i].length;
+ 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;
@@ -188,7 +198,7 @@ class DescriptionFactory
}
// Generalize poly line
- polyline_generalizer.Run(path_description, zoomLevel);
+ 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
@@ -198,18 +208,19 @@ class DescriptionFactory
{
++necessary_pieces;
if (path_description[i].is_via_location)
- { //mark the end of a leg
+ { // 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);
+ 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);
+ via_indices.push_back(necessary_pieces + 1);
BOOST_ASSERT(via_indices.size() >= 2);
// BOOST_ASSERT(0 != necessary_pieces || path_description.empty());
return;
}
};
-#endif /* DESCRIPTIONFACTORY_H_ */
+#endif /* DESCRIPTION_FACTORY_HPP */
diff --git a/Descriptors/BaseDescriptor.h b/descriptors/descriptor_base.hpp
similarity index 66%
rename from Descriptors/BaseDescriptor.h
rename to descriptors/descriptor_base.hpp
index d06b9b6..31c08ea 100644
--- a/Descriptors/BaseDescriptor.h
+++ b/descriptors/descriptor_base.hpp
@@ -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,27 +25,53 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef BASE_DESCRIPTOR_H
-#define BASE_DESCRIPTOR_H
+#ifndef DESCRIPTOR_BASE_HPP
+#define DESCRIPTOR_BASE_HPP
-#include "../DataStructures/PhantomNodes.h"
-#include "../DataStructures/RawRouteData.h"
+#include "../data_structures/phantom_node.hpp"
+#include "../data_structures/raw_route_data.hpp"
#include "../typedefs.h"
#include <osrm/Reply.h>
#include <string>
+#include <unordered_map>
#include <vector>
+
+struct DescriptorTable : public std::unordered_map<std::string, unsigned>
+{
+ unsigned get_id(const std::string &key)
+ {
+ auto iter = find(key);
+ if (iter != end())
+ {
+ return iter->second;
+ }
+ return 0;
+ }
+};
+
+
struct DescriptorConfig
{
DescriptorConfig() : instructions(true), geometry(true), encode_geometry(true), zoom_level(18)
{
}
+
+ template<class OtherT>
+ DescriptorConfig(const OtherT &other) : instructions(other.print_instructions),
+ geometry(other.geometry),
+ encode_geometry(other.compression),
+ zoom_level(other.zoom_level)
+ {
+ BOOST_ASSERT(zoom_level >= 0);
+ }
+
bool instructions;
bool geometry;
bool encode_geometry;
- unsigned short zoom_level;
+ short zoom_level;
};
template <class DataFacadeT> class BaseDescriptor
@@ -58,4 +84,4 @@ template <class DataFacadeT> class BaseDescriptor
virtual void SetConfig(const DescriptorConfig &config) = 0;
};
-#endif // BASE_DESCRIPTOR_H
+#endif // DESCRIPTOR_BASE_HPP
diff --git a/descriptors/gpx_descriptor.hpp b/descriptors/gpx_descriptor.hpp
new file mode 100644
index 0000000..2dd0034
--- /dev/null
+++ b/descriptors/gpx_descriptor.hpp
@@ -0,0 +1,92 @@
+/*
+
+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 GPX_DESCRIPTOR_HPP
+#define GPX_DESCRIPTOR_HPP
+
+#include "descriptor_base.hpp"
+#include "../data_structures/json_container.hpp"
+#include "../Util/xml_renderer.hpp"
+
+#include <iostream>
+
+template <class DataFacadeT> class GPXDescriptor final : public BaseDescriptor<DataFacadeT>
+{
+ private:
+ DescriptorConfig config;
+ DataFacadeT *facade;
+
+ void AddRoutePoint(const FixedPointCoordinate &coordinate, JSON::Array &json_result)
+ {
+ JSON::Object json_lat;
+ JSON::Object json_lon;
+ JSON::Array json_row;
+
+ std::string tmp;
+
+ FixedPointCoordinate::convertInternalLatLonToString(coordinate.lat, tmp);
+ json_lat.values["_lat"] = tmp;
+
+ FixedPointCoordinate::convertInternalLatLonToString(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;
+ entry.values["rtept"] = json_row;
+ json_result.values.push_back(entry);
+ }
+
+ public:
+ explicit GPXDescriptor(DataFacadeT *facade) : facade(facade) {}
+
+ void SetConfig(const DescriptorConfig &c) final { config = c; }
+
+ void Run(const RawRouteData &raw_route, http::Reply &reply) final
+ {
+ JSON::Array json_result;
+ if (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT)
+ {
+ AddRoutePoint(raw_route.segment_end_coordinates.front().source_phantom.location,
+ json_result);
+
+ for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
+ {
+ for (const PathData &path_data : path_data_vector)
+ {
+ const FixedPointCoordinate current_coordinate =
+ facade->GetCoordinateOfNode(path_data.node);
+ AddRoutePoint(current_coordinate, json_result);
+ }
+ }
+ AddRoutePoint(raw_route.segment_end_coordinates.back().target_phantom.location,
+ json_result);
+ }
+ JSON::gpx_render(reply.content, json_result);
+ }
+};
+#endif // GPX_DESCRIPTOR_HPP
diff --git a/Descriptors/JSONDescriptor.h b/descriptors/json_descriptor.hpp
similarity index 77%
rename from Descriptors/JSONDescriptor.h
rename to descriptors/json_descriptor.hpp
index 938e4ef..2aae939 100644
--- a/Descriptors/JSONDescriptor.h
+++ b/descriptors/json_descriptor.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,23 +25,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef JSON_DESCRIPTOR_H_
-#define JSON_DESCRIPTOR_H_
-
-#include "BaseDescriptor.h"
-#include "DescriptionFactory.h"
-#include "../Algorithms/ObjectToBase64.h"
-#include "../Algorithms/ExtractRouteNames.h"
-#include "../DataStructures/JSONContainer.h"
-#include "../DataStructures/SegmentInformation.h"
-#include "../DataStructures/TurnInstructions.h"
-#include "../Util/Azimuth.h"
-#include "../Util/StringUtil.h"
-#include "../Util/TimingUtil.h"
+#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 : public BaseDescriptor<DataFacadeT>
+template <class DataFacadeT> class JSONDescriptor final : public BaseDescriptor<DataFacadeT>
{
private:
DataFacadeT *facade;
@@ -69,13 +72,14 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
ExtractRouteNames<DataFacadeT, Segment> GenerateRouteNames;
public:
- JSONDescriptor(DataFacadeT *facade) : facade(facade), entered_restricted_area_count(0) {}
+ explicit JSONDescriptor(DataFacadeT *facade) : facade(facade), entered_restricted_area_count(0) {}
- void SetConfig(const DescriptorConfig &c) { config = c; }
+ 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 target_traversed_in_reverse,
+ const bool is_via_leg)
{
unsigned added_element_count = 0;
// Get all the coordinates for the computed route
@@ -86,13 +90,14 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
description_factory.AppendSegment(current_coordinate, path_data);
++added_element_count;
}
- description_factory.SetEndSegment(leg_phantoms.target_phantom, target_traversed_in_reverse);
+ 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)
+ void Run(const RawRouteData &raw_route, http::Reply &reply) final
{
JSON::Object json_result;
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
@@ -118,14 +123,15 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
json_result.values["status_message"] = "Found route between points";
// for each unpacked segment add the leg to the description
- for (unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i)
+ 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.target_traversed_in_reverse[i],
+ raw_route.is_via_leg(i));
BOOST_ASSERT(0 < added_segments);
}
description_factory.Run(facade, config.zoom_level);
@@ -133,7 +139,7 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
if (config.geometry)
{
JSON::Value route_geometry =
- description_factory.AppendEncodedPolylineString(config.encode_geometry);
+ description_factory.AppendGeometryString(config.encode_geometry);
json_result.values["route_geometry"] = route_geometry;
}
if (config.instructions)
@@ -145,7 +151,7 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
shortest_path_segments);
json_result.values["route_instructions"] = json_route_instructions;
}
- description_factory.BuildRouteSummary(description_factory.entireLength,
+ 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;
@@ -201,13 +207,15 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
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.AppendEncodedPolylineString(
- config.encode_geometry);
+ 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;
@@ -225,7 +233,7 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
json_result.values["alternative_instructions"] = json_alt_instructions;
}
alternate_description_factory.BuildRouteSummary(
- alternate_description_factory.entireLength, raw_route.alternative_path_length);
+ alternate_description_factory.get_entire_length(), raw_route.alternative_path_length);
JSON::Object json_alternate_route_summary;
JSON::Array json_alternate_route_summary_array;
@@ -272,15 +280,15 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
}
JSON::Object json_hint_object;
- json_hint_object.values["checksum"] = raw_route.check_sum;
+ json_hint_object.values["checksum"] = facade->GetCheckSum();
JSON::Array json_location_hint_array;
std::string hint;
- for (unsigned i = 0; i < raw_route.segment_end_coordinates.size(); ++i)
+ for (const auto i : osrm::irange<std::size_t>(0, raw_route.segment_end_coordinates.size()))
{
- EncodeObjectToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint);
+ ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint);
json_location_hint_array.values.push_back(hint);
}
- EncodeObjectToBase64(raw_route.segment_end_coordinates.back().target_phantom, 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;
@@ -300,7 +308,7 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
{
// Segment information has following format:
//["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
- unsigned necessary_segments_running_index = 1;
+ 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;
@@ -324,16 +332,16 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
if (TurnInstruction::LeaveRoundAbout == current_instruction)
{
temp_instruction =
- IntToString(as_integer(TurnInstruction::EnterRoundAbout));
+ cast::integral_to_string(cast::enum_to_underlying(TurnInstruction::EnterRoundAbout));
current_turn_instruction += temp_instruction;
current_turn_instruction += "-";
- temp_instruction = IntToString(round_about.leave_at_exit + 1);
+ 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 = IntToString(as_integer(current_instruction));
+ 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);
@@ -344,13 +352,17 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
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(
- UintToString(static_cast<unsigned>(segment.length)) + "m");
- const double bearing_value = (segment.bearing / 10.) ;
- json_instruction_row.values.push_back(Azimuth::Get(bearing_value));
- json_instruction_row.values.push_back(static_cast<unsigned>(round(bearing_value)));
+ 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, segment.length, route_segments_list.size());
+ segment.name_id,
+ static_cast<int>(segment.length),
+ static_cast<unsigned>(route_segments_list.size()));
json_instruction_array.values.push_back(json_instruction_row);
}
}
@@ -364,22 +376,18 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
}
}
- // TODO: check if this in an invariant
- if (INVALID_EDGE_WEIGHT != route_length)
- {
- JSON::Array json_last_instruction_row;
- temp_instruction = IntToString(as_integer(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(Azimuth::Get(0.0));
- json_last_instruction_row.values.push_back(0.);
- json_instruction_array.values.push_back(json_last_instruction_row);
- }
+ 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_ */
+#endif /* JSON_DESCRIPTOR_HPP */
diff --git a/Server/Http/CompressionType.h b/extract.cpp
similarity index 78%
copy from Server/Http/CompressionType.h
copy to extract.cpp
index 74d0b62..2ad1f7a 100644
--- a/Server/Http/CompressionType.h
+++ b/extract.cpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
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
+#include "extractor/extractor.hpp"
+#include "Util/simple_logger.hpp"
-namespace http
+int main (int argc, char *argv[])
{
-
-enum CompressionType
-{ noCompression,
- gzipRFC1952,
- deflateRFC1951 };
-
-} // namespace http
-
-#endif // COMPRESSION_TYPE_H
+ try
+ {
+ return Extractor().Run(argc, argv);
+ }
+ catch (const std::exception &e)
+ {
+ SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+ }
+
+}
diff --git a/extractor.cpp b/extractor.cpp
deleted file mode 100644
index b170b74..0000000
--- a/extractor.cpp
+++ /dev/null
@@ -1,286 +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 "Extractor/ExtractorCallbacks.h"
-#include "Extractor/ExtractionContainers.h"
-#include "Extractor/ScriptingEnvironment.h"
-#include "Extractor/PBFParser.h"
-#include "Extractor/XMLParser.h"
-#include "Util/FingerPrint.h"
-#include "Util/GitDescription.h"
-#include "Util/MachineInfo.h"
-#include "Util/OSRMException.h"
-#include "Util/ProgramOptions.h"
-#include "Util/SimpleLogger.h"
-#include "Util/StringUtil.h"
-#include "Util/TimingUtil.h"
-#include "typedefs.h"
-
-#include <cstdlib>
-
-#include <thread>
-#include <chrono>
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <unordered_map>
-
-#include <tbb/task_scheduler_init.h>
-
-ExtractorCallbacks *extractor_callbacks;
-FingerPrint fingerprint;
-
-int main(int argc, char *argv[])
-{
- try
- {
- LogPolicy::GetInstance().Unmute();
-
- TIMER_START(extracting);
-
- boost::filesystem::path config_file_path, input_path, profile_path;
- unsigned requested_num_threads;
-
- // 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("extractor.ini"),
- "Path to a configuration file.");
-
- // declare a group of options that will be allowed both on command line and in config file
- boost::program_options::options_description config_options("Configuration");
- config_options.add_options()("profile,p",
- boost::program_options::value<boost::filesystem::path>(
- &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()),
- "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 file in .osm, .osm.bz2 or .osm.pbf format");
-
- // positional option
- boost::program_options::positional_options_description positional_options;
- positional_options.add("input", 1);
-
- // combine above options for parsing
- boost::program_options::options_description cmdline_options;
- cmdline_options.add(generic_options).add(config_options).add(hidden_options);
-
- boost::program_options::options_description config_file_options;
- config_file_options.add(config_options).add(hidden_options);
-
- boost::program_options::options_description visible_options(
- boost::filesystem::basename(argv[0]) + " <input.osm/.osm.bz2/.osm.pbf> [options]");
- visible_options.add(generic_options).add(config_options);
-
- // parse command line options
- 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 0;
- }
-
- if (option_variables.count("help"))
- {
- SimpleLogger().Write() << visible_options;
- return 0;
- }
-
- boost::program_options::notify(option_variables);
-
- // parse config file
- if (boost::filesystem::is_regular_file(config_file_path))
- {
- SimpleLogger().Write() << "Reading options from: " << config_file_path.string();
- std::string ini_file_contents = ReadIniFileAndLowerContents(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 0;
- }
-
- if (1 > requested_num_threads)
- {
- SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
- return 1;
- }
-
- if (!boost::filesystem::is_regular_file(input_path))
- {
- SimpleLogger().Write(logWARNING) << "Input file " << input_path.string()
- << " not found!";
- return 1;
- }
-
- if (!boost::filesystem::is_regular_file(profile_path))
- {
- SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string()
- << " not found!";
- return 1;
- }
-
- const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
-
- SimpleLogger().Write() << "Input file: " << input_path.filename().string();
- SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
- SimpleLogger().Write() << "Threads: " << requested_num_threads;
- if (recommended_num_threads != requested_num_threads)
- {
- SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
- << recommended_num_threads
- << "! This setting may have performance side-effects.";
- }
-
- tbb::task_scheduler_init init(requested_num_threads);
-
- /*** Setup Scripting Environment ***/
- ScriptingEnvironment scripting_environment(profile_path.string().c_str());
-
- bool file_has_pbf_format(false);
- std::string output_file_name = input_path.string();
- std::string restriction_fileName = input_path.string();
- std::string::size_type pos = output_file_name.find(".osm.bz2");
- if (pos == std::string::npos)
- {
- pos = output_file_name.find(".osm.pbf");
- if (pos != std::string::npos)
- {
- file_has_pbf_format = true;
- } else {
- pos = output_file_name.find(".osm.xml");
- }
- }
- if (pos == std::string::npos)
- {
- pos = output_file_name.find(".pbf");
- if (pos != std::string::npos)
- {
- file_has_pbf_format = true;
- }
- }
- if (pos == std::string::npos)
- {
- pos = output_file_name.find(".osm");
- if (pos == std::string::npos)
- {
- output_file_name.append(".osrm");
- restriction_fileName.append(".osrm.restrictions");
- }
- else
- {
- output_file_name.replace(pos, 5, ".osrm");
- restriction_fileName.replace(pos, 5, ".osrm.restrictions");
- }
- }
- else
- {
- output_file_name.replace(pos, 8, ".osrm");
- restriction_fileName.replace(pos, 8, ".osrm.restrictions");
- }
-
- std::unordered_map<std::string, NodeID> string_map;
- ExtractionContainers extraction_containers;
-
- string_map[""] = 0;
- extractor_callbacks = new ExtractorCallbacks(extraction_containers, string_map);
- BaseParser *parser;
- if (file_has_pbf_format)
- {
- parser = new PBFParser(input_path.string().c_str(),
- extractor_callbacks,
- scripting_environment,
- requested_num_threads);
- }
- else
- {
- parser = new XMLParser(input_path.string().c_str(), extractor_callbacks, scripting_environment);
- }
-
- if (!parser->ReadHeader())
- {
- throw OSRMException("Parser not initialized!");
- }
- SimpleLogger().Write() << "Parsing in progress..";
- TIMER_START(parsing);
-
- parser->Parse();
- delete parser;
- delete extractor_callbacks;
-
- TIMER_STOP(parsing);
- SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing)
- << " seconds";
-
- if (extraction_containers.all_edges_list.empty())
- {
- SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
- return 1;
- }
-
- extraction_containers.PrepareData(output_file_name, restriction_fileName);
-
- TIMER_STOP(extracting);
- SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting)
- << "s";
- SimpleLogger().Write() << "To prepare the data for routing, run: "
- << "./osrm-prepare " << output_file_name << std::endl;
- }
- catch (boost::program_options::too_many_positional_options_error &)
- {
- SimpleLogger().Write(logWARNING) << "Only one input file can be specified";
- return 1;
- }
- catch (std::exception &e)
- {
- SimpleLogger().Write(logWARNING) << e.what();
- return 1;
- }
- return 0;
-}
diff --git a/Extractor/ExtractionContainers.cpp b/extractor/extraction_containers.cpp
similarity index 82%
rename from Extractor/ExtractionContainers.cpp
rename to extractor/extraction_containers.cpp
index 91981d6..604f863 100644
--- a/Extractor/ExtractionContainers.cpp
+++ b/extractor/extraction_containers.cpp
@@ -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,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "ExtractionContainers.h"
-#include "ExtractionWay.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/TimingUtil.h"
-#include "../DataStructures/RangeTable.h"
+#include "extraction_containers.hpp"
+#include "extraction_way.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 <boost/assert.hpp>
#include <boost/filesystem.hpp>
@@ -82,19 +85,24 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
std::cout << "[extractor] Sorting all nodes ... " << std::flush;
TIMER_START(sorting_nodes);
- stxxl::sort(all_nodes_list.begin(), all_nodes_list.end(), CmpNodeByID(), stxxl_memory);
+ 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(), CmpWayByID(), 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. 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(),
@@ -111,39 +119,39 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
while (way_start_and_end_iterator != way_start_end_id_list.end() &&
restrictions_iterator != restrictions_list.end())
{
- if (way_start_and_end_iterator->wayID < restrictions_iterator->fromWay)
+ if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.from.way)
{
++way_start_and_end_iterator;
continue;
}
- if (way_start_and_end_iterator->wayID > restrictions_iterator->fromWay)
+ if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.from.way)
{
++restrictions_iterator;
continue;
}
- BOOST_ASSERT(way_start_and_end_iterator->wayID == restrictions_iterator->fromWay);
- const NodeID via_node_id = restrictions_iterator->restriction.viaNode;
+ 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->firstStart == via_node_id)
+ if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
{
- restrictions_iterator->restriction.fromNode =
- way_start_and_end_iterator->firstTarget;
+ restrictions_iterator->restriction.from.node =
+ way_start_and_end_iterator->first_segment_source_id;
}
- else if (way_start_and_end_iterator->firstTarget == via_node_id)
+ else if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
{
- restrictions_iterator->restriction.fromNode =
- way_start_and_end_iterator->firstStart;
+ restrictions_iterator->restriction.from.node =
+ way_start_and_end_iterator->first_segment_source_id;
}
- else if (way_start_and_end_iterator->lastStart == via_node_id)
+ else if (way_start_and_end_iterator->last_segment_source_id == via_node_id)
{
- restrictions_iterator->restriction.fromNode =
- way_start_and_end_iterator->lastTarget;
+ restrictions_iterator->restriction.from.node =
+ way_start_and_end_iterator->last_segment_target_id;
}
- else if (way_start_and_end_iterator->lastTarget == via_node_id)
+ else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
{
- restrictions_iterator->restriction.fromNode = way_start_and_end_iterator->lastStart;
+ restrictions_iterator->restriction.from.node = way_start_and_end_iterator->last_segment_source_id;
}
++restrictions_iterator;
}
@@ -168,36 +176,36 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
while (way_start_and_end_iterator != way_start_end_id_list.end() &&
restrictions_iterator != restrictions_list.end())
{
- if (way_start_and_end_iterator->wayID < restrictions_iterator->toWay)
+ if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.to.way)
{
++way_start_and_end_iterator;
continue;
}
- if (way_start_and_end_iterator->wayID > restrictions_iterator->toWay)
+ if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.to.way)
{
++restrictions_iterator;
continue;
}
- NodeID via_node_id = restrictions_iterator->restriction.viaNode;
- if (way_start_and_end_iterator->lastStart == via_node_id)
+ NodeID via_node_id = restrictions_iterator->restriction.via.node;
+ if (way_start_and_end_iterator->last_segment_source_id == via_node_id)
{
- restrictions_iterator->restriction.toNode = way_start_and_end_iterator->lastTarget;
+ restrictions_iterator->restriction.to.node = way_start_and_end_iterator->last_segment_target_id;
}
- else if (way_start_and_end_iterator->lastTarget == via_node_id)
+ else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
{
- restrictions_iterator->restriction.toNode = way_start_and_end_iterator->lastStart;
+ restrictions_iterator->restriction.to.node = way_start_and_end_iterator->last_segment_source_id;
}
- else if (way_start_and_end_iterator->firstStart == via_node_id)
+ else if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
{
- restrictions_iterator->restriction.toNode = way_start_and_end_iterator->firstTarget;
+ restrictions_iterator->restriction.to.node = way_start_and_end_iterator->first_segment_target_id;
}
- else if (way_start_and_end_iterator->firstTarget == via_node_id)
+ else if (way_start_and_end_iterator->first_segment_target_id == via_node_id)
{
- restrictions_iterator->restriction.toNode = way_start_and_end_iterator->firstStart;
+ restrictions_iterator->restriction.to.node = way_start_and_end_iterator->first_segment_source_id;
}
- if (std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.fromNode &&
- std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.toNode)
+ 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;
}
@@ -215,8 +223,8 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
for(const auto & restriction_container : restrictions_list)
{
- if (std::numeric_limits<unsigned>::max() != restriction_container.restriction.fromNode &&
- std::numeric_limits<unsigned>::max() != restriction_container.restriction.toNode)
+ if (std::numeric_limits<unsigned>::max() != restriction_container.restriction.from.node &&
+ std::numeric_limits<unsigned>::max() != restriction_container.restriction.to.node)
{
restrictions_out_stream.write((char *)&(restriction_container.restriction),
sizeof(TurnRestriction));
@@ -330,7 +338,6 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min())
{
BOOST_ASSERT(edge_iterator->speed != -1);
- BOOST_ASSERT(edge_iterator->type >= 0);
edge_iterator->target_coordinate.lat = node_iterator->lat;
edge_iterator->target_coordinate.lon = node_iterator->lon;
@@ -367,16 +374,19 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
file_out_stream.write((char *)&one, sizeof(short));
break;
default:
- throw OSRMException("edge has broken direction");
+ throw osrm::exception("edge has broken direction");
}
file_out_stream.write((char *)&integer_weight, sizeof(int));
- file_out_stream.write((char *)&edge_iterator->type, sizeof(short));
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));
- file_out_stream.write((char *)&edge_iterator->is_contra_flow, sizeof(bool));
+
+ // cannot take adress of bit field, so use local
+ 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));
++number_of_used_edges;
}
diff --git a/Extractor/ExtractionContainers.h b/extractor/extraction_containers.hpp
similarity index 72%
rename from Extractor/ExtractionContainers.h
rename to extractor/extraction_containers.hpp
index a272387..8a1df8c 100644
--- a/Extractor/ExtractionContainers.h
+++ b/extractor/extraction_containers.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,12 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef EXTRACTIONCONTAINERS_H_
-#define EXTRACTIONCONTAINERS_H_
+#ifndef EXTRACTION_CONTAINERS_HPP
+#define EXTRACTION_CONTAINERS_HPP
-#include "InternalExtractorEdge.h"
-#include "ExtractorStructs.h"
-#include "../DataStructures/Restriction.h"
+#include "internal_extractor_edge.hpp"
+#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 <stxxl/vector>
@@ -43,12 +44,12 @@ class ExtractionContainers
const static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? INT_MAX : UINT_MAX);
#endif
public:
- typedef stxxl::vector<NodeID> STXXLNodeIDVector;
- typedef stxxl::vector<ExternalMemoryNode> STXXLNodeVector;
- typedef stxxl::vector<InternalExtractorEdge> STXXLEdgeVector;
- typedef stxxl::vector<std::string> STXXLStringVector;
- typedef stxxl::vector<InputRestrictionContainer> STXXLRestrictionsVector;
- typedef stxxl::vector<WayIDStartAndEndEdge> STXXLWayIDStartEndVector;
+ 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;
@@ -60,10 +61,10 @@ class ExtractionContainers
ExtractionContainers();
- virtual ~ExtractionContainers();
+ ~ExtractionContainers();
void PrepareData(const std::string &output_file_name,
const std::string &restrictions_file_name);
};
-#endif /* EXTRACTIONCONTAINERS_H_ */
+#endif /* EXTRACTION_CONTAINERS_HPP */
diff --git a/Extractor/ExtractionHelperFunctions.h b/extractor/extraction_helper_functions.hpp
similarity index 81%
rename from Extractor/ExtractionHelperFunctions.h
rename to extractor/extraction_helper_functions.hpp
index a918744..d2a73c9 100644
--- a/Extractor/ExtractionHelperFunctions.h
+++ b/extractor/extraction_helper_functions.hpp
@@ -25,13 +25,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef EXTRACTION_HELPER_FUNCTIONS_H
-#define EXTRACTION_HELPER_FUNCTIONS_H
+#ifndef EXTRACTION_HELPER_FUNCTIONS_HPP
+#define EXTRACTION_HELPER_FUNCTIONS_HPP
-#include "../Util/StringUtil.h"
+#include "../Util/cast.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string_regex.hpp>
+#include <boost/spirit/include/qi.hpp>
#include <boost/regex.hpp>
#include <limits>
@@ -40,7 +41,7 @@ namespace qi = boost::spirit::qi;
// TODO: Move into LUA
-inline bool durationIsValid(const std::string &s)
+bool durationIsValid(const std::string &s)
{
boost::regex e(
"((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",
@@ -52,7 +53,7 @@ inline bool durationIsValid(const std::string &s)
return matched;
}
-inline unsigned parseDuration(const std::string &s)
+unsigned parseDuration(const std::string &s)
{
unsigned hours = 0;
unsigned minutes = 0;
@@ -68,22 +69,22 @@ inline unsigned parseDuration(const std::string &s)
{
if (1 == result.size())
{
- minutes = StringToUint(result[0]);
+ minutes = cast::string_to_int(result[0]);
}
if (2 == result.size())
{
- minutes = StringToUint(result[1]);
- hours = StringToUint(result[0]);
+ minutes = cast::string_to_int(result[1]);
+ hours = cast::string_to_int(result[0]);
}
if (3 == result.size())
{
- seconds = StringToUint(result[2]);
- minutes = StringToUint(result[1]);
- hours = StringToUint(result[0]);
+ 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 std::numeric_limits<unsigned>::max();
}
-#endif // EXTRACTION_HELPER_FUNCTIONS_H_
+#endif // EXTRACTION_HELPER_FUNCTIONS_HPP
diff --git a/Server/Http/CompressionType.h b/extractor/extraction_node.hpp
similarity index 78%
copy from Server/Http/CompressionType.h
copy to extractor/extraction_node.hpp
index 74d0b62..defd333 100644
--- a/Server/Http/CompressionType.h
+++ b/extractor/extraction_node.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
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 COMPRESSION_TYPE_H
-#define COMPRESSION_TYPE_H
+#ifndef EXTRACTION_NODE_HPP
+#define EXTRACTION_NODE_HPP
-namespace http
+struct ExtractionNode
{
-
-enum CompressionType
-{ noCompression,
- gzipRFC1952,
- deflateRFC1951 };
-
-} // namespace http
-
-#endif // COMPRESSION_TYPE_H
+ ExtractionNode() : traffic_lights(false), barrier(false) { }
+ void clear()
+ {
+ traffic_lights = barrier = false;
+ }
+ bool traffic_lights;
+ bool barrier;
+};
+#endif // EXTRACTION_NODE_HPP
diff --git a/extractor/extraction_way.hpp b/extractor/extraction_way.hpp
new file mode 100644
index 0000000..b414487
--- /dev/null
+++ b/extractor/extraction_way.hpp
@@ -0,0 +1,120 @@
+/*
+
+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 EXTRACTION_WAY_HPP
+#define EXTRACTION_WAY_HPP
+
+#include "../data_structures/travel_mode.hpp"
+#include "../typedefs.h"
+
+#include <string>
+#include <vector>
+
+struct ExtractionWay
+{
+ ExtractionWay() { clear(); }
+
+ void clear()
+ {
+ forward_speed = -1;
+ backward_speed = -1;
+ duration = -1;
+ roundabout = false;
+ is_access_restricted = false;
+ ignore_in_grid = false;
+ name.clear();
+ forward_travel_mode = TRAVEL_MODE_DEFAULT;
+ backward_travel_mode = TRAVEL_MODE_DEFAULT;
+ }
+
+ enum Directions
+ { notSure = 0,
+ oneway,
+ bidirectional,
+ opposite };
+
+ // These accessor methods exists to support the depreciated "way.direction" access
+ // in LUA. Since the direction attribute was removed from ExtractionWay, the
+ // accessors translate to/from the mode attributes.
+ void set_direction(const Directions m)
+ {
+ if (Directions::oneway == m)
+ {
+ forward_travel_mode = TRAVEL_MODE_DEFAULT;
+ backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
+ }
+ else if (Directions::opposite == m)
+ {
+ forward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
+ backward_travel_mode = TRAVEL_MODE_DEFAULT;
+ }
+ else if (Directions::bidirectional == m)
+ {
+ forward_travel_mode = TRAVEL_MODE_DEFAULT;
+ backward_travel_mode = TRAVEL_MODE_DEFAULT;
+ }
+ }
+
+ Directions get_direction() const
+ {
+ if (TRAVEL_MODE_INACCESSIBLE != forward_travel_mode && TRAVEL_MODE_INACCESSIBLE != backward_travel_mode)
+ {
+ return Directions::bidirectional;
+ }
+ else if (TRAVEL_MODE_INACCESSIBLE != forward_travel_mode)
+ {
+ return Directions::oneway;
+ }
+ else if (TRAVEL_MODE_INACCESSIBLE != backward_travel_mode)
+ {
+ return Directions::opposite;
+ }
+ else
+ {
+ return Directions::notSure;
+ }
+ }
+
+ // These accessors exists because it's not possible to take the address of a bitfield,
+ // and LUA therefore cannot read/write the mode attributes directly.
+ void set_forward_mode(const TravelMode m) { forward_travel_mode = m; }
+ TravelMode get_forward_mode() const { return forward_travel_mode; }
+ void set_backward_mode(const TravelMode m) { backward_travel_mode = m; }
+ TravelMode get_backward_mode() const { return backward_travel_mode; }
+
+ double forward_speed;
+ double backward_speed;
+ double duration;
+ std::string name;
+ bool roundabout;
+ bool is_access_restricted;
+ bool ignore_in_grid;
+ TravelMode forward_travel_mode : 4;
+ TravelMode backward_travel_mode : 4;
+};
+
+#endif // EXTRACTION_WAY_HPP
diff --git a/extractor/extractor.cpp b/extractor/extractor.cpp
new file mode 100644
index 0000000..880e9e4
--- /dev/null
+++ b/extractor/extractor.cpp
@@ -0,0 +1,268 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "extractor.hpp"
+
+#include "extraction_containers.hpp"
+#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 "../typedefs.h"
+
+#include <luabind/luabind.hpp>
+
+#include <osmium/io/any_input.hpp>
+
+#include <tbb/parallel_for.h>
+#include <tbb/task_scheduler_init.h>
+
+#include <variant/optional.hpp>
+
+#include <cstdlib>
+
+#include <algorithm>
+#include <atomic>
+#include <chrono>
+#include <fstream>
+#include <iostream>
+#include <thread>
+#include <unordered_map>
+#include <vector>
+
+int Extractor::Run(int argc, char *argv[])
+{
+ 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);
+ tbb::task_scheduler_init init(number_of_threads);
+
+ SimpleLogger().Write() << "Input file: " << extractor_config.input_path.filename().string();
+ SimpleLogger().Write() << "Profile: " << extractor_config.profile_path.filename().string();
+ SimpleLogger().Write() << "Threads: " << number_of_threads;
+
+ // setup scripting environment
+ ScriptingEnvironment scripting_environment(extractor_config.profile_path.string().c_str());
+
+ std::unordered_map<std::string, NodeID> string_map;
+ string_map[""] = 0;
+
+ ExtractionContainers extraction_containers;
+ auto extractor_callbacks =
+ osrm::make_unique<ExtractorCallbacks>(extraction_containers, string_map);
+
+ const osmium::io::File input_file(extractor_config.input_path.string());
+ 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};
+
+ SimpleLogger().Write() << "Parsing in progress..";
+ TIMER_START(parsing);
+
+ std::string generator = header.get("generator");
+ if (generator.empty())
+ {
+ generator = "unknown tool";
+ }
+ SimpleLogger().Write() << "input file generated by " << generator;
+
+ // write .timestamp data file
+ std::string timestamp = header.get("osmosis_replication_timestamp");
+ if (timestamp.empty())
+ {
+ timestamp = "n/a";
+ }
+ SimpleLogger().Write() << "timestamp: " << timestamp;
+
+ boost::filesystem::ofstream timestamp_out(extractor_config.timestamp_file_name);
+ timestamp_out.write(timestamp.c_str(), timestamp.length());
+ timestamp_out.close();
+
+ // initialize vectors holding parsed objects
+ tbb::concurrent_vector<std::pair<std::size_t, ExtractionNode>> resulting_nodes;
+ tbb::concurrent_vector<std::pair<std::size_t, ExtractionWay>> resulting_ways;
+ tbb::concurrent_vector<mapbox::util::optional<InputRestrictionContainer>>
+ resulting_restrictions;
+
+ // setup restriction parser
+ const RestrictionParser restriction_parser(scripting_environment.get_lua_state());
+
+ while (const osmium::memory::Buffer buffer = reader.read())
+ {
+ // 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) {
+ osm_elements.push_back(iter);
+ }
+
+ // clear resulting vectors
+ resulting_nodes.clear();
+ resulting_ways.clear();
+ 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)
+ {
+ const auto entity = osm_elements[x];
+
+ ExtractionNode result_node;
+ ExtractionWay result_way;
+
+ lua_State * local_state = scripting_environment.get_lua_state();
+
+ switch (entity->type())
+ {
+ 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;
+ }
+ }
+ });
+
+ // 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);
+ }
+ for (const auto &result : resulting_ways)
+ {
+ extractor_callbacks->ProcessWay(
+ static_cast<const osmium::Way &>(*(osm_elements[result.first])), result.second);
+ }
+ for (const auto &result : resulting_restrictions)
+ {
+ extractor_callbacks->ProcessRestriction(result);
+ }
+ }
+ 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";
+
+ extractor_callbacks.reset();
+
+ if (extraction_containers.all_edges_list.empty())
+ {
+ SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
+ return 1;
+ }
+
+ extraction_containers.PrepareData(extractor_config.output_file_name,
+ extractor_config.restriction_file_name);
+ TIMER_STOP(extracting);
+ SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting) << "s";
+ SimpleLogger().Write() << "To prepare the data for routing, run: "
+ << "./osrm-prepare " << extractor_config.output_file_name
+ << std::endl;
+ }
+ catch (std::exception &e)
+ {
+ SimpleLogger().Write(logWARNING) << e.what();
+ return 1;
+ }
+ return 0;
+}
diff --git a/extractor/extractor.hpp b/extractor/extractor.hpp
new file mode 100644
index 0000000..e9edbea
--- /dev/null
+++ b/extractor/extractor.hpp
@@ -0,0 +1,13 @@
+#ifndef EXTRACTOR_HPP
+#define EXTRACTOR_HPP
+
+#include <string>
+
+#include <boost/filesystem.hpp>
+
+/** \brief Class of 'extract' utility. */
+struct Extractor
+{
+ int Run(int argc, char *argv[]);
+};
+#endif /* EXTRACTOR_HPP */
diff --git a/extractor/extractor_callbacks.cpp b/extractor/extractor_callbacks.cpp
new file mode 100644
index 0000000..87e4f4f
--- /dev/null
+++ b/extractor/extractor_callbacks.cpp
@@ -0,0 +1,223 @@
+/*
+
+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.
+
+*/
+
+#include "extractor_callbacks.hpp"
+#include "extraction_containers.hpp"
+#include "extraction_node.hpp"
+#include "extraction_way.hpp"
+
+#include "../data_structures/external_memory_node.hpp"
+#include "../data_structures/restriction.hpp"
+#include "../Util/container.hpp"
+#include "../Util/simple_logger.hpp"
+
+#include <osrm/Coordinate.h>
+
+#include <limits>
+#include <string>
+#include <vector>
+
+ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers,
+ std::unordered_map<std::string, NodeID> &string_map)
+ : string_map(string_map), external_memory(extraction_containers)
+{
+}
+
+/** warning: caller needs to take care of synchronization! */
+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
+ });
+}
+
+void ExtractorCallbacks::ProcessRestriction(
+ const mapbox::util::optional<InputRestrictionContainer> &restriction)
+{
+ if (restriction)
+ {
+ external_memory.restrictions_list.push_back(restriction.get());
+ // 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");
+ }
+}
+/** warning: caller needs to take care of synchronization! */
+void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const ExtractionWay &parsed_way)
+{
+ if (((0 >= parsed_way.forward_speed) ||
+ (TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode)) &&
+ ((0 >= parsed_way.backward_speed) ||
+ (TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode)) &&
+ (0 >= parsed_way.duration))
+ { // Only true if the way is specified by the speed profile
+ return;
+ }
+
+ if (input_way.nodes().size() <= 1)
+ { // safe-guard against broken data
+ return;
+ }
+
+ if (std::numeric_limits<decltype(input_way.id())>::max() == input_way.id())
+ {
+ SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << input_way.id()
+ << " of size " << input_way.nodes().size();
+ return;
+ }
+ if (0 < parsed_way.duration)
+ {
+ // 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);
+ }
+
+ if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.forward_speed))
+ {
+ SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << input_way.id();
+ return;
+ }
+
+ // Get the unique identifier for the street name
+ const auto &string_map_iterator = string_map.find(parsed_way.name);
+ unsigned name_id = external_memory.name_list.size();
+ if (string_map.end() == string_map_iterator)
+ {
+ external_memory.name_list.push_back(parsed_way.name);
+ string_map.insert(std::make_pair(parsed_way.name, name_id));
+ }
+ else
+ {
+ name_id = string_map_iterator->second;
+ }
+
+ const bool split_edge = (parsed_way.forward_speed > 0) &&
+ (TRAVEL_MODE_INACCESSIBLE != parsed_way.forward_travel_mode) &&
+ (parsed_way.backward_speed > 0) &&
+ (TRAVEL_MODE_INACCESSIBLE != parsed_way.backward_travel_mode) &&
+ ((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)
+ {
+ // 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(),
+ ((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));
+ 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);
+ 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);
+ external_memory.used_node_id_list.push_back(input_way.nodes().back().ref());
+ }
+
+ // The following information is needed to identify start and end segments of restrictions
+ external_memory.way_start_end_id_list.push_back(
+ {(EdgeID)input_way.id(),
+ (NodeID)input_way.nodes()[0].ref(),
+ (NodeID)input_way.nodes()[1].ref(),
+ (NodeID)input_way.nodes()[input_way.nodes().size() - 2].ref(),
+ (NodeID)input_way.nodes().back().ref()});
+
+ 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)
+ {
+ // 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));
+ };
+
+ if (is_opposite_way)
+ {
+ // SimpleLogger().Write() << "opposite2";
+ 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);
+ external_memory.used_node_id_list.push_back(input_way.nodes().back().ref());
+ }
+
+ external_memory.way_start_end_id_list.push_back(
+ {(EdgeID)input_way.id(),
+ (NodeID)input_way.nodes()[1].ref(),
+ (NodeID)input_way.nodes()[0].ref(),
+ (NodeID)input_way.nodes().back().ref(),
+ (NodeID)input_way.nodes()[input_way.nodes().size() - 2].ref()});
+ }
+}
diff --git a/Extractor/ExtractorCallbacks.h b/extractor/extractor_callbacks.hpp
similarity index 78%
rename from Extractor/ExtractorCallbacks.h
rename to extractor/extractor_callbacks.hpp
index fcdb272..0bb3010 100644
--- a/Extractor/ExtractorCallbacks.h
+++ b/extractor/extractor_callbacks.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,18 +25,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef EXTRACTOR_CALLBACKS_H
-#define EXTRACTOR_CALLBACKS_H
+#ifndef EXTRACTOR_CALLBACKS_HPP
+#define EXTRACTOR_CALLBACKS_HPP
+#include "extraction_way.hpp"
#include "../typedefs.h"
-#include <unordered_map>
+#include <osmium/osm.hpp>
+
+#include <variant/optional.hpp>
+
#include <string>
+#include <unordered_map>
struct ExternalMemoryNode;
class ExtractionContainers;
-struct ExtractionWay;
struct InputRestrictionContainer;
+struct ExtractionNode;
class ExtractorCallbacks
{
@@ -51,13 +56,13 @@ class ExtractorCallbacks
std::unordered_map<std::string, NodeID> &string_map);
// warning: caller needs to take care of synchronization!
- void ProcessNode(const ExternalMemoryNode &node);
+ void ProcessNode(const osmium::Node ¤t_node, const ExtractionNode &result_node);
// warning: caller needs to take care of synchronization!
- bool ProcessRestriction(const InputRestrictionContainer &restriction);
+ void ProcessRestriction(const mapbox::util::optional<InputRestrictionContainer> &restriction);
// warning: caller needs to take care of synchronization!
- void ProcessWay(ExtractionWay &way);
+ void ProcessWay(const osmium::Way ¤t_way, const ExtractionWay &result_way);
};
-#endif /* EXTRACTOR_CALLBACKS_H */
+#endif /* EXTRACTOR_CALLBACKS_HPP */
diff --git a/extractor/extractor_options.cpp b/extractor/extractor_options.cpp
new file mode 100644
index 0000000..d14d8d9
--- /dev/null
+++ b/extractor/extractor_options.cpp
@@ -0,0 +1,167 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "extractor_options.hpp"
+
+#include "../Util/git_sha.hpp"
+#include "../Util/IniFileUtil.h"
+#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)
+{
+ // 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"),
+ "Path to a configuration file.");
+
+ // declare a group of options that will be allowed both on command line and in config file
+ boost::program_options::options_description config_options("Configuration");
+ config_options.add_options()("profile,p",
+ boost::program_options::value<boost::filesystem::path>(
+ &extractor_config.profile_path)->default_value("profile.lua"),
+ "Path to LUA routing profile")(
+ "threads,t",
+ boost::program_options::value<unsigned int>(&extractor_config.requested_num_threads)
+ ->default_value(tbb::task_scheduler_init::default_num_threads()),
+ "Number of threads to use");
+
+ // hidden options, will be allowed both on command line and in config file, but will not be
+ // shown to the user
+ boost::program_options::options_description hidden_options("Hidden options");
+ hidden_options.add_options()(
+ "input,i",
+ boost::program_options::value<boost::filesystem::path>(&extractor_config.input_path),
+ "Input file in .osm, .osm.bz2 or .osm.pbf format");
+
+ // positional option
+ boost::program_options::positional_options_description positional_options;
+ positional_options.add("input", 1);
+
+ // combine above options for parsing
+ boost::program_options::options_description cmdline_options;
+ cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+
+ boost::program_options::options_description config_file_options;
+ config_file_options.add(config_options).add(hidden_options);
+
+ boost::program_options::options_description visible_options(
+ boost::filesystem::basename(argv[0]) + " <input.osm/.osm.bz2/.osm.pbf> [options]");
+ visible_options.add(generic_options).add(config_options);
+
+ // parse command line options
+ 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 false;
+ }
+
+ if (option_variables.count("help"))
+ {
+ SimpleLogger().Write() << visible_options;
+ return false;
+ }
+
+ boost::program_options::notify(option_variables);
+
+ // parse config file
+ if (boost::filesystem::is_regular_file(extractor_config.config_file_path))
+ {
+ SimpleLogger().Write() << "Reading options from: "
+ << extractor_config.config_file_path.string();
+ std::string ini_file_contents =
+ 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"))
+ {
+ SimpleLogger().Write() << visible_options;
+ return false;
+ }
+ return true;
+}
+
+void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_config)
+{
+ boost::filesystem::path &input_path = extractor_config.input_path;
+ extractor_config.output_file_name = input_path.string();
+ extractor_config.restriction_file_name = input_path.string();
+ extractor_config.timestamp_file_name = input_path.string();
+ std::string::size_type pos = extractor_config.output_file_name.find(".osm.bz2");
+ if (pos == std::string::npos)
+ {
+ pos = extractor_config.output_file_name.find(".osm.pbf");
+ if (pos == std::string::npos)
+ {
+ pos = extractor_config.output_file_name.find(".osm.xml");
+ }
+ }
+ if (pos == std::string::npos)
+ {
+ pos = extractor_config.output_file_name.find(".pbf");
+ }
+ if (pos == std::string::npos)
+ {
+ pos = extractor_config.output_file_name.find(".osm");
+ if (pos == std::string::npos)
+ {
+ extractor_config.output_file_name.append(".osrm");
+ extractor_config.restriction_file_name.append(".osrm.restrictions");
+ extractor_config.timestamp_file_name.append(".osrm.timestamp");
+ }
+ else
+ {
+ extractor_config.output_file_name.replace(pos, 5, ".osrm");
+ extractor_config.restriction_file_name.replace(pos, 5, ".osrm.restrictions");
+ extractor_config.timestamp_file_name.replace(pos, 5, ".osrm.timestamp");
+ }
+ }
+ else
+ {
+ extractor_config.output_file_name.replace(pos, 8, ".osrm");
+ extractor_config.restriction_file_name.replace(pos, 8, ".osrm.restrictions");
+ extractor_config.timestamp_file_name.replace(pos, 8, ".osrm.timestamp");
+ }
+}
diff --git a/DataStructures/ImportNode.h b/extractor/extractor_options.hpp
similarity index 63%
rename from DataStructures/ImportNode.h
rename to extractor/extractor_options.hpp
index b8a9451..118da78 100644
--- a/DataStructures/ImportNode.h
+++ b/extractor/extractor_options.hpp
@@ -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,33 +25,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef IMPORTNODE_H_
-#define IMPORTNODE_H_
+#ifndef EXTRACTOR_OPTIONS_HPP
+#define EXTRACTOR_OPTIONS_HPP
-#include "QueryNode.h"
-#include "../DataStructures/HashTable.h"
+#include "extractor.hpp"
-#include <string>
-
-struct ExternalMemoryNode : NodeInfo
+struct ExtractorConfig
{
- ExternalMemoryNode(int lat, int lon, unsigned int id, bool bollard, bool traffic_light);
-
- ExternalMemoryNode();
-
- static ExternalMemoryNode min_value();
-
- static ExternalMemoryNode max_value();
-
- bool bollard;
- bool trafficLight;
+ 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;
+
+ std::string output_file_name;
+ std::string restriction_file_name;
+ std::string timestamp_file_name;
};
-struct ImportNode : public ExternalMemoryNode
+struct ExtractorOptions
{
- HashTable<std::string, std::string> keyVals;
+ static bool ParseArguments(int argc, char *argv[], ExtractorConfig &extractor_config);
- inline void Clear();
+ static void GenerateOutputFilesNames(ExtractorConfig &extractor_config);
};
-#endif /* IMPORTNODE_H_ */
+#endif // EXTRACTOR_OPTIONS_HPP
diff --git a/extractor/first_and_last_segment_of_way.hpp b/extractor/first_and_last_segment_of_way.hpp
new file mode 100644
index 0000000..8e8ad72
--- /dev/null
+++ b/extractor/first_and_last_segment_of_way.hpp
@@ -0,0 +1,88 @@
+/*
+
+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 FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
+#define FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
+
+#include "../data_structures/external_memory_node.hpp"
+#include "../typedefs.h"
+
+#include <limits>
+#include <string>
+
+struct FirstAndLastSegmentOfWay
+{
+ EdgeID way_id;
+ NodeID first_segment_source_id;
+ NodeID first_segment_target_id;
+ NodeID last_segment_source_id;
+ NodeID last_segment_target_id;
+ FirstAndLastSegmentOfWay()
+ : way_id(std::numeric_limits<EdgeID>::max()),
+ first_segment_source_id(std::numeric_limits<NodeID>::max()),
+ first_segment_target_id(std::numeric_limits<NodeID>::max()),
+ last_segment_source_id(std::numeric_limits<NodeID>::max()),
+ last_segment_target_id(std::numeric_limits<NodeID>::max())
+ {
+ }
+
+ FirstAndLastSegmentOfWay(EdgeID w, NodeID fs, NodeID ft, NodeID ls, NodeID lt)
+ : way_id(w), first_segment_source_id(fs), first_segment_target_id(ft),
+ last_segment_source_id(ls), last_segment_target_id(lt)
+ {
+ }
+
+ static FirstAndLastSegmentOfWay min_value()
+ {
+ return {std::numeric_limits<EdgeID>::min(),
+ std::numeric_limits<NodeID>::min(),
+ std::numeric_limits<NodeID>::min(),
+ std::numeric_limits<NodeID>::min(),
+ std::numeric_limits<NodeID>::min()};
+ }
+ static FirstAndLastSegmentOfWay max_value()
+ {
+ return {std::numeric_limits<EdgeID>::max(),
+ std::numeric_limits<NodeID>::max(),
+ std::numeric_limits<NodeID>::max(),
+ std::numeric_limits<NodeID>::max(),
+ std::numeric_limits<NodeID>::max()};
+ }
+};
+
+struct FirstAndLastSegmentOfWayStxxlCompare
+{
+ using value_type = FirstAndLastSegmentOfWay;
+ bool operator()(const FirstAndLastSegmentOfWay &a, const FirstAndLastSegmentOfWay &b) const
+ {
+ return a.way_id < b.way_id;
+ }
+ value_type max_value() { return FirstAndLastSegmentOfWay::max_value(); }
+ value_type min_value() { return FirstAndLastSegmentOfWay::min_value(); }
+};
+
+#endif /* FIRST_AND_LAST_SEGMENT_OF_WAY_HPP */
diff --git a/Extractor/InternalExtractorEdge.h b/extractor/internal_extractor_edge.hpp
similarity index 78%
rename from Extractor/InternalExtractorEdge.h
rename to extractor/internal_extractor_edge.hpp
index 02903e8..ffd2d4a 100644
--- a/Extractor/InternalExtractorEdge.h
+++ b/extractor/internal_extractor_edge.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,10 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef INTERNAL_EXTRACTOR_EDGE_H
-#define INTERNAL_EXTRACTOR_EDGE_H
+#ifndef INTERNAL_EXTRACTOR_EDGE_HPP
+#define INTERNAL_EXTRACTOR_EDGE_HPP
#include "../typedefs.h"
+#include "../data_structures/travel_mode.hpp"
#include <osrm/Coordinate.h>
#include <boost/assert.hpp>
@@ -36,15 +37,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct InternalExtractorEdge
{
InternalExtractorEdge()
- : start(0), target(0), type(0), direction(0), speed(0), name_id(0), is_roundabout(false),
+ : start(0), target(0), direction(0), speed(0), name_id(0), is_roundabout(false),
is_in_tiny_cc(false), is_duration_set(false), is_access_restricted(false),
- is_contra_flow(false), is_split(false)
+ travel_mode(TRAVEL_MODE_INACCESSIBLE), is_split(false)
{
}
explicit InternalExtractorEdge(NodeID start,
NodeID target,
- short type,
short direction,
double speed,
unsigned name_id,
@@ -52,30 +52,28 @@ struct InternalExtractorEdge
bool is_in_tiny_cc,
bool is_duration_set,
bool is_access_restricted,
- bool is_contra_flow,
+ TravelMode travel_mode,
bool is_split)
- : start(start), target(target), type(type), direction(direction), speed(speed),
+ : start(start), target(target), direction(direction), speed(speed),
name_id(name_id), is_roundabout(is_roundabout), is_in_tiny_cc(is_in_tiny_cc),
is_duration_set(is_duration_set), is_access_restricted(is_access_restricted),
- is_contra_flow(is_contra_flow), is_split(is_split)
+ travel_mode(travel_mode), is_split(is_split)
{
- BOOST_ASSERT(0 <= type);
}
// necessary static util functions for stxxl's sorting
static InternalExtractorEdge min_value()
{
- return InternalExtractorEdge(0, 0, 0, 0, 0, 0, false, false, false, false, false, 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, 0, false, false, false, false, false, false);
+ SPECIAL_NODEID, SPECIAL_NODEID, 0, 0, 0, false, false, false, false, TRAVEL_MODE_INACCESSIBLE, false);
}
NodeID start;
NodeID target;
- short type;
short direction;
double speed;
unsigned name_id;
@@ -83,7 +81,7 @@ struct InternalExtractorEdge
bool is_in_tiny_cc;
bool is_duration_set;
bool is_access_restricted;
- bool is_contra_flow;
+ TravelMode travel_mode : 4;
bool is_split;
FixedPointCoordinate source_coordinate;
@@ -92,7 +90,7 @@ struct InternalExtractorEdge
struct CmpEdgeByStartID
{
- typedef InternalExtractorEdge value_type;
+ using value_type = InternalExtractorEdge;
bool operator()(const InternalExtractorEdge &a, const InternalExtractorEdge &b) const
{
return a.start < b.start;
@@ -105,7 +103,7 @@ struct CmpEdgeByStartID
struct CmpEdgeByTargetID
{
- typedef InternalExtractorEdge value_type;
+ using value_type = InternalExtractorEdge;
bool operator()(const InternalExtractorEdge &a, const InternalExtractorEdge &b) const
{
@@ -117,4 +115,4 @@ struct CmpEdgeByTargetID
value_type min_value() { return InternalExtractorEdge::min_value(); }
};
-#endif // INTERNAL_EXTRACTOR_EDGE_H
+#endif // INTERNAL_EXTRACTOR_EDGE_HPP
diff --git a/extractor/restriction_parser.cpp b/extractor/restriction_parser.cpp
new file mode 100644
index 0000000..2f53d33
--- /dev/null
+++ b/extractor/restriction_parser.cpp
@@ -0,0 +1,241 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "restriction_parser.hpp"
+#include "extraction_way.hpp"
+#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 <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/regex.hpp>
+#include <boost/ref.hpp>
+#include <boost/regex.hpp>
+
+namespace
+{
+int lua_error_callback(lua_State *lua_state)
+{
+ luabind::object error_msg(luabind::from_stack(lua_state, -1));
+ std::ostringstream error_stream;
+ error_stream << error_msg;
+ throw osrm::exception("ERROR occured in profile script:\n" + error_stream.str());
+}
+}
+
+RestrictionParser::RestrictionParser(lua_State *lua_state)
+ : /*lua_state(scripting_environment.getLuaState()),*/ use_turn_restrictions(true)
+{
+ ReadUseRestrictionsSetting(lua_state);
+
+ if (use_turn_restrictions)
+ {
+ ReadRestrictionExceptions(lua_state);
+ }
+}
+
+void RestrictionParser::ReadUseRestrictionsSetting(lua_State *lua_state)
+{
+ if (0 == luaL_dostring(lua_state, "return use_turn_restrictions\n") &&
+ lua_isboolean(lua_state, -1))
+ {
+ use_turn_restrictions = lua_toboolean(lua_state, -1);
+ }
+
+ if (use_turn_restrictions)
+ {
+ SimpleLogger().Write() << "Using turn restrictions";
+ }
+ else
+ {
+ SimpleLogger().Write() << "Ignoring turn restrictions";
+ }
+}
+
+void RestrictionParser::ReadRestrictionExceptions(lua_State *lua_state)
+{
+ if (lua_function_exists(lua_state, "get_exceptions"))
+ {
+ luabind::set_pcall_callback(&lua_error_callback);
+ // get list of turn restriction exceptions
+ luabind::call_function<void>(
+ lua_state, "get_exceptions", boost::ref(restriction_exceptions));
+ const unsigned exception_count = restriction_exceptions.size();
+ SimpleLogger().Write() << "Found " << exception_count
+ << " exceptions to turn restrictions:";
+ for (const std::string &str : restriction_exceptions)
+ {
+ SimpleLogger().Write() << " " << str;
+ }
+ }
+ else
+ {
+ SimpleLogger().Write() << "Found no exceptions to turn restrictions";
+ }
+}
+
+mapbox::util::optional<InputRestrictionContainer>
+RestrictionParser::TryParse(const osmium::Relation &relation) const
+{
+ // return if turn restrictions should be ignored
+ if (!use_turn_restrictions)
+ {
+ return mapbox::util::optional<InputRestrictionContainer>();
+ }
+
+ osmium::tags::KeyPrefixFilter filter(false);
+ filter.add(true, "restriction");
+
+ const osmium::TagList &tag_list = relation.tags();
+
+ osmium::tags::KeyPrefixFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end());
+ osmium::tags::KeyPrefixFilter::iterator fi_end(filter, tag_list.end(), tag_list.end());
+
+ // if it's a restriction, continue;
+ if (std::distance(fi_begin, fi_end) == 0)
+ {
+ return mapbox::util::optional<InputRestrictionContainer>();
+ }
+
+ // check if the restriction should be ignored
+ const char *except = relation.get_value_by_key("except");
+ if (except != nullptr && ShouldIgnoreRestriction(except))
+ {
+ return mapbox::util::optional<InputRestrictionContainer>();
+ }
+
+ bool is_only_restriction = false;
+
+ for (auto iter = fi_begin; iter != fi_end; ++iter)
+ {
+ if (std::string("restriction") == iter->key() ||
+ std::string("restriction::hgv") == iter->key())
+ {
+ const std::string restriction_value(iter->value());
+
+ if (restriction_value.find("only_") == 0)
+ {
+ is_only_restriction = true;
+ }
+ }
+ }
+
+ InputRestrictionContainer restriction_container(is_only_restriction);
+
+ for (const auto &member : relation.members())
+ {
+ const char *role = member.role();
+ if (strcmp("from", role) != 0 && strcmp("to", role) != 0 && strcmp("via", role) != 0)
+ {
+ continue;
+ }
+
+ switch (member.type())
+ {
+ case osmium::item_type::node:
+ // Make sure nodes appear only in the role if a via node
+ if (0 == strcmp("from", role) || 0 == strcmp("to", role))
+ {
+ continue;
+ }
+ BOOST_ASSERT(0 == strcmp("via", role));
+ // set the via node id
+ // SimpleLogger().Write() << "via: " << member.ref();
+
+ restriction_container.restriction.via.node = member.ref();
+ break;
+
+ case osmium::item_type::way:
+ BOOST_ASSERT(0 == strcmp("from", role) || 0 == strcmp("to", role) ||
+ 0 == strcmp("via", role));
+ if (0 == strcmp("from", role))
+ {
+ // 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();
+ }
+ break;
+ case osmium::item_type::relation:
+ // not yet supported, but who knows what the future holds...
+ continue;
+ break;
+ default:
+ BOOST_ASSERT(false);
+ 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);
+}
+
+bool RestrictionParser::ShouldIgnoreRestriction(const std::string &except_tag_string) const
+{
+ // should this restriction be ignored? yes if there's an overlap between:
+ // a) the list of modes in the except tag of the restriction
+ // (except_tag_string), eg: except=bus;bicycle
+ // b) the lua profile defines a hierachy of modes,
+ // eg: [access, vehicle, bicycle]
+
+ if (except_tag_string.empty())
+ {
+ return false;
+ }
+
+ // Be warned, this is quadratic work here, but we assume that
+ // only a few exceptions are actually defined.
+ std::vector<std::string> exceptions;
+ boost::algorithm::split_regex(exceptions, except_tag_string, boost::regex("[;][ ]*"));
+ 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;
+}
diff --git a/Algorithms/PolylineCompressor.h b/extractor/restriction_parser.hpp
similarity index 59%
rename from Algorithms/PolylineCompressor.h
rename to extractor/restriction_parser.hpp
index 5472bd8..d5adb43 100644
--- a/Algorithms/PolylineCompressor.h
+++ b/extractor/restriction_parser.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,27 +25,37 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef POLYLINECOMPRESSOR_H_
-#define POLYLINECOMPRESSOR_H_
+#ifndef RESTRICTION_PARSER_HPP
+#define RESTRICTION_PARSER_HPP
-struct SegmentInformation;
+#include "../data_structures/restriction.hpp"
-#include "../DataStructures/JSONContainer.h"
+#include <osmium/osm.hpp>
+#include <osmium/tags/regex_filter.hpp>
+
+#include <variant/optional.hpp>
#include <string>
#include <vector>
-class PolylineCompressor
-{
- private:
- void encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output) const;
-
- void encodeNumber(int number_to_encode, std::string &output) const;
+struct lua_State;
+class ScriptingEnvironment;
+class RestrictionParser
+{
public:
- JSON::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
+ // RestrictionParser(ScriptingEnvironment &scripting_environment);
+ RestrictionParser(lua_State *lua_state);
+ mapbox::util::optional<InputRestrictionContainer> TryParse(const osmium::Relation &relation) const;
+
+ private:
+ void ReadUseRestrictionsSetting(lua_State *lua_state);
+ void ReadRestrictionExceptions(lua_State *lua_state);
+ bool ShouldIgnoreRestriction(const std::string &except_tag_string) const;
- JSON::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
+ // lua_State *lua_state;
+ std::vector<std::string> restriction_exceptions;
+ bool use_turn_restrictions;
};
-#endif /* POLYLINECOMPRESSOR_H_ */
+#endif /* RESTRICTION_PARSER_HPP */
diff --git a/extractor/scripting_environment.cpp b/extractor/scripting_environment.cpp
new file mode 100644
index 0000000..c51651e
--- /dev/null
+++ b/extractor/scripting_environment.cpp
@@ -0,0 +1,146 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "scripting_environment.hpp"
+
+#include "extraction_helper_functions.hpp"
+#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 "../typedefs.h"
+
+#include <luabind/tag_function.hpp>
+
+#include <osmium/osm.hpp>
+
+#include <sstream>
+namespace {
+// wrapper method as luabind doesn't automatically overload funcs w/ default parameters
+template<class T>
+auto get_value_by_key(T const& object, const char *key) -> decltype(object.get_value_by_key(key))
+{
+ return object.get_value_by_key(key, "");
+}
+
+int lua_error_callback(lua_State *L) // This is so I can use my own function as an
+// exception handler, pcall_log()
+{
+ luabind::object error_msg(luabind::from_stack(L, -1));
+ std::ostringstream error_stream;
+ error_stream << error_msg;
+ throw osrm::exception("ERROR occured in profile script:\n" + error_stream.str());
+}
+}
+
+
+ScriptingEnvironment::ScriptingEnvironment(const std::string &file_name)
+: file_name(file_name)
+{
+ SimpleLogger().Write() << "Using script " << file_name;
+}
+
+void ScriptingEnvironment::init_lua_state(lua_State* lua_state)
+{
+ typedef double (osmium::Location::* location_member_ptr_type)() const;
+
+ luabind::open(lua_state);
+ // open utility libraries string library;
+ luaL_openlibs(lua_state);
+
+ luaAddScriptFolderToLoadPath(lua_state, file_name.c_str());
+
+ // Add our function to the state's global scope
+ luabind::module(lua_state)[
+ luabind::def("print", LUA_print<std::string>),
+ luabind::def("durationIsValid", durationIsValid),
+ luabind::def("parseDuration", parseDuration),
+
+ luabind::class_<std::vector<std::string>>("vector")
+ .def("Add", static_cast<void (std::vector<std::string>::*)(const std::string &)>(&std::vector<std::string>::push_back)),
+
+ luabind::class_<osmium::Location>("Location")
+ .def<location_member_ptr_type>("lat", &osmium::Location::lat)
+ .def<location_member_ptr_type>("lon", &osmium::Location::lon),
+
+ luabind::class_<osmium::Node>("Node")
+ // .def<node_member_ptr_type>("tags", &osmium::Node::tags)
+ .def("get_value_by_key", &osmium::Node::get_value_by_key)
+ .def("get_value_by_key", &get_value_by_key<osmium::Node>),
+
+ luabind::class_<ExtractionNode>("ResultNode")
+ .def_readwrite("traffic_lights", &ExtractionNode::traffic_lights)
+ .def_readwrite("barrier", &ExtractionNode::barrier),
+
+ luabind::class_<ExtractionWay>("ResultWay")
+ // .def(luabind::constructor<>())
+ .def_readwrite("forward_speed", &ExtractionWay::forward_speed)
+ .def_readwrite("backward_speed", &ExtractionWay::backward_speed)
+ .def_readwrite("name", &ExtractionWay::name)
+ .def_readwrite("roundabout", &ExtractionWay::roundabout)
+ .def_readwrite("is_access_restricted", &ExtractionWay::is_access_restricted)
+ .def_readwrite("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>)
+ ];
+
+ if (0 != luaL_dofile(lua_state, file_name.c_str()))
+ {
+ luabind::object error_msg(luabind::from_stack(lua_state, -1));
+ std::ostringstream error_stream;
+ error_stream << error_msg;
+ throw osrm::exception("ERROR occured in profile script:\n" + error_stream.str());
+ }
+}
+
+lua_State *ScriptingEnvironment::get_lua_state()
+{
+ std::lock_guard<std::mutex> lock(init_mutex);
+ bool initialized = false;
+ auto& ref = script_contexts.local(initialized);
+ if (!initialized)
+ {
+ std::shared_ptr<lua_State> state(luaL_newstate(), lua_close);
+ ref = state;
+ init_lua_state(ref.get());
+ }
+ luabind::set_pcall_callback(&lua_error_callback);
+
+ return ref.get();
+}
diff --git a/Extractor/ScriptingEnvironment.h b/extractor/scripting_environment.hpp
similarity index 79%
rename from Extractor/ScriptingEnvironment.h
rename to extractor/scripting_environment.hpp
index 2b1fffe..6e0b079 100644
--- a/Extractor/ScriptingEnvironment.h
+++ b/extractor/scripting_environment.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,11 +25,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SCRIPTINGENVIRONMENT_H_
-#define SCRIPTINGENVIRONMENT_H_
+#ifndef SCRIPTING_ENVIRONMENT_HPP
+#define SCRIPTING_ENVIRONMENT_HPP
#include <string>
#include <memory>
+#include <mutex>
#include <tbb/enumerable_thread_specific.h>
struct lua_State;
@@ -37,16 +38,16 @@ struct lua_State;
class ScriptingEnvironment
{
public:
- ScriptingEnvironment();
- explicit ScriptingEnvironment(const char *file_name);
+ ScriptingEnvironment() = delete;
+ explicit ScriptingEnvironment(const std::string &file_name);
- lua_State *getLuaState();
+ lua_State *get_lua_state();
private:
- void initLuaState(lua_State* lua_state);
-
+ void init_lua_state(lua_State* lua_state);
+ std::mutex init_mutex;
std::string file_name;
tbb::enumerable_thread_specific<std::shared_ptr<lua_State>> script_contexts;
};
-#endif /* SCRIPTINGENVIRONMENT_H_ */
+#endif /* SCRIPTING_ENVIRONMENT_HPP */
diff --git a/features/bicycle/mode.feature b/features/bicycle/mode.feature
index eac0430..2bfa4de 100644
--- a/features/bicycle/mode.feature
+++ b/features/bicycle/mode.feature
@@ -1,89 +1,177 @@
@routing @bicycle @mode
Feature: Bike - Mode flag
- Background:
- Given the profile "bicycle"
+# bicycle modes:
+# 1 bike
+# 2 pushing
+# 3 ferry
+# 4 train
- @todo
+ Background:
+ Given the profile "bicycle"
+
Scenario: Bike - Mode when using a ferry
- Given the node map
- | a | b | |
- | | c | d |
+ Given the node map
+ | a | b | |
+ | | c | d |
- And the ways
- | nodes | highway | route | duration |
- | ab | primary | | |
- | bc | | ferry | 0:01 |
- | cd | primary | | |
+ And the ways
+ | nodes | highway | route | duration |
+ | ab | primary | | |
+ | bc | | ferry | 0:01 |
+ | cd | primary | | |
- When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd | head,right,left, destination | bike,ferry,bike |
- | d | a | cd,bc,ab | head,right,left, destination | bike,ferry,bike |
- | c | a | bc,ab | head,left,destination | ferry,bike |
- | d | b | cd,bc | head,right,destination | bike,ferry |
- | a | c | ab,bc | head,right,destination | bike,ferry |
- | b | d | bc,cd | head,left,destination | ferry,bike |
-
- @todo
- Scenario: Bike - Mode when pushing bike against oneways
- Given the node map
- | a | b | |
- | | c | d |
+ When I route I should get
+ | from | to | route | turns | modes |
+ | a | d | ab,bc,cd | head,right,left,destination | 1,3,1 |
+ | d | a | cd,bc,ab | head,right,left,destination | 1,3,1 |
+ | c | a | bc,ab | head,left,destination | 3,1 |
+ | d | b | cd,bc | head,right,destination | 1,3 |
+ | a | c | ab,bc | head,right,destination | 1,3 |
+ | b | d | bc,cd | head,left,destination | 3,1 |
- And the ways
- | nodes | highway | oneway |
- | ab | primary | |
- | bc | primary | yes |
- | cd | primary | |
+ Scenario: Bike - Mode when using a train
+ Given the node map
+ | a | b | |
+ | | c | d |
- When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd | head,right,left,destination | bike,push,bike |
- | d | a | cd,bc,ab | head,right,left,destination | bike,push,bike |
- | c | a | bc,ab | head,left,destination | push,bike |
- | d | b | cd,bc | head,right,destination | bike,push |
- | a | c | ab,bc | head,right,destination | bike,push |
- | b | d | bc,cd | head,left,destination | push,bike |
-
- @todo
- Scenario: Bike - Mode when pushing on pedestrain streets
+ And the ways
+ | nodes | highway | railway | bicycle |
+ | ab | primary | | |
+ | bc | | train | yes |
+ | cd | primary | | |
+
+ When I route I should get
+ | from | to | route | turns | modes |
+ | a | d | ab,bc,cd | head,right,left,destination | 1,4,1 |
+ | d | a | cd,bc,ab | head,right,left,destination | 1,4,1 |
+ | c | a | bc,ab | head,left,destination | 4,1 |
+ | d | b | cd,bc | head,right,destination | 1,4 |
+ | a | c | ab,bc | head,right,destination | 1,4 |
+ | b | d | bc,cd | head,left,destination | 4,1 |
+
+ Scenario: Bike - Mode when pushing bike against oneways
+ Given the node map
+ | a | b | |
+ | | c | d |
+
+ And the ways
+ | nodes | highway | oneway |
+ | ab | primary | |
+ | bc | primary | yes |
+ | cd | primary | |
+
+ When I route I should get
+ | from | to | route | turns | modes |
+ | a | d | ab,bc,cd | head,right,left,destination | 1,1,1 |
+ | d | a | cd,bc,ab | head,right,left,destination | 1,2,1 |
+ | c | a | bc,ab | head,left,destination | 2,1 |
+ | d | b | cd,bc | head,right,destination | 1,2 |
+ | a | c | ab,bc | head,right,destination | 1,1 |
+ | b | d | bc,cd | head,left,destination | 1,1 |
+
+ Scenario: Bike - Mode when pushing on pedestrain streets
+ Given the node map
+ | a | b | |
+ | | c | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | bc | pedestrian |
+ | cd | primary |
+
+ When I route I should get
+ | from | to | route | turns | modes |
+ | a | d | ab,bc,cd | head,right,left,destination | 1,2,1 |
+ | d | a | cd,bc,ab | head,right,left,destination | 1,2,1 |
+ | c | a | bc,ab | head,left,destination | 2,1 |
+ | d | b | cd,bc | head,right,destination | 1,2 |
+ | a | c | ab,bc | head,right,destination | 1,2 |
+ | b | d | bc,cd | head,left,destination | 2,1 |
+
+ Scenario: Bike - Mode when pushing on pedestrain areas
+ Given the node map
+ | a | b | | |
+ | | c | d | f |
+
+ And the ways
+ | nodes | highway | area |
+ | ab | primary | |
+ | bcd | pedestrian | yes |
+ | df | primary | |
+
+ When I route I should get
+ | from | to | route | modes |
+ | a | f | ab,bcd,df | 1,2,1 |
+ | f | a | df,bcd,ab | 1,2,1 |
+ | d | a | bcd,ab | 2,1 |
+ | f | b | df,bcd | 1,2 |
+ | a | d | ab,bcd | 1,2 |
+ | b | f | bcd,df | 2,1 |
+
+ Scenario: Bike - Mode when pushing on steps
+ Given the node map
+ | a | b | | |
+ | | c | d | f |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | bc | steps |
+ | cd | primary |
+
+ When I route I should get
+ | from | to | route | turns | modes |
+ | a | d | ab,bc,cd | head,right,left,destination | 1,2,1 |
+ | d | a | cd,bc,ab | head,right,left,destination | 1,2,1 |
+ | c | a | bc,ab | head,left,destination | 2,1 |
+ | d | b | cd,bc | head,right,destination | 1,2 |
+ | a | c | ab,bc | head,right,destination | 1,2 |
+ | b | d | bc,cd | head,left,destination | 2,1 |
+
+ Scenario: Bike - Mode when bicycle=dismount
+ Given the node map
+ | a | b | | |
+ | | c | d | f |
+
+ And the ways
+ | nodes | highway | bicycle |
+ | ab | primary | |
+ | bc | primary | dismount |
+ | cd | primary | |
+
+ When I route I should get
+ | from | to | route | turns | modes |
+ | a | d | ab,bc,cd | head,right,left,destination | 1,2,1 |
+ | d | a | cd,bc,ab | head,right,left,destination | 1,2,1 |
+ | c | a | bc,ab | head,left,destination | 2,1 |
+ | d | b | cd,bc | head,right,destination | 1,2 |
+ | a | c | ab,bc | head,right,destination | 1,2 |
+ | b | d | bc,cd | head,left,destination | 2,1 |
+
+ Scenario: Bicycle - Modes when starting on forward oneway
Given the node map
- | a | b | |
- | | c | d |
+ | a | b |
And the ways
- | nodes | highway |
- | ab | primary |
- | bc | pedestrian |
- | cd | primary |
+ | nodes | oneway |
+ | ab | yes |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd | head,right,left,destination | bike,push,bike |
- | d | a | cd,bc,ab | head,right,left,destination | bike,push,bike |
- | c | a | bc,ab | head,left,destination | push,bike |
- | d | b | cd,bc | head,right,destination | bike,push |
- | a | c | ab,bc | head,right,destination | bike,push |
- | b | d | bc,cd | head,left,destination | push,bike |
-
- @todo
- Scenario: Bike - Mode when pushing on pedestrain areas
+ | from | to | route | modes |
+ | a | b | ab | 1 |
+ | b | a | ab | 2 |
+
+ Scenario: Bicycle - Modes when starting on reverse oneway
Given the node map
- | a | b | | |
- | | c | d | f |
+ | a | b |
And the ways
- | nodes | highway | area |
- | ab | primary | |
- | bcd | pedestrian | yes |
- | df | primary | |
+ | nodes | oneway |
+ | ab | -1 |
When I route I should get
- | from | to | route | modes |
- | a | f | ab,bcd,df | bike,push,bike |
- | f | a | df,bcd,ab | bike,push,bike |
- | d | a | bcd,ab | push,bike |
- | f | b | df,bcd | bike,push |
- | a | d | ab,bcd | bike,push |
- | b | f | bcd,df | push,bike |
+ | from | to | route | modes |
+ | a | b | ab | 2 |
+ | b | a | ab | 1 |
diff --git a/features/bicycle/pushing.feature b/features/bicycle/pushing.feature
index 2b23829..5741fb1 100644
--- a/features/bicycle/pushing.feature
+++ b/features/bicycle/pushing.feature
@@ -4,9 +4,9 @@ Feature: Bike - Accessability of different way types
Background:
Given the profile "bicycle"
Given the shortcuts
- | key | value |
- | bike | 49s ~20% |
- | foot | 121s ~20% |
+ | key | value |
+ | bike | 15 km/h ~20% |
+ | foot | 5 km/h ~20% |
Scenario: Bike - Pushing bikes on pedestrian-only ways
Then routability should be
@@ -98,11 +98,11 @@ Feature: Bike - Accessability of different way types
| cd | primary | |
When I route I should get
- | from | to | route | turns |
- | a | d | ab,bc,cd | head,right,left,destination |
- | d | a | cd,bc,ab | head,enter_contraflow,leave_contraflow,destination |
- | c | a | bc,ab | head,leave_contraflow,destination |
- | d | b | cd,bc | head,enter_contraflow,destination |
+ | from | to | route | turns |
+ | a | d | ab,bc,cd | head,right,left,destination |
+ | d | a | cd,bc,ab | head,right,left,destination |
+ | c | a | bc,ab | head,left,destination |
+ | d | b | cd,bc | head,right,destination |
@todo
Scenario: Bike - Instructions when pushing bike on footway/pedestrian, etc.
@@ -117,8 +117,8 @@ Feature: Bike - Accessability of different way types
| cd | primary |
When I route I should get
- | from | to | route | turns |
- | a | d | ab,bc,cd | head,right,left,destination |
- | d | a | cd,bc,ab | head,enter_contraflow,leave_contraflow,destination |
- | c | a | bc,ab | head,leave_contraflow,destination |
- | d | b | cd,bc | head,enter_contraflow,destination |
+ | from | to | route | turns |
+ | a | d | ab,bc,cd | head,right,left,destination |
+ | d | a | cd,bc,ab | head,right,left,destination |
+ | c | a | bc,ab | head,left,destination |
+ | d | b | cd,bc | head,right,destination |
diff --git a/features/car/ferry.feature b/features/car/ferry.feature
index 3e90cf0..abbe5ed 100644
--- a/features/car/ferry.feature
+++ b/features/car/ferry.feature
@@ -17,12 +17,31 @@ Feature: Car - Handle ferry routes
| efg | primary | | |
When I route I should get
- | from | to | route |
- | a | g | abc,cde,efg |
- | b | f | abc,cde,efg |
- | e | c | cde |
- | e | b | cde,abc |
- | e | a | cde,abc |
- | c | e | cde |
- | c | f | cde,efg |
- | c | g | cde,efg |
+ | from | to | route | modes |
+ | a | g | abc,cde,efg | 1,2,1 |
+ | b | f | abc,cde,efg | 1,2,1 |
+ | e | c | cde | 2 |
+ | e | b | cde,abc | 2,1 |
+ | e | a | cde,abc | 2,1 |
+ | c | e | cde | 2 |
+ | c | f | cde,efg | 2,1 |
+ | c | g | cde,efg | 2,1 |
+
+ Scenario: Car - Properly handle durations
+ Given the node map
+ | a | b | c | | |
+ | | | d | | |
+ | | | e | f | g |
+
+ And the ways
+ | nodes | highway | route | duration |
+ | abc | primary | | |
+ | cde | | ferry | 00:01:00 |
+ | 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/link.feature b/features/car/link.feature
new file mode 100644
index 0000000..f4628e4
--- /dev/null
+++ b/features/car/link.feature
@@ -0,0 +1,111 @@
+ at routing @link @car
+Feature: Car - Speed on links
+# Check that there's a reasonable ratio between the
+# speed of a way and it's corresponding link type.
+
+ Background: Use specific speeds
+ Given the profile "car"
+ Given a grid size of 1000 meters
+
+ Scenario: Car - Use motorway_link when reasonable
+ Given the node map
+ | | | e | | | | f | | |
+ | x | a | b | | | | c | d | y |
+
+ And the ways
+ | nodes | highway |
+ | xa | unclassified |
+ | ab | motorway_link |
+ | bc | motorway_link |
+ | cd | motorway_link |
+ | ae | motorway |
+ | ef | motorway |
+ | fd | motorway |
+ | dy | unclassified |
+
+ When I route I should get
+ | from | to | route |
+ | x | y | xa,ae,ef,fd,dy |
+ | b | c | bc |
+
+ Scenario: Car - Use trunk_link when reasonable
+ Given the node map
+ | | | e | | | | f | | |
+ | x | a | b | | | | c | d | y |
+
+ And the ways
+ | nodes | highway |
+ | xa | unclassified |
+ | ab | trunk_link |
+ | bc | trunk_link |
+ | cd | trunk_link |
+ | ae | trunk |
+ | ef | trunk |
+ | fd | trunk |
+ | dy | unclassified |
+ When I route I should get
+ | from | to | route |
+ | x | y | xa,ae,ef,fd,dy |
+ | b | c | bc |
+
+ Scenario: Car - Use primary_link when reasonable
+ Given the node map
+ | | | e | | | | f | | |
+ | x | a | b | | | | c | d | y |
+
+ And the ways
+ | nodes | highway |
+ | xa | unclassified |
+ | ab | primary_link |
+ | bc | primary_link |
+ | cd | primary_link |
+ | ae | primary |
+ | ef | primary |
+ | fd | primary |
+ | dy | unclassified |
+ When I route I should get
+ | from | to | route |
+ | x | y | xa,ae,ef,fd,dy |
+ | b | c | bc |
+
+ Scenario: Car - Use secondary_link when reasonable
+ Given the node map
+ | | | e | | | | f | | |
+ | x | a | b | | | | c | d | y |
+
+ And the ways
+ | nodes | highway |
+ | xa | unclassified |
+ | ab | secondary_link |
+ | bc | secondary_link |
+ | cd | secondary_link |
+ | ae | secondary |
+ | ef | secondary |
+ | fd | secondary |
+ | dy | unclassified |
+
+ When I route I should get
+ | from | to | route |
+ | x | y | xa,ae,ef,fd,dy |
+ | b | c | bc |
+
+ Scenario: Car - Use tertiary_link when reasonable
+ Given the node map
+ | | | e | | | | f | | |
+ | x | a | b | | | | c | d | y |
+
+ And the ways
+ | nodes | highway |
+ | xa | unclassified |
+ | ab | tertiary_link |
+ | bc | tertiary_link |
+ | cd | tertiary_link |
+ | ae | tertiary |
+ | ef | tertiary |
+ | fd | tertiary |
+ | dy | unclassified |
+
+ When I route I should get
+ | from | to | route |
+ | x | y | xa,ae,ef,fd,dy |
+ | b | c | bc |
diff --git a/features/car/maxspeed.feature b/features/car/maxspeed.feature
index 9e77cde..8f85d3a 100644
--- a/features/car/maxspeed.feature
+++ b/features/car/maxspeed.feature
@@ -8,44 +8,54 @@ OSRM will use 4/5 of the projected free-flow speed.
Scenario: Car - Respect maxspeeds when lower that way type speed
Given the node map
- | a | b | c |
+ | a | b | c | d | e | f | g |
And the ways
- | nodes | highway | maxspeed |
- | ab | trunk | |
- | bc | trunk | 60 |
+ | nodes | highway | maxspeed |
+ | ab | trunk | |
+ | bc | trunk | 60 |
+ | cd | trunk | FR:urban |
+ | de | trunk | CH:rural |
+ | ef | trunk | CH:trunk |
+ | fg | trunk | CH:motorway |
When I route I should get
- | from | to | route | speed |
- | a | b | ab | 67 km/h |
- | b | c | bc | 48 km/h +- 1 |
+ | from | to | route | speed |
+ | a | b | ab | 78 km/h |
+ | b | c | bc | 59 km/h +- 1 |
+ | c | d | cd | 50 km/h |
+ | d | e | de | 75 km/h |
+ | e | f | ef | 90 km/h |
+ | f | g | fg | 105 km/h |
Scenario: Car - Do not ignore maxspeed when higher than way speed
Given the node map
- | a | b | c |
+ | a | b | c | d |
And the ways
- | nodes | highway | maxspeed |
- | ab | residential | |
- | bc | residential | 90 |
+ | nodes | highway | maxspeed |
+ | ab | residential | |
+ | bc | residential | 90 |
+ | cd | living_street | FR:urban |
When I route I should get
| from | to | route | speed |
- | a | b | ab | 20 km/h |
- | b | c | bc | 72 km/h +- 1 |
+ | a | b | ab | 31 km/h |
+ | b | c | bc | 83 km/h +- 1 |
+ | c | d | cd | 50 km/h |
Scenario: Car - Forward/backward maxspeed
Given a grid size of 100 meters
Then routability should be
- | highway | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw |
- | primary | | | | 51 km/h | 51 km/h |
- | primary | 60 | | | 48 km/h | 48 km/h |
- | primary | | 60 | | 48 km/h | 65 km/h |
- | primary | | | 60 | 51 km/h | 48 km/h |
- | primary | 15 | 60 | | 48 km/h | 15 km/h +- 1 |
- | primary | 15 | | 60 | 12 km/h +- 1| 48 km/h |
- | primary | 15 | 30 | 60 | 24 km/h | 48 km/h |
+ | highway | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw |
+ | primary | | | | 65 km/h | 65 km/h |
+ | primary | 60 | | | 60 km/h | 60 km/h |
+ | primary | | 60 | | 60 km/h | 65 km/h |
+ | primary | | | 60 | 65 km/h | 60 km/h |
+ | primary | 15 | 60 | | 60 km/h | 23 km/h |
+ | primary | 15 | | 60 | 23 km/h | 60 km/h |
+ | primary | 15 | 30 | 60 | 34 km/h | 60 km/h |
Scenario: Car - Maxspeed should not allow routing on unroutable ways
Then routability should be
diff --git a/features/car/restrictions.feature b/features/car/restrictions.feature
index b4ccdbe..f381f2f 100644
--- a/features/car/restrictions.feature
+++ b/features/car/restrictions.feature
@@ -312,3 +312,72 @@ Feature: Car - Turn restrictions
| e | f | ae,xa,bx,fb |
| c | f | dc,da,ae,ge,hg,hg,ge,ae,xa,bx,fb |
| d | f | da,ae,ge,hg,hg,ge,ae,xa,bx,fb |
+
+ @except
+ Scenario: Car - two only_ restrictions share same to-way
+ Given the node map
+ | | | e | | | | f | | |
+ | | | | | a | | | | |
+ | | | | | | | | | |
+ | | | c | | x | | d | | |
+ | | | | | y | | | | |
+ | | | | | | | | | |
+ | | | | | b | | | | |
+
+ And the ways
+ | nodes | oneway |
+ | ef | no |
+ | ce | no |
+ | fd | no |
+ | ca | no |
+ | ad | no |
+ | ax | no |
+ | xy | no |
+ | yb | no |
+ | cb | no |
+ | db | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | ax | xy | x | only_straight_on |
+ | restriction | by | xy | y | only_straight_on |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | ax,xy,yb |
+ | b | a | yb,xy,ax |
+
+ @except
+ Scenario: Car - two only_ restrictions share same from-way
+ Given the node map
+ | | | e | | | | f | | |
+ | | | | | a | | | | |
+ | | | | | | | | | |
+ | | | c | | x | | d | | |
+ | | | | | y | | | | |
+ | | | | | | | | | |
+ | | | | | b | | | | |
+
+ And the ways
+ | nodes | oneway |
+ | ef | no |
+ | ce | no |
+ | fd | no |
+ | ca | no |
+ | ad | no |
+ | ax | no |
+ | xy | no |
+ | yb | no |
+ | cb | no |
+ | db | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | xy | xa | x | only_straight_on |
+ | restriction | xy | yb | y | only_straight_on |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | ax,xy,yb |
+ | b | a | yb,xy,ax |
+
diff --git a/features/car/speed.feature b/features/car/speed.feature
index 4f54a33..a81baeb 100644
--- a/features/car/speed.feature
+++ b/features/car/speed.feature
@@ -8,17 +8,17 @@ Feature: Car - speeds
Scenario: Car - speed of various way types
Then routability should be
| highway | oneway | bothw |
- | motorway | no | 72 km/h |
- | motorway_link | no | 60 km/h |
- | trunk | no | 67 km/h +- 1 |
- | trunk_link | no | 55 km/h +- 1 |
- | primary | no | 52 km/h +- 1 |
- | primary_link | no | 48 km/h |
- | secondary | no | 43 km/h +- 1 |
- | secondary_link | no | 40 km/h |
- | tertiary | no | 32 km/h |
- | tertiary_link | no | 24 km/h |
- | unclassified | no | 20 km/h |
- | residential | no | 20 km/h |
- | living_street | no | 8 km/h |
- | service | no | 12 km/h |
+ | motorway | no | 82 km/h |
+ | motorway_link | no | 47 km/h |
+ | trunk | no | 79 km/h +- 1 |
+ | trunk_link | no | 43 km/h +- 1 |
+ | primary | no | 63 km/h +- 1 |
+ | primary_link | no | 34 km/h |
+ | secondary | no | 54 km/h +- 1 |
+ | secondary_link | no | 31 km/h |
+ | tertiary | no | 43 km/h |
+ | tertiary_link | no | 26 km/h |
+ | unclassified | no | 31 km/h |
+ | residential | no | 31 km/h |
+ | living_street | no | 18 km/h |
+ | service | no | 23 km/h |
diff --git a/features/car/surface.feature b/features/car/surface.feature
new file mode 100644
index 0000000..5dd4ed6
--- /dev/null
+++ b/features/car/surface.feature
@@ -0,0 +1,141 @@
+ at routing @car @surface
+Feature: Car - Surfaces
+
+ Background:
+ Given the profile "car"
+
+ Scenario: Car - Routeability of tracktype tags
+ Then routability should be
+ | highway | tracktype | bothw |
+ | trunk | grade1 | x |
+ | trunk | grade2 | x |
+ | trunk | grade3 | x |
+ | trunk | grade4 | x |
+ | trunk | grade5 | x |
+ | trunk | nonsense | x |
+
+ Scenario: Car - Routability of smoothness tags
+ Then routability should be
+ | highway | smoothness | bothw |
+ | trunk | excellent | x |
+ | trunk | good | x |
+ | trunk | intermediate | x |
+ | trunk | bad | x |
+ | trunk | very_bad | x |
+ | trunk | horrible | x |
+ | trunk | very_horrible | x |
+ | trunk | impassable | |
+ | trunk | nonsense | x |
+
+ Scenario: Car - Routabiliy of surface tags
+ Then routability should be
+ | highway | surface | bothw |
+ | trunk | asphalt | x |
+ | trunk | sett | x |
+ | trunk | gravel | x |
+ | trunk | nonsense | x |
+
+ Scenario: Car - Good surfaces should not grant access
+ Then routability should be
+ | highway | access | tracktype | smoothness | surface | forw | backw |
+ | motorway | | | | | x | |
+ | motorway | no | grade1 | excellent | asphalt | | |
+ | motorway | private | grade1 | excellent | asphalt | | |
+ | motorway | agricultural | grade1 | excellent | asphalt | | |
+ | motorway | forestry | grade1 | excellent | asphalt | | |
+ | motorway | emergency | grade1 | excellent | asphalt | | |
+ | primary | | | | | x | x |
+ | primary | no | grade1 | excellent | asphalt | | |
+ | primary | private | grade1 | excellent | asphalt | | |
+ | primary | agricultural | grade1 | excellent | asphalt | | |
+ | primary | forestry | grade1 | excellent | asphalt | | |
+ | primary | emergency | grade1 | excellent | asphalt | | |
+
+ Scenario: Car - Impassable surfaces should deny access
+ Then routability should be
+ | highway | access | smoothness | forw | backw |
+ | motorway | | impassable | | |
+ | motorway | yes | | x | |
+ | motorway | yes | impassable | | |
+ | primary | | impassable | | |
+ | primary | yes | | x | x |
+ | primary | yes | impassable | | |
+
+ Scenario: Car - Surface should reduce speed
+ Then routability should be
+ | highway | oneway | surface | forw | backw |
+ | motorway | no | | 80 km/h +-1 | 80 km/h +-1 |
+ | motorway | no | asphalt | 80 km/h +-1 | 80 km/h +-1 |
+ | motorway | no | concrete | 80 km/h +-1 | 80 km/h +-1 |
+ | motorway | no | concrete:plates | 80 km/h +-1 | 80 km/h +-1 |
+ | motorway | no | concrete:lanes | 80 km/h +-1 | 80 km/h +-1 |
+ | motorway | no | paved | 80 km/h +-1 | 80 km/h +-1 |
+ | motorway | no | cement | 72 km/h +-1 | 72 km/h +-1 |
+ | motorway | no | compacted | 72 km/h +-1 | 72 km/h +-1 |
+ | motorway | no | fine_gravel | 72 km/h +-1 | 72 km/h +-1 |
+ | motorway | no | paving_stones | 60 km/h +-1 | 60 km/h +-1 |
+ | motorway | no | metal | 60 km/h +-1 | 60 km/h +-1 |
+ | motorway | no | bricks | 60 km/h +-1 | 60 km/h +-1 |
+ | motorway | no | grass | 42 km/h +-1 | 42 km/h +-1 |
+ | motorway | no | wood | 42 km/h +-1 | 42 km/h +-1 |
+ | motorway | no | sett | 42 km/h +-1 | 42 km/h +-1 |
+ | motorway | no | grass_paver | 42 km/h +-1 | 42 km/h +-1 |
+ | motorway | no | gravel | 42 km/h +-1 | 42 km/h +-1 |
+ | motorway | no | unpaved | 42 km/h +-1 | 42 km/h +-1 |
+ | motorway | no | ground | 42 km/h +-1 | 42 km/h +-1 |
+ | motorway | no | dirt | 42 km/h +-1 | 42 km/h +-1 |
+ | motorway | no | pebblestone | 42 km/h +-1 | 42 km/h +-1 |
+ | motorway | no | tartan | 42 km/h +-1 | 42 km/h +-1 |
+ | motorway | no | cobblestone | 34 km/h +-1 | 34 km/h +-1 |
+ | motorway | no | clay | 34 km/h +-1 | 34 km/h +-1 |
+ | motorway | no | earth | 26 km/h +-1 | 26 km/h +-1 |
+ | motorway | no | stone | 26 km/h +-1 | 26 km/h +-1 |
+ | motorway | no | rocky | 26 km/h +-1 | 26 km/h +-1 |
+ | motorway | no | sand | 26 km/h +-1 | 26 km/h +-1 |
+
+ Scenario: Car - Tracktypes should reduce speed
+ Then routability should be
+ | highway | oneway | tracktype | forw | backw |
+ | motorway | no | | 80 km/h +-1 | 80 km/h +-1 |
+ | motorway | no | grade1 | 60 km/h +-1 | 60 km/h +-1 |
+ | motorway | no | grade2 | 42 km/h +-1 | 42 km/h +-1 |
+ | motorway | no | grade3 | 34 km/h +-1 | 34 km/h +-1 |
+ | motorway | no | grade4 | 31 km/h +-1 | 31 km/h +-1 |
+ | motorway | no | grade5 | 26 km/h +-1 | 26 km/h +-1 |
+
+ Scenario: Car - Smoothness should reduce speed
+ Then routability should be
+ | highway | oneway | smoothness | forw | backw |
+ | motorway | no | | 80 km/h +-1 | 80 km/h +-1 |
+ | motorway | no | intermediate | 72 km/h +-1 | 72 km/h +-1 |
+ | motorway | no | bad | 42 km/h +-1 | 42 km/h +-1 |
+ | motorway | no | very_bad | 26 km/h +-1 | 26 km/h +-1 |
+ | motorway | no | horrible | 18 km/h +-1 | 18 km/h +-1 |
+ | motorway | no | very_horrible | 15 km/h +-1 | 15 km/h +-1 |
+
+ Scenario: Car - Combination of surface tags should use lowest speed
+ Then routability should be
+ | highway | oneway | tracktype | surface | smoothness | backw | forw |
+ | motorway | no | | | | 80 km/h | 80 km/h |
+ | service | no | grade1 | asphalt | excellent | 23 km/h | 23 km/h |
+ | motorway | no | grade5 | asphalt | excellent | 26 km/h | 26 km/h |
+ | motorway | no | grade1 | mud | excellent | 18 km/h | 18 km/h |
+ | motorway | no | grade1 | asphalt | very_horrible | 15 km/h | 15 km/h |
+ | service | no | grade5 | mud | very_horrible | 15 km/h | 15 km/h |
+
+ Scenario: Car - Surfaces should not affect oneway direction
+ Then routability should be
+ | highway | oneway | tracktype | smoothness | surface | forw | backw |
+ | primary | | grade1 | excellent | asphalt | x | x |
+ | primary | | grade5 | very_bad | mud | x | x |
+ | primary | | nonsense | nonsense | nonsense | x | x |
+ | primary | no | grade1 | excellent | asphalt | x | x |
+ | primary | no | grade5 | very_bad | mud | x | x |
+ | primary | no | nonsense | nonsense | nonsense | x | x |
+ | primary | yes | grade1 | excellent | asphalt | x | |
+ | primary | yes | grade5 | very_bad | mud | x | |
+ | primary | yes | nonsense | nonsense | nonsense | x | |
+ | primary | -1 | grade1 | excellent | asphalt | | x |
+ | primary | -1 | grade5 | very_bad | mud | | x |
+ | primary | -1 | nonsense | nonsense | nonsense | | x |
+
diff --git a/features/foot/ferry.feature b/features/foot/ferry.feature
index 4308756..866644d 100644
--- a/features/foot/ferry.feature
+++ b/features/foot/ferry.feature
@@ -17,15 +17,15 @@ Feature: Foot - Handle ferry routes
| efg | primary | | |
When I route I should get
- | from | to | route |
- | a | g | abc,cde,efg |
- | b | f | abc,cde,efg |
- | e | c | cde |
- | e | b | cde,abc |
- | e | a | cde,abc |
- | c | e | cde |
- | c | f | cde,efg |
- | c | g | cde,efg |
+ | from | to | route | modes |
+ | a | g | abc,cde,efg | 1,2,1 |
+ | b | f | abc,cde,efg | 1,2,1 |
+ | e | c | cde | 2 |
+ | e | b | cde,abc | 2,1 |
+ | e | a | cde,abc | 2,1 |
+ | c | e | cde | 2 |
+ | c | f | cde,efg | 2,1 |
+ | c | g | cde,efg | 2,1 |
Scenario: Foot - Ferry duration, single node
Given the node map
diff --git a/features/options/extract/files.feature b/features/options/extract/files.feature
index 3061263..aceab19 100644
--- a/features/options/extract/files.feature
+++ b/features/options/extract/files.feature
@@ -1,7 +1,7 @@
@extract @options @files
Feature: osrm-extract command line options: files
# expansions:
-# {base} => path to current input file
+# {osm_base} => path to current input file
# {profile} => path to current profile script
Background:
@@ -14,12 +14,12 @@ Feature: osrm-extract command line options: files
And the data has been saved to disk
Scenario: osrm-extract - Passing base file
- When I run "osrm-extract {base}.osm --profile {profile}"
+ When I run "osrm-extract {osm_base}.osm --profile {profile}"
Then stderr should be empty
And it should exit with code 0
Scenario: osrm-extract - Order of options should not matter
- When I run "osrm-extract --profile {profile} {base}.osm"
+ When I run "osrm-extract --profile {profile} {osm_base}.osm"
Then stderr should be empty
And it should exit with code 0
diff --git a/features/options/prepare/files.feature b/features/options/prepare/files.feature
index de356a8..6e82a6b 100644
--- a/features/options/prepare/files.feature
+++ b/features/options/prepare/files.feature
@@ -1,7 +1,7 @@
@prepare @options @files
Feature: osrm-prepare command line options: files
# expansions:
-# {base} => path to current input file
+# {extracted_base} => path to current extracted input file
# {profile} => path to current profile script
Background:
@@ -14,12 +14,12 @@ Feature: osrm-prepare command line options: files
And the data has been extracted
Scenario: osrm-prepare - Passing base file
- When I run "osrm-prepare {base}.osrm --profile {profile}"
+ When I run "osrm-prepare {extracted_base}.osrm --profile {profile}"
Then stderr should be empty
And it should exit with code 0
Scenario: osrm-prepare - Order of options should not matter
- When I run "osrm-prepare --profile {profile} {base}.osrm"
+ When I run "osrm-prepare --profile {profile} {extracted_base}.osrm"
Then stderr should be empty
And it should exit with code 0
diff --git a/features/options/routed/files.feature b/features/options/routed/files.feature
index 716b2a4..15ce679 100644
--- a/features/options/routed/files.feature
+++ b/features/options/routed/files.feature
@@ -1,11 +1,16 @@
- at routed @options @files
+ at routed @options @files @todo
Feature: osrm-routed command line options: files
# Normally when launching osrm-routed, it will keep running as a server until it's shut down.
# For testing program options, the --trial option is used, which causes osrm-routed to quit
# immediately after initialization. This makes testing easier and faster.
#
-# The {base} part of the options to osrm-routed will be expanded to the actual base path of
-# the preprocessed file.
+# The {prepared_base} part of the options to osrm-routed will be expanded to the actual base path of
+# the prepared input file.
+
+# TODO
+# Since we're not using osmr-datastore for all testing, osrm-routed is kept running.
+# This means this test fails because osrm-routed is already running.
+# It probably needs to be rewritten to first quit osrm-routed.
Background:
Given the profile "testbot"
@@ -17,7 +22,7 @@ Feature: osrm-routed command line options: files
And the data has been prepared
Scenario: osrm-routed - Passing base file
- When I run "osrm-routed {base}.osrm --trial"
+ When I run "osrm-routed {prepared_base}.osrm --trial"
Then stdout should contain /^\[info\] starting up engines/
And stdout should contain /\d{1,2}\.\d{1,2}\.\d{1,2}/
And stdout should contain /compiled at/
diff --git a/features/step_definitions/data.rb b/features/step_definitions/data.rb
index e0985a4..f1e58ba 100644
--- a/features/step_definitions/data.rb
+++ b/features/step_definitions/data.rb
@@ -158,3 +158,19 @@ Given /^the data has been prepared$/ do
@process_error = e
end
end
+
+Given /^osrm\-routed is stopped$/ do
+ begin
+ OSRMLoader.shutdown
+ rescue OSRMError => e
+ @process_error = e
+ end
+end
+
+Given /^data is loaded directly/ do
+ @load_method = 'directly'
+end
+
+Given /^data is loaded with datastore$/ do
+ @load_method = 'datastore'
+end
diff --git a/features/step_definitions/distance_matrix.rb b/features/step_definitions/distance_matrix.rb
new file mode 100644
index 0000000..f85bdcc
--- /dev/null
+++ b/features/step_definitions/distance_matrix.rb
@@ -0,0 +1,56 @@
+When /^I request a travel time matrix I should get$/ do |table|
+
+ no_route = 2147483647 # MAX_INT
+
+ raise "*** Top-left cell of matrix table must be empty" unless table.headers[0]==""
+
+ nodes = []
+ column_headers = table.headers[1..-1]
+ row_headers = table.rows.map { |h| h.first }
+ unless column_headers==row_headers
+ raise "*** Column and row headers must match in matrix table, got #{column_headers.inspect} and #{row_headers.inspect}"
+ end
+ column_headers.each do |node_name|
+ node = find_node_by_name(node_name)
+ raise "*** unknown node '#{node_name}" unless node
+ nodes << node
+ end
+
+ reprocess
+ actual = []
+ actual << table.headers
+ OSRMLoader.load(self,"#{prepared_file}.osrm") do
+
+ # compute matrix
+ params = @query_params
+ response = request_table nodes, params
+ if response.body.empty? == false
+ json = JSON.parse response.body
+ result = json['distance_table']
+ end
+
+ # compare actual and expected result, one row at a time
+ table.rows.each_with_index do |row,ri|
+
+ # fuzzy match
+ ok = true
+ 0.upto(nodes.size-1) do |i|
+ if FuzzyMatch.match result[ri][i], row[i+1]
+ result[ri][i] = row[i+1]
+ elsif row[i+1]=="" and result[ri][i]==no_route
+ result[ri][i] = ""
+ else
+ result[ri][i] = result[ri][i].to_s
+ ok = false
+ end
+ end
+
+ # add row header
+ r = [row[0],result[ri]].flatten
+
+ # store row for comparison
+ actual << r
+ end
+ end
+ table.routing_diff! actual
+end
diff --git a/features/step_definitions/locate.rb b/features/step_definitions/locate.rb
index 9d3d74f..3e67be3 100644
--- a/features/step_definitions/locate.rb
+++ b/features/step_definitions/locate.rb
@@ -1,7 +1,7 @@
When /^I request locate I should get$/ do |table|
reprocess
actual = []
- OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
+ OSRMLoader.load(self,"#{prepared_file}.osrm") do
table.hashes.each_with_index do |row,ri|
in_node = find_node_by_name row['in']
raise "*** unknown in-node '#{row['in']}" unless in_node
diff --git a/features/step_definitions/nearest.rb b/features/step_definitions/nearest.rb
index ae5a79c..532c1f0 100644
--- a/features/step_definitions/nearest.rb
+++ b/features/step_definitions/nearest.rb
@@ -1,7 +1,7 @@
When /^I request nearest I should get$/ do |table|
reprocess
actual = []
- OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
+ OSRMLoader.load(self,"#{prepared_file}.osrm") do
table.hashes.each_with_index do |row,ri|
in_node = find_node_by_name row['in']
raise "*** unknown in-node '#{row['in']}" unless in_node
diff --git a/features/step_definitions/options.rb b/features/step_definitions/options.rb
index ac3bc99..e2e5066 100644
--- a/features/step_definitions/options.rb
+++ b/features/step_definitions/options.rb
@@ -1,6 +1,6 @@
When(/^I run "osrm\-routed\s?(.*?)"$/) do |options|
begin
- Timeout.timeout(1) { run_bin 'osrm-routed', options }
+ Timeout.timeout(SHUTDOWN_TIMEOUT) { run_bin 'osrm-routed', options }
rescue Timeout::Error
raise "*** osrm-routed didn't quit. Maybe the --trial option wasn't used?"
end
@@ -14,36 +14,44 @@ When(/^I run "osrm\-prepare\s?(.*?)"$/) do |options|
run_bin 'osrm-prepare', options
end
+When(/^I run "osrm\-datastore\s?(.*?)"$/) do |options|
+ run_bin 'osrm-datastore', options
+end
+
Then /^it should exit with code (\d+)$/ do |code|
- @exit_code.should == code.to_i
+ expect(@exit_code).to eq( code.to_i )
end
Then /^stdout should contain "(.*?)"$/ do |str|
- @stdout.should include(str)
+ expect(@stdout).to include(str)
end
Then /^stderr should contain "(.*?)"$/ do |str|
- @stderr.should include(str)
+ expect(@stderr).to include(str)
end
Then(/^stdout should contain \/(.*)\/$/) do |regex_str|
regex = Regexp.new regex_str
- @stdout.should =~ regex
+ expect(@stdout).to match( regex )
end
Then(/^stderr should contain \/(.*)\/$/) do |regex_str|
regex = Regexp.new regex_str
- @stderr.should =~ regex
+ expect(@stderr).to match( regex )
end
Then /^stdout should be empty$/ do
- @stdout.should == ""
+ expect(@stdout).to eq("")
end
Then /^stderr should be empty$/ do
- @stderr.should == ""
+ expect(@stderr).to eq("")
end
Then /^stdout should contain (\d+) lines?$/ do |lines|
- @stdout.lines.count.should == lines.to_i
+ expect(@stdout.lines.count).to eq( lines.to_i )
+end
+
+Given (/^the query options$/) do |table|
+ @query_params = table.rows_hash
end
diff --git a/features/step_definitions/requests.rb b/features/step_definitions/requests.rb
index 519a739..41257e5 100644
--- a/features/step_definitions/requests.rb
+++ b/features/step_definitions/requests.rb
@@ -1,14 +1,14 @@
When /^I request \/(.*)$/ do |path|
reprocess
- OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
+ OSRMLoader.load(self,"#{prepared_file}.osrm") do
@response = request_path path
end
end
Then /^I should get a response/ do
- @response.code.should == "200"
- @response.body.should_not == nil
- @response.body.should_not == ''
+ expect(@response.code).to eq("200")
+ expect(@response.body).not_to eq(nil)
+ expect(@response.body).not_to eq('')
end
Then /^response should be valid JSON$/ do
@@ -16,31 +16,31 @@ Then /^response should be valid JSON$/ do
end
Then /^response should be well-formed$/ do
- @json['status'].class.should == Fixnum
+ expect(@json['status'].class).to eq(Fixnum)
end
Then /^status code should be (\d+)$/ do |code|
@json = JSON.parse @response.body
- @json['status'].should == code.to_i
+ expect(@json['status']).to eq(code.to_i)
end
Then /^status message should be "(.*?)"$/ do |message|
@json = JSON.parse @response.body
- @json['status_message'].should == message
+ expect(@json['status_message']).to eq(message)
end
Then /^response should be a well-formed route$/ do
step "response should be well-formed"
- @json['status_message'].class.should == String
- @json['route_summary'].class.should == Hash
- @json['route_geometry'].class.should == String
- @json['route_instructions'].class.should == Array
- @json['via_points'].class.should == Array
- @json['via_indices'].class.should == Array
+ expect(@json['status_message'].class).to eq(String)
+ expect(@json['route_summary'].class).to eq(Hash)
+ expect(@json['route_geometry'].class).to eq(String)
+ expect(@json['route_instructions'].class).to eq(Array)
+ expect(@json['via_points'].class).to eq(Array)
+ expect(@json['via_indices'].class).to eq(Array)
end
Then /^"([^"]*)" should return code (\d+)$/ do |binary, code|
- @process_error.is_a?(OSRMError).should == true
- @process_error.process.should == binary
- @process_error.code.to_i.should == code.to_i
-end
\ No newline at end of file
+ expect(@process_error.is_a?(OSRMError)).to eq(true)
+ expect(@process_error.process).to eq(binary)
+ expect(@process_error.code.to_i).to eq(code.to_i)
+end
diff --git a/features/step_definitions/routability.rb b/features/step_definitions/routability.rb
index 161171f..dcbde5a 100644
--- a/features/step_definitions/routability.rb
+++ b/features/step_definitions/routability.rb
@@ -4,7 +4,7 @@ def test_routability_row i
a = Location.new @origin[0]+(1+WAY_SPACING*i)*@zoom, @origin[1]
b = Location.new @origin[0]+(3+WAY_SPACING*i)*@zoom, @origin[1]
r = {}
- r[:response] = request_route direction=='forw' ? [a,b] : [b,a]
+ r[:response] = request_route (direction=='forw' ? [a,b] : [b,a]), @query_params
r[:query] = @query
r[:json] = JSON.parse(r[:response].body)
@@ -44,7 +44,7 @@ Then /^routability should be$/ do |table|
if table.headers&["forw","backw","bothw"] == []
raise "*** routability tabel must contain either 'forw', 'backw' or 'bothw' column"
end
- OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
+ OSRMLoader.load(self,"#{prepared_file}.osrm") do
table.hashes.each_with_index do |row,i|
output_row = row.dup
attempts = []
@@ -54,11 +54,11 @@ Then /^routability should be$/ do |table|
want = shortcuts_hash[row[direction]] || row[direction] #expand shortcuts
case want
when '', 'x'
- output_row[direction] = result[direction][:status].to_s
+ output_row[direction] = result[direction][:status] ? result[direction][:status].to_s : ''
when /^\d+s/
- output_row[direction] = "#{result[direction][:time]}s"
+ output_row[direction] = result[direction][:time] ? "#{result[direction][:time]}s" : ''
when /^\d+ km\/h/
- output_row[direction] = "#{result[direction][:speed]} km/h"
+ output_row[direction] = result[direction][:speed] ? "#{result[direction][:speed]} km/h" : ''
else
raise "*** Unknown expectation format: #{want}"
end
diff --git a/features/step_definitions/routing.rb b/features/step_definitions/routing.rb
index 92b69ea..c25f5b7 100644
--- a/features/step_definitions/routing.rb
+++ b/features/step_definitions/routing.rb
@@ -1,13 +1,13 @@
When /^I route I should get$/ do |table|
reprocess
actual = []
- OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
+ 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 = {}
+ params = @query_params
waypoints = []
if row['from'] and row['to']
node = find_node_by_name(row['from'])
@@ -104,22 +104,22 @@ When /^I route I should get$/ do |table|
end
end
if table.headers.include? 'bearing'
- got['bearing'] = bearings
+ got['bearing'] = instructions ? bearings : ''
end
if table.headers.include? 'compass'
- got['compass'] = compasses
+ got['compass'] = instructions ? compasses : ''
end
if table.headers.include? 'turns'
- got['turns'] = turns
+ got['turns'] = instructions ? turns : ''
end
if table.headers.include? 'modes'
- got['modes'] = modes
+ got['modes'] = instructions ? modes : ''
end
if table.headers.include? 'times'
- got['times'] = times
+ got['times'] = instructions ? times : ''
end
if table.headers.include? 'distances'
- got['distances'] = distances
+ got['distances'] = instructions ? distances : ''
end
end
end
diff --git a/features/step_definitions/timestamp.rb b/features/step_definitions/timestamp.rb
index 53d4083..df45615 100644
--- a/features/step_definitions/timestamp.rb
+++ b/features/step_definitions/timestamp.rb
@@ -2,6 +2,6 @@ Then /^I should get a valid timestamp/ do
step "I should get a response"
step "response should be valid JSON"
step "response should be well-formed"
- @json['timestamp'].class.should == String
- @json['timestamp'].should == OSM_TIMESTAMP
+ expect(@json['timestamp'].class).to eq(String)
+ expect(@json['timestamp']).to eq("2000-01-01T00:00:00Z")
end
diff --git a/features/support/data.rb b/features/support/data.rb
index 7c1ba88..1ff1861 100644
--- a/features/support/data.rb
+++ b/features/support/data.rb
@@ -1,6 +1,7 @@
require 'OSM/objects' #osmlib gem
require 'OSM/Database'
require 'builder'
+require 'fileutils'
class Location
attr_accessor :lon,:lat
@@ -11,6 +12,7 @@ class Location
end
end
+
def set_input_format format
raise '*** Input format must be eiter "osm" or "pbf"' unless ['pbf','osm'].include? format.to_s
@input_format = format.to_s
@@ -21,7 +23,7 @@ def input_format
end
def sanitized_scenario_title
- @sanitized_scenario_title ||= @scenario_title.gsub /[^0-9A-Za-z.\-]/, '_'
+ @sanitized_scenario_title ||= @scenario_title.to_s.gsub /[^0-9A-Za-z.\-]/, '_'
end
def set_grid_size meters
@@ -154,7 +156,10 @@ def reset_data
end
reset_profile
reset_osm
- @fingerprint = nil
+ @fingerprint_osm = nil
+ @fingerprint_extract = nil
+ @fingerprint_prepare = nil
+ @fingerprint_route = nil
end
def make_osm_id
@@ -204,20 +209,30 @@ def osm_str
@osm_str
end
+def osm_file
+ @osm_file ||= "#{DATA_FOLDER}/#{fingerprint_osm}"
+end
+
+def extracted_file
+ @extracted_file ||= "#{osm_file}_#{fingerprint_extract}"
+end
+
+def prepared_file
+ @prepared_file ||= "#{osm_file}_#{fingerprint_extract}_#{fingerprint_prepare}"
+end
+
def write_osm
- #write .oms file if needed
Dir.mkdir DATA_FOLDER unless File.exist? DATA_FOLDER
- @osm_file = "#{DATA_FOLDER}/#{sanitized_scenario_title}_#{fingerprint}"
- unless File.exist?("#{@osm_file}.osm")
- File.open( "#{@osm_file}.osm", 'w') {|f| f.write(osm_str) }
+ unless File.exist?("#{osm_file}.osm")
+ File.open( "#{osm_file}.osm", 'w') {|f| f.write(osm_str) }
end
end
def convert_osm_to_pbf
- unless File.exist?("#{@osm_file}.osm.pbf")
+ unless File.exist?("#{osm_file}.osm.pbf")
log_preprocess_info
- log "== Converting #{@osm_file}.osm to protobuffer format...", :preprocess
- unless system "osmosis --read-xml #{@osm_file}.osm --write-pbf #{@osm_file}.osm.pbf omitmetadata=true >>#{PREPROCESS_LOG_FILE} 2>&1"
+ log "== Converting #{osm_file}.osm to protobuffer format...", :preprocess
+ unless system "osmosis --read-xml #{osm_file}.osm --write-pbf #{osm_file}.osm.pbf omitmetadata=true >>#{PREPROCESS_LOG_FILE} 2>&1"
raise OsmosisError.new $?, "osmosis exited with code #{$?.exitstatus}"
end
log '', :preprocess
@@ -225,22 +240,27 @@ def convert_osm_to_pbf
end
def extracted?
- File.exist?("#{@osm_file}.osrm") &&
- File.exist?("#{@osm_file}.osrm.names") &&
- File.exist?("#{@osm_file}.osrm.restrictions")
+ Dir.chdir TEST_FOLDER do
+ File.exist?("#{extracted_file}.osrm") &&
+ File.exist?("#{extracted_file}.osrm.names") &&
+ File.exist?("#{extracted_file}.osrm.restrictions")
+ end
end
def prepared?
- File.exist?("#{@osm_file}.osrm.hsgr")
+ Dir.chdir TEST_FOLDER do
+ File.exist?("#{prepared_file}.osrm.hsgr")
+ end
end
def write_timestamp
- File.open( "#{@osm_file}.osrm.timestamp", 'w') {|f| f.write(OSM_TIMESTAMP) }
+ File.open( "#{prepared_file}.osrm.timestamp", 'w') {|f| f.write(OSM_TIMESTAMP) }
end
def pbf?
input_format=='pbf'
end
+
def write_input_data
Dir.chdir TEST_FOLDER do
write_osm
@@ -252,23 +272,43 @@ end
def extract_data
Dir.chdir TEST_FOLDER do
log_preprocess_info
- log "== Extracting #{@osm_file}.osm...", :preprocess
- unless system "#{BIN_PATH}/osrm-extract #{@osm_file}.osm#{'.pbf' if pbf?} --profile #{PROFILES_PATH}/#{@profile}.lua >>#{PREPROCESS_LOG_FILE} 2>&1"
+ log "== Extracting #{osm_file}.osm...", :preprocess
+ unless system "#{BIN_PATH}/osrm-extract #{osm_file}.osm#{'.pbf' if pbf?} --profile #{PROFILES_PATH}/#{@profile}.lua >>#{PREPROCESS_LOG_FILE} 2>&1"
log "*** Exited with code #{$?.exitstatus}.", :preprocess
raise ExtractError.new $?.exitstatus, "osrm-extract exited with code #{$?.exitstatus}."
end
- log '', :preprocess
+ begin
+ ["osrm","osrm.names","osrm.restrictions"].each do |file|
+ File.rename "#{osm_file}.#{file}", "#{extracted_file}.#{file}"
+ end
+ rescue Exception => e
+ raise FileError.new nil, "failed to rename data file after extracting."
+ end
end
end
def prepare_data
Dir.chdir TEST_FOLDER do
log_preprocess_info
- log "== Preparing #{@osm_file}.osm...", :preprocess
- unless system "#{BIN_PATH}/osrm-prepare #{@osm_file}.osrm --profile #{PROFILES_PATH}/#{@profile}.lua >>#{PREPROCESS_LOG_FILE} 2>&1"
+ log "== Preparing #{extracted_file}.osm...", :preprocess
+ unless system "#{BIN_PATH}/osrm-prepare #{extracted_file}.osrm --profile #{PROFILES_PATH}/#{@profile}.lua >>#{PREPROCESS_LOG_FILE} 2>&1"
log "*** Exited with code #{$?.exitstatus}.", :preprocess
raise PrepareError.new $?.exitstatus, "osrm-prepare exited with code #{$?.exitstatus}."
end
+ begin
+ ["osrm.hsgr","osrm.fileIndex","osrm.geometry","osrm.nodes","osrm.ramIndex"].each do |file|
+ File.rename "#{extracted_file}.#{file}", "#{prepared_file}.#{file}"
+ end
+ rescue Exception => e
+ raise FileError.new nil, "failed to rename data file after preparing."
+ end
+ begin
+ ["osrm.names","osrm.edges","osrm.restrictions"].each do |file|
+ FileUtils.cp "#{extracted_file}.#{file}", "#{prepared_file}.#{file}"
+ end
+ rescue Exception => e
+ raise FileError.new nil, "failed to copy data file after preparing."
+ end
log '', :preprocess
end
end
diff --git a/features/support/env.rb b/features/support/env.rb
index a6a9ca0..a01341d 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -1,15 +1,15 @@
require 'rspec/expectations'
+
DEFAULT_PORT = 5000
DEFAULT_TIMEOUT = 2
-
ROOT_FOLDER = Dir.pwd
OSM_USER = 'osrm'
OSM_GENERATOR = 'osrm-test'
OSM_UID = 1
TEST_FOLDER = File.join ROOT_FOLDER, 'test'
DATA_FOLDER = 'cache'
-OSM_TIMESTAMP = '2000-00-00T00:00:00Z'
+OSM_TIMESTAMP = '2000-01-01T00:00:00Z'
DEFAULT_SPEEDPROFILE = 'bicycle'
WAY_SPACING = 100
DEFAULT_GRID_SIZE = 100 #meters
@@ -17,6 +17,26 @@ PROFILES_PATH = File.join ROOT_FOLDER, 'profiles'
BIN_PATH = File.join ROOT_FOLDER, 'build'
DEFAULT_INPUT_FORMAT = 'osm'
DEFAULT_ORIGIN = [1,1]
+LAUNCH_TIMEOUT = 1
+SHUTDOWN_TIMEOUT = 10
+DEFAULT_LOAD_METHOD = 'datastore'
+OSRM_ROUTED_LOG_FILE = 'osrm-routed.log'
+
+if ENV['OS']==/Windows.*/ then
+ TERMSIGNAL='TERM'
+else
+ TERMSIGNAL=9
+end
+
+
+def log_time_and_run cmd
+ log_time cmd
+ `#{cmd}`
+end
+
+def log_time cmd
+ puts "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S:%L')}] #{cmd}"
+end
puts "Ruby version #{RUBY_VERSION}"
@@ -44,6 +64,7 @@ unless File.exists? TEST_FOLDER
raise "*** Test folder #{TEST_FOLDER} doesn't exist."
end
+
if ENV['OS']=~/Windows.*/ then
EXE='.exe'
QQ='"'
@@ -53,5 +74,12 @@ else
end
AfterConfiguration do |config|
+ if OSRMLoader::OSRMBaseLoader.new.osrm_up?
+ raise "*** osrm-routed is already running."
+ end
clear_log_files
-end
\ No newline at end of file
+end
+
+at_exit do
+ OSRMLoader::OSRMBaseLoader.new.shutdown
+end
diff --git a/features/support/exceptions.rb b/features/support/exceptions.rb
index 2901bfe..02f59d3 100644
--- a/features/support/exceptions.rb
+++ b/features/support/exceptions.rb
@@ -31,6 +31,12 @@ class OSRMError < StandardError
end
end
+class FileError < OSRMError
+ def initialize code, msg
+ super 'fileutil', code, msg, PREPROCESS_LOG_FILE, 5
+ end
+end
+
class OsmosisError < OSRMError
def initialize code, msg
super 'osmosis', code, msg, PREPROCESS_LOG_FILE, 40
diff --git a/features/support/hash.rb b/features/support/hash.rb
index 197cd42..6980b66 100644
--- a/features/support/hash.rb
+++ b/features/support/hash.rb
@@ -32,18 +32,32 @@ def lua_lib_hash
end
def bin_extract_hash
- bin_extract_hash ||= hash_of_files "#{BIN_PATH}/osrm-extract#{EXE}"
+ @bin_extract_hash ||= hash_of_files "#{BIN_PATH}/osrm-extract#{EXE}"
+ @bin_extract_hash
end
def bin_prepare_hash
- bin_prepare_hash ||= hash_of_files "#{BIN_PATH}/osrm-prepare#{EXE}"
+ @bin_prepare_hash ||= hash_of_files "#{BIN_PATH}/osrm-prepare#{EXE}"
end
def bin_routed_hash
- bin_routed_hash ||= hash_of_files "#{BIN_PATH}/osrm-routed#{EXE}"
+ @bin_routed_hash ||= hash_of_files "#{BIN_PATH}/osrm-routed#{EXE}"
end
-#combine state of data, profile and binaries into a hash that identifies the exact test scenario
-def fingerprint
- @fingerprint ||= Digest::SHA1.hexdigest "#{bin_extract_hash}-#{bin_prepare_hash}-#{bin_routed_hash}-#{profile_hash}-#{lua_lib_hash}-#{osm_hash}"
+# combine state of data, profile and binaries into a hashes that identifies
+# the exact test situation at different stages, so we can later skip steps when possible.
+def fingerprint_osm
+ @fingerprint_osm ||= Digest::SHA1.hexdigest "#{osm_hash}"
end
+
+def fingerprint_extract
+ @fingerprint_extract ||= Digest::SHA1.hexdigest "#{profile_hash}-#{lua_lib_hash}-#{bin_extract_hash}"
+end
+
+def fingerprint_prepare
+ @fingerprint_prepare ||= Digest::SHA1.hexdigest "#{bin_prepare_hash}"
+end
+
+def fingerprint_route
+ @fingerprint_route ||= Digest::SHA1.hexdigest "#{bin_routed_hash}"
+end
\ No newline at end of file
diff --git a/features/support/hooks.rb b/features/support/hooks.rb
index 4c58a17..3370142 100644
--- a/features/support/hooks.rb
+++ b/features/support/hooks.rb
@@ -1,7 +1,9 @@
STRESS_TIMEOUT = 300
+
Before do |scenario|
+
# feature name
case scenario
when Cucumber::Ast::Scenario
@@ -18,13 +20,15 @@ Before do |scenario|
@scenario_title = scenario.scenario_outline.name
end
-
+ @load_method = DEFAULT_LOAD_METHOD
+ @query_params = {}
@scenario_time = Time.now.strftime("%Y-%m-%dT%H:%m:%SZ")
reset_data
@has_logged_preprocess_info = false
@has_logged_scenario_info = false
set_grid_size DEFAULT_GRID_SIZE
set_origin DEFAULT_ORIGIN
+
end
Around('@stress') do |scenario, block|
diff --git a/features/support/launch.rb b/features/support/launch.rb
index e55867a..0f983c1 100644
--- a/features/support/launch.rb
+++ b/features/support/launch.rb
@@ -1,95 +1,137 @@
require 'socket'
require 'open3'
+require 'json'
-if ENV['OS']==/Windows.*/ then
- TERMSIGNAL='TERM'
-else
- TERMSIGNAL=9
-end
+# Only one isntance of osrm-routed is ever launched, to avoid collisions.
+# The default is to keep osrm-routed running and load data with datastore.
+# however, osrm-routed it shut down and relaunched for each scenario thats
+# loads data directly.
+class OSRMLoader
-OSRM_ROUTED_LOG_FILE = 'osrm-routed.log'
+ class OSRMBaseLoader
+ @@pid = nil
-class OSRMBackgroundLauncher
- def initialize input_file, &block
- @input_file = input_file
- Dir.chdir TEST_FOLDER do
- begin
- launch
- yield
- ensure
- shutdown
+ def launch
+ Timeout.timeout(LAUNCH_TIMEOUT) do
+ osrm_up
+ wait_for_connection
end
+ rescue Timeout::Error
+ raise RoutedError.new "Launching osrm-routed timed out."
end
- end
- private
+ def shutdown
+ Timeout.timeout(SHUTDOWN_TIMEOUT) do
+ osrm_down
+ end
+ rescue Timeout::Error
+ kill
+ raise RoutedError.new "Shutting down osrm-routed timed out."
+ end
- def launch
- Timeout.timeout(OSRM_TIMEOUT) do
- osrm_up
- wait_for_connection
+ def osrm_up?
+ if @@pid
+ begin
+ if Process.waitpid(@@pid, Process::WNOHANG) then
+ false
+ else
+ true
+ end
+ rescue Errno::ESRCH, Errno::ECHILD
+ false
+ end
+ end
end
- rescue Timeout::Error
- raise RoutedError.new "Launching osrm-routed timed out."
- end
- def shutdown
- Timeout.timeout(OSRM_TIMEOUT) do
- osrm_down
+ def osrm_down
+ if @@pid
+ Process.kill TERMSIGNAL, @@pid
+ wait_for_shutdown
+ @@pid = nil
+ end
end
- rescue Timeout::Error
- kill
- raise RoutedError.new "Shutting down osrm-routed timed out."
- end
+ def kill
+ if @@pid
+ Process.kill 'KILL', @@pid
+ end
+ end
- def osrm_up?
- if @pid
- begin
- if Process.waitpid(@pid, Process::WNOHANG) then
- false
- else
- true
+ def wait_for_connection
+ while true
+ begin
+ socket = TCPSocket.new('127.0.0.1', OSRM_PORT)
+ return
+ rescue Errno::ECONNREFUSED
+ sleep 0.1
end
- rescue Errno::ESRCH, Errno::ECHILD
- false
end
end
- end
- def osrm_up
- return if osrm_up?
- @pid = Process.spawn("#{BIN_PATH}/osrm-routed #{@input_file} --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
- Process.detach(@pid) # avoid zombie processes
+ def wait_for_shutdown
+ while osrm_up?
+ sleep 0.01
+ end
+ end
end
- def osrm_down
- if @pid
- Process.kill TERMSIGNAL, @pid
- wait_for_shutdown
+ # looading data directly when lauching osrm-routed:
+ # under this scheme, osmr-routed is launched and shutdown for each scenario,
+ # and osrm-datastore is not used
+ class OSRMDirectLoader < OSRMBaseLoader
+ def load world, input_file, &block
+ @world = world
+ @input_file = input_file
+ Dir.chdir TEST_FOLDER do
+ shutdown
+ launch
+ yield
+ shutdown
+ end
end
- end
- def kill
- if @pid
- Process.kill 'KILL', @pid
+ def osrm_up
+ return if @@pid
+ @@pid = Process.spawn("#{BIN_PATH}/osrm-routed #{@input_file} --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
+ Process.detach(@@pid) # avoid zombie processes
end
+
end
- def wait_for_connection
- while true
- begin
- socket = TCPSocket.new('127.0.0.1', OSRM_PORT)
- return
- rescue Errno::ECONNREFUSED
- sleep 0.1
+ # looading data with osrm-datastore:
+ # under this scheme, osmr-routed is launched once and kept running for all scenarios,
+ # and osrm-datastore is used to load data for each scenario
+ class OSRMDatastoreLoader < OSRMBaseLoader
+ def load world, input_file, &block
+ @world = world
+ @input_file = input_file
+ Dir.chdir TEST_FOLDER do
+ load_data
+ launch unless @@pid
+ yield
end
end
+
+ def load_data
+ run_bin "osrm-datastore", @input_file
+ end
+
+ def osrm_up
+ return if osrm_up?
+ @@pid = Process.spawn("#{BIN_PATH}/osrm-routed --sharedmemory=1 --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
+ Process.detach(@@pid) # avoid zombie processes
+ end
end
- def wait_for_shutdown
- while osrm_up?
- sleep 0.1
+ def self.load world, input_file, &block
+ method = world.instance_variable_get "@load_method"
+ if method == 'datastore'
+ OSRMDatastoreLoader.new.load world, input_file, &block
+ elsif method == 'directly'
+ OSRMDirectLoader.new.load world, input_file, &block
+ else
+ raise "*** Unknown load method '#{method}'"
end
end
+
end
diff --git a/features/support/log.rb b/features/support/log.rb
index e5d34cc..8e6f9c1 100644
--- a/features/support/log.rb
+++ b/features/support/log.rb
@@ -29,7 +29,10 @@ def log_scenario_fail_info
log "========================================="
log "Failed scenario: #{@scenario_title}"
log "Time: #{@scenario_time}"
- log "Fingerprint: #{@fingerprint}"
+ log "Fingerprint osm stage: #{@fingerprint_osm}"
+ log "Fingerprint extract stage: #{@fingerprint_extract}"
+ log "Fingerprint prepare stage: #{@fingerprint_prepare}"
+ log "Fingerprint route stage: #{@fingerprint_route}"
log "Profile: #{@profile}"
log
log '```xml' #so output can be posted directly to github comment fields
@@ -41,6 +44,7 @@ def log_scenario_fail_info
end
def log_fail expected,got,attempts
+ return
log_scenario_fail_info
log "== "
log "Expected: #{expected}"
diff --git a/features/support/route.rb b/features/support/route.rb
index 745edc0..a8c7822 100644
--- a/features/support/route.rb
+++ b/features/support/route.rb
@@ -43,6 +43,11 @@ def request_route waypoints, params={}
request_path "viaroute", waypoints, defaults.merge(params)
end
+def request_table waypoints, params={}
+ defaults = { 'output' => 'json' }
+ request_path "table", waypoints, defaults.merge(params)
+end
+
def got_route? response
if response.code == "200" && !response.body.empty?
json = JSON.parse response.body
diff --git a/features/support/run.rb b/features/support/run.rb
index 794050a..42dc597 100644
--- a/features/support/run.rb
+++ b/features/support/run.rb
@@ -1,17 +1,27 @@
def run_bin bin, options
Dir.chdir TEST_FOLDER do
opt = options.dup
-
- if opt.include? '{base}'
- raise "*** {base} is missing" unless @osm_file
- opt.gsub! "{base}", "#{@osm_file}"
+
+ if opt.include? '{osm_base}'
+ raise "*** {osm_base} is missing" unless osm_file
+ opt.gsub! "{osm_base}", "#{osm_file}"
+ end
+
+ if opt.include? '{extracted_base}'
+ raise "*** {extracted_base} is missing" unless extracted_file
+ opt.gsub! "{extracted_base}", "#{extracted_file}"
end
+ if opt.include? '{prepared_base}'
+ raise "*** {prepared_base} is missing" unless prepared_file
+ opt.gsub! "{prepared_base}", "#{prepared_file}"
+ end
if opt.include? '{profile}'
opt.gsub! "{profile}", "#{PROFILES_PATH}/#{@profile}.lua"
end
- @stdout = `#{QQ}#{BIN_PATH}/#{bin}#{EXE}#{QQ} #{opt} 2>error.log`
+ cmd = "#{QQ}#{BIN_PATH}/#{bin}#{EXE}#{QQ} #{opt} 2>error.log"
+ @stdout = `#{cmd}`
@stderr = File.read 'error.log'
@exit_code = $?.exitstatus
end
diff --git a/features/testbot/bad.feature b/features/testbot/bad.feature
index f0f3cfa..d7e3c95 100644
--- a/features/testbot/bad.feature
+++ b/features/testbot/bad.feature
@@ -1,4 +1,4 @@
- at routing @bad
+ at routing @bad @testbot
Feature: Handle bad data in a graceful manner
Background:
diff --git a/features/testbot/basic.feature b/features/testbot/basic.feature
index 4164319..599b062 100644
--- a/features/testbot/basic.feature
+++ b/features/testbot/basic.feature
@@ -1,4 +1,4 @@
- at routing @basic
+ at routing @basic @testbot
Feature: Basic Routing
Background:
diff --git a/features/testbot/bearing.feature b/features/testbot/bearing.feature
index c306af9..9b3dc4e 100644
--- a/features/testbot/bearing.feature
+++ b/features/testbot/bearing.feature
@@ -1,4 +1,4 @@
- at routing @bearing
+ at routing @bearing @testbot
Feature: Compass bearing
Background:
diff --git a/features/testbot/bearing_param.feature b/features/testbot/bearing_param.feature
index e9db873..810f690 100644
--- a/features/testbot/bearing_param.feature
+++ b/features/testbot/bearing_param.feature
@@ -1,4 +1,4 @@
- at routing @bearing_param @todo
+ at routing @bearing_param @todo @testbot
Feature: Bearing parameter
Background:
diff --git a/features/testbot/compression.feature b/features/testbot/compression.feature
new file mode 100644
index 0000000..146ad63
--- /dev/null
+++ b/features/testbot/compression.feature
@@ -0,0 +1,22 @@
+ at routing @graph @testbot
+Feature: Geometry Compression
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Compressed segments have correct order
+ Given the node map
+ | a | | d | | | | h |
+ | b | | | | e | | f |
+ | | c | | | | | g |
+
+ And the ways
+ | nodes |
+ | abcdef |
+ | fh |
+ | fg |
+
+ When I route I should get
+ | from | to | route | distance | speed |
+ | b | e | abcdef | 589m | 35 km/h |
+ | e | b | abcdef | 589m | 35 km/h |
diff --git a/features/testbot/datastore.feature b/features/testbot/datastore.feature
new file mode 100644
index 0000000..568ae7a
--- /dev/null
+++ b/features/testbot/datastore.feature
@@ -0,0 +1,31 @@
+ at routing @datastore @testbot
+Feature: Temporary tests related to osrm-datastore
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Scenario ab
+ Given the node map
+ | a | b |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | b | a | ab |
+
+ Scenario: Scenaria xy
+ Given the node map
+ | x | y |
+
+ And the ways
+ | nodes |
+ | xy |
+
+ When I route I should get
+ | from | to | route |
+ | x | y | xy |
+ | y | x | xy |
diff --git a/features/testbot/distance.feature b/features/testbot/distance.feature
index f9f166b..55b5f64 100644
--- a/features/testbot/distance.feature
+++ b/features/testbot/distance.feature
@@ -1,4 +1,4 @@
- at routing @distance
+ at routing @distance @testbot
Feature: Distance calculation
Background:
@@ -145,7 +145,7 @@ Feature: Distance calculation
| a | h | abcdefgh | 70m +-14 |
Scenario: Geometric distances
- Given a grid size of 1000 meters
+ Given a grid size of 100 meters
Given the node map
| v | w | y | a | b | c | d |
| u | | | | | | e |
@@ -184,30 +184,30 @@ Feature: Distance calculation
When I route I should get
| from | to | route | distance |
- | x | a | xa | 3000m +-2 |
- | x | b | xb | 3162m +-2 |
- | x | c | xc | 3606m +-2 |
- | x | d | xd | 4243m +-2 |
- | x | e | xe | 3606m +-2 |
- | x | f | xf | 3162m +-2 |
- | x | g | xg | 3000m +-2 |
- | x | h | xh | 3162m +-2 |
- | x | i | xi | 3606m +-2 |
- | x | j | xj | 4243m +-2 |
- | x | k | xk | 3606m +-2 |
- | x | l | xl | 3162m +-2 |
- | x | m | xm | 3000m +-2 |
- | x | n | xn | 3162m +-2 |
- | x | o | xo | 3606m +-2 |
- | x | p | xp | 4243m +-2 |
- | x | q | xq | 3606m +-2 |
- | x | r | xr | 3162m +-2 |
- | x | s | xs | 3000m +-2 |
- | x | t | xt | 3162m +-2 |
- | x | u | xu | 3606m +-2 |
- | x | v | xv | 4243m +-2 |
- | x | w | xw | 3606m +-2 |
- | x | y | xy | 3162m +-2 |
+ | x | a | xa | 300m +-2 |
+ | x | b | xb | 316m +-2 |
+ | x | c | xc | 360m +-2 |
+ | x | d | xd | 424m +-2 |
+ | x | e | xe | 360m +-2 |
+ | x | f | xf | 316m +-2 |
+ | x | g | xg | 300m +-2 |
+ | x | h | xh | 316m +-2 |
+ | x | i | xi | 360m +-2 |
+ | x | j | xj | 424m +-2 |
+ | x | k | xk | 360m +-2 |
+ | x | l | xl | 316m +-2 |
+ | x | m | xm | 300m +-2 |
+ | x | n | xn | 316m +-2 |
+ | x | o | xo | 360m +-2 |
+ | x | p | xp | 424m +-2 |
+ | x | q | xq | 360m +-2 |
+ | x | r | xr | 316m +-2 |
+ | x | s | xs | 300m +-2 |
+ | x | t | xt | 316m +-2 |
+ | x | u | xu | 360m +-2 |
+ | x | v | xv | 424m +-2 |
+ | x | w | xw | 360m +-2 |
+ | x | y | xy | 316m +-2 |
@maze
Scenario: Distance of a maze of short segments
diff --git a/features/testbot/distance_matrix.feature b/features/testbot/distance_matrix.feature
new file mode 100644
index 0000000..390ae98
--- /dev/null
+++ b/features/testbot/distance_matrix.feature
@@ -0,0 +1,102 @@
+ at matrix @testbot
+Feature: Basic Distance Matrix
+# note that results are travel time, specified in 1/10th of seconds
+# since testbot uses a default speed of 100m/10s, the result matches
+# the number of meters as long as the way type is the default 'primary'
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Testbot - Travel time matrix of minimal network
+ Given the node map
+ | a | b |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I request a travel time matrix I should get
+ | | a | b |
+ | a | 0 | 100 |
+ | b | 100 | 0 |
+
+ Scenario: Testbot - Travel time matrix with different way speeds
+ Given the node map
+ | a | b | c | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | bc | secondary |
+ | cd | tertiary |
+
+ When I request a travel time matrix I should get
+ | | a | b | c | d |
+ | a | 0 | 100 | 300 | 600 |
+ | b | 100 | 0 | 200 | 500 |
+ | c | 300 | 200 | 0 | 300 |
+ | d | 600 | 500 | 300 | 0 |
+
+ Scenario: Testbot - Travel time matrix with fuzzy match
+ Given the node map
+ | a | b |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I request a travel time matrix I should get
+ | | a | b |
+ | a | 0 | 95 +- 10 |
+ | b | 95 ~10% | 0 |
+
+ Scenario: Testbot - Travel time matrix of small grid
+ Given the node map
+ | a | b | c |
+ | d | e | f |
+
+ And the ways
+ | nodes |
+ | abc |
+ | def |
+ | ad |
+ | be |
+ | cf |
+
+ When I request a travel time matrix I should get
+ | | a | b | e | f |
+ | a | 0 | 100 | 200 | 300 |
+ | b | 100 | 0 | 100 | 200 |
+ | e | 200 | 100 | 0 | 100 |
+ | f | 300 | 200 | 100 | 0 |
+
+ Scenario: Testbot - Travel time matrix of network with unroutable parts
+ Given the node map
+ | a | b |
+
+ And the ways
+ | nodes | oneway |
+ | ab | yes |
+
+ When I request a travel time matrix I should get
+ | | a | b |
+ | a | 0 | 100 |
+ | b | | 0 |
+
+ Scenario: Testbot - Travel time matrix of network with oneways
+ Given the node map
+ | x | a | b | y |
+ | | d | e | |
+
+ And the ways
+ | nodes | oneway |
+ | abeda | yes |
+ | xa | |
+ | by | |
+
+ When I request a travel time matrix I should get
+ | | x | y | d | e |
+ | x | 0 | 300 | 400 | 300 |
+ | y | 500 | 0 | 300 | 200 |
+ | d | 200 | 300 | 0 | 300 |
+ | e | 300 | 400 | 100 | 0 |
diff --git a/features/testbot/fastest.feature b/features/testbot/fastest.feature
index 9a5cf24..8c24a53 100644
--- a/features/testbot/fastest.feature
+++ b/features/testbot/fastest.feature
@@ -1,4 +1,4 @@
- at routing @fastest
+ at routing @fastest @testbot
Feature: Choosing fastest route
Background:
diff --git a/features/testbot/geometry.feature b/features/testbot/geometry.feature
index 553af93..8b38c06 100644
--- a/features/testbot/geometry.feature
+++ b/features/testbot/geometry.feature
@@ -1,4 +1,4 @@
- at routing
+ at routing @testbot
Feature: Retrieve geometry
Background: Use some profile
diff --git a/features/testbot/graph.feature b/features/testbot/graph.feature
index a870106..adff998 100644
--- a/features/testbot/graph.feature
+++ b/features/testbot/graph.feature
@@ -1,4 +1,4 @@
- at routing @graph
+ at routing @graph @testbot
Feature: Basic Routing
#Test the input data descibed on https://github.com/DennisOSRM/Project-OSRM/wiki/Graph-representation
@@ -19,3 +19,22 @@ Feature: Basic Routing
When I route I should get
| from | to | route |
| a | e | abc,dce |
+
+ Scenario: Turn instructions on compressed road network geometry
+ Given the node map
+ | x | a | | |
+ | | b | | |
+ | f | | | e |
+ | | | | |
+ | | | | |
+ | y | c | | d |
+
+ And the ways
+ | nodes | name |
+ | xa | first |
+ | abcdef | compr |
+ | fy | last |
+
+ When I route I should get
+ | from | to | route | turns |
+ | x | y | first,compr,last | head,right,left,destination |
diff --git a/features/testbot/load.feature b/features/testbot/load.feature
new file mode 100644
index 0000000..cf5e470
--- /dev/null
+++ b/features/testbot/load.feature
@@ -0,0 +1,63 @@
+ at routing @load @testbot
+Feature: Ways of loading data
+# Several scenarios that change between direct/datastore makes
+# it easier to check that the test framework behaves as expected.
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Load data with datastore - ab
+ Given data is loaded with datastore
+ Given the node map
+ | a | b |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | b | a | ab |
+
+ Scenario: Load data directly - st
+ Given data is loaded directly
+ Given the node map
+ | s | t |
+
+ And the ways
+ | nodes |
+ | st |
+
+ When I route I should get
+ | from | to | route |
+ | s | t | st |
+ | t | s | st |
+
+ Scenario: Load data datstore - xy
+ Given data is loaded with datastore
+ Given the node map
+ | x | y |
+
+ And the ways
+ | nodes |
+ | xy |
+
+ When I route I should get
+ | from | to | route |
+ | x | y | xy |
+ | y | x | xy |
+
+ Scenario: Load data directly - cd
+ Given data is loaded directly
+ Given the node map
+ | c | d |
+
+ And the ways
+ | nodes |
+ | cd |
+
+ When I route I should get
+ | from | to | route |
+ | c | d | cd |
+ | d | c | cd |
diff --git a/features/testbot/loop.feature b/features/testbot/loop.feature
index eb5b45e..fe898ec 100644
--- a/features/testbot/loop.feature
+++ b/features/testbot/loop.feature
@@ -1,4 +1,4 @@
- at routing @726
+ at routing @726 @testbot
Feature: Avoid weird loops caused by rounding errors
Background:
@@ -73,6 +73,6 @@ Feature: Avoid weird loops caused by rounding errors
| cf | secondary |
When I route I should get
- | waypoints | route | turns |
- | a,2,d | ab,be,ef,cf,cd | head,left,right,right,left,destination |
- | a,1,d | ab,be,ef,cf,cd | head,left,right,right,left,destination |
+ | waypoints | route | turns |
+ | a,2,d | ab,be,ef,ef,cf,cd | head,left,right,via,right,left,destination |
+ | a,1,d | ab,be,ef,ef,cf,cd | head,left,right,via,right,left,destination |
diff --git a/features/testbot/mode.feature b/features/testbot/mode.feature
index bcc087e..11fe83a 100644
--- a/features/testbot/mode.feature
+++ b/features/testbot/mode.feature
@@ -1,26 +1,227 @@
@routing @testbot @mode
-Feature: Testbot - Mode flag
+Feature: Testbot - Travel mode
+
+# testbot modes:
+# 1 normal
+# 2 route
+# 3 river downstream
+# 4 river upstream
+# 5 steps down
+# 6 steps up
Background:
- Given the profile "testbot"
+ Given the profile "testbot"
+
+ Scenario: Testbot - Modes in each direction, different forward/backward speeds
+ Given the node map
+ | | 0 | 1 | |
+ | a | | | b |
+
+ And the ways
+ | nodes | highway | oneway |
+ | ab | river | |
+
+ When I route I should get
+ | from | to | route | modes |
+ | a | 0 | ab | 3 |
+ | a | b | ab | 3 |
+ | 0 | 1 | ab | 3 |
+ | 0 | b | ab | 3 |
+ | b | 1 | ab | 4 |
+ | b | a | ab | 4 |
+ | 1 | 0 | ab | 4 |
+ | 1 | a | ab | 4 |
+
+ Scenario: Testbot - Modes in each direction, same forward/backward speeds
+ Given the node map
+ | | 0 | 1 | |
+ | a | | | b |
+
+ And the ways
+ | nodes | highway |
+ | ab | steps |
+
+ When I route I should get
+ | from | to | route | modes | time |
+ | 0 | 1 | ab | 5 | 60s +-1 |
+ | 1 | 0 | ab | 6 | 60s +-1 |
+
+ @oneway
+ Scenario: Testbot - Modes for oneway, different forward/backward speeds
+ Given the node map
+ | a | b |
- @todo
- Scenario: Bike - Mode
+ And the ways
+ | nodes | highway | oneway |
+ | ab | river | yes |
+
+ When I route I should get
+ | from | to | route | modes |
+ | a | b | ab | 3 |
+ | b | a | | |
+
+ @oneway
+ Scenario: Testbot - Modes for oneway, same forward/backward speeds
+ Given the node map
+ | a | b |
+
+ And the ways
+ | nodes | highway | oneway |
+ | ab | steps | yes |
+
+ When I route I should get
+ | from | to | route | modes |
+ | a | b | ab | 5 |
+ | b | a | | |
+
+ @oneway
+ Scenario: Testbot - Modes for reverse oneway, different forward/backward speeds
Given the node map
- | a | b | |
- | | c | d |
+ | a | b |
And the ways
+ | nodes | highway | oneway |
+ | ab | river | -1 |
+
+ When I route I should get
+ | from | to | route | modes |
+ | a | b | | |
+ | b | a | ab | 4 |
+
+ @oneway
+ Scenario: Testbot - Modes for reverse oneway, same forward/backward speeds
+ Given the node map
+ | a | b |
+
+ And the ways
+ | nodes | highway | oneway |
+ | ab | steps | -1 |
+
+ When I route I should get
+ | from | to | route | modes |
+ | a | b | | |
+ | b | a | ab | 6 |
+
+ @via
+ Scenario: Testbot - Mode should be set at via points
+ Given the node map
+ | a | 1 | b |
+
+ And the ways
+ | nodes | highway |
+ | ab | river |
+
+ When I route I should get
+ | waypoints | route | modes | turns |
+ | a,1,b | ab,ab | 3,3 | head,via,destination |
+ | b,1,a | ab,ab | 4,4 | head,via,destination |
+
+ Scenario: Testbot - Starting at a tricky node
+ Given the node map
+ | | a | | | |
+ | | | | b | c |
+
+ And the ways
+ | nodes | highway |
+ | ab | river |
+ | bc | primary |
+
+ When I route I should get
+ | from | to | route | modes |
+ | b | a | ab | 4 |
+
+ Scenario: Testbot - Mode changes on straight way without name change
+ Given the node map
+ | a | 1 | b | 2 | c |
+
+ And the ways
+ | nodes | highway | name |
+ | ab | primary | Avenue |
+ | bc | river | Avenue |
+
+ When I route I should get
+ | from | to | route | modes | turns |
+ | a | c | Avenue,Avenue | 1,3 | head,straight,destination |
+ | c | a | Avenue,Avenue | 4,1 | head,straight,destination |
+ | 1 | 2 | Avenue,Avenue | 1,3 | head,straight,destination |
+ | 2 | 1 | Avenue,Avenue | 4,1 | head,straight,destination |
+
+ Scenario: Testbot - Mode for routes
+ Given the node map
+ | a | b | | | |
+ | | c | d | e | f |
+
+ And the ways
| nodes | highway | route | duration |
| ab | primary | | |
| bc | | ferry | 0:01 |
| cd | primary | | |
+ | de | primary | | |
+ | ef | primary | | |
+
+ When I route I should get
+ | from | to | route | turns | modes |
+ | a | d | ab,bc,cd | head,right,left,destination | 1,2,1 |
+ | d | a | cd,bc,ab | head,right,left,destination | 1,2,1 |
+ | c | a | bc,ab | head,left,destination | 2,1 |
+ | d | b | cd,bc | head,right,destination | 1,2 |
+ | a | c | ab,bc | head,right,destination | 1,2 |
+ | b | d | bc,cd | head,left,destination | 2,1 |
+ | a | f | ab,bc,cd,de,ef | head,right,left,straight,straight,destination | 1,2,1,1,1 |
+
+ Scenario: Testbot - Modes, triangle map
+ Given the node map
+ | | | | | | | d |
+ | | | | | | 2 | |
+ | | | | | 6 | | 5 |
+ | a | 0 | b | c | | | |
+ | | | | | 4 | | 1 |
+ | | | | | | 3 | |
+ | | | | | | | e |
+
+ And the ways
+ | nodes | highway | oneway |
+ | abc | primary | |
+ | cd | primary | yes |
+ | ce | river | |
+ | de | primary | |
+
+ When I route I should get
+ | from | to | route | modes |
+ | 0 | 1 | abc,ce,de | 1,3,1 |
+ | 1 | 0 | de,ce,abc | 1,4,1 |
+ | 0 | 2 | abc,cd | 1,1 |
+ | 2 | 0 | cd,de,ce,abc | 1,1,4,1 |
+ | 0 | 3 | abc,ce | 1,3 |
+ | 3 | 0 | ce,abc | 4,1 |
+ | 4 | 3 | ce | 3 |
+ | 3 | 4 | ce | 4 |
+ | 3 | 1 | ce,de | 3,1 |
+ | 1 | 3 | de,ce | 1,4 |
+ | a | e | abc,ce | 1,3 |
+ | e | a | ce,abc | 4,1 |
+ | a | d | abc,cd | 1,1 |
+ | d | a | de,ce,abc | 1,4,1 |
+
+ Scenario: Testbot - River in the middle
+ Given the node map
+ | a | b | c | | |
+ | | | d | | |
+ | | | e | f | g |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | cde | river |
+ | efg | primary |
When I route I should get
- | from | to | route | turns | modes |
- | a | d | ab,bc,cd | head,right,left,destination | bot,ferry,bot |
- | d | a | cd,bc,ab | head,right left,destination | bot,ferry,bot |
- | c | a | bc,ab | head,left,destination | ferry,bot |
- | d | b | cd,bc | head,right,destination | bot,ferry |
- | a | c | ab,bc | head,right,destination | bot,ferry |
- | b | d | bc,cd | head,left,destination | ferry,bot |
+ | from | to | route | modes |
+ | a | g | abc,cde,efg | 1,3,1 |
+ | b | f | abc,cde,efg | 1,3,1 |
+ | e | c | cde | 4 |
+ | e | b | cde,abc | 4,1 |
+ | e | a | cde,abc | 4,1 |
+ | c | e | cde | 3 |
+ | c | f | cde,efg | 3,1 |
+ | c | g | cde,efg | 3,1 |
diff --git a/features/testbot/oneway.feature b/features/testbot/oneway.feature
index c21d8b1..766bf8b 100644
--- a/features/testbot/oneway.feature
+++ b/features/testbot/oneway.feature
@@ -6,11 +6,12 @@ Feature: Testbot - oneways
Scenario: Routing on a oneway roundabout
Given the node map
- | x | | | v | | |
- | | | d | c | | |
+ | | | | | v | |
+ | x | | d | c | | |
| | e | | | b | |
| | f | | | a | |
- | | | g | h | | |
+ | | | g | h | | y |
+ | | z | | | | |
And the ways
| nodes | oneway |
@@ -23,6 +24,9 @@ Feature: Testbot - oneways
| gh | yes |
| ha | yes |
| vx | yes |
+ | vy | yes |
+ | yz | yes |
+ | xe | yes |
When I route I should get
| from | to | route |
@@ -42,3 +46,57 @@ Feature: Testbot - oneways
| g | f | gh,ha,ab,bc,cd,de,ef |
| h | g | ha,ab,bc,cd,de,ef,fg |
| a | h | ab,bc,cd,de,ef,fg,gh |
+
+ Scenario: Testbot - Simple oneway
+ Then routability should be
+ | highway | foot | oneway | forw | backw |
+ | primary | no | yes | x | |
+
+ Scenario: Simple reverse oneway
+ Then routability should be
+ | highway | foot | oneway | forw | backw |
+ | primary | no | -1 | | x |
+
+ Scenario: Testbot - Around the Block
+ Given the node map
+ | a | b |
+ | d | c |
+
+ And the ways
+ | nodes | oneway | foot |
+ | ab | yes | no |
+ | bc | | no |
+ | cd | | no |
+ | da | | no |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | b | a | bc,cd,da |
+
+ Scenario: Testbot - Handle various oneway tag values
+ Then routability should be
+ | foot | oneway | forw | backw |
+ | no | | x | x |
+ | no | nonsense | x | x |
+ | no | no | x | x |
+ | no | false | x | x |
+ | no | 0 | x | x |
+ | no | yes | x | |
+ | no | true | x | |
+ | no | 1 | x | |
+ | no | -1 | | x |
+
+ Scenario: Testbot - Two consecutive oneways
+ Given the node map
+ | a | b | c |
+
+ And the ways
+ | nodes | oneway |
+ | ab | yes |
+ | bc | yes |
+
+
+ When I route I should get
+ | from | to | route |
+ | a | c | ab,bc |
diff --git a/features/testbot/origin.feature b/features/testbot/origin.feature
index c43e04e..b5b1945 100644
--- a/features/testbot/origin.feature
+++ b/features/testbot/origin.feature
@@ -1,4 +1,4 @@
- at routing @origin
+ at routing @origin @testbot
Feature: Routing close to the [0,0] origin
Background:
diff --git a/features/testbot/penalty.feature b/features/testbot/penalty.feature
index 85f43c7..e4f3cb6 100644
--- a/features/testbot/penalty.feature
+++ b/features/testbot/penalty.feature
@@ -1,4 +1,4 @@
- at routing @penalty @signal
+ at routing @penalty @signal @testbot
Feature: Penalties
# Testbot uses a signal penalty of 7s.
diff --git a/features/testbot/planetary.feature b/features/testbot/planetary.feature
index f2ba21e..19925fe 100644
--- a/features/testbot/planetary.feature
+++ b/features/testbot/planetary.feature
@@ -1,4 +1,4 @@
- at routing @planetary
+ at routing @planetary @testbot
Feature: Distance calculation
Scenario: Approximated Longitudinal distances at equator
diff --git a/features/testbot/projection.feature b/features/testbot/projection.feature
index ed2f2fc..d7a0b89 100644
--- a/features/testbot/projection.feature
+++ b/features/testbot/projection.feature
@@ -1,4 +1,4 @@
- at routing @projection
+ at routing @projection @testbot
Feature: Projection to nearest point on road
# Waypoints are projected perpendiculary onto the closest road
diff --git a/features/testbot/protobuffer.feature b/features/testbot/protobuffer.feature
index a77ff34..e32de26 100644
--- a/features/testbot/protobuffer.feature
+++ b/features/testbot/protobuffer.feature
@@ -1,4 +1,4 @@
- at routing @pbf
+ at routing @pbf @testbot
Feature: Importing protobuffer (.pbf) format
# Test normally read .osm, which is faster than .pbf files,
# since we don't need to use osmosis to first convert to .pbf
diff --git a/features/testbot/snap.feature b/features/testbot/snap.feature
index c8a04bf..bee75bc 100644
--- a/features/testbot/snap.feature
+++ b/features/testbot/snap.feature
@@ -1,4 +1,4 @@
- at routing @snap
+ at routing @snap @testbot
Feature: Snap start/end point to the nearest way
Background:
diff --git a/features/testbot/status.feature b/features/testbot/status.feature
index 4fa15eb..1b12b33 100644
--- a/features/testbot/status.feature
+++ b/features/testbot/status.feature
@@ -1,4 +1,4 @@
- at routing @status
+ at routing @status @testbot
Feature: Status messages
Background:
diff --git a/features/testbot/time.feature b/features/testbot/time.feature
index e0ccc37..c838796 100644
--- a/features/testbot/time.feature
+++ b/features/testbot/time.feature
@@ -1,4 +1,4 @@
- at routing @time
+ at routing @time @testbot
Feature: Estimation of travel time
# Testbot speeds:
# Primary road: 36km/h = 36000m/3600s = 100m/10s
diff --git a/features/testbot/turns.feature b/features/testbot/turns.feature
index 87bf21f..6eba4f9 100644
--- a/features/testbot/turns.feature
+++ b/features/testbot/turns.feature
@@ -1,4 +1,4 @@
- at routing @turns
+ at routing @turns @testbot
Feature: Turn directions/codes
Background:
diff --git a/features/testbot/utf.feature b/features/testbot/utf.feature
index e9d324c..d979e9f 100644
--- a/features/testbot/utf.feature
+++ b/features/testbot/utf.feature
@@ -1,4 +1,4 @@
- at routing @utf
+ at routing @utf @testbot
Feature: Handling of UTF characters
Background:
diff --git a/features/testbot/uturn.feature b/features/testbot/uturn.feature
new file mode 100644
index 0000000..943796e
--- /dev/null
+++ b/features/testbot/uturn.feature
@@ -0,0 +1,69 @@
+ at routing @uturn @via @testbot
+Feature: U-turns at via points
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: U-turns at via points disabled by default
+ Given the node map
+ | a | b | c | d |
+ | | e | f | g |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | cd |
+ | be |
+ | dg |
+ | ef |
+ | fg |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e,c | ab,be,be,ef,fg,dg,cd | head,right,via,left,straight,left,left,destination |
+
+ Scenario: Query param to allow U-turns at all via points
+ Given the node map
+ | a | b | c | d |
+ | | e | f | g |
+
+ And the query options
+ | uturns | true |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | cd |
+ | be |
+ | dg |
+ | ef |
+ | fg |
+
+ When I route I should get
+ | waypoints | route |
+ | a,e,c | ab,be,be,bc |
+
+ @todo
+ Scenario: Instructions at via points at u-turns
+ Given the node map
+ | a | b | c | d |
+ | | e | f | g |
+
+ And the query options
+ | uturns | true |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | cd |
+ | be |
+ | dg |
+ | ef |
+ | fg |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,e,c | ab,be,be,bc | head,right,uturn,right,destination |
diff --git a/features/testbot/via.feature b/features/testbot/via.feature
index 79fe540..9eb8f55 100644
--- a/features/testbot/via.feature
+++ b/features/testbot/via.feature
@@ -13,9 +13,9 @@ Feature: Via points
| abc |
When I route I should get
- | waypoints | route |
- | a,b,c | abc |
- | c,b,a | abc |
+ | waypoints | route |
+ | a,b,c | abc,abc |
+ | c,b,a | abc,abc |
Scenario: Via point at a dead end
Given the node map
@@ -28,9 +28,9 @@ Feature: Via points
| bd |
When I route I should get
- | waypoints | route |
- | a,d,c | abc,bd,bd,abc |
- | c,d,a | abc,bd,bd,abc |
+ | waypoints | route |
+ | a,d,c | abc,bd,bd,bd,abc |
+ | c,d,a | abc,bd,bd,bd,abc |
Scenario: Multiple via points
Given the node map
@@ -48,9 +48,9 @@ Feature: Via points
| dh |
When I route I should get
- | waypoints | route |
- | a,c,f | ab,bcd,de,efg |
- | a,c,f,h | ab,bcd,de,efg,gh |
+ | waypoints | route |
+ | a,c,f | ab,bcd,bcd,de,efg |
+ | a,c,f,h | ab,bcd,bcd,de,efg,efg,gh |
Scenario: Via points on ring of oneways
# xa it to avoid only having a single ring, which cna trigger edge cases
@@ -73,9 +73,9 @@ Feature: Via points
| waypoints | route | distance | turns |
| 1,3 | ab,bc,cd | 400m +-1 | head,straight,straight,destination |
| 3,1 | cd,de,ef,fa,ab | 1000m +-1 | head,right,right,right,right,destination |
- | 1,2,3 | ab,bc,cd | 400m +-1 | head,straight,straight,destination |
- | 1,3,2 | ab,bc,cd,de,ef,fa,ab,bc | 1600m +-1 | head,straight,straight,right,right,right,right,straight,destination |
- | 3,2,1 | cd,de,ef,fa,ab,bc,cd,de,ef,fa,ab | 2400m +-1 | head,right,right,right,right,straight,straight,right,right,right,right,destination |
+ | 1,2,3 | ab,bc,bc,cd | 400m +-1 | head,straight,via,straight,destination |
+ | 1,3,2 | ab,bc,cd,cd,de,ef,fa,ab,bc | 1600m +-1 | head,straight,straight,via,right,right,right,right,straight,destination |
+ | 3,2,1 | cd,de,ef,fa,ab,bc,bc,cd,de,ef,fa,ab | 2400m +-1 | head,right,right,right,right,straight,via,straight,right,right,right,right,destination |
@bug
Scenario: Via points on ring on the same oneway
diff --git a/Plugins/DistanceTablePlugin.h b/plugins/distance_table.hpp
similarity index 62%
rename from Plugins/DistanceTablePlugin.h
rename to plugins/distance_table.hpp
index d3e307b..6ef90a5 100644
--- a/Plugins/DistanceTablePlugin.h
+++ b/plugins/distance_table.hpp
@@ -28,16 +28,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef DISTANCE_TABLE_PLUGIN_H
#define DISTANCE_TABLE_PLUGIN_H
-#include "BasePlugin.h"
-
-#include "../Algorithms/ObjectToBase64.h"
-#include "../DataStructures/JSONContainer.h"
-#include "../DataStructures/QueryEdge.h"
-#include "../DataStructures/SearchEngine.h"
-#include "../Descriptors/BaseDescriptor.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/StringUtil.h"
-#include "../Util/TimingUtil.h"
+#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 <cstdlib>
@@ -47,70 +48,51 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
#include <vector>
-template <class DataFacadeT> class DistanceTablePlugin : public BasePlugin
+template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
{
private:
- std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
+ std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
public:
explicit DistanceTablePlugin(DataFacadeT *facade) : descriptor_string("table"), facade(facade)
{
- search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
+ search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
}
virtual ~DistanceTablePlugin() {}
- const std::string GetDescriptor() const { return descriptor_string; }
+ const std::string GetDescriptor() const final { return descriptor_string; }
- void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
+ void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
{
- // check number of parameters
- if (2 > route_parameters.coordinates.size())
+ if (!check_all_coordinates(route_parameters.coordinates))
{
reply = http::Reply::StockReply(http::Reply::badRequest);
return;
}
- RawRouteData raw_route;
- raw_route.check_sum = facade->GetCheckSum();
-
- if (std::any_of(begin(route_parameters.coordinates),
- end(route_parameters.coordinates),
- [&](FixedPointCoordinate coordinate)
- { return !coordinate.isValid(); }))
- {
- reply = http::Reply::StockReply(http::Reply::badRequest);
- return;
- }
-
- for (const FixedPointCoordinate &coordinate : route_parameters.coordinates)
- {
- raw_route.raw_via_node_coordinates.emplace_back(std::move(coordinate));
- }
-
- const bool checksum_OK = (route_parameters.check_sum == raw_route.check_sum);
+ const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
unsigned max_locations =
- std::min(100u, static_cast<unsigned>(raw_route.raw_via_node_coordinates.size()));
+ std::min(100u, static_cast<unsigned>(route_parameters.coordinates.size()));
PhantomNodeArray phantom_node_vector(max_locations);
- for (unsigned i = 0; i < max_locations; ++i)
+ for (const auto i : osrm::irange(0u, max_locations))
{
if (checksum_OK && i < route_parameters.hints.size() &&
!route_parameters.hints[i].empty())
{
PhantomNode current_phantom_node;
- DecodeObjectFromBase64(route_parameters.hints[i], current_phantom_node);
- if (current_phantom_node.isValid(facade->GetNumberOfNodes()))
+ ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
+ if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
{
phantom_node_vector[i].emplace_back(std::move(current_phantom_node));
continue;
}
}
- facade->IncrementalFindPhantomNodeForCoordinate(raw_route.raw_via_node_coordinates[i],
+ facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i],
phantom_node_vector[i],
- route_parameters.zoom_level,
1);
- BOOST_ASSERT(phantom_node_vector[i].front().isValid(facade->GetNumberOfNodes()));
+ BOOST_ASSERT(phantom_node_vector[i].front().is_valid(facade->GetNumberOfNodes()));
}
// TIMER_START(distance_table);
@@ -123,10 +105,11 @@ template <class DataFacadeT> class DistanceTablePlugin : public BasePlugin
reply = http::Reply::StockReply(http::Reply::badRequest);
return;
}
+
JSON::Object json_object;
JSON::Array json_array;
- const unsigned number_of_locations = static_cast<unsigned>(phantom_node_vector.size());
- for (unsigned row = 0; row < number_of_locations; ++row)
+ 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;
auto row_begin_iterator = result_table->begin() + (row * number_of_locations);
diff --git a/Plugins/HelloWorldPlugin.h b/plugins/hello_world.hpp
similarity index 73%
rename from Plugins/HelloWorldPlugin.h
rename to plugins/hello_world.hpp
index 2d99a10..c8b07b0 100644
--- a/Plugins/HelloWorldPlugin.h
+++ b/plugins/hello_world.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,13 +28,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef HELLO_WORLD_PLUGIN_H
#define HELLO_WORLD_PLUGIN_H
-#include "BasePlugin.h"
-#include "../DataStructures/JSONContainer.h"
-#include "../Util/StringUtil.h"
+#include "plugin_base.hpp"
+
+#include "../data_structures/json_container.hpp"
+#include "../Util/cast.hpp"
+#include "../Util/json_renderer.hpp"
#include <string>
-class HelloWorldPlugin : public BasePlugin
+class HelloWorldPlugin final : public BasePlugin
{
private:
std::string temp_string;
@@ -42,9 +44,9 @@ class HelloWorldPlugin : public BasePlugin
public:
HelloWorldPlugin() : descriptor_string("hello") {}
virtual ~HelloWorldPlugin() {}
- const std::string GetDescriptor() const { return descriptor_string; }
+ const std::string GetDescriptor() const final { return descriptor_string; }
- void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply)
+ void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply) final
{
reply.status = http::Reply::ok;
@@ -52,20 +54,22 @@ class HelloWorldPlugin : public BasePlugin
std::string temp_string;
json_result.values["title"] = "Hello World";
- temp_string = IntToString(routeParameters.zoom_level);
+ temp_string = cast::integral_to_string(routeParameters.zoom_level);
json_result.values["zoom_level"] = temp_string;
- temp_string = UintToString(routeParameters.check_sum);
+ temp_string = cast::integral_to_string(routeParameters.check_sum);
json_result.values["check_sum"] = temp_string;
json_result.values["instructions"] = (routeParameters.print_instructions ? "yes" : "no");
json_result.values["geometry"] = (routeParameters.geometry ? "yes" : "no");
json_result.values["compression"] = (routeParameters.compression ? "yes" : "no");
- json_result.values["output_format"] = (!routeParameters.output_format.empty() ? "yes" : "no");
+ json_result.values["output_format"] =
+ (!routeParameters.output_format.empty() ? "yes" : "no");
- json_result.values["jsonp_parameter"] = (!routeParameters.jsonp_parameter.empty() ? "yes" : "no");
+ json_result.values["jsonp_parameter"] =
+ (!routeParameters.jsonp_parameter.empty() ? "yes" : "no");
json_result.values["language"] = (!routeParameters.language.empty() ? "yes" : "no");
- temp_string = UintToString(static_cast<unsigned>(routeParameters.coordinates.size()));
+ temp_string = cast::integral_to_string(routeParameters.coordinates.size());
json_result.values["location_count"] = temp_string;
JSON::Array json_locations;
@@ -75,9 +79,9 @@ class HelloWorldPlugin : public BasePlugin
JSON::Object json_location;
JSON::Array json_coordinates;
- json_coordinates.values.push_back(coordinate.lat / COORDINATE_PRECISION);
- json_coordinates.values.push_back(coordinate.lon / COORDINATE_PRECISION);
- json_location.values[UintToString(counter)] = json_coordinates;
+ json_coordinates.values.push_back(static_cast<double>(coordinate.lat / COORDINATE_PRECISION));
+ json_coordinates.values.push_back(static_cast<double>(coordinate.lon / COORDINATE_PRECISION));
+ json_location.values[cast::integral_to_string(counter)] = json_coordinates;
json_locations.values.push_back(json_location);
++counter;
}
diff --git a/Plugins/LocatePlugin.h b/plugins/locate.hpp
similarity index 78%
rename from Plugins/LocatePlugin.h
rename to plugins/locate.hpp
index 518259d..6171395 100644
--- a/Plugins/LocatePlugin.h
+++ b/plugins/locate.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,24 +28,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef LOCATE_PLUGIN_H
#define LOCATE_PLUGIN_H
-#include "BasePlugin.h"
-#include "../DataStructures/JSONContainer.h"
-#include "../Util/StringUtil.h"
+#include "plugin_base.hpp"
+
+#include "../data_structures/json_container.hpp"
+#include "../Util/json_renderer.hpp"
+#include "../Util/string_util.hpp"
#include <string>
// locates the nearest node in the road network for a given coordinate.
-template <class DataFacadeT> class LocatePlugin : public BasePlugin
+template <class DataFacadeT> class LocatePlugin final : public BasePlugin
{
public:
explicit LocatePlugin(DataFacadeT *facade) : descriptor_string("locate"), facade(facade) {}
- const std::string GetDescriptor() const { return descriptor_string; }
+ const std::string GetDescriptor() const final { return descriptor_string; }
- void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
+ void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
{
// check number of parameters
- if (route_parameters.coordinates.empty() ||
- !route_parameters.coordinates.front().isValid())
+ if (route_parameters.coordinates.empty() || !route_parameters.coordinates.front().is_valid())
{
reply = http::Reply::StockReply(http::Reply::badRequest);
return;
@@ -63,8 +64,8 @@ template <class DataFacadeT> class LocatePlugin : public BasePlugin
reply.status = http::Reply::ok;
json_result.values["status"] = 0;
JSON::Array json_coordinate;
- json_coordinate.values.push_back(result.lat/COORDINATE_PRECISION);
- json_coordinate.values.push_back(result.lon/COORDINATE_PRECISION);
+ 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;
}
diff --git a/Plugins/NearestPlugin.h b/plugins/nearest.hpp
similarity index 50%
rename from Plugins/NearestPlugin.h
rename to plugins/nearest.hpp
index 27bd016..ac1079b 100644
--- a/Plugins/NearestPlugin.h
+++ b/plugins/nearest.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
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 NEAREST_PLUGIN_H
#define NEAREST_PLUGIN_H
-#include "BasePlugin.h"
-#include "../DataStructures/JSONContainer.h"
-#include "../DataStructures/PhantomNodes.h"
+#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 <string>
@@ -38,30 +41,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* This Plugin locates the nearest point on a street in the road network for a given coordinate.
*/
-template <class DataFacadeT> class NearestPlugin : public BasePlugin
+template <class DataFacadeT> class NearestPlugin final : public BasePlugin
{
public:
explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest") {}
- const std::string GetDescriptor() const { return descriptor_string; }
+ const std::string GetDescriptor() const final { return descriptor_string; }
- void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
+ void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
{
// check number of parameters
- if (route_parameters.coordinates.empty() || !route_parameters.coordinates.front().isValid())
+ if (route_parameters.coordinates.empty() || !route_parameters.coordinates.front().is_valid())
{
reply = http::Reply::StockReply(http::Reply::badRequest);
return;
}
-
+ auto number_of_results = static_cast<std::size_t>(route_parameters.num_results);
std::vector<PhantomNode> phantom_node_vector;
facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates.front(),
phantom_node_vector,
- route_parameters.zoom_level,
- 1);
+ static_cast<int>(number_of_results));
JSON::Object json_result;
- if (phantom_node_vector.empty() || !phantom_node_vector.front().isValid())
+ if (phantom_node_vector.empty() || !phantom_node_vector.front().is_valid())
{
json_result.values["status"] = 207;
}
@@ -69,17 +71,41 @@ template <class DataFacadeT> class NearestPlugin : public BasePlugin
{
reply.status = http::Reply::ok;
json_result.values["status"] = 0;
- 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;
- }
+ if (number_of_results > 1)
+ {
+ 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)))
+ {
+ JSON::Array json_coordinate;
+ 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;
+ results.values.push_back(result);
+ }
+ json_result.values["results"] = results;
+ }
+ else
+ {
+ 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::render(reply.content, json_result);
}
diff --git a/Plugins/BasePlugin.h b/plugins/plugin_base.hpp
similarity index 79%
rename from Plugins/BasePlugin.h
rename to plugins/plugin_base.hpp
index 11c6940..bb23a4d 100644
--- a/Plugins/BasePlugin.h
+++ b/plugins/plugin_base.hpp
@@ -28,8 +28,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef BASEPLUGIN_H_
#define BASEPLUGIN_H_
-#include "../Util/StringUtil.h"
-
#include <osrm/Coordinate.h>
#include <osrm/Reply.h>
#include <osrm/RouteParameters.h>
@@ -45,6 +43,20 @@ class BasePlugin
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
+ {
+ if (2 > coordinates.size() ||
+ std::any_of(std::begin(coordinates),
+ std::end(coordinates),
+ [](const FixedPointCoordinate &coordinate)
+ {
+ return !coordinate.is_valid();
+ }))
+ {
+ return false;
+ }
+ return true;
+ }
};
#endif /* BASEPLUGIN_H_ */
diff --git a/Plugins/TimestampPlugin.h b/plugins/timestamp.hpp
similarity index 84%
rename from Plugins/TimestampPlugin.h
rename to plugins/timestamp.hpp
index 63f63b2..acdf32e 100644
--- a/Plugins/TimestampPlugin.h
+++ b/plugins/timestamp.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -28,20 +28,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef TIMESTAMP_PLUGIN_H
#define TIMESTAMP_PLUGIN_H
-#include "../DataStructures/JSONContainer.h"
-#include "BasePlugin.h"
+#include "plugin_base.hpp"
+
+#include "../data_structures/json_container.hpp"
+#include "../Util/json_renderer.hpp"
#include <string>
-template <class DataFacadeT> class TimestampPlugin : public BasePlugin
+template <class DataFacadeT> class TimestampPlugin final : public BasePlugin
{
public:
explicit TimestampPlugin(const DataFacadeT *facade)
: facade(facade), descriptor_string("timestamp")
{
}
- const std::string GetDescriptor() const { return descriptor_string; }
- void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
+ const std::string GetDescriptor() const final { return descriptor_string; }
+ void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
{
reply.status = http::Reply::ok;
JSON::Object json_result;
diff --git a/plugins/viaroute.hpp b/plugins/viaroute.hpp
new file mode 100644
index 0000000..236ee39
--- /dev/null
+++ b/plugins/viaroute.hpp
@@ -0,0 +1,190 @@
+/*
+
+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 VIA_ROUTE_HPP
+#define VIA_ROUTE_HPP
+
+#include "plugin_base.hpp"
+
+#include "../algorithms/object_encoder.hpp"
+#include "../data_structures/search_engine.hpp"
+#include "../descriptors/descriptor_base.hpp"
+#include "../descriptors/gpx_descriptor.hpp"
+#include "../descriptors/json_descriptor.hpp"
+#include "../Util/integer_range.hpp"
+#include "../Util/json_renderer.hpp"
+#include "../Util/make_unique.hpp"
+#include "../Util/simple_logger.hpp"
+
+#include <cstdlib>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
+{
+ private:
+ DescriptorTable descriptor_table;
+ std::string descriptor_string;
+ std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
+ DataFacadeT *facade;
+
+ public:
+ explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade)
+ {
+ search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
+
+ descriptor_table.emplace("json", 0);
+ descriptor_table.emplace("gpx", 1);
+ // descriptor_table.emplace("geojson", 2);
+ }
+
+ virtual ~ViaRoutePlugin() {}
+
+ const std::string GetDescriptor() const final { return descriptor_string; }
+
+ void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
+ {
+ if (!check_all_coordinates(route_parameters.coordinates))
+ {
+ reply = http::Reply::StockReply(http::Reply::badRequest);
+ return;
+ }
+ 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());
+
+ for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
+ {
+ if (checksum_OK && i < route_parameters.hints.size() &&
+ !route_parameters.hints[i].empty())
+ {
+ ObjectEncoder::DecodeFromBase64(route_parameters.hints[i],
+ phantom_node_pair_list[i]);
+ if (phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
+ {
+ continue;
+ }
+ }
+ std::vector<PhantomNode> phantom_node_vector;
+ if (facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i],
+ phantom_node_vector, 1))
+ {
+ BOOST_ASSERT(!phantom_node_vector.empty());
+ phantom_node_pair_list[i].first = phantom_node_vector.front();
+ if (phantom_node_vector.size() > 1)
+ {
+ phantom_node_pair_list[i].second = phantom_node_vector.back();
+ }
+ }
+ }
+
+ auto check_component_id_is_tiny = [](const phantom_node_pair &phantom_pair)
+ {
+ return phantom_pair.first.component_id != 0;
+ };
+
+ const bool every_phantom_is_in_tiny_cc =
+ std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
+ check_component_id_is_tiny);
+
+ // are all phantoms from a tiny cc?
+ const auto component_id = phantom_node_pair_list.front().first.component_id;
+
+ auto check_component_id_is_equal = [component_id](const phantom_node_pair &phantom_pair)
+ {
+ return component_id == phantom_pair.first.component_id;
+ };
+
+ const bool every_phantom_has_equal_id =
+ std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
+ check_component_id_is_equal);
+
+ auto swap_phantom_from_big_cc_into_front = [](phantom_node_pair &phantom_pair)
+ {
+ if (0 != phantom_pair.first.component_id)
+ {
+ using namespace std;
+ swap(phantom_pair.first, phantom_pair.second);
+ }
+ };
+
+ // this case is true if we take phantoms from the big CC
+ if (!every_phantom_is_in_tiny_cc || !every_phantom_has_equal_id)
+ {
+ std::for_each(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
+ swap_phantom_from_big_cc_into_front);
+ }
+
+ RawRouteData raw_route;
+ auto build_phantom_pairs =
+ [&raw_route](const phantom_node_pair &first_pair, const phantom_node_pair &second_pair)
+ {
+ raw_route.segment_end_coordinates.emplace_back(
+ PhantomNodes{first_pair.first, second_pair.first});
+ };
+ osrm::for_each_pair(phantom_node_pair_list, build_phantom_pairs);
+
+ if (route_parameters.alternate_route && 1 == raw_route.segment_end_coordinates.size())
+ {
+ search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
+ raw_route);
+ }
+ else
+ {
+ search_engine_ptr->shortest_path(raw_route.segment_end_coordinates,
+ route_parameters.uturns, raw_route);
+ }
+
+ if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
+ {
+ SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
+ }
+
+ std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
+ switch (descriptor_table.get_id(route_parameters.output_format))
+ {
+ case 1:
+ descriptor = osrm::make_unique<GPXDescriptor<DataFacadeT>>(facade);
+ break;
+ // case 2:
+ // descriptor = osrm::make_unique<GEOJSONDescriptor<DataFacadeT>>();
+ // break;
+ default:
+ descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
+ break;
+ }
+
+ descriptor->SetConfig(route_parameters);
+ descriptor->Run(raw_route, reply);
+ }
+};
+
+#endif // VIA_ROUTE_HPP
diff --git a/prepare.cpp b/prepare.cpp
index bb0dab4..e50f134 100644
--- a/prepare.cpp
+++ b/prepare.cpp
@@ -25,484 +25,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "Algorithms/IteratorBasedCRC32.h"
-#include "Contractor/Contractor.h"
-#include "Contractor/EdgeBasedGraphFactory.h"
-#include "DataStructures/BinaryHeap.h"
-#include "DataStructures/DeallocatingVector.h"
-#include "DataStructures/QueryEdge.h"
-#include "DataStructures/StaticGraph.h"
-#include "DataStructures/StaticRTree.h"
-#include "DataStructures/RestrictionMap.h"
-#include "Util/GitDescription.h"
-#include "Util/GraphLoader.h"
-#include "Util/LuaUtil.h"
-#include "Util/OSRMException.h"
+#include "contractor/processing_chain.hpp"
-#include "Util/SimpleLogger.h"
-#include "Util/StringUtil.h"
-#include "Util/TimingUtil.h"
-#include "typedefs.h"
-
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-
-#include <luabind/luabind.hpp>
-
-#include <thread>
-#include <chrono>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <tbb/task_scheduler_init.h>
-#include <tbb/parallel_sort.h>
-
-typedef QueryEdge::EdgeData EdgeData;
-typedef DynamicGraph<EdgeData>::InputEdge InputEdge;
-typedef StaticGraph<EdgeData>::InputEdge StaticEdge;
-
-std::vector<NodeInfo> internal_to_external_node_map;
-std::vector<TurnRestriction> restriction_list;
-std::vector<NodeID> barrier_node_list;
-std::vector<NodeID> traffic_light_list;
-std::vector<ImportEdge> edge_list;
+#include <boost/program_options.hpp>
int main(int argc, char *argv[])
{
try
{
- LogPolicy::GetInstance().Unmute();
- TIMER_START(preparing);
- TIMER_START(expansion);
-
- boost::filesystem::path config_file_path, input_path, restrictions_path, profile_path;
- unsigned int requested_num_threads;
-
- // 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"),
- "Path to a configuration file.");
-
- // declare a group of options that will be allowed both on command line and in config file
- boost::program_options::options_description config_options("Configuration");
- config_options.add_options()(
- "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"),
- "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()),
- "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 file in .osm, .osm.bz2 or .osm.pbf format");
-
- // positional option
- boost::program_options::positional_options_description positional_options;
- positional_options.add("input", 1);
-
- // combine above options for parsing
- boost::program_options::options_description cmdline_options;
- cmdline_options.add(generic_options).add(config_options).add(hidden_options);
-
- boost::program_options::options_description config_file_options;
- config_file_options.add(config_options).add(hidden_options);
-
- boost::program_options::options_description visible_options(
- "Usage: " + boost::filesystem::basename(argv[0]) + " <input.osrm> [options]");
- visible_options.add(generic_options).add(config_options);
-
- // parse command line options
- boost::program_options::variables_map option_variables;
- boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
- .options(cmdline_options)
- .positional(positional_options)
- .run(),
- option_variables);
-
- if (option_variables.count("version"))
- {
- SimpleLogger().Write() << g_GIT_DESCRIPTION;
- return 0;
- }
-
- if (option_variables.count("help"))
- {
- SimpleLogger().Write() << "\n" << visible_options;
- return 0;
- }
-
- boost::program_options::notify(option_variables);
-
- if (!option_variables.count("restrictions"))
- {
- restrictions_path = std::string(input_path.string() + ".restrictions");
- }
-
- if (!option_variables.count("input"))
- {
- SimpleLogger().Write() << "\n" << visible_options;
- return 0;
- }
-
- if (!boost::filesystem::is_regular_file(input_path))
- {
- SimpleLogger().Write(logWARNING) << "Input file " << input_path.string()
- << " not found!";
- return 1;
- }
-
- if (!boost::filesystem::is_regular_file(profile_path))
- {
- SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string()
- << " not found!";
- return 1;
- }
-
- if (1 > requested_num_threads)
- {
- SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
- return 1;
- }
-
- const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
-
- SimpleLogger().Write() << "Input file: " << input_path.filename().string();
- SimpleLogger().Write() << "Restrictions file: " << restrictions_path.filename().string();
- SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
- SimpleLogger().Write() << "Threads: " << requested_num_threads;
- if (recommended_num_threads != requested_num_threads)
- {
- SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
- << recommended_num_threads
- << "! This setting may have performance side-effects.";
- }
-
- tbb::task_scheduler_init init(requested_num_threads);
-
- LogPolicy::GetInstance().Unmute();
- boost::filesystem::ifstream restriction_stream(restrictions_path, std::ios::binary);
- TurnRestriction restriction;
- FingerPrint fingerprint_loaded, fingerprint_orig;
- unsigned number_of_usable_restrictions = 0;
- restriction_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
- if (!fingerprint_loaded.TestPrepare(fingerprint_orig))
- {
- SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n"
- "Reprocess to get rid of this warning.";
- }
-
- restriction_stream.read((char *)&number_of_usable_restrictions, sizeof(unsigned));
- restriction_list.resize(number_of_usable_restrictions);
- if (number_of_usable_restrictions > 0)
- {
- restriction_stream.read((char *)&(restriction_list[0]),
- number_of_usable_restrictions * sizeof(TurnRestriction));
- }
- restriction_stream.close();
-
- boost::filesystem::ifstream in;
- in.open(input_path, std::ios::in | std::ios::binary);
-
- const std::string node_filename = input_path.string() + ".nodes";
- const std::string edge_out = input_path.string() + ".edges";
- const std::string geometry_filename = input_path.string() + ".geometry";
- const std::string graphOut = input_path.string() + ".hsgr";
- const std::string rtree_nodes_path = input_path.string() + ".ramIndex";
- const std::string rtree_leafs_path = input_path.string() + ".fileIndex";
-
- /*** Setup Scripting Environment ***/
-
- // Create a new lua state
- lua_State *lua_state = luaL_newstate();
-
- // Connect LuaBind to this lua state
- luabind::open(lua_state);
-
- // open utility libraries string library;
- luaL_openlibs(lua_state);
-
- // adjust lua load path
- luaAddScriptFolderToLoadPath(lua_state, profile_path.string().c_str());
-
- // Now call our function in a lua script
- if (0 != luaL_dofile(lua_state, profile_path.string().c_str()))
- {
- std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
- return 1;
- }
-
- EdgeBasedGraphFactory::SpeedProfileProperties speed_profile;
-
- if (0 != luaL_dostring(lua_state, "return traffic_signal_penalty\n"))
- {
- std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
- return 1;
- }
- speed_profile.trafficSignalPenalty = 10 * lua_tointeger(lua_state, -1);
- SimpleLogger().Write(logDEBUG)
- << "traffic_signal_penalty: " << speed_profile.trafficSignalPenalty;
-
- if (0 != luaL_dostring(lua_state, "return u_turn_penalty\n"))
- {
- std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
- return 1;
- }
- speed_profile.uTurnPenalty = 10 * lua_tointeger(lua_state, -1);
-
- speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function");
-
- #ifdef WIN32
- #pragma message ("Memory consumption on Windows can be higher due to memory alignment")
- #else
- static_assert(sizeof(ImportEdge) == 20,
- "changing ImportEdge type has influence on memory consumption!");
- #endif
- std::vector<ImportEdge> edge_list;
- NodeID number_of_node_based_nodes =
- readBinaryOSRMGraphFromStream(in,
- edge_list,
- barrier_node_list,
- traffic_light_list,
- &internal_to_external_node_map,
- restriction_list);
- in.close();
-
- if (edge_list.empty())
- {
- SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
- return 1;
- }
-
- SimpleLogger().Write() << restriction_list.size() << " restrictions, "
- << barrier_node_list.size() << " bollard nodes, "
- << traffic_light_list.size() << " traffic lights";
-
- /***
- * Building an edge-expanded graph from node-based input and turn restrictions
- */
-
- 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 =
- std::unique_ptr<RestrictionMap>(new RestrictionMap(node_based_graph, restriction_list));
- EdgeBasedGraphFactory *edge_based_graph_factor =
- new 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();
-
- edge_based_graph_factor->Run(edge_out, geometry_filename, lua_state);
-
- restriction_list.clear();
- restriction_list.shrink_to_fit();
- barrier_node_list.clear();
- barrier_node_list.shrink_to_fit();
- traffic_light_list.clear();
- traffic_light_list.shrink_to_fit();
-
- unsigned number_of_edge_based_nodes = edge_based_graph_factor->GetNumberOfEdgeBasedNodes();
- BOOST_ASSERT(number_of_edge_based_nodes != std::numeric_limits<unsigned>::max());
- DeallocatingVector<EdgeBasedEdge> edgeBasedEdgeList;
- #ifndef WIN32
- static_assert(sizeof(EdgeBasedEdge) == 16,
- "changing ImportEdge type has influence on memory consumption!");
- #endif
-
- edge_based_graph_factor->GetEdgeBasedEdges(edgeBasedEdgeList);
- std::vector<EdgeBasedNode> node_based_edge_list;
- edge_based_graph_factor->GetEdgeBasedNodes(node_based_edge_list);
- delete edge_based_graph_factor;
-
- // TODO actually use scoping: Split this up in subfunctions
- node_based_graph.reset();
-
- TIMER_STOP(expansion);
-
- // Building grid-like nearest-neighbor data structure
- SimpleLogger().Write() << "building r-tree ...";
- StaticRTree<EdgeBasedNode> *rtree =
- new StaticRTree<EdgeBasedNode>(node_based_edge_list,
- rtree_nodes_path.c_str(),
- rtree_leafs_path.c_str(),
- internal_to_external_node_map);
- delete rtree;
- IteratorbasedCRC32<std::vector<EdgeBasedNode>> crc32;
- unsigned node_based_edge_list_CRC32 =
- crc32(node_based_edge_list.begin(), node_based_edge_list.end());
- node_based_edge_list.clear();
- node_based_edge_list.shrink_to_fit();
- SimpleLogger().Write() << "CRC32: " << node_based_edge_list_CRC32;
-
- /***
- * Writing info on original (node-based) nodes
- */
-
- SimpleLogger().Write() << "writing node map ...";
- boost::filesystem::ofstream node_stream(node_filename, std::ios::binary);
- const unsigned size_of_mapping = internal_to_external_node_map.size();
- node_stream.write((char *)&size_of_mapping, sizeof(unsigned));
- if (size_of_mapping > 0)
- {
- node_stream.write((char *)&(internal_to_external_node_map[0]),
- size_of_mapping * sizeof(NodeInfo));
- }
- node_stream.close();
- internal_to_external_node_map.clear();
- internal_to_external_node_map.shrink_to_fit();
-
- /***
- * Contracting the edge-expanded graph
- */
-
- SimpleLogger().Write() << "initializing contractor";
- Contractor *contractor = new Contractor(number_of_edge_based_nodes, edgeBasedEdgeList);
-
- TIMER_START(contraction);
- contractor->Run();
- TIMER_STOP(contraction);
-
- SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
-
- DeallocatingVector<QueryEdge> contracted_edge_list;
- contractor->GetEdges(contracted_edge_list);
- delete contractor;
-
- /***
- * Sorting contracted edges in a way that the static query graph can read some in in-place.
- */
-
- std::sort(contracted_edge_list.begin(), contracted_edge_list.end());
- unsigned max_used_node_id = 0;
- unsigned contracted_edge_count = contracted_edge_list.size();
- SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
- << " edges";
-
- boost::filesystem::ofstream hsgr_output_stream(graphOut, std::ios::binary);
- hsgr_output_stream.write((char *)&fingerprint_orig, sizeof(FingerPrint));
- for (const QueryEdge &edge : contracted_edge_list)
- {
- BOOST_ASSERT(UINT_MAX != edge.source);
- BOOST_ASSERT(UINT_MAX != edge.target);
-
- max_used_node_id = std::max(max_used_node_id, edge.source);
- max_used_node_id = std::max(max_used_node_id, edge.target);
- }
- SimpleLogger().Write(logDEBUG) << "input graph has " << number_of_edge_based_nodes
- << " nodes";
- SimpleLogger().Write(logDEBUG) << "contracted graph has " << max_used_node_id << " nodes";
- max_used_node_id += 1;
-
- std::vector<StaticGraph<EdgeData>::NodeArrayEntry> node_array;
- node_array.resize(number_of_edge_based_nodes + 1);
-
- SimpleLogger().Write() << "Building node array";
- StaticGraph<EdgeData>::EdgeIterator edge = 0;
- StaticGraph<EdgeData>::EdgeIterator position = 0;
- StaticGraph<EdgeData>::EdgeIterator last_edge = edge;
-
- for (StaticGraph<EdgeData>::NodeIterator node = 0; node < max_used_node_id; ++node)
- {
- last_edge = edge;
- while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node))
- {
- ++edge;
- }
- node_array[node].first_edge = position; //=edge
- position += edge - last_edge; // remove
- }
-
- for (unsigned sentinel_counter = max_used_node_id; sentinel_counter != node_array.size();
- ++sentinel_counter)
- {
- // sentinel element, guarded against underflow
- node_array[sentinel_counter].first_edge = contracted_edge_count;
- }
-
- unsigned node_array_size = node_array.size();
- // serialize crc32, aka checksum
- hsgr_output_stream.write((char *)&node_based_edge_list_CRC32, sizeof(unsigned));
- // serialize number of nodes
- hsgr_output_stream.write((char *)&node_array_size, sizeof(unsigned));
- // serialize number of edges
- hsgr_output_stream.write((char *)&contracted_edge_count, sizeof(unsigned));
- // serialize all nodes
- if (node_array_size > 0)
- {
- hsgr_output_stream.write((char *)&node_array[0],
- sizeof(StaticGraph<EdgeData>::NodeArrayEntry) * node_array_size);
- }
- // serialize all edges
-
- SimpleLogger().Write() << "Building edge array";
- edge = 0;
- int number_of_used_edges = 0;
-
- StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
- for (unsigned edge = 0; edge < contracted_edge_list.size(); ++edge)
- {
- // no eigen loops
- BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target);
- current_edge.target = contracted_edge_list[edge].target;
- current_edge.data = contracted_edge_list[edge].data;
-
- // every target needs to be valid
- BOOST_ASSERT(current_edge.target < max_used_node_id);
-#ifndef NDEBUG
- if (current_edge.data.distance <= 0)
- {
- SimpleLogger().Write(logWARNING)
- << "Edge: " << edge << ",source: " << contracted_edge_list[edge].source
- << ", target: " << contracted_edge_list[edge].target
- << ", dist: " << current_edge.data.distance;
-
- SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node "
- << contracted_edge_list[edge].source << "/"
- << node_array.size() - 1;
- return 1;
- }
-#endif
- hsgr_output_stream.write((char *)¤t_edge,
- sizeof(StaticGraph<EdgeData>::EdgeArrayEntry));
- ++number_of_used_edges;
- }
- hsgr_output_stream.close();
-
- TIMER_STOP(preparing);
-
- SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
- SimpleLogger().Write() << "Expansion : "
- << (number_of_node_based_nodes / TIMER_SEC(expansion))
- << " nodes/sec and "
- << (number_of_edge_based_nodes / TIMER_SEC(expansion))
- << " edges/sec";
-
- SimpleLogger().Write() << "Contraction: "
- << (number_of_edge_based_nodes / TIMER_SEC(contraction))
- << " nodes/sec and "
- << number_of_used_edges / TIMER_SEC(contraction)
- << " edges/sec";
-
- node_array.clear();
- SimpleLogger().Write() << "finished preprocessing";
+ return Prepare().Process(argc, argv);
}
catch (boost::program_options::too_many_positional_options_error &)
{
@@ -519,5 +50,4 @@ int main(int argc, char *argv[])
SimpleLogger().Write(logWARNING) << "Exception occured: " << e.what() << std::endl;
return 1;
}
- return 0;
}
diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua
index 3efa3d0..713c6b7 100644
--- a/profiles/bicycle.lua
+++ b/profiles/bicycle.lua
@@ -1,4 +1,5 @@
require("lib/access")
+require("lib/maxspeed")
-- Begin of globals
barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true }
@@ -94,7 +95,13 @@ u_turn_penalty = 20
use_turn_restrictions = false
turn_penalty = 60
turn_bias = 1.4
--- End of globals
+
+
+--modes
+mode_normal = 1
+mode_pushing = 2
+mode_ferry = 3
+mode_train = 4
local function parse_maxspeed(source)
@@ -118,42 +125,40 @@ function get_exceptions(vector)
end
end
-function node_function (node)
- local barrier = node.tags:Find ("barrier")
+function node_function (node, result)
+ local barrier = node:get_value_by_key("barrier")
local access = Access.find_access_tag(node, access_tags_hierachy)
- local traffic_signal = node.tags:Find("highway")
+ local traffic_signal = node:get_value_by_key("highway")
-- flag node if it carries a traffic light
- if traffic_signal == "traffic_signals" then
- node.traffic_light = true
+ if traffic_signal and traffic_signal == "traffic_signals" then
+ result.traffic_lights = true
end
-- parse access and barrier tags
if access and access ~= "" then
if access_tag_blacklist[access] then
- node.bollard = true
+ result.barrier = true
else
- node.bollard = false
+ result.barrier = false
end
elseif barrier and barrier ~= "" then
if barrier_whitelist[barrier] then
- node.bollard = false
+ result.barrier = false
else
- node.bollard = true
+ result.barrier = true
end
end
-
- -- return 1
end
-function way_function (way)
+function way_function (way, result)
-- initial routability check, filters out buildings, boundaries, etc
- local highway = way.tags:Find("highway")
- local route = way.tags:Find("route")
- local man_made = way.tags:Find("man_made")
- local railway = way.tags:Find("railway")
- local amenity = way.tags:Find("amenity")
- local public_transport = way.tags:Find("public_transport")
+ local highway = way:get_value_by_key("highway")
+ local route = way:get_value_by_key("route")
+ local man_made = way:get_value_by_key("man_made")
+ 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")
if (not highway or highway == '') and
(not route or route == '') and
(not railway or railway=='') and
@@ -161,208 +166,216 @@ function way_function (way)
(not man_made or man_made=='') and
(not public_transport or public_transport=='')
then
- return 0
+ return
end
-- don't route on ways or railways that are still under construction
if highway=='construction' or railway=='construction' then
- return 0
+ return
end
-- access
local access = Access.find_access_tag(way, access_tags_hierachy)
- if access_tag_blacklist[access] then
- return 0
+ if access and access_tag_blacklist[access] then
+ return
end
-- other tags
- local name = way.tags:Find("name")
- local ref = way.tags:Find("ref")
- local junction = way.tags:Find("junction")
- local maxspeed = parse_maxspeed(way.tags:Find ( "maxspeed") )
- local maxspeed_forward = parse_maxspeed(way.tags:Find( "maxspeed:forward"))
- local maxspeed_backward = parse_maxspeed(way.tags:Find( "maxspeed:backward"))
- local barrier = way.tags:Find("barrier")
- local oneway = way.tags:Find("oneway")
- local onewayClass = way.tags:Find("oneway:bicycle")
- local cycleway = way.tags:Find("cycleway")
- local cycleway_left = way.tags:Find("cycleway:left")
- local cycleway_right = way.tags:Find("cycleway:right")
- local duration = way.tags:Find("duration")
- local service = way.tags:Find("service")
- local area = way.tags:Find("area")
- local foot = way.tags:Find("foot")
- local surface = way.tags:Find("surface")
+ local name = way:get_value_by_key("name")
+ local ref = way:get_value_by_key("ref")
+ local junction = way:get_value_by_key("junction")
+ local maxspeed = parse_maxspeed(way:get_value_by_key ( "maxspeed") )
+ local maxspeed_forward = parse_maxspeed(way:get_value_by_key( "maxspeed:forward"))
+ local maxspeed_backward = parse_maxspeed(way:get_value_by_key( "maxspeed:backward"))
+ local barrier = way:get_value_by_key("barrier")
+ local oneway = way:get_value_by_key("oneway")
+ local onewayClass = way:get_value_by_key("oneway:bicycle")
+ local cycleway = way:get_value_by_key("cycleway")
+ local cycleway_left = way:get_value_by_key("cycleway:left")
+ local cycleway_right = way:get_value_by_key("cycleway:right")
+ local duration = way:get_value_by_key("duration")
+ local service = way:get_value_by_key("service")
+ local area = way:get_value_by_key("area")
+ local foot = way:get_value_by_key("foot")
+ local surface = way:get_value_by_key("surface")
+ local bicycle = way:get_value_by_key("bicycle")
-- name
- if "" ~= ref and "" ~= name then
- way.name = name .. ' / ' .. ref
- elseif "" ~= ref then
- way.name = ref
- elseif "" ~= name then
- way.name = name
- else
+ if ref and "" ~= ref and name and "" ~= name then
+ result.name = name .. ' / ' .. ref
+ elseif ref and "" ~= ref then
+ result.name = ref
+ elseif name and "" ~= name then
+ result.name = name
+ elseif highway then
-- if no name exists, use way type
-- this encoding scheme is excepted to be a temporary solution
- way.name = "{highway:"..highway.."}"
+ result.name = "{highway:"..highway.."}"
end
-- roundabout handling
- if "roundabout" == junction then
- way.roundabout = true;
+ if junction and "roundabout" == junction then
+ result.roundabout = true;
end
-- speed
if route_speeds[route] then
-- ferries (doesn't cover routes tagged using relations)
- way.direction = Way.bidirectional
- way.ignore_in_grid = true
- if durationIsValid(duration) then
- way.duration = math.max( 1, parseDuration(duration) )
+ result.forward_mode = mode_ferry
+ result.backward_mode = mode_ferry
+ result.ignore_in_grid = true
+ if duration and durationIsValid(duration) then
+ result.duration = math.max( 1, parseDuration(duration) )
else
- way.speed = route_speeds[route]
+ result.forward_speed = route_speeds[route]
+ result.backward_speed = route_speeds[route]
end
elseif railway and platform_speeds[railway] then
-- railway platforms (old tagging scheme)
- way.speed = platform_speeds[railway]
+ result.forward_speed = platform_speeds[railway]
+ result.backward_speed = platform_speeds[railway]
elseif platform_speeds[public_transport] then
-- public_transport platforms (new tagging platform)
- way.speed = platform_speeds[public_transport]
+ result.forward_speed = platform_speeds[public_transport]
+ result.backward_speed = platform_speeds[public_transport]
elseif railway and railway_speeds[railway] then
+ result.forward_mode = mode_train
+ result.backward_mode = mode_train
-- railways
if access and access_tag_whitelist[access] then
- way.speed = railway_speeds[railway]
- way.direction = Way.bidirectional
+ result.forward_speed = railway_speeds[railway]
+ result.backward_speed = railway_speeds[railway]
end
elseif amenity and amenity_speeds[amenity] then
-- parking areas
- way.speed = amenity_speeds[amenity]
+ result.forward_speed = amenity_speeds[amenity]
+ result.backward_speed = amenity_speeds[amenity]
elseif bicycle_speeds[highway] then
-- regular ways
- way.speed = bicycle_speeds[highway]
+ result.forward_speed = bicycle_speeds[highway]
+ result.backward_speed = bicycle_speeds[highway]
elseif access and access_tag_whitelist[access] then
-- unknown way, but valid access tag
- way.speed = default_speed
+ result.forward_speed = default_speed
+ result.backward_speed = default_speed
else
-- biking not allowed, maybe we can push our bike?
-- essentially requires pedestrian profiling, for example foot=no mean we can't push a bike
- -- TODO: if we can push, the way should be marked as pedestrion mode, but there's no way to do it yet from lua..
- if foot ~= 'no' then
+ if foot ~= 'no' and junction ~= "roundabout" then
if pedestrian_speeds[highway] then
-- pedestrian-only ways and areas
- way.speed = pedestrian_speeds[highway]
+ result.forward_speed = pedestrian_speeds[highway]
+ result.backward_speed = pedestrian_speeds[highway]
+ result.forward_mode = mode_pushing
+ result.backward_mode = mode_pushing
elseif man_made and man_made_speeds[man_made] then
-- man made structures
- way.speed = man_made_speeds[man_made]
+ result.forward_speed = man_made_speeds[man_made]
+ result.backward_speed = man_made_speeds[man_made]
+ result.forward_mode = mode_pushing
+ result.backward_mode = mode_pushing
elseif foot == 'yes' then
- way.speed = walking_speed
+ result.forward_speed = walking_speed
+ result.backward_speed = walking_speed
+ result.forward_mode = mode_pushing
+ result.backward_mode = mode_pushing
+ elseif foot_forward == 'yes' then
+ result.forward_speed = walking_speed
+ result.forward_mode = mode_pushing
+ result.backward_mode = 0
+ elseif foot_backward == 'yes' then
+ result.forward_speed = walking_speed
+ result.forward_mode = 0
+ result.backward_mode = mode_pushing
end
end
end
-- direction
- way.direction = Way.bidirectional
local impliedOneway = false
if junction == "roundabout" or highway == "motorway_link" or highway == "motorway" then
- way.direction = Way.oneway
impliedOneway = true
end
if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then
- way.direction = Way.oneway
+ result.backward_mode = 0
elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then
- way.direction = Way.bidirectional
+ -- prevent implied oneway
elseif onewayClass == "-1" then
- way.direction = Way.opposite
+ result.forward_mode = 0
elseif oneway == "no" or oneway == "0" or oneway == "false" then
- way.direction = Way.bidirectional
+ -- prevent implied oneway
elseif cycleway and string.find(cycleway, "opposite") == 1 then
if impliedOneway then
- way.direction = Way.opposite
- else
- way.direction = Way.bidirectional
+ result.forward_mode = 0
+ result.backward_mode = mode_normal
+ result.backward_speed = bicycle_speeds["cycleway"]
end
elseif cycleway_left and cycleway_tags[cycleway_left] and cycleway_right and cycleway_tags[cycleway_right] then
- way.direction = Way.bidirectional
+ -- prevent implied
elseif cycleway_left and cycleway_tags[cycleway_left] then
if impliedOneway then
- way.direction = Way.opposite
- else
- way.direction = Way.bidirectional
+ result.forward_mode = 0
+ result.backward_mode = mode_normal
+ result.backward_speed = bicycle_speeds["cycleway"]
end
elseif cycleway_right and cycleway_tags[cycleway_right] then
if impliedOneway then
- way.direction = Way.oneway
- else
- way.direction = Way.bidirectional
+ result.forward_mode = mode_normal
+ result.backward_speed = bicycle_speeds["cycleway"]
+ result.backward_mode = 0
end
elseif oneway == "-1" then
- way.direction = Way.opposite
- elseif oneway == "yes" or oneway == "1" or oneway == "true" then
- way.direction = Way.oneway
+ result.forward_mode = 0
+ elseif oneway == "yes" or oneway == "1" or oneway == "true" or impliedOneway then
+ result.backward_mode = 0
end
-- pushing bikes
if bicycle_speeds[highway] or pedestrian_speeds[highway] then
- if foot ~= 'no' then
- if junction ~= "roundabout" then
- if way.direction == Way.oneway then
- way.backward_speed = walking_speed
- elseif way.direction == Way.opposite then
- way.backward_speed = walking_speed
- way.speed = way.speed
- end
+ if foot ~= "no" and junction ~= "roundabout" then
+ if result.backward_mode == 0 then
+ result.backward_speed = walking_speed
+ result.backward_mode = mode_pushing
+ elseif result.forward_mode == 0 then
+ result.forward_speed = walking_speed
+ result.forward_mode = mode_pushing
end
end
- if way.backward_speed == way.speed then
- -- TODO: no way yet to mark a way as pedestrian mode if forward/backward speeds are equal
- way.direction = Way.bidirectional
- end
end
-- cycleways
if cycleway and cycleway_tags[cycleway] then
- way.speed = bicycle_speeds["cycleway"]
+ result.forward_speed = bicycle_speeds["cycleway"]
elseif cycleway_left and cycleway_tags[cycleway_left] then
- way.speed = bicycle_speeds["cycleway"]
+ result.forward_speed = bicycle_speeds["cycleway"]
elseif cycleway_right and cycleway_tags[cycleway_right] then
- way.speed = bicycle_speeds["cycleway"]
+ result.forward_speed = bicycle_speeds["cycleway"]
+ end
+
+ -- dismount
+ if bicycle == "dismount" then
+ result.forward_mode = mode_pushing
+ result.backward_mode = mode_pushing
+ result.forward_speed = walking_speed
+ result.backward_speed = walking_speed
end
-- surfaces
if surface then
surface_speed = surface_speeds[surface]
if surface_speed then
- if way.speed > 0 then
- way.speed = surface_speed
+ if result.forward_speed > 0 then
+ result.forward_speed = surface_speed
end
- if way.backward_speed > 0 then
- way.backward_speed = surface_speed
+ if result.backward_speed > 0 then
+ result.backward_speed = surface_speed
end
end
end
-- maxspeed
- -- TODO: maxspeed of backward direction
- if take_minimum_of_speeds then
- if maxspeed and maxspeed>0 then
- way.speed = math.min(way.speed, maxspeed)
- end
- end
-
- -- Override speed settings if explicit forward/backward maxspeeds are given
- if way.speed > 0 and maxspeed_forward ~= nil and maxspeed_forward > 0 then
- if Way.bidirectional == way.direction then
- way.backward_speed = way.speed
- end
- way.speed = maxspeed_forward
- end
- if maxspeed_backward ~= nil and maxspeed_backward > 0 then
- way.backward_speed = maxspeed_backward
- end
-
- way.type = 1
- return 1
+ MaxSpeed.limit( result, maxspeed, maxspeed_forward, maxspeed_backward )
end
function turn_function (angle)
diff --git a/profiles/car.lua b/profiles/car.lua
index 9c65852..cd1f06b 100644
--- a/profiles/car.lua
+++ b/profiles/car.lua
@@ -1,7 +1,7 @@
-- Begin of globals
--require("lib/access") --function temporarily inlined
-barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = 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, ["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_restricted = { ["destination"] = true, ["delivery"] = true }
@@ -13,15 +13,15 @@ restriction_exception_tags = { "motorcar", "motor_vehicle", "vehicle" }
speed_profile = {
["motorway"] = 90,
- ["motorway_link"] = 75,
+ ["motorway_link"] = 45,
["trunk"] = 85,
- ["trunk_link"] = 70,
+ ["trunk_link"] = 40,
["primary"] = 65,
- ["primary_link"] = 60,
+ ["primary_link"] = 30,
["secondary"] = 55,
- ["secondary_link"] = 50,
+ ["secondary_link"] = 25,
["tertiary"] = 40,
- ["tertiary_link"] = 30,
+ ["tertiary_link"] = 20,
["unclassified"] = 25,
["residential"] = 25,
["living_street"] = 10,
@@ -32,13 +32,106 @@ speed_profile = {
["default"] = 10
}
+
+-- surface/trackype/smoothness
+-- values were estimated from looking at the photos at the relevant wiki pages
+
+-- max speed for surfaces
+surface_speeds = {
+ ["asphalt"] = nil, -- nil mean no limit. removing the line has the same effect
+ ["concrete"] = nil,
+ ["concrete:plates"] = nil,
+ ["concrete:lanes"] = nil,
+ ["paved"] = nil,
+
+ ["cement"] = 80,
+ ["compacted"] = 80,
+ ["fine_gravel"] = 80,
+
+ ["paving_stones"] = 60,
+ ["metal"] = 60,
+ ["bricks"] = 60,
+
+ ["grass"] = 40,
+ ["wood"] = 40,
+ ["sett"] = 40,
+ ["grass_paver"] = 40,
+ ["gravel"] = 40,
+ ["unpaved"] = 40,
+ ["ground"] = 40,
+ ["dirt"] = 40,
+ ["pebblestone"] = 40,
+ ["tartan"] = 40,
+
+ ["cobblestone"] = 30,
+ ["clay"] = 30,
+
+ ["earth"] = 20,
+ ["stone"] = 20,
+ ["rocky"] = 20,
+ ["sand"] = 20,
+
+ ["mud"] = 10
+}
+
+-- max speed for tracktypes
+tracktype_speeds = {
+ ["grade1"] = 60,
+ ["grade2"] = 40,
+ ["grade3"] = 30,
+ ["grade4"] = 25,
+ ["grade5"] = 20
+}
+
+-- max speed for smoothnesses
+smoothness_speeds = {
+ ["intermediate"] = 80,
+ ["bad"] = 40,
+ ["very_bad"] = 20,
+ ["horrible"] = 10,
+ ["very_horrible"] = 5,
+ ["impassable"] = 0
+}
+
+-- http://wiki.openstreetmap.org/wiki/Speed_limits
+maxspeed_table_default = {
+ ["urban"] = 50,
+ ["rural"] = 90,
+ ["trunk"] = 110,
+ ["motorway"] = 130
+}
+
+-- List only exceptions
+maxspeed_table = {
+ ["ch:rural"] = 80,
+ ["ch:trunk"] = 100,
+ ["ch:motorway"] = 120,
+ ["de:living_street"] = 7,
+ ["ru:living_street"] = 20,
+ ["ru:urban"] = 60,
+ ["ua:urban"] = 60,
+ ["at:rural"] = 100,
+ ["de:rural"] = 100,
+ ["at:trunk"] = 100,
+ ["cz:trunk"] = 0,
+ ["ro:trunk"] = 100,
+ ["cz:motorway"] = 0,
+ ["de:motorway"] = 0,
+ ["ru:motorway"] = 110,
+ ["gb:nsl_single"] = (60*1609)/1000,
+ ["gb:nsl_dual"] = (70*1609)/1000,
+ ["gb:motorway"] = (70*1609)/1000,
+ ["uk:nsl_single"] = (60*1609)/1000,
+ ["uk:nsl_dual"] = (70*1609)/1000,
+ ["uk:motorway"] = (70*1609)/1000
+}
+
traffic_signal_penalty = 2
+use_turn_restrictions = true
--- End of globals
local take_minimum_of_speeds = false
local obey_oneway = true
local obey_bollards = true
-local use_turn_restrictions = true
local ignore_areas = true -- future feature
local u_turn_penalty = 20
@@ -48,14 +141,18 @@ local max = math.max
local speed_reduction = 0.8
-local function find_access_tag(source,access_tags_hierachy)
+--modes
+local mode_normal = 1
+local mode_ferry = 2
+
+local function find_access_tag(source, access_tags_hierachy)
for i,v in ipairs(access_tags_hierachy) do
- local has_tag = source.tags:Holds(v)
- if has_tag then
- return source.tags:Find(v)
+ local access_tag = source:get_value_by_key(v)
+ if access_tag and "" ~= access_tag then
+ return access_tag
end
end
- return nil
+ return ""
end
function get_exceptions(vector)
@@ -69,11 +166,21 @@ local function parse_maxspeed(source)
return 0
end
local n = tonumber(source:match("%d*"))
- if not n then
- n = 0
- end
- if string.match(source, "mph") or string.match(source, "mp/h") then
- n = (n*1609)/1000;
+ if n then
+ if string.match(source, "mph") or string.match(source, "mp/h") then
+ n = (n*1609)/1000;
+ end
+ else
+ -- parse maxspeed like FR:urban
+ source = string.lower(source)
+ n = maxspeed_table[source]
+ if not n then
+ local highway_type = string.match(source, "%a%a:(%a+)")
+ n = maxspeed_table_default[highway_type]
+ if not n then
+ n = 0
+ end
+ end
end
return n
end
@@ -86,61 +193,59 @@ end
-- return penalty
-- end
-function node_function (node)
- local access = find_access_tag(node, access_tags_hierachy)
-
- --flag node if it carries a traffic light
- if node.tags:Holds("highway") then
- if node.tags:Find("highway") == "traffic_signals" then
- node.traffic_light = true;
- end
- end
-
+function node_function (node, result)
-- parse access and barrier tags
- if access and access ~= "" then
+ local access = find_access_tag(node, access_tags_hierachy)
+ if access ~= "" then
if access_tag_blacklist[access] then
- node.bollard = true
+ result.barrier = true
end
- elseif node.tags:Holds("barrier") then
- local barrier = node.tags:Find("barrier")
- if barrier_whitelist[barrier] then
- return
- else
- node.bollard = true
+ else
+ local barrier = node:get_value_by_key("barrier")
+ if barrier and "" ~= barrier then
+ if barrier_whitelist[barrier] then
+ return
+ else
+ result.barrier = true
+ end
end
end
+
+ -- check if node is a traffic light
+ local tag = node:get_value_by_key("highway")
+ if tag and "traffic_signals" == tag then
+ result.traffic_lights = true;
+ end
end
-function way_function (way)
+function way_function (way, result)
+ local highway = way:get_value_by_key("highway")
+ local route = way:get_value_by_key("route")
+
+ if not ((highway and highway ~= "") or (route and route ~= "")) then
+ return
+ end
+
-- we dont route over areas
- local is_area = way.tags:Holds("area")
- if ignore_areas and is_area then
- local area = way.tags:Find("area")
- if "yes" == area then
- return
- end
+ local area = way:get_value_by_key("area")
+ if ignore_areas and area and "yes" == area then
+ return
end
-- check if oneway tag is unsupported
- local oneway = way.tags:Find("oneway")
- if "reversible" == oneway then
+ local oneway = way:get_value_by_key("oneway")
+ if oneway and "reversible" == oneway then
return
end
- local is_impassable = way.tags:Holds("impassable")
- if is_impassable then
- local impassable = way.tags:Find("impassable")
- if "yes" == impassable then
- return
- end
+ local impassable = way:get_value_by_key("impassable")
+ if impassable and "yes" == impassable then
+ return
end
- local is_status = way.tags:Holds("status")
- if is_status then
- local status = way.tags:Find("status")
- if "impassable" == status then
- return
- end
+ local status = way:get_value_by_key("status")
+ if status and "impassable" == status then
+ return
end
-- Check if we are allowed to access the way
@@ -149,20 +254,18 @@ function way_function (way)
return
end
- -- Second, parse the way according to these properties
- local highway = way.tags:Find("highway")
- local route = way.tags:Find("route")
-
-- Handling ferries and piers
local route_speed = speed_profile[route]
if(route_speed and route_speed > 0) then
highway = route;
- local duration = way.tags:Find("duration")
- if durationIsValid(duration) then
- way.duration = max( parseDuration(duration), 1 );
+ local duration = way:get_value_by_key("duration")
+ if duration and durationIsValid(duration) then
+ result.duration = max( parseDuration(duration), 1 );
end
- way.direction = Way.bidirectional
- way.speed = route_speed
+ result.forward_mode = mode_ferry
+ result.backward_mode = mode_ferry
+ result.forward_speed = route_speed
+ result.backward_speed = route_speed
end
-- leave early of this way is not accessible
@@ -170,104 +273,125 @@ function way_function (way)
return
end
- if way.speed == -1 then
+ if result.forward_speed == -1 then
local highway_speed = speed_profile[highway]
- local max_speed = parse_maxspeed( way.tags:Find("maxspeed") )
+ local max_speed = parse_maxspeed( way:get_value_by_key("maxspeed") )
-- Set the avg speed on the way if it is accessible by road class
if highway_speed then
- if max_speed > highway_speed then
- way.speed = max_speed
+ if max_speed and max_speed > highway_speed then
+ result.forward_speed = max_speed
+ result.backward_speed = max_speed
-- max_speed = math.huge
else
- way.speed = highway_speed
+ result.forward_speed = highway_speed
+ result.backward_speed = highway_speed
end
else
-- Set the avg speed on ways that are marked accessible
if access_tag_whitelist[access] then
- way.speed = speed_profile["default"]
+ result.forward_speed = speed_profile["default"]
+ result.backward_speed = speed_profile["default"]
end
end
if 0 == max_speed then
max_speed = math.huge
end
- way.speed = min(way.speed, max_speed)
+ result.forward_speed = min(result.forward_speed, max_speed)
+ result.backward_speed = min(result.backward_speed, max_speed)
end
- if -1 == way.speed then
+ if -1 == result.forward_speed and -1 == result.backward_speed then
return
end
+ -- reduce speed on bad surfaces
+ local surface = way:get_value_by_key("surface")
+ local tracktype = way:get_value_by_key("tracktype")
+ local smoothness = way:get_value_by_key("smoothness")
+
+ if surface and surface_speeds[surface] then
+ result.forward_speed = math.min(surface_speeds[surface], result.forward_speed)
+ result.backward_speed = math.min(surface_speeds[surface], result.backward_speed)
+ end
+ if tracktype and tracktype_speeds[tracktype] then
+ result.forward_speed = math.min(tracktype_speeds[tracktype], result.forward_speed)
+ result.backward_speed = math.min(tracktype_speeds[tracktype], result.backward_speed)
+ end
+ if smoothness and smoothness_speeds[smoothness] then
+ result.forward_speed = math.min(smoothness_speeds[smoothness], result.forward_speed)
+ result.backward_speed = math.min(smoothness_speeds[smoothness], result.backward_speed)
+ end
+
-- parse the remaining tags
- local name = way.tags:Find("name")
- local ref = way.tags:Find("ref")
- local junction = way.tags:Find("junction")
- -- local barrier = way.tags:Find("barrier")
- -- local cycleway = way.tags:Find("cycleway")
- local service = way.tags:Find("service")
+ local name = way:get_value_by_key("name")
+ local ref = way:get_value_by_key("ref")
+ local junction = way:get_value_by_key("junction")
+ -- local barrier = way:get_value_by_key("barrier", "")
+ -- local cycleway = way:get_value_by_key("cycleway", "")
+ local service = way:get_value_by_key("service")
-- Set the name that will be used for instructions
- if "" ~= ref then
- way.name = ref
- elseif "" ~= name then
- way.name = name
+ if ref and "" ~= ref then
+ result.name = ref
+ elseif name and "" ~= name then
+ result.name = name
-- else
- -- way.name = highway -- if no name exists, use way type
+ -- result.name = highway -- if no name exists, use way type
end
- if "roundabout" == junction then
- way.roundabout = true;
+ if junction and "roundabout" == junction then
+ result.roundabout = true;
end
-- Set access restriction flag if access is allowed under certain restrictions only
if access ~= "" and access_tag_restricted[access] then
- way.is_access_restricted = true
+ result.is_access_restricted = true
end
-- Set access restriction flag if service is allowed under certain restrictions only
- if service ~= "" and service_tag_restricted[service] then
- way.is_access_restricted = true
+ if service and service ~= "" and service_tag_restricted[service] then
+ result.is_access_restricted = true
end
-- Set direction according to tags on way
- way.direction = Way.bidirectional
- if obey_oneway then
+ if obey_oneway then
if oneway == "-1" then
- way.direction = Way.opposite
+ result.forward_mode = 0
elseif oneway == "yes" or
oneway == "1" or
oneway == "true" or
junction == "roundabout" or
(highway == "motorway_link" and oneway ~="no") or
(highway == "motorway" and oneway ~= "no") then
- way.direction = Way.oneway
+ result.backward_mode = 0
end
end
-- Override speed settings if explicit forward/backward maxspeeds are given
- local maxspeed_forward = parse_maxspeed(way.tags:Find( "maxspeed:forward"))
- local maxspeed_backward = parse_maxspeed(way.tags:Find( "maxspeed:backward"))
- if maxspeed_forward > 0 then
- if Way.bidirectional == way.direction then
- way.backward_speed = way.speed
+ local maxspeed_forward = parse_maxspeed(way:get_value_by_key( "maxspeed:forward"))
+ local maxspeed_backward = parse_maxspeed(way:get_value_by_key( "maxspeed:backward"))
+ if maxspeed_forward and maxspeed_forward > 0 then
+ if 0 ~= result.forward_mode and 0 ~= result.backward_mode then
+ result.backward_speed = result.forward_speed
end
- way.speed = maxspeed_forward
+ result.forward_speed = maxspeed_forward
end
- if maxspeed_backward > 0 then
- way.backward_speed = maxspeed_backward
+ if maxspeed_backward and maxspeed_backward > 0 then
+ result.backward_speed = maxspeed_backward
end
-- Override general direction settings of there is a specific one for our mode of travel
if ignore_in_grid[highway] then
- way.ignore_in_grid = true
+ result.ignore_in_grid = true
end
- way.type = 1
-- scale speeds to get better avg driving times
- way.speed = way.speed * speed_reduction
- if maxspeed_backward > 0 then
- way.backward_speed = way.backward_speed*speed_reduction
+ if result.forward_speed > 0 then
+ result.forward_speed = result.forward_speed*speed_reduction + 11;
+ end
+ if result.backward_speed > 0 then
+ result.backward_speed = result.backward_speed*speed_reduction + 11;
end
- return
end
-- These are wrappers to parse vectors of nodes and ways and thus to speed up any tracing JIT
diff --git a/profiles/examples/postgis.lua b/profiles/examples/postgis.lua
index b101a27..6e32e4c 100644
--- a/profiles/examples/postgis.lua
+++ b/profiles/examples/postgis.lua
@@ -65,11 +65,11 @@ function way_function (way)
local cursor = assert( sql_con:execute(sql_query) ) -- execute querty
local row = cursor:fetch( {}, "a" ) -- fetch first (and only) row
- way.speed = 20.0 -- default speed
+ way.forward_speed = 20.0 -- default speed
if row then
local val = tonumber(row.val) -- read 'val' from row
if val > 10 then
- way.speed = way.speed / math.log10( val ) -- reduce speed by amount of industry close by
+ way.forward_speed = way.forward_speed / math.log10( val ) -- reduce speed by amount of industry close by
end
end
cursor:close() -- done with this query
diff --git a/profiles/foot.lua b/profiles/foot.lua
index ae0dd60..5a37097 100644
--- a/profiles/foot.lua
+++ b/profiles/foot.lua
@@ -63,143 +63,149 @@ traffic_signal_penalty = 2
u_turn_penalty = 2
use_turn_restrictions = false
+--modes
+local mode_normal = 1
+local mode_ferry = 2
+
function get_exceptions(vector)
for i,v in ipairs(restriction_exception_tags) do
vector:Add(v)
end
end
-function node_function (node)
- local barrier = node.tags:Find ("barrier")
+function node_function (node, result)
+ local barrier = node:get_value_by_key("barrier")
local access = Access.find_access_tag(node, access_tags_hierachy)
- local traffic_signal = node.tags:Find("highway")
+ local traffic_signal = node:get_value_by_key("highway")
-- flag node if it carries a traffic light
- if traffic_signal == "traffic_signals" then
- node.traffic_light = true
+ if traffic_signal and traffic_signal == "traffic_signals" then
+ result.traffic_light = true
end
-- parse access and barrier tags
if access and access ~= "" then
if access_tag_blacklist[access] then
- node.bollard = true
+ result.barrier = true
else
- node.bollard = false
+ result.barrier = false
end
elseif barrier and barrier ~= "" then
if barrier_whitelist[barrier] then
- node.bollard = false
+ result.barrier = false
else
- node.bollard = true
+ result.barrier = true
end
end
return 1
end
-function way_function (way)
- -- initial routability check, filters out buildings, boundaries, etc
- local highway = way.tags:Find("highway")
- local route = way.tags:Find("route")
- local man_made = way.tags:Find("man_made")
- local railway = way.tags:Find("railway")
- local amenity = way.tags:Find("amenity")
- local public_transport = way.tags:Find("public_transport")
- if (not highway or highway == '') and
+function way_function (way, result)
+ -- initial routability check, filters out buildings, boundaries, etc
+ local highway = way:get_value_by_key("highway")
+ local route = way:get_value_by_key("route")
+ local man_made = way:get_value_by_key("man_made")
+ 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")
+ 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=='')
- then
- return 0
+ (not public_transport or public_transport=='')
+ then
+ return
end
-- don't route on ways that are still under construction
if highway=='construction' then
- return 0
+ return
end
-- access
local access = Access.find_access_tag(way, access_tags_hierachy)
if access_tag_blacklist[access] then
- return 0
+ return
end
- local name = way.tags:Find("name")
- local ref = way.tags:Find("ref")
- local junction = way.tags:Find("junction")
- local onewayClass = way.tags:Find("oneway:foot")
- local duration = way.tags:Find("duration")
- local service = way.tags:Find("service")
- local area = way.tags:Find("area")
- local foot = way.tags:Find("foot")
- local surface = way.tags:Find("surface")
+ local name = way:get_value_by_key("name")
+ local ref = way:get_value_by_key("ref")
+ local junction = way:get_value_by_key("junction")
+ local onewayClass = way:get_value_by_key("oneway:foot")
+ local duration = way:get_value_by_key("duration")
+ local service = way:get_value_by_key("service")
+ local area = way:get_value_by_key("area")
+ local foot = way:get_value_by_key("foot")
+ local surface = way:get_value_by_key("surface")
-- name
- if "" ~= ref and "" ~= name then
- way.name = name .. ' / ' .. ref
- elseif "" ~= ref then
- way.name = ref
- elseif "" ~= name then
- way.name = name
- else
- way.name = "{highway:"..highway.."}" -- if no name exists, use way type
+ if ref and "" ~= ref and name and "" ~= name then
+ result.name = name .. ' / ' .. ref
+ elseif ref and "" ~= ref then
+ result.name = ref
+ elseif name and "" ~= name then
+ result.name = name
+ elseif highway then
+ result.name = "{highway:"..highway.."}" -- if no name exists, use way type
-- this encoding scheme is excepted to be a temporary solution
end
-- roundabouts
if "roundabout" == junction then
- way.roundabout = true;
+ result.roundabout = true;
end
-- speed
if route_speeds[route] then
-- ferries (doesn't cover routes tagged using relations)
- way.direction = Way.bidirectional
- way.ignore_in_grid = true
- if durationIsValid(duration) then
- way.duration = math.max( 1, parseDuration(duration) )
+ result.ignore_in_grid = true
+ if duration and durationIsValid(duration) then
+ result.duration = math.max( 1, parseDuration(duration) )
else
- way.speed = route_speeds[route]
+ result.forward_speed = route_speeds[route]
+ result.backward_speed = route_speeds[route]
end
+ result.forward_mode = mode_ferry
+ result.backward_mode = mode_ferry
elseif railway and platform_speeds[railway] then
-- railway platforms (old tagging scheme)
- way.speed = platform_speeds[railway]
+ result.forward_speed = platform_speeds[railway]
+ result.backward_speed = platform_speeds[railway]
elseif platform_speeds[public_transport] then
-- public_transport platforms (new tagging platform)
- way.speed = platform_speeds[public_transport]
+ result.forward_speed = platform_speeds[public_transport]
+ result.backward_speed = platform_speeds[public_transport]
elseif amenity and amenity_speeds[amenity] then
-- parking areas
- way.speed = amenity_speeds[amenity]
+ result.forward_speed = amenity_speeds[amenity]
+ result.backward_speed = amenity_speeds[amenity]
elseif speeds[highway] then
-- regular ways
- way.speed = speeds[highway]
+ result.forward_speed = speeds[highway]
+ result.backward_speed = speeds[highway]
elseif access and access_tag_whitelist[access] then
-- unknown way, but valid access tag
- way.speed = walking_speed
+ result.forward_speed = walking_speed
+ result.backward_speed = walking_speed
end
-- oneway
if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then
- way.direction = Way.oneway
+ result.backward_mode = 0
elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then
- way.direction = Way.bidirectional
+ -- nothing to do
elseif onewayClass == "-1" then
- way.direction = Way.opposite
- else
- way.direction = Way.bidirectional
+ result.forward_mode = 0
end
-- surfaces
if surface then
surface_speed = surface_speeds[surface]
if surface_speed then
- way.speed = math.min(way.speed, surface_speed)
- way.backward_speed = math.min(way.backward_speed, surface_speed)
+ result.forward_speed = math.min(result.forward_speed, surface_speed)
+ result.backward_speed = math.min(result.backward_speed, surface_speed)
end
end
-
- way.type = 1
- return 1
end
diff --git a/profiles/lib/access.lua b/profiles/lib/access.lua
index 094db62..76d2e2c 100644
--- a/profiles/lib/access.lua
+++ b/profiles/lib/access.lua
@@ -4,10 +4,10 @@ module "Access"
function find_access_tag(source,access_tags_hierachy)
for i,v in ipairs(access_tags_hierachy) do
- local tag = source.tags:Find(v)
- if tag ~= '' then
+ local tag = source:get_value_by_key(v)
+ if tag and tag ~= '' then
return tag
end
end
return nil
-end
\ No newline at end of file
+end
diff --git a/profiles/lib/maxspeed.lua b/profiles/lib/maxspeed.lua
new file mode 100644
index 0000000..aca344a
--- /dev/null
+++ b/profiles/lib/maxspeed.lua
@@ -0,0 +1,17 @@
+local math = math
+
+module "MaxSpeed"
+
+function limit(way,max,maxf,maxb)
+ if maxf and maxf>0 then
+ way.forward_speed = math.min(way.forward_speed, maxf)
+ elseif max and max>0 then
+ way.forward_speed = math.min(way.forward_speed, max)
+ end
+
+ if maxb and maxb>0 then
+ way.backward_speed = math.min(way.backward_speed, maxb)
+ elseif max and max>0 then
+ way.backward_speed = math.min(way.backward_speed, max)
+ end
+end
diff --git a/profiles/testbot.lua b/profiles/testbot.lua
index 66d6599..7bd1416 100644
--- a/profiles/testbot.lua
+++ b/profiles/testbot.lua
@@ -6,10 +6,19 @@
-- Secondary road: 18km/h = 18000m/3600s = 100m/20s
-- Tertiary road: 12km/h = 12000m/3600s = 100m/30s
+-- modes:
+-- 1: normal
+-- 2: route
+-- 3: river downstream
+-- 4: river upstream
+-- 5: steps down
+-- 6: steps up
+
speed_profile = {
["primary"] = 36,
["secondary"] = 18,
["tertiary"] = 12,
+ ["steps"] = 6,
["default"] = 24
}
@@ -36,39 +45,47 @@ function limit_speed(speed, limits)
return speed
end
-function node_function (node)
- local traffic_signal = node.tags:Find("highway")
+function node_function (node, result)
+ local traffic_signal = node:get_value_by_key("highway")
- if traffic_signal == "traffic_signals" then
- node.traffic_light = true;
+ if traffic_signal and traffic_signal == "traffic_signals" then
+ result.traffic_lights = true;
-- TODO: a way to set the penalty value
end
- return 1
end
-function way_function (way)
- local highway = way.tags:Find("highway")
- local name = way.tags:Find("name")
- local oneway = way.tags:Find("oneway")
- local route = way.tags:Find("route")
- local duration = way.tags:Find("duration")
- local maxspeed = tonumber(way.tags:Find ( "maxspeed"))
- local maxspeed_forward = tonumber(way.tags:Find( "maxspeed:forward"))
- local maxspeed_backward = tonumber(way.tags:Find( "maxspeed:backward"))
- local junction = way.tags:Find("junction")
-
- way.name = name
-
- if route ~= nil and durationIsValid(duration) then
- way.duration = math.max( 1, parseDuration(duration) )
+function way_function (way, result)
+ local highway = way:get_value_by_key("highway")
+ local name = way:get_value_by_key("name")
+ local oneway = way:get_value_by_key("oneway")
+ local route = way:get_value_by_key("route")
+ local duration = way:get_value_by_key("duration")
+ local maxspeed = tonumber(way:get_value_by_key ( "maxspeed"))
+ local maxspeed_forward = tonumber(way:get_value_by_key( "maxspeed:forward"))
+ local maxspeed_backward = tonumber(way:get_value_by_key( "maxspeed:backward"))
+ local junction = way:get_value_by_key("junction")
+
+ if name then
+ result.name = name
+ end
+
+ if duration and durationIsValid(duration) then
+ result.duration = math.max( 1, parseDuration(duration) )
+ result.forward_mode = 2
+ result.backward_mode = 2
else
local speed_forw = speed_profile[highway] or speed_profile['default']
local speed_back = speed_forw
if highway == "river" then
local temp_speed = speed_forw;
+ result.forward_mode = 3
+ result.backward_mode = 4
speed_forw = temp_speed*1.5
speed_back = temp_speed/1.5
+ elseif highway == "steps" then
+ result.forward_mode = 5
+ result.backward_mode = 6
end
if maxspeed_forward ~= nil and maxspeed_forward > 0 then
@@ -87,26 +104,19 @@ function way_function (way)
end
end
- way.speed = speed_forw
- if speed_back ~= way_forw then
- way.backward_speed = speed_back
- end
+ result.forward_speed = speed_forw
+ result.backward_speed = speed_back
end
if oneway == "no" or oneway == "0" or oneway == "false" then
- way.direction = Way.bidirectional
+ -- nothing to do
elseif oneway == "-1" then
- way.direction = Way.opposite
+ result.forward_mode = 0
elseif oneway == "yes" or oneway == "1" or oneway == "true" or junction == "roundabout" then
- way.direction = Way.oneway
- else
- way.direction = Way.bidirectional
+ result.backward_mode = 0
end
if junction == 'roundabout' then
- way.roundabout = true
+ result.roundabout = true
end
-
- way.type = 1
- return 1
end
diff --git a/routed.cpp b/routed.cpp
index adf2e2d..1be6dd8 100644
--- a/routed.cpp
+++ b/routed.cpp
@@ -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,
@@ -26,11 +26,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Library/OSRM.h"
-#include "Server/ServerFactory.h"
-#include "Util/GitDescription.h"
+#include "Server/Server.h"
+#include "Util/git_sha.hpp"
#include "Util/ProgramOptions.h"
-#include "Util/SimpleLogger.h"
-#include "Util/FingerPrint.h"
+#include "Util/simple_logger.hpp"
#ifdef __linux__
#include <sys/mman.h>
@@ -41,7 +40,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <signal.h>
#include <chrono>
-#include <functional>
#include <future>
#include <iostream>
#include <thread>
@@ -101,27 +99,16 @@ int main(int argc, const char *argv[])
SimpleLogger().Write(logWARNING) << argv[0] << " could not be locked to RAM";
}
#endif
- SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << ", "
- << "compiled at " << __DATE__ << ", " __TIME__;
+ SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION;
if (use_shared_memory)
{
SimpleLogger().Write(logDEBUG) << "Loading from shared memory";
}
- else
- {
- SimpleLogger().Write() << "HSGR file:\t" << server_paths["hsgrdata"];
- SimpleLogger().Write(logDEBUG) << "Nodes file:\t" << server_paths["nodesdata"];
- SimpleLogger().Write(logDEBUG) << "Edges file:\t" << server_paths["edgesdata"];
- SimpleLogger().Write(logDEBUG) << "Geometry file:\t" << server_paths["geometries"];
- SimpleLogger().Write(logDEBUG) << "RAM file:\t" << server_paths["ramindex"];
- SimpleLogger().Write(logDEBUG) << "Index file:\t" << server_paths["fileindex"];
- SimpleLogger().Write(logDEBUG) << "Names file:\t" << server_paths["namesdata"];
- SimpleLogger().Write(logDEBUG) << "Timestamp file:\t" << server_paths["timestamp"];
- SimpleLogger().Write(logDEBUG) << "Threads:\t" << requested_thread_num;
- SimpleLogger().Write(logDEBUG) << "IP address:\t" << ip_address;
- SimpleLogger().Write(logDEBUG) << "IP port:\t" << ip_port;
- }
+
+ SimpleLogger().Write(logDEBUG) << "Threads:\t" << requested_thread_num;
+ SimpleLogger().Write(logDEBUG) << "IP address:\t" << ip_address;
+ SimpleLogger().Write(logDEBUG) << "IP port:\t" << ip_port;
#ifndef _WIN32
int sig = 0;
sigset_t new_mask;
@@ -131,8 +118,8 @@ int main(int argc, const char *argv[])
#endif
OSRM osrm_lib(server_paths, use_shared_memory);
- Server *routing_server =
- ServerFactory::CreateServer(ip_address, ip_port, requested_thread_num);
+ auto routing_server =
+ Server::CreateServer(ip_address, ip_port, requested_thread_num);
routing_server->GetRequestHandlerPtr().RegisterRoutingMachine(&osrm_lib);
@@ -169,19 +156,19 @@ int main(int argc, const char *argv[])
auto status = future.wait_for(std::chrono::seconds(2));
- if (status != std::future_status::ready)
+ if (status == std::future_status::ready)
{
- SimpleLogger().Write(logWARNING) << "Didn't exit within 2 seconds. Hard abort!";
- server_task.reset(); // just kill it
+ server_thread.join();
}
else
{
- server_thread.join();
+ SimpleLogger().Write(logWARNING) << "Didn't exit within 2 seconds. Hard abort!";
+ server_task.reset(); // just kill it
}
}
SimpleLogger().Write() << "freeing objects";
- delete routing_server;
+ routing_server.reset();
SimpleLogger().Write() << "shutdown completed";
}
catch (const std::exception &e)
diff --git a/RoutingAlgorithms/AlternativePathRouting.h b/routing_algorithms/alternative_path.hpp
similarity index 82%
rename from RoutingAlgorithms/AlternativePathRouting.h
rename to routing_algorithms/alternative_path.hpp
index 3506f93..84b5856 100644
--- a/RoutingAlgorithms/AlternativePathRouting.h
+++ b/routing_algorithms/alternative_path.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,27 +25,31 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ALTERNATIVE_PATH_ROUTING_H
-#define ALTERNATIVE_PATH_ROUTING_H
+#ifndef ALTERNATIVE_PATH_ROUTING_HPP
+#define ALTERNATIVE_PATH_ROUTING_HPP
-#include "BasicRoutingInterface.h"
-#include "../DataStructures/SearchEngineData.h"
+#include "routing_base.hpp"
+#include "../data_structures/search_engine_data.hpp"
+#include "../Util/integer_range.hpp"
+#include "../Util/container.hpp"
#include <boost/assert.hpp>
#include <unordered_map>
+#include <unordered_set>
+
#include <vector>
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 : private BasicRoutingInterface<DataFacadeT>
+template <class DataFacadeT> class AlternativeRouting final : private BasicRoutingInterface<DataFacadeT>
{
- typedef BasicRoutingInterface<DataFacadeT> super;
- typedef typename DataFacadeT::EdgeData EdgeData;
- typedef SearchEngineData::QueryHeap QueryHeap;
- typedef std::pair<NodeID, NodeID> SearchSpaceEdge;
+ using super = BasicRoutingInterface<DataFacadeT>;
+ using EdgeData = typename DataFacadeT::EdgeData;
+ using QueryHeap = SearchEngineData::QueryHeap;
+ using SearchSpaceEdge = std::pair<NodeID, NodeID>;
struct RankedCandidateNode
{
@@ -96,6 +100,11 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
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());
+
if (phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID)
{
// SimpleLogger().Write(logDEBUG) << "fwd-a insert: " <<
@@ -107,8 +116,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
}
if (phantom_node_pair.source_phantom.reverse_node_id != SPECIAL_NODEID)
{
- // SimpleLogger().Write(logDEBUG) << "fwd-b insert: " <<
- // phantom_node_pair.source_phantom.reverse_node_id << ", w: " <<
+ // SimpleLogger().Write(logDEBUG) << "fwd-b insert: " <<
+ // phantom_node_pair.source_phantom.reverse_node_id << ", w: " <<
// -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset();
forward_heap1.Insert(phantom_node_pair.source_phantom.reverse_node_id,
-phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
@@ -144,7 +153,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
&middle_node,
&upper_bound_to_shortest_path_distance,
via_node_candidate_list,
- forward_search_space);
+ forward_search_space,
+ min_edge_offset);
}
if (0 < reverse_heap1.Size())
{
@@ -153,7 +163,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
&middle_node,
&upper_bound_to_shortest_path_distance,
via_node_candidate_list,
- reverse_search_space);
+ reverse_search_space,
+ min_edge_offset);
}
}
@@ -162,7 +173,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
return;
}
- sort_unique_resize(via_node_candidate_list);
+ osrm::sort_unique_resize(via_node_candidate_list);
std::vector<NodeID> packed_forward_path;
std::vector<NodeID> packed_reverse_path;
@@ -170,49 +181,58 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
super::RetrievePackedPathFromSingleHeap(forward_heap1, middle_node, packed_forward_path);
super::RetrievePackedPathFromSingleHeap(reverse_heap1, middle_node, packed_reverse_path);
+ // this set is is used as an indicator if a node is on the shortest path
+ std::unordered_set<NodeID> nodes_in_path(packed_forward_path.size() +
+ packed_reverse_path.size());
+ nodes_in_path.insert(packed_forward_path.begin(), packed_forward_path.end());
+ nodes_in_path.insert(middle_node);
+ nodes_in_path.insert(packed_reverse_path.begin(), packed_reverse_path.end());
+
std::unordered_map<NodeID, int> approximated_forward_sharing;
std::unordered_map<NodeID, int> approximated_reverse_sharing;
- unsigned index_into_forward_path = 0;
// sweep over search space, compute forward sharing for each current edge (u,v)
for (const SearchSpaceEdge ¤t_edge : forward_search_space)
{
const NodeID u = current_edge.first;
const NodeID v = current_edge.second;
- if ((packed_forward_path.size() < index_into_forward_path) &&
- (current_edge == forward_search_space[index_into_forward_path]))
+
+ if (nodes_in_path.find(v) != nodes_in_path.end())
{
- // current_edge is on shortest path => sharing(u):=queue.GetKey(u);
- ++index_into_forward_path;
- approximated_forward_sharing[v] = forward_heap1.GetKey(u);
+ // current_edge is on shortest path => sharing(v):=queue.GetKey(v);
+ approximated_forward_sharing.emplace(v, forward_heap1.GetKey(v));
}
else
{
- // sharing (s) = sharing (t)
- approximated_forward_sharing[v] = approximated_forward_sharing[u];
+ // current edge is not on shortest path. Check if we know a value for the other
+ // endpoint
+ const auto sharing_of_u_iterator = approximated_forward_sharing.find(u);
+ if (sharing_of_u_iterator != approximated_forward_sharing.end())
+ {
+ approximated_forward_sharing.emplace(v, sharing_of_u_iterator->second);
+ }
}
}
- unsigned index_into_reverse_path = 0;
// sweep over search space, compute backward sharing
for (const SearchSpaceEdge ¤t_edge : reverse_search_space)
{
const NodeID u = current_edge.first;
const NodeID v = current_edge.second;
- if ((packed_reverse_path.size() < index_into_reverse_path) &&
- (current_edge == reverse_search_space[index_into_reverse_path]))
+ if (nodes_in_path.find(v) != nodes_in_path.end())
{
// current_edge is on shortest path => sharing(u):=queue.GetKey(u);
- ++index_into_reverse_path;
- approximated_reverse_sharing[v] = reverse_heap1.GetKey(u);
+ approximated_reverse_sharing.emplace(v, reverse_heap1.GetKey(v));
}
else
{
- // sharing (s) = sharing (t)
- const auto rev_iterator = approximated_reverse_sharing.find(u);
- const int rev_sharing =
- (rev_iterator != approximated_reverse_sharing.end()) ? rev_iterator->second : 0;
- approximated_reverse_sharing[v] = rev_sharing;
+ // current edge is not on shortest path. Check if we know a value for the other
+ // endpoint
+ const auto sharing_of_u_iterator = approximated_reverse_sharing.find(u);
+ if (sharing_of_u_iterator != approximated_reverse_sharing.end())
+ {
+ approximated_reverse_sharing.emplace(v, sharing_of_u_iterator->second);
+ }
}
}
@@ -251,8 +271,6 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
}
}
- // SimpleLogger().Write() << preselected_node_list.size() << " passed preselection";
-
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);
@@ -264,10 +282,13 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
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);
- const int maximum_allowed_sharing = static_cast<int>(
- upper_bound_to_shortest_path_distance * VIAPATH_GAMMA);
+ 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 &&
length_of_via_path <= upper_bound_to_shortest_path_distance * (1 + VIAPATH_EPSILON))
{
@@ -289,7 +310,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
upper_bound_to_shortest_path_distance,
&length_of_via_path,
&s_v_middle,
- &v_t_middle))
+ &v_t_middle,
+ min_edge_offset))
{
// select first admissable
selected_via_node = candidate.node;
@@ -329,8 +351,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
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));
+ raw_route_data.alt_source_traversed_in_reverse.push_back((
+ packed_alternate_path.front() != phantom_node_pair.source_phantom.forward_node_id));
raw_route_data.alt_target_traversed_in_reverse.push_back(
(packed_alternate_path.back() != phantom_node_pair.target_phantom.forward_node_id));
@@ -339,7 +361,9 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
packed_alternate_path, phantom_node_pair, raw_route_data.unpacked_alternative);
raw_route_data.alternative_path_length = length_of_via_path;
- } else {
+ }
+ else
+ {
BOOST_ASSERT(raw_route_data.alternative_path_length == INVALID_EDGE_WEIGHT);
}
}
@@ -373,7 +397,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
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 std::vector<NodeID> &packed_shortest_path,
+ const EdgeWeight min_edge_offset)
{
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
super::facade->GetNumberOfNodes());
@@ -399,6 +424,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
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
@@ -411,6 +437,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
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;
@@ -428,48 +455,52 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
// partial unpacking, compute sharing
// First partially unpack s-->v until paths deviate, note length of common path.
- const unsigned s_v_min_path_size =
+ const int64_t s_v_min_path_size =
std::min(packed_s_v_path.size(), packed_shortest_path.size()) - 1;
- for (unsigned i = 0; i < s_v_min_path_size; ++i)
+ for (const int64_t current_node : osrm::irange<int64_t>(0, s_v_min_path_size))
{
- if (packed_s_v_path[i] == packed_shortest_path[i] &&
- packed_s_v_path[i + 1] == packed_shortest_path[i + 1])
+ if (packed_s_v_path[current_node] == packed_shortest_path[current_node] &&
+ packed_s_v_path[current_node + 1] == packed_shortest_path[current_node + 1])
{
- EdgeID edgeID =
- facade->FindEdgeInEitherDirection(packed_s_v_path[i], packed_s_v_path[i + 1]);
+ EdgeID edgeID = facade->FindEdgeInEitherDirection(
+ packed_s_v_path[current_node], packed_s_v_path[current_node + 1]);
*sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
}
else
{
- if (packed_s_v_path[i] == packed_shortest_path[i])
+ if (packed_s_v_path[current_node] == packed_shortest_path[current_node])
{
- super::UnpackEdge(
- packed_s_v_path[i], packed_s_v_path[i + 1], partially_unpacked_via_path);
- super::UnpackEdge(packed_shortest_path[i],
- packed_shortest_path[i + 1],
+ super::UnpackEdge(packed_s_v_path[current_node],
+ packed_s_v_path[current_node + 1],
+ partially_unpacked_via_path);
+ super::UnpackEdge(packed_shortest_path[current_node],
+ packed_shortest_path[current_node + 1],
partially_unpacked_shortest_path);
break;
}
}
}
// traverse partially unpacked edge and note common prefix
- for (int i = 0,
- packed_path_length = std::min(partially_unpacked_via_path.size(),
- partially_unpacked_shortest_path.size()) -
- 1;
- (i < packed_path_length) &&
- (partially_unpacked_via_path[i] == partially_unpacked_shortest_path[i] &&
- partially_unpacked_via_path[i + 1] == partially_unpacked_shortest_path[i + 1]);
- ++i)
- {
- EdgeID edgeID = facade->FindEdgeInEitherDirection(partially_unpacked_via_path[i],
- partially_unpacked_via_path[i + 1]);
- *sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
+ 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]);
+ ++current_node)
+ {
+ EdgeID selected_edge =
+ facade->FindEdgeInEitherDirection(partially_unpacked_via_path[current_node],
+ partially_unpacked_via_path[current_node + 1]);
+ *sharing_of_via_path += facade->GetEdgeData(selected_edge).distance;
}
// Second, partially unpack v-->t in reverse order until paths deviate and note lengths
- int via_path_index = packed_v_t_path.size() - 1;
- int shortest_path_index = packed_shortest_path.size() - 1;
+ int64_t via_path_index = packed_v_t_path.size() - 1;
+ int64_t shortest_path_index = packed_shortest_path.size() - 1;
for (; via_path_index > 0 && shortest_path_index > 0;
--via_path_index, --shortest_path_index)
{
@@ -572,11 +603,17 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
NodeID *middle_node,
int *upper_bound_to_shortest_path_distance,
std::vector<NodeID> &search_space_intersection,
- std::vector<SearchSpaceEdge> &search_space) const
+ std::vector<SearchSpaceEdge> &search_space,
+ const EdgeWeight min_edge_offset) const
{
const NodeID node = forward_heap.DeleteMin();
const int distance = forward_heap.GetKey(node);
- const int scaled_distance = static_cast<int>(distance / (1. + VIAPATH_EPSILON));
+ // const NodeID parentnode = forward_heap.GetData(node).parent;
+ // SimpleLogger().Write() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled edge ("
+ // << parentnode << "," << node << "), dist: " << distance;
+
+ const int scaled_distance =
+ static_cast<int>((distance + min_edge_offset) / (1. + VIAPATH_EPSILON));
if ((INVALID_EDGE_WEIGHT != *upper_bound_to_shortest_path_distance) &&
(scaled_distance > *upper_bound_to_shortest_path_distance))
{
@@ -589,7 +626,6 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
if (reverse_heap.WasInserted(node))
{
search_space_intersection.emplace_back(node);
-
const int new_distance = reverse_heap.GetKey(node) + distance;
if (new_distance < *upper_bound_to_shortest_path_distance)
{
@@ -597,6 +633,11 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
{
*middle_node = node;
*upper_bound_to_shortest_path_distance = new_distance;
+ // SimpleLogger().Write() << "accepted middle_node " << *middle_node << " at
+ // distance " << new_distance;
+ // } else {
+ // SimpleLogger().Write() << "discarded middle_node " << *middle_node << "
+ // at distance " << new_distance;
}
}
}
@@ -641,7 +682,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
const int length_of_shortest_path,
int *length_of_via_path,
NodeID *s_v_middle,
- NodeID *v_t_middle) const
+ NodeID *v_t_middle,
+ const EdgeWeight min_edge_offset) const
{
new_forward_heap.Clear();
new_reverse_heap.Clear();
@@ -658,6 +700,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
existing_forward_heap,
s_v_middle,
&upper_bound_s_v_path_length,
+ min_edge_offset,
false);
}
@@ -676,6 +719,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
existing_reverse_heap,
v_t_middle,
&upper_bound_of_v_t_path_length,
+ min_edge_offset,
true);
}
@@ -844,15 +888,17 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
{
if (!forward_heap3.Empty())
{
- super::RoutingStep(forward_heap3, reverse_heap3, &middle, &upper_bound, 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, false);
+ super::RoutingStep(
+ reverse_heap3, forward_heap3, &middle, &upper_bound, min_edge_offset, false);
}
}
return (upper_bound <= t_test_path_length);
}
};
-#endif /* ALTERNATIVE_PATH_ROUTING_H */
+#endif /* ALTERNATIVE_PATH_ROUTING_HPP */
diff --git a/RoutingAlgorithms/ManyToManyRouting.h b/routing_algorithms/many_to_many.hpp
similarity index 95%
rename from RoutingAlgorithms/ManyToManyRouting.h
rename to routing_algorithms/many_to_many.hpp
index 7819c67..f1e9960 100644
--- a/RoutingAlgorithms/ManyToManyRouting.h
+++ b/routing_algorithms/many_to_many.hpp
@@ -25,11 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MANY_TO_MANY_ROUTING_H
-#define MANY_TO_MANY_ROUTING_H
+#ifndef MANY_TO_MANY_ROUTING_HPP
+#define MANY_TO_MANY_ROUTING_HPP
-#include "BasicRoutingInterface.h"
-#include "../DataStructures/SearchEngineData.h"
+#include "routing_base.hpp"
+#include "../data_structures/search_engine_data.hpp"
#include "../typedefs.h"
#include <boost/assert.hpp>
@@ -39,10 +39,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unordered_map>
#include <vector>
-template <class DataFacadeT> class ManyToManyRouting : public BasicRoutingInterface<DataFacadeT>
+template <class DataFacadeT> class ManyToManyRouting final : public BasicRoutingInterface<DataFacadeT>
{
- typedef BasicRoutingInterface<DataFacadeT> super;
- typedef SearchEngineData::QueryHeap QueryHeap;
+ using super = BasicRoutingInterface<DataFacadeT>;
+ using QueryHeap = SearchEngineData::QueryHeap;
SearchEngineData &engine_working_data;
struct NodeBucket
@@ -54,7 +54,7 @@ template <class DataFacadeT> class ManyToManyRouting : public BasicRoutingInterf
{
}
};
- typedef std::unordered_map<NodeID, std::vector<NodeBucket>> SearchSpaceWithBuckets;
+ using SearchSpaceWithBuckets = std::unordered_map<NodeID, std::vector<NodeBucket>>;
public:
ManyToManyRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
@@ -67,7 +67,7 @@ template <class DataFacadeT> class ManyToManyRouting : public BasicRoutingInterf
std::shared_ptr<std::vector<EdgeWeight>> operator()(const PhantomNodeArray &phantom_nodes_array)
const
{
- const unsigned number_of_locations = static_cast<unsigned>(phantom_nodes_array.size());
+ const auto number_of_locations = phantom_nodes_array.size();
std::shared_ptr<std::vector<EdgeWeight>> result_table =
std::make_shared<std::vector<EdgeWeight>>(number_of_locations * number_of_locations,
std::numeric_limits<EdgeWeight>::max());
diff --git a/RoutingAlgorithms/BasicRoutingInterface.h b/routing_algorithms/routing_base.hpp
similarity index 81%
rename from RoutingAlgorithms/BasicRoutingInterface.h
rename to routing_algorithms/routing_base.hpp
index 464c088..20610ea 100644
--- a/RoutingAlgorithms/BasicRoutingInterface.h
+++ b/routing_algorithms/routing_base.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,14 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef BASIC_ROUTING_INTERFACE_H
-#define BASIC_ROUTING_INTERFACE_H
+#ifndef ROUTING_BASE_HPP
+#define ROUTING_BASE_HPP
-#include "../DataStructures/RawRouteData.h"
-#include "../DataStructures/SearchEngineData.h"
-#include "../DataStructures/TurnInstructions.h"
-#include "../Util/ContainerUtils.h"
-#include "../Util/SimpleLogger.h"
+#include "../data_structures/raw_route_data.hpp"
+#include "../data_structures/search_engine_data.hpp"
+#include "../data_structures/turn_instructions.hpp"
+// #include "../Util/simple_logger.hpp.h"
#include <boost/assert.hpp>
@@ -63,10 +62,15 @@ template <class DataFacadeT> class BasicRoutingInterface
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;
+
if (reverse_heap.WasInserted(node))
{
const int new_distance = reverse_heap.GetKey(node) + distance;
@@ -76,18 +80,22 @@ 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;
}
}
}
- if (distance > *upper_bound)
+ if (distance + min_edge_offset > *upper_bound)
{
+ // SimpleLogger().Write() << "min_edge_offset: " << min_edge_offset;
forward_heap.DeleteAll();
return;
}
// Stalling
- for (auto edge : facade->GetAdjacentEdgeRange(node))
+ for (const auto edge : facade->GetAdjacentEdgeRange(node))
{
const EdgeData &data = facade->GetEdgeData(edge);
const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
@@ -108,7 +116,7 @@ template <class DataFacadeT> class BasicRoutingInterface
}
}
- for (auto edge : facade->GetAdjacentEdgeRange(node))
+ for (const auto edge : facade->GetAdjacentEdgeRange(node))
{
const EdgeData &data = facade->GetEdgeData(edge);
bool forward_directionFlag = (forward_direction ? data.forward : data.backward);
@@ -171,8 +179,8 @@ template <class DataFacadeT> class BasicRoutingInterface
// facade->FindEdge does not suffice here in case of shortcuts.
// The above explanation unclear? Think!
EdgeID smaller_edge_id = SPECIAL_EDGEID;
- int edge_weight = INT_MAX;
- for (auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
+ int edge_weight = std::numeric_limits<EdgeWeight>::max();
+ for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
{
const int weight = facade->GetEdgeData(edge_id).distance;
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
@@ -192,7 +200,7 @@ template <class DataFacadeT> class BasicRoutingInterface
*/
if (SPECIAL_EDGEID == smaller_edge_id)
{
- for (auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
+ for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
{
const int weight = facade->GetEdgeData(edge_id).distance;
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
@@ -218,6 +226,8 @@ template <class DataFacadeT> class BasicRoutingInterface
BOOST_ASSERT_MSG(!ed.shortcut, "original edge flagged as shortcut");
unsigned name_index = facade->GetNameIndexFromEdgeID(ed.id);
const TurnInstruction turn_instruction = facade->GetTurnInstructionForEdgeID(ed.id);
+ const TravelMode travel_mode = facade->GetTravelModeForEdgeID(ed.id);
+
if (!facade->EdgeIsCompressed(ed.id))
{
@@ -225,7 +235,8 @@ template <class DataFacadeT> class BasicRoutingInterface
unpacked_path.emplace_back(facade->GetGeometryIndexForEdgeID(ed.id),
name_index,
turn_instruction,
- ed.distance);
+ ed.distance,
+ travel_mode);
}
else
{
@@ -233,20 +244,20 @@ template <class DataFacadeT> class BasicRoutingInterface
facade->GetUncompressedGeometry(facade->GetGeometryIndexForEdgeID(ed.id),
id_vector);
- const int start_index =
+ const std::size_t start_index =
(unpacked_path.empty()
? ((start_traversed_in_reverse)
? id_vector.size() -
phantom_node_pair.source_phantom.fwd_segment_position - 1
: phantom_node_pair.source_phantom.fwd_segment_position)
: 0);
- const int end_index = id_vector.size();
+ const std::size_t end_index = id_vector.size();
BOOST_ASSERT(start_index >= 0);
BOOST_ASSERT(start_index <= end_index);
- for (int i = start_index; i < end_index; ++i)
+ for (std::size_t i = start_index; i < end_index; ++i)
{
- unpacked_path.emplace_back(id_vector[i], name_index, TurnInstruction::NoTurn, 0);
+ 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;
@@ -258,42 +269,43 @@ template <class DataFacadeT> class BasicRoutingInterface
std::vector<unsigned> id_vector;
facade->GetUncompressedGeometry(phantom_node_pair.target_phantom.packed_geometry_id,
id_vector);
- if (target_traversed_in_reverse)
- {
- std::reverse(id_vector.begin(), id_vector.end());
- }
const bool is_local_path = (phantom_node_pair.source_phantom.packed_geometry_id ==
phantom_node_pair.target_phantom.packed_geometry_id) &&
unpacked_path.empty();
- int start_index = 0;
- int end_index = phantom_node_pair.target_phantom.fwd_segment_position;
- if (target_traversed_in_reverse)
- {
- end_index =
- id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position;
- }
+ std::size_t start_index = 0;
if (is_local_path)
{
start_index = phantom_node_pair.source_phantom.fwd_segment_position;
- end_index = phantom_node_pair.target_phantom.fwd_segment_position;
if (target_traversed_in_reverse)
{
start_index =
id_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position;
- end_index =
- id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position;
}
}
- BOOST_ASSERT(start_index >= 0);
- for (int i = start_index; i != end_index; (start_index < end_index ? ++i : --i))
+ std::size_t end_index = phantom_node_pair.target_phantom.fwd_segment_position;
+ if (target_traversed_in_reverse)
{
- BOOST_ASSERT(i >= -1);
+ std::reverse(id_vector.begin(), id_vector.end());
+ end_index =
+ id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position;
+ }
+
+ if (start_index > end_index)
+ {
+ start_index = std::min(start_index, id_vector.size()-1);
+ }
+
+ for (std::size_t i = start_index; i != end_index; (start_index < end_index ? ++i : --i))
+ {
+ BOOST_ASSERT(i < id_vector.size());
+ BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode>0 );
unpacked_path.emplace_back(PathData{id_vector[i],
- phantom_node_pair.target_phantom.name_id,
- TurnInstruction::NoTurn,
- 0});
+ phantom_node_pair.target_phantom.name_id,
+ TurnInstruction::NoTurn,
+ 0,
+ phantom_node_pair.target_phantom.forward_travel_mode});
}
}
@@ -304,8 +316,8 @@ template <class DataFacadeT> class BasicRoutingInterface
// the last node.
if (unpacked_path.size() > 1)
{
- const unsigned last_index = unpacked_path.size() - 1;
- const unsigned second_to_last_index = last_index - 1;
+ const std::size_t last_index = unpacked_path.size() - 1;
+ const std::size_t second_to_last_index = last_index - 1;
// looks like a trivially true check but tests for underflow
BOOST_ASSERT(last_index > second_to_last_index);
@@ -330,8 +342,8 @@ template <class DataFacadeT> class BasicRoutingInterface
recursion_stack.pop();
EdgeID smaller_edge_id = SPECIAL_EDGEID;
- int edge_weight = INT_MAX;
- for (auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
+ int edge_weight = std::numeric_limits<EdgeWeight>::max();
+ for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
{
const int weight = facade->GetEdgeData(edge_id).distance;
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
@@ -344,7 +356,7 @@ template <class DataFacadeT> class BasicRoutingInterface
if (SPECIAL_EDGEID == smaller_edge_id)
{
- for (auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
+ for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
{
const int weight = facade->GetEdgeData(edge_id).distance;
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
@@ -355,7 +367,7 @@ template <class DataFacadeT> class BasicRoutingInterface
}
}
}
- BOOST_ASSERT_MSG(edge_weight != INT_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)
@@ -379,20 +391,10 @@ template <class DataFacadeT> class BasicRoutingInterface
const NodeID middle_node_id,
std::vector<NodeID> &packed_path) const
{
- NodeID current_node_id = middle_node_id;
- while (current_node_id != forward_heap.GetData(current_node_id).parent)
- {
- current_node_id = forward_heap.GetData(current_node_id).parent;
- packed_path.emplace_back(current_node_id);
- }
+ RetrievePackedPathFromSingleHeap(forward_heap, middle_node_id, packed_path);
std::reverse(packed_path.begin(), packed_path.end());
packed_path.emplace_back(middle_node_id);
- current_node_id = middle_node_id;
- while (current_node_id != reverse_heap.GetData(current_node_id).parent)
- {
- current_node_id = reverse_heap.GetData(current_node_id).parent;
- packed_path.emplace_back(current_node_id);
- }
+ RetrievePackedPathFromSingleHeap(reverse_heap, middle_node_id, packed_path);
}
inline void RetrievePackedPathFromSingleHeap(const SearchEngineData::QueryHeap &search_heap,
@@ -408,4 +410,4 @@ template <class DataFacadeT> class BasicRoutingInterface
}
};
-#endif // BASIC_ROUTING_INTERFACE_H
+#endif // ROUTING_BASE_HPP
diff --git a/RoutingAlgorithms/ShortestPathRouting.h b/routing_algorithms/shortest_path.hpp
similarity index 69%
rename from RoutingAlgorithms/ShortestPathRouting.h
rename to routing_algorithms/shortest_path.hpp
index cc5afe5..cab09ab 100644
--- a/RoutingAlgorithms/ShortestPathRouting.h
+++ b/routing_algorithms/shortest_path.hpp
@@ -1,6 +1,6 @@
/*
-Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -25,19 +25,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SHORTEST_PATH_ROUTING_H
-#define SHORTEST_PATH_ROUTING_H
+#ifndef SHORTEST_PATH_HPP
+#define SHORTEST_PATH_HPP
#include <boost/assert.hpp>
-#include "BasicRoutingInterface.h"
-#include "../DataStructures/SearchEngineData.h"
+#include "routing_base.hpp"
+#include "../data_structures/search_engine_data.hpp"
+#include "../Util/integer_range.hpp"
#include "../typedefs.h"
-template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInterface<DataFacadeT>
+template <class DataFacadeT> class ShortestPathRouting final : public BasicRoutingInterface<DataFacadeT>
{
- typedef BasicRoutingInterface<DataFacadeT> super;
- typedef SearchEngineData::QueryHeap QueryHeap;
+ using super = BasicRoutingInterface<DataFacadeT>;
+ using QueryHeap = SearchEngineData::QueryHeap;
SearchEngineData &engine_working_data;
public:
@@ -49,14 +50,15 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
~ShortestPathRouting() {}
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
+ const std::vector<bool> &uturn_indicators,
RawRouteData &raw_route_data) const
{
int distance1 = 0;
int distance2 = 0;
bool search_from_1st_node = true;
bool search_from_2nd_node = true;
- NodeID middle1 = UINT_MAX;
- NodeID middle2 = UINT_MAX;
+ NodeID middle1 = SPECIAL_NODEID;
+ NodeID middle2 = SPECIAL_NODEID;
std::vector<std::vector<NodeID>> packed_legs1(phantom_nodes_vector.size());
std::vector<std::vector<NodeID>> packed_legs2(phantom_nodes_vector.size());
@@ -72,7 +74,7 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
QueryHeap &forward_heap2 = *(engine_working_data.forwardHeap2);
QueryHeap &reverse_heap2 = *(engine_working_data.backwardHeap2);
- int current_leg = 0;
+ std::size_t current_leg = 0;
// Get distance to next pair of target nodes.
for (const PhantomNodes &phantom_node_pair : phantom_nodes_vector)
{
@@ -80,36 +82,50 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
forward_heap2.Clear();
reverse_heap1.Clear();
reverse_heap2.Clear();
- int local_upper_bound1 = INT_MAX;
- int local_upper_bound2 = INT_MAX;
+ int local_upper_bound1 = INVALID_EDGE_WEIGHT;
+ int local_upper_bound2 = INVALID_EDGE_WEIGHT;
- middle1 = UINT_MAX;
- middle2 = UINT_MAX;
+ 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;
// insert new starting nodes into forward heap, adjusted by previous distances.
- if (search_from_1st_node &&
+ if ((allow_u_turn || search_from_1st_node) &&
phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID)
{
forward_heap1.Insert(
phantom_node_pair.source_phantom.forward_node_id,
- distance1 - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
+ (allow_u_turn ? 0 : distance1) - 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();
forward_heap2.Insert(
phantom_node_pair.source_phantom.forward_node_id,
- distance1 - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
+ (allow_u_turn ? 0 : distance1) - 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();
+
}
- if (search_from_2nd_node &&
+ 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,
- distance2 - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
+ (allow_u_turn ? 0 : distance2) - 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();
forward_heap2.Insert(
phantom_node_pair.source_phantom.reverse_node_id,
- distance2 - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
+ (allow_u_turn ? 0 : distance2) - 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();
}
// insert new backward nodes into backward heap, unadjusted.
@@ -118,27 +134,31 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
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();
+ }
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();
}
// run two-Target Dijkstra routing step.
while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
{
- if (0 < forward_heap1.Size())
+ if (!forward_heap1.Empty())
{
super::RoutingStep(
- forward_heap1, reverse_heap1, &middle1, &local_upper_bound1, true);
+ forward_heap1, reverse_heap1, &middle1, &local_upper_bound1, min_edge_offset, true);
}
- if (0 < reverse_heap1.Size())
+ if (!reverse_heap1.Empty())
{
super::RoutingStep(
- reverse_heap1, forward_heap1, &middle1, &local_upper_bound1, false);
+ reverse_heap1, forward_heap1, &middle1, &local_upper_bound1, min_edge_offset, false);
}
}
@@ -146,15 +166,15 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
{
while (0 < (forward_heap2.Size() + reverse_heap2.Size()))
{
- if (0 < forward_heap2.Size())
+ if (!forward_heap2.Empty())
{
super::RoutingStep(
- forward_heap2, reverse_heap2, &middle2, &local_upper_bound2, true);
+ forward_heap2, reverse_heap2, &middle2, &local_upper_bound2, min_edge_offset, true);
}
- if (0 < reverse_heap2.Size())
+ if (!reverse_heap2.Empty())
{
super::RoutingStep(
- reverse_heap2, forward_heap2, &middle2, &local_upper_bound2, false);
+ reverse_heap2, forward_heap2, &middle2, &local_upper_bound2, min_edge_offset, false);
}
}
}
@@ -180,7 +200,7 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
}
// Was at most one of the two paths not found?
- BOOST_ASSERT_MSG((INT_MAX != distance1 || INT_MAX != 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;
@@ -202,15 +222,17 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
}
// if one of the paths was not found, replace it with the other one.
- if (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(),
temporary_packed_leg2.begin(),
temporary_packed_leg2.end());
local_upper_bound1 = local_upper_bound2;
}
- if (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(),
temporary_packed_leg1.begin(),
temporary_packed_leg1.end());
@@ -223,7 +245,7 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
BOOST_ASSERT((0 == current_leg) || !packed_legs1[current_leg - 1].empty());
BOOST_ASSERT((0 == current_leg) || !packed_legs2[current_leg - 1].empty());
- if (0 < current_leg)
+ if (!allow_u_turn && 0 < current_leg)
{
const NodeID end_id_of_segment1 = packed_legs1[current_leg - 1].back();
const NodeID end_id_of_segment2 = packed_legs2[current_leg - 1].back();
@@ -236,13 +258,8 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
std::swap(temporary_packed_leg1, temporary_packed_leg2);
std::swap(local_upper_bound1, local_upper_bound2);
}
- }
- // remove the shorter path if both legs end at the same segment
- if (0 < current_leg)
- {
- const NodeID start_id_of_leg1 = temporary_packed_leg1.front();
- const NodeID start_id_of_leg2 = temporary_packed_leg2.front();
+ // remove the shorter path if both legs end at the same segment
if (start_id_of_leg1 == start_id_of_leg2)
{
const NodeID last_id_of_packed_legs1 = packed_legs1[current_leg - 1].back();
@@ -270,8 +287,8 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
temporary_packed_leg2.end());
BOOST_ASSERT(packed_legs2[current_leg].size() == temporary_packed_leg2.size());
- if ((packed_legs1[current_leg].back() == packed_legs2[current_leg].back()) &&
- phantom_node_pair.target_phantom.isBidirected())
+ 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();
search_from_1st_node &=
@@ -292,27 +309,27 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
}
raw_route_data.unpacked_path_segments.resize(packed_legs1.size());
- for (unsigned i = 0; i < packed_legs1.size(); ++i)
+ for (const std::size_t index : osrm::irange<std::size_t>(0, packed_legs1.size()))
{
BOOST_ASSERT(!phantom_nodes_vector.empty());
BOOST_ASSERT(packed_legs1.size() == raw_route_data.unpacked_path_segments.size());
- PhantomNodes unpack_phantom_node_pair = phantom_nodes_vector[i];
+ PhantomNodes unpack_phantom_node_pair = phantom_nodes_vector[index];
super::UnpackPath(
// -- packed input
- packed_legs1[i],
+ packed_legs1[index],
// -- start and end of (sub-)route
unpack_phantom_node_pair,
// -- unpacked output
- raw_route_data.unpacked_path_segments[i]);
+ raw_route_data.unpacked_path_segments[index]);
raw_route_data.source_traversed_in_reverse.push_back(
- (packed_legs1[i].front() != phantom_nodes_vector[i].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[i].back() != phantom_nodes_vector[i].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);
}
};
-#endif /* SHORTEST_PATH_ROUTING_H */
+#endif /* SHORTEST_PATH_HPP */
diff --git a/taginfo.json b/taginfo.json
new file mode 100644
index 0000000..17a4f8f
--- /dev/null
+++ b/taginfo.json
@@ -0,0 +1,84 @@
+{
+ "data_format": 1,
+ "data_url": "https://raw.githubusercontent.com/Project-OSRM/osrm-backend/develop/taginfo.json",
+ "project": {
+ "name": "Open Source Routing Machine (car profile)",
+ "description": "High-performance routing engine for shortest paths in road networks.",
+ "project_url": "http://project-osrm.org",
+ "icon_url": "http://project-osrm.org/images/osrm_icon.png",
+ "contact_name": "Dennis Luxen",
+ "contact_email": "info at project-osrm.org"
+ },
+ "tags": [
+ {
+ "key": "highway",
+ "description": "Type of road.",
+ "object_types": [ "way" ]
+ },
+ {
+ "key": "service",
+ "value": "parking_aisle",
+ "object_types": [ "way" ]
+ },
+ {
+ "key": "oneway",
+ "object_types": [ "way" ]
+ },
+ {
+ "key": "area",
+ "value": "yes",
+ "object_types": [ "way" ],
+ "description": "Roads with area=yes are ignored by default."
+ },
+ {
+ "key": "impassable",
+ "description": "This is used by HOT."
+ },
+ {
+ "key": "status",
+ "description": "This is used by HOT."
+ },
+ {
+ "key": "access",
+ "object_types": [ "way" ]
+ },
+ {
+ "key": "barrier"
+ },
+ {
+ "key": "maxspeed",
+ "object_types": [ "way" ]
+ },
+ {
+ "key": "maxspeed:forward",
+ "object_types": [ "way" ]
+ },
+ {
+ "key": "maxspeed:backward",
+ "object_types": [ "way" ]
+ },
+ {
+ "key": "duration"
+ },
+ {
+ "key": "name",
+ "object_types": [ "way" ],
+ "description": "Name of road for navigation instructions."
+ },
+ {
+ "key": "ref",
+ "object_types": [ "way" ],
+ "description": "Ref of road for navigation instructions, overrides name."
+ },
+ {
+ "key": "junction",
+ "object_types": [ "way" ],
+ "value": "roundabout"
+ },
+ {
+ "key": "type",
+ "value": "restriction",
+ "object_types": [ "relation" ]
+ }
+ ]
+}
diff --git a/third_party/osmium/area/assembler.hpp b/third_party/osmium/area/assembler.hpp
new file mode 100644
index 0000000..155fa24
--- /dev/null
+++ b/third_party/osmium/area/assembler.hpp
@@ -0,0 +1,783 @@
+#ifndef OSMIUM_AREA_ASSEMBLER_HPP
+#define OSMIUM_AREA_ASSEMBLER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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 <algorithm>
+#include <iostream>
+#include <iterator>
+#include <list>
+#include <map>
+#include <vector>
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/area.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/tags/filter.hpp>
+
+#include <osmium/area/detail/proto_ring.hpp>
+#include <osmium/area/detail/node_ref_segment.hpp>
+#include <osmium/area/detail/segment_list.hpp>
+#include <osmium/area/problem_reporter.hpp>
+
+namespace osmium {
+
+ namespace area {
+
+ using osmium::area::detail::ProtoRing;
+
+ struct AssemblerConfig {
+
+ osmium::area::ProblemReporter* problem_reporter;
+
+ // Enables debug output to stderr
+ bool debug;
+
+ explicit AssemblerConfig(osmium::area::ProblemReporter* pr = nullptr, bool d=false) :
+ problem_reporter(pr),
+ debug(d) {
+ }
+
+ /**
+ * Enable or disable debug output to stderr. This is for Osmium
+ * developers only.
+ */
+ void enable_debug_output(bool d=true) {
+ debug = d;
+ }
+
+ }; // struct AssemblerConfig
+
+ /**
+ * Assembles area objects from multipolygon relations and their
+ * members. This is called by the MultipolygonCollector object
+ * after all members have been collected.
+ */
+ class Assembler {
+
+ const AssemblerConfig m_config;
+
+ // The way segments
+ osmium::area::detail::SegmentList m_segment_list;
+
+ // The rings we are building from the way segments
+ std::list<ProtoRing> m_rings;
+
+ std::vector<ProtoRing*> m_outer_rings;
+ std::vector<ProtoRing*> m_inner_rings;
+
+ int m_inner_outer_mismatches { 0 };
+
+ bool debug() const {
+ return m_config.debug;
+ }
+
+ /**
+ * Checks whether the given NodeRefs have the same location.
+ * Uses the actual location for the test, not the id. If both
+ * have the same location, but not the same id, a problem
+ * point will be added to the list of problem points.
+ */
+ bool has_same_location(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) {
+ if (nr1.location() != nr2.location()) {
+ return false;
+ }
+ if (nr1.ref() != nr2.ref()) {
+ if (m_config.problem_reporter) {
+ m_config.problem_reporter->report_duplicate_node(nr1.ref(), nr2.ref(), nr1.location());
+ }
+ }
+ return true;
+ }
+
+ void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Way& way) const {
+ osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
+ for (const osmium::Tag& tag : way.tags()) {
+ tl_builder.add_tag(tag.key(), tag.value());
+ }
+ }
+
+ void add_common_tags(osmium::builder::TagListBuilder& tl_builder, std::set<const osmium::Way*>& ways) const {
+ std::map<std::string, size_t> counter;
+ for (const osmium::Way* way : ways) {
+ for (const auto& tag : way->tags()) {
+ std::string kv {tag.key()};
+ kv.append(1, '\0');
+ kv.append(tag.value());
+ ++counter[kv];
+ }
+ }
+
+ size_t num_ways = ways.size();
+ for (const auto& t_c : counter) {
+ if (debug()) {
+ std::cerr << " tag " << t_c.first << " is used " << t_c.second << " times in " << num_ways << " ways\n";
+ }
+ if (t_c.second == num_ways) {
+ size_t len = std::strlen(t_c.first.c_str());
+ tl_builder.add_tag(t_c.first.c_str(), t_c.first.c_str() + len + 1);
+ }
+ }
+ }
+
+ struct MPFilter : public osmium::tags::KeyFilter {
+
+ MPFilter() : osmium::tags::KeyFilter(true) {
+ add(false, "type");
+ add(false, "created_by");
+ add(false, "source");
+ add(false, "note");
+ add(false, "test:id");
+ add(false, "test:section");
+ }
+
+ }; // struct MPFilter
+
+ static MPFilter& filter() {
+ static MPFilter filter;
+ return filter;
+ }
+
+ void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Relation& relation) const {
+ auto count = std::count_if(relation.tags().begin(), relation.tags().end(), filter());
+
+ if (debug()) {
+ std::cerr << " found " << count << " tags on relation (without ignored ones)\n";
+ }
+
+ if (count > 0) {
+ if (debug()) {
+ std::cerr << " use tags from relation\n";
+ }
+
+ // write out all tags except type=*
+ osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
+ for (const osmium::Tag& tag : relation.tags()) {
+ if (strcmp(tag.key(), "type")) {
+ tl_builder.add_tag(tag.key(), tag.value());
+ }
+ }
+ } else {
+ if (debug()) {
+ std::cerr << " use tags from outer ways\n";
+ }
+ std::set<const osmium::Way*> ways;
+ for (const auto& ring : m_outer_rings) {
+ ring->get_ways(ways);
+ }
+ if (ways.size() == 1) {
+ if (debug()) {
+ std::cerr << " only one outer way\n";
+ }
+ osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
+ for (const osmium::Tag& tag : (*ways.begin())->tags()) {
+ tl_builder.add_tag(tag.key(), tag.value());
+ }
+ } else {
+ if (debug()) {
+ std::cerr << " multiple outer ways, get common tags\n";
+ }
+ osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
+ add_common_tags(tl_builder, ways);
+ }
+ }
+ }
+
+ /**
+ * Go through all the rings and find rings that are not closed.
+ * Problems are reported through the problem reporter.
+ *
+ * @returns true if any rings were not closed, false otherwise
+ */
+ bool check_for_open_rings() {
+ bool open_rings = false;
+
+ for (const auto& ring : m_rings) {
+ if (!ring.closed()) {
+ open_rings = true;
+ if (m_config.problem_reporter) {
+ m_config.problem_reporter->report_ring_not_closed(ring.get_segment_front().first().location(), ring.get_segment_back().second().location());
+ }
+ }
+ }
+
+ return open_rings;
+ }
+
+ /**
+ * Check whether there are any rings that can be combined with the
+ * given ring to one larger ring by appending the other ring to
+ * the end of this ring.
+ * If the rings can be combined they are and the function returns
+ * true.
+ */
+ bool possibly_combine_rings_back(ProtoRing& ring) {
+ const osmium::NodeRef& nr = ring.get_segment_back().second();
+
+ if (debug()) {
+ std::cerr << " possibly_combine_rings_back()\n";
+ }
+ for (auto it = m_rings.begin(); it != m_rings.end(); ++it) {
+ if (&*it != &ring && !it->closed()) {
+ if (has_same_location(nr, it->get_segment_front().first())) {
+ if (debug()) {
+ std::cerr << " ring.last=it->first\n";
+ }
+ ring.merge_ring(*it, debug());
+ m_rings.erase(it);
+ return true;
+ }
+ if (has_same_location(nr, it->get_segment_back().second())) {
+ if (debug()) {
+ std::cerr << " ring.last=it->last\n";
+ }
+ ring.merge_ring_reverse(*it, debug());
+ m_rings.erase(it);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check whether there are any rings that can be combined with the
+ * given ring to one larger ring by prepending the other ring to
+ * the start of this ring.
+ * If the rings can be combined they are and the function returns
+ * true.
+ */
+ bool possibly_combine_rings_front(ProtoRing& ring) {
+ const osmium::NodeRef& nr = ring.get_segment_front().first();
+
+ if (debug()) {
+ std::cerr << " possibly_combine_rings_front()\n";
+ }
+ for (auto it = m_rings.begin(); it != m_rings.end(); ++it) {
+ if (&*it != &ring && !it->closed()) {
+ if (has_same_location(nr, it->get_segment_back().second())) {
+ if (debug()) {
+ std::cerr << " ring.first=it->last\n";
+ }
+ ring.swap_segments(*it);
+ ring.merge_ring(*it, debug());
+ m_rings.erase(it);
+ return true;
+ }
+ if (has_same_location(nr, it->get_segment_front().first())) {
+ if (debug()) {
+ std::cerr << " ring.first=it->first\n";
+ }
+ ring.reverse();
+ ring.merge_ring(*it, debug());
+ m_rings.erase(it);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ void split_off_subring(osmium::area::detail::ProtoRing& ring, osmium::area::detail::ProtoRing::segments_type::iterator it, osmium::area::detail::ProtoRing::segments_type::iterator it_begin, osmium::area::detail::ProtoRing::segments_type::iterator it_end) {
+ if (debug()) {
+ std::cerr << " subring found at: " << *it << "\n";
+ }
+ ProtoRing new_ring(it_begin, it_end);
+ ring.remove_segments(it_begin, it_end);
+ if (debug()) {
+ std::cerr << " split into two rings:\n";
+ std::cerr << " " << new_ring << "\n";
+ std::cerr << " " << ring << "\n";
+ }
+ m_rings.push_back(std::move(new_ring));
+ }
+
+ bool has_closed_subring_back(ProtoRing& ring, const NodeRef& nr) {
+ if (ring.segments().size() < 3) {
+ return false;
+ }
+ if (debug()) {
+ std::cerr << " has_closed_subring_back()\n";
+ }
+ auto end = ring.segments().end();
+ for (auto it = ring.segments().begin() + 1; it != end - 1; ++it) {
+ if (has_same_location(nr, it->first())) {
+ split_off_subring(ring, it, it, end);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool has_closed_subring_front(ProtoRing& ring, const NodeRef& nr) {
+ if (ring.segments().size() < 3) {
+ return false;
+ }
+ if (debug()) {
+ std::cerr << " has_closed_subring_front()\n";
+ }
+ auto end = ring.segments().end();
+ for (auto it = ring.segments().begin() + 1; it != end - 1; ++it) {
+ if (has_same_location(nr, it->second())) {
+ split_off_subring(ring, it, ring.segments().begin(), it+1);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool check_for_closed_subring(ProtoRing& ring) {
+ if (debug()) {
+ std::cerr << " check_for_closed_subring()\n";
+ }
+
+ osmium::area::detail::ProtoRing::segments_type segments(ring.segments().size());
+ std::copy(ring.segments().begin(), ring.segments().end(), segments.begin());
+ std::sort(segments.begin(), segments.end());
+ auto it = std::adjacent_find(segments.begin(), segments.end(), [this](const osmium::area::detail::NodeRefSegment& s1, const osmium::area::detail::NodeRefSegment& s2) {
+ return has_same_location(s1.first(), s2.first());
+ });
+ if (it == segments.end()) {
+ return false;
+ }
+ auto r1 = std::find_first_of(ring.segments().begin(), ring.segments().end(), it, it+1);
+ assert(r1 != ring.segments().end());
+ auto r2 = std::find_first_of(ring.segments().begin(), ring.segments().end(), it+1, it+2);
+ assert(r2 != ring.segments().end());
+
+ if (debug()) {
+ std::cerr << " found subring in ring " << ring << " at " << it->first() << "\n";
+ }
+
+ auto m = std::minmax(r1, r2);
+
+ ProtoRing new_ring(m.first, m.second);
+ ring.remove_segments(m.first, m.second);
+
+ if (debug()) {
+ std::cerr << " split ring1=" << new_ring << "\n";
+ std::cerr << " split ring2=" << ring << "\n";
+ }
+
+ m_rings.emplace_back(new_ring);
+
+ return true;
+ }
+
+ void combine_rings_front(const osmium::area::detail::NodeRefSegment& segment, ProtoRing& ring) {
+ if (debug()) {
+ std::cerr << " => match at front of ring\n";
+ }
+ ring.add_segment_front(segment);
+ has_closed_subring_front(ring, segment.first());
+ if (possibly_combine_rings_front(ring)) {
+ check_for_closed_subring(ring);
+ }
+ }
+
+ void combine_rings_back(const osmium::area::detail::NodeRefSegment& segment, ProtoRing& ring) {
+ if (debug()) {
+ std::cerr << " => match at back of ring\n";
+ }
+ ring.add_segment_back(segment);
+ has_closed_subring_back(ring, segment.second());
+ if (possibly_combine_rings_back(ring)) {
+ check_for_closed_subring(ring);
+ }
+ }
+
+ /**
+ * Append each outer ring together with its inner rings to the
+ * area in the buffer.
+ */
+ void add_rings_to_area(osmium::builder::AreaBuilder& builder) const {
+ for (const ProtoRing* ring : m_outer_rings) {
+ if (debug()) {
+ std::cerr << " ring " << *ring << " is outer\n";
+ }
+ {
+ osmium::builder::OuterRingBuilder ring_builder(builder.buffer(), &builder);
+ ring_builder.add_node_ref(ring->get_segment_front().first());
+ for (const auto& segment : ring->segments()) {
+ ring_builder.add_node_ref(segment.second());
+ }
+ }
+ for (ProtoRing* inner : ring->inner_rings()) {
+ osmium::builder::InnerRingBuilder ring_builder(builder.buffer(), &builder);
+ ring_builder.add_node_ref(inner->get_segment_front().first());
+ for (const auto& segment : inner->segments()) {
+ ring_builder.add_node_ref(segment.second());
+ }
+ }
+ }
+ }
+
+ bool add_to_existing_ring(osmium::area::detail::NodeRefSegment segment) {
+ int n=0;
+ for (auto& ring : m_rings) {
+ if (debug()) {
+ std::cerr << " check against ring " << n << " " << ring;
+ }
+ if (ring.closed()) {
+ if (debug()) {
+ std::cerr << " => ring CLOSED\n";
+ }
+ } else {
+ if (has_same_location(ring.get_segment_back().second(), segment.first())) {
+ combine_rings_back(segment, ring);
+ return true;
+ }
+ if (has_same_location(ring.get_segment_back().second(), segment.second())) {
+ segment.swap_locations();
+ combine_rings_back(segment, ring);
+ return true;
+ }
+ if (has_same_location(ring.get_segment_front().first(), segment.first())) {
+ segment.swap_locations();
+ combine_rings_front(segment, ring);
+ return true;
+ }
+ if (has_same_location(ring.get_segment_front().first(), segment.second())) {
+ combine_rings_front(segment, ring);
+ return true;
+ }
+ if (debug()) {
+ std::cerr << " => no match\n";
+ }
+ }
+
+ ++n;
+ }
+ return false;
+ }
+
+ void check_inner_outer(ProtoRing& ring) {
+ const osmium::NodeRef& min_node = ring.min_node();
+ if (debug()) {
+ std::cerr << " check_inner_outer min_node=" << min_node << "\n";
+ }
+
+ int count = 0;
+ int above = 0;
+
+ for (auto it = m_segment_list.begin(); it != m_segment_list.end() && it->first().location().x() <= min_node.location().x(); ++it) {
+ if (!ring.contains(*it)) {
+ if (debug()) {
+ std::cerr << " segments for count: " << *it;
+ }
+ if (it->to_left_of(min_node.location())) {
+ ++count;
+ if (debug()) {
+ std::cerr << " counted\n";
+ }
+ } else {
+ if (debug()) {
+ std::cerr << " not counted\n";
+ }
+ }
+ if (it->first().location() == min_node.location()) {
+ if (it->second().location().y() > min_node.location().y()) {
+ ++above;
+ }
+ }
+ if (it->second().location() == min_node.location()) {
+ if (it->first().location().y() > min_node.location().y()) {
+ ++above;
+ }
+ }
+ }
+ }
+
+ if (debug()) {
+ std::cerr << " count=" << count << " above=" << above << "\n";
+ }
+
+ count += above % 2;
+
+ if (count % 2) {
+ ring.set_inner();
+ }
+ }
+
+ void check_inner_outer_roles() {
+ if (debug()) {
+ std::cerr << " check_inner_outer_roles\n";
+ }
+
+ for (const auto ringptr : m_outer_rings) {
+ for (const auto segment : ringptr->segments()) {
+ if (!segment.role_outer()) {
+ ++m_inner_outer_mismatches;
+ if (debug()) {
+ std::cerr << " segment " << segment << " from way " << segment.way()->id() << " should have role 'outer'\n";
+ }
+ if (m_config.problem_reporter) {
+ m_config.problem_reporter->report_role_should_be_outer(segment.way()->id(), segment.first().location(), segment.second().location());
+ }
+ }
+ }
+ }
+ for (const auto ringptr : m_inner_rings) {
+ for (const auto segment : ringptr->segments()) {
+ if (!segment.role_inner()) {
+ ++m_inner_outer_mismatches;
+ if (debug()) {
+ std::cerr << " segment " << segment << " from way " << segment.way()->id() << " should have role 'inner'\n";
+ }
+ if (m_config.problem_reporter) {
+ m_config.problem_reporter->report_role_should_be_inner(segment.way()->id(), segment.first().location(), segment.second().location());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Create rings from segments.
+ */
+ bool create_rings() {
+ m_segment_list.sort();
+ m_segment_list.erase_duplicate_segments();
+
+ // Now we look for segments crossing each other. If there are
+ // any, the multipolygon is invalid.
+ // In the future this could be improved by trying to fix those
+ // cases.
+ if (m_segment_list.find_intersections(m_config.problem_reporter)) {
+ return false;
+ }
+
+ // Now iterator over all segments and add them to rings. Each segment
+ // is tacked on to either end of an existing ring if possible, or a
+ // new ring is started with it.
+ for (const auto& segment : m_segment_list) {
+ if (debug()) {
+ std::cerr << " checking segment " << segment << "\n";
+ }
+ if (!add_to_existing_ring(segment)) {
+ if (debug()) {
+ std::cerr << " new ring for segment " << segment << "\n";
+ }
+ m_rings.emplace_back(segment);
+ }
+ }
+
+ if (debug()) {
+ std::cerr << " Rings:\n";
+ for (const auto& ring : m_rings) {
+ std::cerr << " " << ring;
+ if (ring.closed()) {
+ std::cerr << " (closed)";
+ }
+ std::cerr << "\n";
+ }
+ }
+
+ if (check_for_open_rings()) {
+ if (debug()) {
+ std::cerr << " not all rings are closed\n";
+ }
+ return false;
+ }
+
+ if (debug()) {
+ std::cerr << " Find inner/outer...\n";
+ }
+
+ if (m_rings.size() == 1) {
+ m_outer_rings.push_back(&m_rings.front());
+ } else {
+ for (auto& ring : m_rings) {
+ check_inner_outer(ring);
+ if (ring.outer()) {
+ if (!ring.is_cw()) {
+ ring.reverse();
+ }
+ m_outer_rings.push_back(&ring);
+ } else {
+ if (ring.is_cw()) {
+ ring.reverse();
+ }
+ m_inner_rings.push_back(&ring);
+ }
+ }
+
+ if (m_outer_rings.size() == 1) {
+ for (auto inner : m_inner_rings) {
+ m_outer_rings.front()->add_inner_ring(inner);
+ }
+ } else {
+ // sort outer rings by size, smallest first
+ std::sort(m_outer_rings.begin(), m_outer_rings.end(), [](ProtoRing* a, ProtoRing* b) {
+ return a->area() < b->area();
+ });
+ for (auto inner : m_inner_rings) {
+ for (auto outer : m_outer_rings) {
+ if (inner->is_in(outer)) {
+ outer->add_inner_ring(inner);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ check_inner_outer_roles();
+
+ return true;
+ }
+
+ public:
+
+ typedef osmium::area::AssemblerConfig config_type;
+
+ explicit Assembler(const config_type& config) :
+ m_config(config),
+ m_segment_list(config.debug) {
+ }
+
+ ~Assembler() = default;
+
+ /**
+ * Assemble an area from the given way.
+ * The resulting area is put into the out_buffer.
+ */
+ void operator()(const osmium::Way& way, osmium::memory::Buffer& out_buffer) {
+ if (m_config.problem_reporter) {
+ m_config.problem_reporter->set_object(osmium::item_type::way, way.id());
+ }
+
+ if (!way.ends_have_same_id()) {
+ if (m_config.problem_reporter) {
+ m_config.problem_reporter->report_duplicate_node(way.nodes().front().ref(), way.nodes().back().ref(), way.nodes().front().location());
+ }
+ }
+
+ m_segment_list.extract_segments_from_way(way, "outer");
+
+ if (debug()) {
+ std::cerr << "\nBuild way id()=" << way.id() << " segments.size()=" << m_segment_list.size() << "\n";
+ }
+
+ // Now create the Area object and add the attributes and tags
+ // from the relation.
+ {
+ osmium::builder::AreaBuilder builder(out_buffer);
+ builder.initialize_from_object(way);
+
+ if (create_rings()) {
+ add_tags_to_area(builder, way);
+ add_rings_to_area(builder);
+ }
+ }
+ out_buffer.commit();
+ }
+
+ /**
+ * Assemble an area from the given relation and its members.
+ * All members are to be found in the in_buffer at the offsets
+ * given by the members parameter.
+ * The resulting area is put into the out_buffer.
+ */
+ void operator()(const osmium::Relation& relation, const std::vector<size_t>& members, const osmium::memory::Buffer& in_buffer, osmium::memory::Buffer& out_buffer) {
+ if (m_config.problem_reporter) {
+ m_config.problem_reporter->set_object(osmium::item_type::relation, relation.id());
+ }
+
+ m_segment_list.extract_segments_from_ways(relation, members, in_buffer);
+
+ if (debug()) {
+ std::cerr << "\nBuild relation id()=" << relation.id() << " members.size()=" << members.size() << " segments.size()=" << m_segment_list.size() << "\n";
+ }
+
+ size_t area_offset = out_buffer.committed();
+
+ // Now create the Area object and add the attributes and tags
+ // from the relation.
+ {
+ osmium::builder::AreaBuilder builder(out_buffer);
+ builder.initialize_from_object(relation);
+
+ if (create_rings()) {
+ add_tags_to_area(builder, relation);
+ add_rings_to_area(builder);
+ }
+ }
+ out_buffer.commit();
+
+ const osmium::TagList& area_tags = out_buffer.get<osmium::Area>(area_offset).tags(); // tags of the area we just built
+
+ // Find all closed ways that are inner rings and check their
+ // tags. If they are not the same as the tags of the area we
+ // just built, add them to a list and later build areas for
+ // them, too.
+ std::vector<const osmium::Way*> ways_that_should_be_areas;
+ if (m_inner_outer_mismatches == 0) {
+ auto memit = relation.members().begin();
+ for (size_t offset : members) {
+ if (!std::strcmp(memit->role(), "inner")) {
+ const osmium::Way& way = in_buffer.get<const osmium::Way>(offset);
+ if (way.is_closed() && way.tags().size() > 0) {
+ auto d = std::count_if(way.tags().begin(), way.tags().end(), filter());
+ if (d > 0) {
+ osmium::tags::KeyFilter::iterator way_fi_begin(filter(), way.tags().begin(), way.tags().end());
+ osmium::tags::KeyFilter::iterator way_fi_end(filter(), way.tags().end(), way.tags().end());
+ osmium::tags::KeyFilter::iterator area_fi_begin(filter(), area_tags.begin(), area_tags.end());
+ osmium::tags::KeyFilter::iterator area_fi_end(filter(), area_tags.end(), area_tags.end());
+
+ if (!std::equal(way_fi_begin, way_fi_end, area_fi_begin) || d != std::distance(area_fi_begin, area_fi_end)) {
+ ways_that_should_be_areas.push_back(&way);
+ }
+ }
+ }
+ }
+ ++memit;
+ }
+ }
+
+ // Now build areas for all ways found in the last step.
+ for (const osmium::Way* way : ways_that_should_be_areas) {
+ Assembler assembler(m_config);
+ assembler(*way, out_buffer);
+ }
+ }
+
+ }; // class Assembler
+
+ } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_ASSEMBLER_HPP
diff --git a/third_party/osmium/area/detail/node_ref_segment.hpp b/third_party/osmium/area/detail/node_ref_segment.hpp
new file mode 100644
index 0000000..5b251bb
--- /dev/null
+++ b/third_party/osmium/area/detail/node_ref_segment.hpp
@@ -0,0 +1,262 @@
+#ifndef OSMIUM_AREA_DETAIL_NODE_REF_SEGMENT_HPP
+#define OSMIUM_AREA_DETAIL_NODE_REF_SEGMENT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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 <algorithm>
+#include <cstdint>
+#include <cstring>
+#include <iosfwd>
+#include <utility>
+
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node_ref.hpp>
+
+namespace osmium {
+
+ class Way;
+
+ namespace area {
+
+ /**
+ * @brief Namespace for Osmium internal use
+ */
+ namespace detail {
+
+ /**
+ * This helper class for the Assembler class models a segment.
+ * Segments are the connection between
+ * two nodes and they all have their smaller coordinate at the
+ * beginning of the segment. Smaller, in this case, means smaller x
+ * coordinate, and if they are the same smaller y coordinate.
+ */
+ class NodeRefSegment {
+
+ osmium::NodeRef m_first;
+ osmium::NodeRef m_second;
+
+ /// Role of the member this segment was from.
+ const char* m_role;
+
+ /// Way this segment was from.
+ const osmium::Way* m_way;
+
+ public:
+
+ void swap_locations() {
+ using std::swap;
+ swap(m_first, m_second);
+ }
+
+ explicit NodeRefSegment() noexcept :
+ m_first(),
+ m_second(),
+ m_role(nullptr),
+ m_way(nullptr) {
+ }
+
+ explicit NodeRefSegment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2, const char* role, const osmium::Way* way) :
+ m_first(nr1),
+ m_second(nr2),
+ m_role(role),
+ m_way(way) {
+ if (nr2.location() < nr1.location()) {
+ swap_locations();
+ }
+ }
+
+ NodeRefSegment(const NodeRefSegment&) = default;
+ NodeRefSegment(NodeRefSegment&&) = default;
+
+ NodeRefSegment& operator=(const NodeRefSegment&) = default;
+ NodeRefSegment& operator=(NodeRefSegment&&) = default;
+
+ ~NodeRefSegment() = default;
+
+ /// Return first NodeRef of Segment according to sorting order (bottom left to top right).
+ const osmium::NodeRef& first() const noexcept {
+ return m_first;
+ }
+
+ /// Return second NodeRef of Segment according to sorting order (bottom left to top right).
+ const osmium::NodeRef& second() const noexcept {
+ return m_second;
+ }
+
+ bool to_left_of(const osmium::Location location) const {
+ // std::cerr << "segment " << first() << "--" << second() << " to_left_of(" << location << "\n";
+
+ if (first().location() == location || second().location() == location) {
+ return false;
+ }
+
+ const std::pair<osmium::Location, osmium::Location> mm = std::minmax(first().location(), second().location(), [](const osmium::Location a, const osmium::Location b) {
+ return a.y() < b.y();
+ });
+
+ if (mm.first.y() >= location.y() || mm.second.y() < location.y() || first().location().x() > location.x()) {
+ // std::cerr << " false\n";
+ return false;
+ }
+
+ int64_t ax = mm.first.x();
+ int64_t bx = mm.second.x();
+ int64_t lx = location.x();
+ int64_t ay = mm.first.y();
+ int64_t by = mm.second.y();
+ int64_t ly = location.y();
+ return ((bx - ax)*(ly - ay) - (by - ay)*(lx - ax)) <= 0;
+ }
+
+ bool role_outer() const noexcept {
+ return !strcmp(m_role, "outer");
+ }
+
+ bool role_inner() const noexcept {
+ return !strcmp(m_role, "inner");
+ }
+
+ const osmium::Way* way() const noexcept {
+ return m_way;
+ }
+
+ }; // class NodeRefSegment
+
+ /// NodeRefSegments are equal if both their locations are equal
+ inline bool operator==(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+ return lhs.first().location() == rhs.first().location() && lhs.second().location() == rhs.second().location();
+ }
+
+ inline bool operator!=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+ return ! (lhs == rhs);
+ }
+
+ /**
+ * NodeRefSegments are "smaller" if they are to the left and down of another
+ * segment. The first() location is checked first() and only if they have the
+ * same first() location the second() location is taken into account.
+ */
+ inline bool operator<(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+ return (lhs.first().location() == rhs.first().location() && lhs.second().location() < rhs.second().location()) || lhs.first().location() < rhs.first().location();
+ }
+
+ inline bool operator>(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+ return rhs < lhs;
+ }
+
+ inline bool operator<=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+ return ! (rhs < lhs);
+ }
+
+ inline bool operator>=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
+ return ! (lhs < rhs);
+ }
+
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const NodeRefSegment& segment) {
+ return out << segment.first() << "--" << segment.second();
+ }
+
+ inline bool outside_x_range(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
+ if (s1.first().location().x() > s2.second().location().x()) {
+ return true;
+ }
+ return false;
+ }
+
+ inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) {
+ auto m1 = std::minmax(s1.first().location().y(), s1.second().location().y());
+ auto m2 = std::minmax(s2.first().location().y(), s2.second().location().y());
+ if (m1.first > m2.second || m2.first > m1.second) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Calculate the intersection between to NodeRefSegments. The result is returned
+ * as a Location. Note that because the Location uses integers with limited
+ * precision internally, the result might be slightly different than the
+ * numerically correct location.
+ *
+ * If the segments touch in one of their endpoints, it doesn't count as an
+ * intersection.
+ *
+ * If the segments intersect not in a single point but in multiple points, ie
+ * if they overlap, this is NOT detected.
+ *
+ * @returns Undefined osmium::Location if there is no intersection or a defined
+ * Location if the segments intersect.
+ */
+ inline osmium::Location calculate_intersection(const NodeRefSegment& s1, const NodeRefSegment& s2) {
+ if (s1.first().location() == s2.first().location() ||
+ s1.first().location() == s2.second().location() ||
+ s1.second().location() == s2.first().location() ||
+ s1.second().location() == s2.second().location()) {
+ return osmium::Location();
+ }
+
+ auto d = (static_cast<int64_t>(s2.second().y()) - static_cast<int64_t>(s2.first().y())) *
+ (static_cast<int64_t>(s1.second().x()) - static_cast<int64_t>(s1.first().x())) -
+ (static_cast<int64_t>(s2.second().x()) - static_cast<int64_t>(s2.first().x())) *
+ (static_cast<int64_t>(s1.second().y()) - static_cast<int64_t>(s1.first().y()));
+
+ if (d != 0) {
+ double denom = ((s2.second().lat() - s2.first().lat())*(s1.second().lon() - s1.first().lon())) -
+ ((s2.second().lon() - s2.first().lon())*(s1.second().lat() - s1.first().lat()));
+
+ double nume_a = ((s2.second().lon() - s2.first().lon())*(s1.first().lat() - s2.first().lat())) -
+ ((s2.second().lat() - s2.first().lat())*(s1.first().lon() - s2.first().lon()));
+
+ double nume_b = ((s1.second().lon() - s1.first().lon())*(s1.first().lat() - s2.first().lat())) -
+ ((s1.second().lat() - s1.first().lat())*(s1.first().lon() - s2.first().lon()));
+
+ if ((denom > 0 && nume_a >= 0 && nume_a <= denom && nume_b >= 0 && nume_b <= denom) ||
+ (denom < 0 && nume_a <= 0 && nume_a >= denom && nume_b <= 0 && nume_b >= denom)) {
+ double ua = nume_a / denom;
+ double ix = s1.first().lon() + ua*(s1.second().lon() - s1.first().lon());
+ double iy = s1.first().lat() + ua*(s1.second().lat() - s1.first().lat());
+ return osmium::Location(ix, iy);
+ }
+ }
+
+ return osmium::Location();
+ }
+
+ } // namespace detail
+
+ } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_DETAIL_NODE_REF_SEGMENT_HPP
diff --git a/third_party/osmium/area/detail/proto_ring.hpp b/third_party/osmium/area/detail/proto_ring.hpp
new file mode 100644
index 0000000..63fec5b
--- /dev/null
+++ b/third_party/osmium/area/detail/proto_ring.hpp
@@ -0,0 +1,274 @@
+#ifndef OSMIUM_AREA_DETAIL_PROTO_RING_HPP
+#define OSMIUM_AREA_DETAIL_PROTO_RING_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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 <algorithm>
+#include <cassert>
+#include <iostream>
+#include <list>
+#include <set>
+#include <vector>
+
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/area/detail/node_ref_segment.hpp>
+
+namespace osmium {
+
+ namespace area {
+
+ namespace detail {
+
+ /**
+ * A ring in the process of being built by the Assembler object.
+ */
+ class ProtoRing {
+
+ public:
+
+ typedef std::vector<NodeRefSegment> segments_type;
+
+ private:
+
+ // segments in this ring
+ segments_type m_segments;
+
+ bool m_outer {true};
+
+ // if this is an outer ring, these point to it's inner rings (if any)
+ std::vector<ProtoRing*> m_inner;
+
+ public:
+
+ explicit ProtoRing(const NodeRefSegment& segment) noexcept :
+ m_segments() {
+ add_segment_back(segment);
+ }
+
+ explicit ProtoRing(segments_type::const_iterator sbegin, segments_type::const_iterator send) :
+ m_segments(static_cast<size_t>(std::distance(sbegin, send))) {
+ std::copy(sbegin, send, m_segments.begin());
+ }
+
+ bool outer() const noexcept {
+ return m_outer;
+ }
+
+ void set_inner() noexcept {
+ m_outer = false;
+ }
+
+ segments_type& segments() noexcept {
+ return m_segments;
+ }
+
+ const segments_type& segments() const noexcept {
+ return m_segments;
+ }
+
+ void remove_segments(segments_type::iterator sbegin, segments_type::iterator send) {
+ m_segments.erase(sbegin, send);
+ }
+
+ void add_segment_front(const NodeRefSegment& segment) {
+ m_segments.insert(m_segments.begin(), segment);
+ }
+
+ void add_segment_back(const NodeRefSegment& segment) {
+ m_segments.push_back(segment);
+ }
+
+ const NodeRefSegment& get_segment_front() const {
+ return m_segments.front();
+ }
+
+ NodeRefSegment& get_segment_front() {
+ return m_segments.front();
+ }
+
+ const NodeRefSegment& get_segment_back() const {
+ return m_segments.back();
+ }
+
+ NodeRefSegment& get_segment_back() {
+ return m_segments.back();
+ }
+
+ bool closed() const {
+ return m_segments.front().first().location() == m_segments.back().second().location();
+ }
+
+ int64_t sum() const {
+ int64_t sum = 0;
+
+ for (const auto& segment : m_segments) {
+ sum += static_cast<int64_t>(segment.first().location().x()) * static_cast<int64_t>(segment.second().location().y()) -
+ static_cast<int64_t>(segment.second().location().x()) * static_cast<int64_t>(segment.first().location().y());
+ }
+
+ return sum;
+ }
+
+ bool is_cw() const {
+ return sum() <= 0;
+ }
+
+ int64_t area() const {
+ return std::abs(sum()) / 2;
+ }
+
+ void swap_segments(ProtoRing& other) {
+ std::swap(m_segments, other.m_segments);
+ }
+
+ void add_inner_ring(ProtoRing* ring) {
+ m_inner.push_back(ring);
+ }
+
+ const std::vector<ProtoRing*> inner_rings() const {
+ return m_inner;
+ }
+
+ void print(std::ostream& out) const {
+ out << "[";
+ bool first = true;
+ for (const auto& segment : m_segments) {
+ if (first) {
+ out << segment.first().ref();
+ }
+ out << ',' << segment.second().ref();
+ first = false;
+ }
+ out << "]";
+ }
+
+ void reverse() {
+ std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment& segment) {
+ segment.swap_locations();
+ });
+ std::reverse(m_segments.begin(), m_segments.end());
+ }
+
+ /**
+ * Merge other ring to end of this ring.
+ */
+ void merge_ring(const ProtoRing& other, bool debug) {
+ if (debug) {
+ std::cerr << " MERGE rings ";
+ print(std::cerr);
+ std::cerr << " to ";
+ other.print(std::cerr);
+ std::cerr << "\n";
+ }
+ m_segments.insert(m_segments.end(), other.m_segments.begin(), other.m_segments.end());
+ if (debug) {
+ std::cerr << " result ring: ";
+ print(std::cerr);
+ std::cerr << "\n";
+ }
+ }
+
+ void merge_ring_reverse(const ProtoRing& other, bool debug) {
+ if (debug) {
+ std::cerr << " MERGE rings (reverse) ";
+ print(std::cerr);
+ std::cerr << " to ";
+ other.print(std::cerr);
+ std::cerr << "\n";
+ }
+ size_t n = m_segments.size();
+ m_segments.resize(n + other.m_segments.size());
+ std::transform(other.m_segments.rbegin(), other.m_segments.rend(), m_segments.begin() + static_cast<segments_type::difference_type>(n), [](NodeRefSegment segment) {
+ segment.swap_locations();
+ return segment;
+ });
+ if (debug) {
+ std::cerr << " result ring: ";
+ print(std::cerr);
+ std::cerr << "\n";
+ }
+ }
+
+ const NodeRef& min_node() const {
+ auto it = std::min_element(m_segments.begin(), m_segments.end());
+ if (location_less()(it->first(), it->second())) {
+ return it->first();
+ } else {
+ return it->second();
+ }
+ }
+
+ bool is_in(ProtoRing* outer) {
+ osmium::Location testpoint = segments().front().first().location();
+ bool is_in = false;
+
+ for (size_t i = 0, j = outer->segments().size()-1; i < outer->segments().size(); j = i++) {
+ if (((outer->segments()[i].first().location().y() > testpoint.y()) != (outer->segments()[j].first().location().y() > testpoint.y())) &&
+ (testpoint.x() < (outer->segments()[j].first().location().x() - outer->segments()[i].first().location().x()) * (testpoint.y() - outer->segments()[i].first().location().y()) / (outer->segments()[j].first().location().y() - outer->segments()[i].first().location().y()) + outer->segments()[i].first().location().x()) ) {
+ is_in = !is_in;
+ }
+ }
+
+ return is_in;
+ }
+
+ void get_ways(std::set<const osmium::Way*>& ways) {
+ for (const auto& segment : m_segments) {
+ ways.insert(segment.way());
+ }
+ }
+
+ bool contains(const NodeRefSegment& segment) const {
+ for (const auto& s : m_segments) {
+ if (s == segment || (s.first() == segment.second() && s.second() == segment.first())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ }; // class ProtoRing
+
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const ProtoRing& ring) {
+ ring.print(out);
+ return out;
+ }
+
+ } // namespace detail
+
+ } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_DETAIL_PROTO_RING_HPP
diff --git a/third_party/osmium/area/detail/segment_list.hpp b/third_party/osmium/area/detail/segment_list.hpp
new file mode 100644
index 0000000..a14f792
--- /dev/null
+++ b/third_party/osmium/area/detail/segment_list.hpp
@@ -0,0 +1,216 @@
+#ifndef OSMIUM_AREA_DETAIL_SEGMENT_LIST_HPP
+#define OSMIUM_AREA_DETAIL_SEGMENT_LIST_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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 <algorithm>
+#include <cassert>
+#include <iostream>
+#include <vector>
+
+#include <osmium/area/problem_reporter.hpp>
+#include <osmium/area/detail/node_ref_segment.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+ namespace area {
+
+ namespace detail {
+
+ /**
+ * This is a helper class for the area assembler. It models
+ * a list of segments.
+ */
+ class SegmentList {
+
+ typedef std::vector<NodeRefSegment> slist_type;
+
+ slist_type m_segments;
+
+ bool m_debug;
+
+ public:
+
+ explicit SegmentList(bool debug) noexcept :
+ m_debug(debug) {
+ }
+
+ ~SegmentList() = default;
+
+ SegmentList(const SegmentList&) = delete;
+ SegmentList(SegmentList&&) = delete;
+
+ SegmentList& operator=(const SegmentList&) = delete;
+ SegmentList& operator=(SegmentList&&) = delete;
+
+ /// The number of segments in the list.
+ size_t size() const noexcept {
+ return m_segments.size();
+ }
+
+ bool empty() const noexcept {
+ return m_segments.empty();
+ }
+
+ typedef slist_type::const_iterator const_iterator;
+
+ const_iterator begin() const noexcept {
+ return m_segments.begin();
+ }
+
+ const_iterator end() const noexcept {
+ return m_segments.end();
+ }
+
+ /**
+ * Enable or disable debug output to stderr. This is for Osmium
+ * developers only.
+ */
+ void enable_debug_output(bool debug=true) noexcept {
+ m_debug = debug;
+ }
+
+ /// Clear the list of segments. All segments are removed.
+ void clear() {
+ m_segments.clear();
+ }
+
+ /// Sort the list of segments.
+ void sort() {
+ std::sort(m_segments.begin(), m_segments.end());
+ }
+
+ /**
+ * Extract segments from given way and add them to the list.
+ *
+ * Segments connecting two nodes with the same location (ie same
+ * node or different node with same location) are removed.
+ *
+ * XXX should two nodes with same location be reported?
+ */
+ void extract_segments_from_way(const osmium::Way& way, const char* role) {
+ osmium::NodeRef last_nr;
+ for (const osmium::NodeRef& nr : way.nodes()) {
+ if (last_nr.location() && last_nr.location() != nr.location()) {
+ m_segments.emplace_back(last_nr, nr, role, &way);
+ }
+ last_nr = nr;
+ }
+ }
+
+ /**
+ * Extract all segments from all ways that make up this
+ * multipolygon relation and add them to the list.
+ */
+ void extract_segments_from_ways(const osmium::Relation& relation, const std::vector<size_t>& members, const osmium::memory::Buffer& in_buffer) {
+ auto member_it = relation.members().begin();
+ for (size_t offset : members) {
+ const osmium::Way& way = in_buffer.get<const osmium::Way>(offset);
+ extract_segments_from_way(way, member_it->role());
+ ++member_it;
+ }
+ }
+
+ /**
+ * Find duplicate segments (ie same start and end point) in the
+ * list and remove them. This will always remove pairs of the same
+ * segment. So if there are three, for instance, two will be
+ * removed and one will be left.
+ */
+ void erase_duplicate_segments() {
+ while (true) {
+ auto it = std::adjacent_find(m_segments.begin(), m_segments.end());
+ if (it == m_segments.end()) {
+ return;
+ }
+ if (m_debug) {
+ std::cerr << " erase duplicate segment: " << *it << "\n";
+ }
+ m_segments.erase(it, it+2);
+ }
+ }
+
+ /**
+ * Find intersection between segments.
+ *
+ * @param problem_reporter Any intersections found are reported to this object.
+ * @returns true if there are intersections.
+ */
+ bool find_intersections(osmium::area::ProblemReporter* problem_reporter) const {
+ if (m_segments.empty()) {
+ return false;
+ }
+
+ bool found_intersections = false;
+
+ for (auto it1 = m_segments.begin(); it1 != m_segments.end()-1; ++it1) {
+ const NodeRefSegment& s1 = *it1;
+ for (auto it2 = it1+1; it2 != m_segments.end(); ++it2) {
+ const NodeRefSegment& s2 = *it2;
+
+ assert(s1 != s2); // erase_duplicate_segments() should have made sure of that
+
+ if (outside_x_range(s2, s1)) {
+ break;
+ }
+
+ if (y_range_overlap(s1, s2)) {
+ osmium::Location intersection = calculate_intersection(s1, s2);
+ if (intersection) {
+ found_intersections = true;
+ if (m_debug) {
+ std::cerr << " segments " << s1 << " and " << s2 << " intersecting at " << intersection << "\n";
+ }
+ if (problem_reporter) {
+ problem_reporter->report_intersection(s1.way()->id(), s1.first().location(), s1.second().location(), s2.way()->id(), s2.first().location(), s2.second().location(), intersection);
+ }
+ }
+ }
+ }
+ }
+
+ return found_intersections;
+ }
+
+ }; // class SegmentList
+
+ } // namespace detail
+
+ } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_DETAIL_SEGMENT_LIST_HPP
diff --git a/third_party/osmium/area/multipolygon_collector.hpp b/third_party/osmium/area/multipolygon_collector.hpp
new file mode 100644
index 0000000..af48176
--- /dev/null
+++ b/third_party/osmium/area/multipolygon_collector.hpp
@@ -0,0 +1,212 @@
+#ifndef OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
+#define OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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 <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <vector>
+
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/relations/collector.hpp>
+#include <osmium/relations/detail/member_meta.hpp>
+
+namespace osmium {
+
+ struct invalid_location;
+
+ namespace relations {
+ class RelationMeta;
+ }
+
+ /**
+ * @brief Code related to the building of areas (multipolygons) from relations.
+ */
+ namespace area {
+
+ /**
+ * This class collects all data needed for creating areas from
+ * relations tagged with type=multipolygon or type=boundary.
+ * Most of its functionality is derived from the parent class
+ * osmium::relations::Collector.
+ *
+ * The actual assembling of the areas is done by the assembler
+ * class given as template argument.
+ *
+ * @tparam TAssembler Multipolygon Assembler class.
+ */
+ template <class TAssembler>
+ class MultipolygonCollector : public osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> {
+
+ typedef typename osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> collector_type;
+
+ typedef typename TAssembler::config_type assembler_config_type;
+ const assembler_config_type m_assembler_config;
+
+ osmium::memory::Buffer m_output_buffer;
+
+ static constexpr size_t initial_output_buffer_size = 1024 * 1024;
+ static constexpr size_t max_buffer_size_for_flush = 100 * 1024;
+
+ void flush_output_buffer() {
+ if (this->callback()) {
+ osmium::memory::Buffer buffer(initial_output_buffer_size);
+ std::swap(buffer, m_output_buffer);
+ this->callback()(std::move(buffer));
+ }
+ }
+
+ void possibly_flush_output_buffer() {
+ if (m_output_buffer.committed() > max_buffer_size_for_flush) {
+ flush_output_buffer();
+ }
+ }
+
+ public:
+
+ explicit MultipolygonCollector(const assembler_config_type& assembler_config) :
+ collector_type(),
+ m_assembler_config(assembler_config),
+ m_output_buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes) {
+ }
+
+ /**
+ * We are interested in all relations tagged with type=multipolygon or
+ * type=boundary.
+ *
+ * Overwritten from the base class.
+ */
+ bool keep_relation(const osmium::Relation& relation) const {
+ const char* type = relation.tags().get_value_by_key("type");
+
+ // ignore relations without "type" tag
+ if (!type) {
+ return false;
+ }
+
+ if ((!strcmp(type, "multipolygon")) || (!strcmp(type, "boundary"))) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Overwritten from the base class.
+ */
+ bool keep_member(const osmium::relations::RelationMeta& /*relation_meta*/, const osmium::RelationMember& member) const {
+ // We are only interested in members of type way.
+ return member.type() == osmium::item_type::way;
+ }
+
+ /**
+ * This is called when a way is not in any multipolygon
+ * relation.
+ *
+ * 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) {
+ // way is closed and has enough nodes, build simple multipolygon
+ try {
+ TAssembler assembler(m_assembler_config);
+ assembler(way, m_output_buffer);
+ possibly_flush_output_buffer();
+ } catch (osmium::invalid_location&) {
+ // XXX ignore
+ }
+ }
+ }
+
+ void complete_relation(osmium::relations::RelationMeta& relation_meta) {
+ const osmium::Relation& relation = this->get_relation(relation_meta);
+ std::vector<size_t> offsets;
+ for (const auto& member : relation.members()) {
+ if (member.ref() != 0) {
+ offsets.push_back(this->get_offset(member.type(), member.ref()));
+ }
+ }
+ try {
+ TAssembler assembler(m_assembler_config);
+ assembler(relation, offsets, this->members_buffer(), m_output_buffer);
+ possibly_flush_output_buffer();
+ } catch (osmium::invalid_location&) {
+ // XXX ignore
+ }
+
+ // clear member metas
+ for (const auto& member : relation.members()) {
+ if (member.ref() != 0) {
+ auto& mmv = this->member_meta(member.type());
+ auto range = std::equal_range(mmv.begin(), mmv.end(), osmium::relations::MemberMeta(member.ref()));
+ assert(range.first != range.second);
+
+ // if this is the last time this object was needed
+ // then mark it as removed
+ if (osmium::relations::count_not_removed(range.first, range.second) == 1) {
+ this->get_member(range.first->buffer_offset()).set_removed(true);
+ }
+
+ for (auto it = range.first; it != range.second; ++it) {
+ if (!it->removed() && relation.id() == this->get_relation(it->relation_pos()).id()) {
+ it->remove();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ void flush() {
+ flush_output_buffer();
+ }
+
+ osmium::memory::Buffer read() {
+ osmium::memory::Buffer buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes);
+ std::swap(buffer, m_output_buffer);
+ return buffer;
+ }
+
+ }; // class MultipolygonCollector
+
+ } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
diff --git a/third_party/osmium/area/problem_reporter.hpp b/third_party/osmium/area/problem_reporter.hpp
new file mode 100644
index 0000000..5e255db
--- /dev/null
+++ b/third_party/osmium/area/problem_reporter.hpp
@@ -0,0 +1,149 @@
+#ifndef OSMIUM_AREA_PROBLEM_REPORTER_HPP
+#define OSMIUM_AREA_PROBLEM_REPORTER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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 <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+ namespace area {
+
+ /**
+ * When assembling a multipolygon/area from a multipolygon relation
+ * or a closed way several problems can be detected. This includes
+ * intersections between lines, wrong role attributes on relation
+ * members etc. These problems are reported by the area::Assembler
+ * class to the ProblemReporter class or one of its child classes.
+ *
+ * This is the parent class which does nothing with the reports.
+ * Child classes are expected to implement different ways of
+ * reporting the problems.
+ */
+ class ProblemReporter {
+
+ protected:
+
+ // Type of object we are currently working on
+ osmium::item_type m_object_type;
+
+ // ID of the relation/way we are currently working on
+ osmium::object_id_type m_object_id;
+
+ public:
+
+ ProblemReporter() = default;
+
+ virtual ~ProblemReporter() = default;
+
+ /**
+ * Set the object the next problem reports will be on.
+ *
+ * @param object_type The type of the object.
+ * @param object_id The ID of the object.
+ */
+ void set_object(osmium::item_type object_type, osmium::object_id_type object_id) noexcept {
+ m_object_type = object_type;
+ m_object_id = object_id;
+ }
+
+// Disable "unused-parameter" warning, so that the compiler will not complain.
+// We can't remove the parameter names, because then doxygen will complain.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
+ /**
+ * Report a duplicate node, ie. two nodes with the same location.
+ *
+ * @param node_id1 ID of the first node.
+ * @param node_id2 ID of the second node.
+ * @param location Location of both nodes.
+ */
+ virtual void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) {
+ }
+
+ /**
+ * Report an intersection between two segments.
+ *
+ * @param way1_id ID of the first involved way.
+ * @param way1_seg_start Location where the segment of the first way with the intersection starts
+ * @param way1_seg_end Location where the segment of the first way with the intersection ends
+ * @param way2_id ID of the second involved way.
+ * @param way2_seg_start Location where the segment of the second way with the intersection starts
+ * @param way2_seg_end Location where the segment of the second way with the intersection ends
+ * @param intersection Location of the intersection. This might be slightly off the correct location due to rounding.
+ */
+ virtual void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
+ osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) {
+ }
+
+ /**
+ * Report an open ring.
+ *
+ * @param end1 Location of the first open end.
+ * @param end2 Location of the second open end.
+ */
+ virtual void report_ring_not_closed(osmium::Location end1, osmium::Location end2) {
+ }
+
+ /**
+ * Report a segment that should have role "outer", but has a different role.
+ *
+ * @param way_id ID of the way this segment is in.
+ * @param seg_start Start of the segment with the wrong role.
+ * @param seg_end End of the segment with the wrong role.
+ */
+ virtual void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
+ }
+
+ /**
+ * Report a segment that should have role "inner", but has a different role.
+ *
+ * @param way_id ID of the way this segment is in.
+ * @param seg_start Start of the segment with the wrong role.
+ * @param seg_end End of the segment with the wrong role.
+ */
+ virtual void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
+ }
+
+#pragma GCC diagnostic pop
+
+ }; // class ProblemReporter
+
+ } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_PROBLEM_REPORTER_HPP
diff --git a/third_party/osmium/area/problem_reporter_exception.hpp b/third_party/osmium/area/problem_reporter_exception.hpp
new file mode 100644
index 0000000..29c7ad4
--- /dev/null
+++ b/third_party/osmium/area/problem_reporter_exception.hpp
@@ -0,0 +1,96 @@
+#ifndef OSMIUM_AREA_PROBLEM_REPORTER_EXCEPTION_HPP
+#define OSMIUM_AREA_PROBLEM_REPORTER_EXCEPTION_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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 <sstream>
+#include <stdexcept>
+
+#include <osmium/area/problem_reporter_stream.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+ namespace area {
+
+ class ProblemReporterException : public ProblemReporterStream {
+
+ std::stringstream m_sstream;
+
+ public:
+
+ ProblemReporterException() :
+ ProblemReporterStream(m_sstream) {
+ }
+
+ virtual ~ProblemReporterException() = default;
+
+ void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
+ m_sstream.str();
+ ProblemReporterStream::report_duplicate_node(node_id1, node_id2, location);
+ throw std::runtime_error(m_sstream.str());
+ }
+
+ void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
+ osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
+ m_sstream.str();
+ ProblemReporterStream::report_intersection(way1_id, way1_seg_start, way1_seg_end, way2_id, way2_seg_start, way2_seg_end, intersection);
+ throw std::runtime_error(m_sstream.str());
+ }
+
+ void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
+ m_sstream.str();
+ ProblemReporterStream::report_ring_not_closed(end1, end2);
+ throw std::runtime_error(m_sstream.str());
+ }
+
+ void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+ m_sstream.str();
+ ProblemReporterStream::report_role_should_be_outer(way_id, seg_start, seg_end);
+ throw std::runtime_error(m_sstream.str());
+ }
+
+ void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+ m_sstream.str();
+ ProblemReporterStream::report_role_should_be_inner(way_id, seg_start, seg_end);
+ throw std::runtime_error(m_sstream.str());
+ }
+
+ }; // class ProblemReporterException
+
+ } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_PROBLEM_REPORTER_EXCEPTION_HPP
diff --git a/third_party/osmium/area/problem_reporter_ogr.hpp b/third_party/osmium/area/problem_reporter_ogr.hpp
new file mode 100644
index 0000000..a9eb135
--- /dev/null
+++ b/third_party/osmium/area/problem_reporter_ogr.hpp
@@ -0,0 +1,206 @@
+#ifndef OSMIUM_AREA_PROBLEM_REPORTER_OGR_HPP
+#define OSMIUM_AREA_PROBLEM_REPORTER_OGR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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.
+
+*/
+
+#define OSMIUM_COMPILE_WITH_CFLAGS_OGR `gdal-config --cflags`
+#define OSMIUM_LINK_WITH_LIBS_OGR `gdal-config --libs`
+
+#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"
+# include <ogr_api.h>
+# include <ogrsf_frmts.h>
+#pragma GCC diagnostic pop
+
+#include <memory>
+#include <stdexcept>
+
+#include <osmium/area/problem_reporter.hpp>
+#include <osmium/geom/ogr.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+ namespace area {
+
+ /**
+ * Report problems when assembling areas by adding them to
+ * layers in an OGR datasource.
+ */
+ class ProblemReporterOGR : public ProblemReporter {
+
+ osmium::geom::OGRFactory<> m_ogr_factory;
+
+ OGRDataSource* m_data_source;
+
+ OGRLayer* m_layer_perror;
+ OGRLayer* m_layer_lerror;
+
+ void write_point(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location location) {
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_perror->GetLayerDefn());
+ std::unique_ptr<OGRPoint> ogr_point = m_ogr_factory.create_point(location);
+ feature->SetGeometry(ogr_point.get());
+ feature->SetField("id1", static_cast<double>(id1));
+ feature->SetField("id2", static_cast<double>(id2));
+ feature->SetField("problem_type", problem_type);
+
+ if (m_layer_perror->CreateFeature(feature) != OGRERR_NONE) {
+ std::runtime_error("Failed to create feature on layer 'perrors'");
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ }
+
+ void write_line(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location loc1, osmium::Location loc2) {
+ std::unique_ptr<OGRPoint> ogr_point1 = m_ogr_factory.create_point(loc1);
+ std::unique_ptr<OGRPoint> ogr_point2 = m_ogr_factory.create_point(loc2);
+ std::unique_ptr<OGRLineString> ogr_linestring = std::unique_ptr<OGRLineString>(new OGRLineString());
+ ogr_linestring->addPoint(ogr_point1.get());
+ ogr_linestring->addPoint(ogr_point2.get());
+ OGRFeature* feature = OGRFeature::CreateFeature(m_layer_lerror->GetLayerDefn());
+ feature->SetGeometry(ogr_linestring.get());
+ feature->SetField("id1", static_cast<double>(id1));
+ feature->SetField("id2", static_cast<double>(id2));
+ feature->SetField("problem_type", problem_type);
+
+ if (m_layer_lerror->CreateFeature(feature) != OGRERR_NONE) {
+ std::runtime_error("Failed to create feature on layer 'lerrors'");
+ }
+
+ OGRFeature::DestroyFeature(feature);
+ }
+
+ public:
+
+ explicit ProblemReporterOGR(OGRDataSource* data_source) :
+ m_data_source(data_source) {
+
+ OGRSpatialReference sparef;
+ sparef.SetWellKnownGeogCS("WGS84");
+
+ m_layer_perror = m_data_source->CreateLayer("perrors", &sparef, wkbPoint, nullptr);
+ if (!m_layer_perror) {
+ std::runtime_error("Layer creation failed for layer 'perrors'");
+ }
+
+ OGRFieldDefn layer_perror_field_id1("id1", OFTReal);
+ layer_perror_field_id1.SetWidth(10);
+
+ if (m_layer_perror->CreateField(&layer_perror_field_id1) != OGRERR_NONE) {
+ std::runtime_error("Creating field 'id1' failed for layer 'perrors'");
+ }
+
+ OGRFieldDefn layer_perror_field_id2("id2", OFTReal);
+ layer_perror_field_id2.SetWidth(10);
+
+ if (m_layer_perror->CreateField(&layer_perror_field_id2) != OGRERR_NONE) {
+ std::runtime_error("Creating field 'id2' failed for layer 'perrors'");
+ }
+
+ OGRFieldDefn layer_perror_field_problem_type("problem_type", OFTString);
+ layer_perror_field_problem_type.SetWidth(30);
+
+ if (m_layer_perror->CreateField(&layer_perror_field_problem_type) != OGRERR_NONE) {
+ std::runtime_error("Creating field 'problem_type' failed for layer 'perrors'");
+ }
+
+ /**************/
+
+ m_layer_lerror = m_data_source->CreateLayer("lerrors", &sparef, wkbLineString, nullptr);
+ if (!m_layer_lerror) {
+ std::runtime_error("Layer creation failed for layer 'lerrors'");
+ }
+
+ OGRFieldDefn layer_lerror_field_id1("id1", OFTReal);
+ layer_lerror_field_id1.SetWidth(10);
+
+ if (m_layer_lerror->CreateField(&layer_lerror_field_id1) != OGRERR_NONE) {
+ std::runtime_error("Creating field 'id1' failed for layer 'lerrors'");
+ }
+
+ OGRFieldDefn layer_lerror_field_id2("id2", OFTReal);
+ layer_lerror_field_id2.SetWidth(10);
+
+ if (m_layer_lerror->CreateField(&layer_lerror_field_id2) != OGRERR_NONE) {
+ std::runtime_error("Creating field 'id2' failed for layer 'lerrors'");
+ }
+
+ OGRFieldDefn layer_lerror_field_problem_type("problem_type", OFTString);
+ layer_lerror_field_problem_type.SetWidth(30);
+
+ if (m_layer_lerror->CreateField(&layer_lerror_field_problem_type) != OGRERR_NONE) {
+ std::runtime_error("Creating field 'problem_type' failed for layer 'lerrors'");
+ }
+ }
+
+ virtual ~ProblemReporterOGR() = default;
+
+ void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
+ write_point("duplicate_node", node_id1, node_id2, location);
+ }
+
+ void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
+ osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
+ write_point("intersection", m_object_id, 0, intersection);
+ write_line("intersection", m_object_id, way1_id, way1_seg_start, way1_seg_end);
+ write_line("intersection", m_object_id, way2_id, way2_seg_start, way2_seg_end);
+ }
+
+ void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
+ write_point("ring_not_closed", m_object_id, 0, end1);
+ write_point("ring_not_closed", m_object_id, 0, end2);
+ }
+
+ void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+ write_line("role_should_be_outer", m_object_id, way_id, seg_start, seg_end);
+ }
+
+ void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+ write_line("role_should_be_inner", m_object_id, way_id, seg_start, seg_end);
+ }
+
+ }; // class ProblemReporterOGR
+
+ } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_PROBLEM_REPORTER_OGR_HPP
diff --git a/third_party/osmium/area/problem_reporter_stream.hpp b/third_party/osmium/area/problem_reporter_stream.hpp
new file mode 100644
index 0000000..6bee568
--- /dev/null
+++ b/third_party/osmium/area/problem_reporter_stream.hpp
@@ -0,0 +1,96 @@
+#ifndef OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP
+#define OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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 <ostream>
+
+#include <osmium/area/problem_reporter.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+ namespace area {
+
+ class ProblemReporterStream : public ProblemReporter {
+
+ std::ostream* m_out;
+
+ public:
+
+ explicit ProblemReporterStream(std::ostream& out) :
+ m_out(&out) {
+ }
+
+ virtual ~ProblemReporterStream() = default;
+
+ void header(const char* msg) {
+ *m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << ": ";
+ }
+
+ void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
+ header("duplicate node");
+ *m_out << "node_id1=" << node_id1 << " node_id2=" << node_id2 << " location=" << location << "\n";
+ }
+
+ void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
+ osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
+ header("intersection");
+ *m_out << "way1_id=" << way1_id << " way1_seg_start=" << way1_seg_start << " way1_seg_end=" << way1_seg_end
+ << " way2_id=" << way2_id << " way2_seg_start=" << way2_seg_start << " way2_seg_end=" << way2_seg_end << " intersection=" << intersection << "\n";
+ }
+
+ void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
+ header("ring not closed");
+ *m_out << "end1=" << end1 << " end2=" << end2 << "\n";
+ }
+
+ void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+ header("role should be outer");
+ *m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n";
+ }
+
+ void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
+ header("role should be inner");
+ *m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n";
+ }
+
+ }; // class ProblemReporterStream
+
+ } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP
diff --git a/third_party/osmium/builder/builder.hpp b/third_party/osmium/builder/builder.hpp
new file mode 100644
index 0000000..61e853e
--- /dev/null
+++ b/third_party/osmium/builder/builder.hpp
@@ -0,0 +1,220 @@
+#ifndef OSMIUM_BUILDER_BUILDER_HPP
+#define OSMIUM_BUILDER_BUILDER_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 <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <new>
+#include <type_traits>
+
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+ /**
+ * @brief Classes for building OSM objects and other items in buffers
+ */
+ namespace builder {
+
+ class Builder {
+
+ osmium::memory::Buffer& m_buffer;
+ Builder* m_parent;
+ size_t m_item_offset;
+
+ Builder(const Builder&) = delete;
+ Builder(Builder&&) = delete;
+
+ Builder& operator=(const Builder&) = delete;
+ Builder& operator=(Builder&&) = delete;
+
+ protected:
+
+ explicit Builder(osmium::memory::Buffer& buffer, Builder* parent, osmium::memory::item_size_type size) :
+ m_buffer(buffer),
+ m_parent(parent),
+ m_item_offset(buffer.written()) {
+ m_buffer.reserve_space(size);
+ assert(buffer.is_aligned());
+ if (m_parent) {
+ m_parent->add_size(size);
+ }
+ }
+
+ ~Builder() = default;
+
+ osmium::memory::Item& item() const {
+ return *reinterpret_cast<osmium::memory::Item*>(m_buffer.data() + m_item_offset);
+ }
+
+ public:
+
+ /**
+ * Add padding to buffer (if needed) to align data properly.
+ *
+ * This calculates how many padding bytes are needed and adds
+ * as many zero bytes to the buffer. It also adds this number
+ * to the size of the current item (if the "self" param is
+ * true) and recursively to all the parent items.
+ *
+ * @param self If true add number of padding bytes to size
+ * of current item. Size is always added to
+ * parent item (if any).
+ *
+ */
+ 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);
+ if (self) {
+ add_size(padding);
+ } else if (m_parent) {
+ m_parent->add_size(padding);
+ assert(m_parent->size() % osmium::memory::align_bytes == 0);
+ }
+ }
+ }
+
+ void add_size(uint32_t size) {
+ item().add_size(size);
+ if (m_parent) {
+ m_parent->add_size(size);
+ }
+ }
+
+ uint32_t size() const noexcept {
+ return item().byte_size();
+ }
+
+ void add_item(const osmium::memory::Item* item) {
+ std::memcpy(m_buffer.reserve_space(item->padded_size()), item, item->padded_size());
+ add_size(item->padded_size());
+ }
+
+ /**
+ * Reserve space for an object of class T in buffer and return
+ * pointer to it.
+ */
+ template <class T>
+ T* reserve_space_for() {
+ assert(m_buffer.is_aligned());
+ return reinterpret_cast<T*>(m_buffer.reserve_space(sizeof(T)));
+ }
+
+ /**
+ * Append data to buffer.
+ *
+ * @param data Pointer to data.
+ * @param length Length of data in bytes. If data is a
+ * \0-terminated string, length must contain the
+ * \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);
+ return length;
+ }
+
+ /**
+ * Append \0-terminated string to buffer.
+ */
+ osmium::memory::item_size_type append(const char* str) {
+ return append(str, static_cast<osmium::memory::item_size_type>(std::strlen(str) + 1));
+ }
+
+ /// Return the buffer this builder is using.
+ osmium::memory::Buffer& buffer() noexcept {
+ return m_buffer;
+ }
+
+ }; // class Builder
+
+ 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");
+
+ public:
+
+ explicit ObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+ Builder(buffer, parent, sizeof(TItem)) {
+ new (&item()) TItem();
+ }
+
+ TItem& object() noexcept {
+ return static_cast<TItem&>(item());
+ }
+
+ /**
+ * Add user name to buffer.
+ *
+ * @param user Pointer to user name.
+ * @param length Length of user name including \0 byte.
+ */
+ void add_user(const char* user, const string_size_type length) {
+ object().set_user_size(length);
+ add_size(append(user, length));
+ add_padding(true);
+ }
+
+ /**
+ * Add user name to buffer.
+ *
+ * @param user Pointer to \0-terminated user name.
+ */
+ void add_user(const char* user) {
+ add_user(user, static_cast_with_assert<string_size_type>(std::strlen(user) + 1));
+ }
+
+ /**
+ * Add user name to buffer.
+ *
+ * @param user User name.
+ */
+ void add_user(const std::string& user) {
+ add_user(user.data(), static_cast_with_assert<string_size_type>(user.size() + 1));
+ }
+
+ }; // class ObjectBuilder
+
+ } // namespace builder
+
+} // namespace osmium
+
+#endif // OSMIUM_BUILDER_BUILDER_HPP
diff --git a/third_party/osmium/builder/builder_helper.hpp b/third_party/osmium/builder/builder_helper.hpp
new file mode 100644
index 0000000..3e00f81
--- /dev/null
+++ b/third_party/osmium/builder/builder_helper.hpp
@@ -0,0 +1,103 @@
+#ifndef OSMIUM_BUILDER_BUILDER_HELPER_HPP
+#define OSMIUM_BUILDER_BUILDER_HELPER_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 <cstddef>
+#include <initializer_list>
+#include <functional>
+#include <map>
+#include <utility>
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/memory/buffer.hpp>
+
+namespace osmium {
+
+ class NodeRef;
+ class TagList;
+ class WayNodeList;
+
+ namespace builder {
+
+ inline const osmium::WayNodeList& build_way_node_list(osmium::memory::Buffer& buffer, const std::initializer_list<osmium::NodeRef>& nodes) {
+ size_t pos = buffer.committed();
+ {
+ osmium::builder::WayNodeListBuilder wnl_builder(buffer);
+ for (const auto& node_ref : nodes) {
+ wnl_builder.add_node_ref(node_ref);
+ }
+ }
+ buffer.commit();
+ return buffer.get<const osmium::WayNodeList>(pos);
+ }
+
+ inline const osmium::TagList& build_tag_list(osmium::memory::Buffer& buffer, const std::initializer_list<std::pair<const char*, const char*>>& tags) {
+ size_t pos = buffer.committed();
+ {
+ osmium::builder::TagListBuilder tl_builder(buffer);
+ for (const auto& p : tags) {
+ tl_builder.add_tag(p.first, p.second);
+ }
+ }
+ buffer.commit();
+ return buffer.get<const osmium::TagList>(pos);
+ }
+
+ inline const osmium::TagList& build_tag_list_from_map(osmium::memory::Buffer& buffer, const std::map<const char*, const char*>& tags) {
+ size_t pos = buffer.committed();
+ {
+ osmium::builder::TagListBuilder tl_builder(buffer);
+ for (const auto& p : tags) {
+ tl_builder.add_tag(p.first, p.second);
+ }
+ }
+ buffer.commit();
+ return buffer.get<const osmium::TagList>(pos);
+ }
+
+ inline const osmium::TagList& build_tag_list_from_func(osmium::memory::Buffer& buffer, std::function<void(osmium::builder::TagListBuilder&)> func) {
+ size_t pos = buffer.committed();
+ {
+ osmium::builder::TagListBuilder tl_builder(buffer);
+ func(tl_builder);
+ }
+ buffer.commit();
+ return buffer.get<const osmium::TagList>(pos);
+ }
+
+ } // namespace builder
+
+} // namespace osmium
+
+#endif // OSMIUM_BUILDER_BUILDER_HELPER_HPP
diff --git a/third_party/osmium/builder/osm_object_builder.hpp b/third_party/osmium/builder/osm_object_builder.hpp
new file mode 100644
index 0000000..851eb85
--- /dev/null
+++ b/third_party/osmium/builder/osm_object_builder.hpp
@@ -0,0 +1,283 @@
+#ifndef OSMIUM_BUILDER_OSM_OBJECT_BUILDER_HPP
+#define OSMIUM_BUILDER_OSM_OBJECT_BUILDER_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 <cstring>
+#include <initializer_list>
+#include <new>
+#include <utility>
+
+#include <osmium/builder/builder.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+ namespace memory {
+ class Buffer;
+ }
+
+ namespace builder {
+
+ class TagListBuilder : public ObjectBuilder<TagList> {
+
+ public:
+
+ explicit TagListBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+ ObjectBuilder<TagList>(buffer, parent) {
+ }
+
+ ~TagListBuilder() {
+ add_padding();
+ }
+
+ /**
+ * Add tag to buffer.
+ *
+ * @param key Tag key.
+ * @param value Tag value.
+ */
+ void add_tag(const char* key, const char* value) {
+ add_size(append(key) + append(value));
+ }
+
+ /**
+ * Add tag to buffer.
+ *
+ * @param key Tag key.
+ * @param value Tag value.
+ */
+ void add_tag(const std::string& key, const std::string& value) {
+ add_size(append(key.data(), static_cast_with_assert<string_size_type>(key.size() + 1)) +
+ append(value.data(), static_cast_with_assert<string_size_type>(value.size() + 1)));
+ }
+
+ }; // class TagListBuilder
+
+ template <class T>
+ class NodeRefListBuilder : public ObjectBuilder<T> {
+
+ public:
+
+ explicit NodeRefListBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+ ObjectBuilder<T>(buffer, parent) {
+ }
+
+ ~NodeRefListBuilder() {
+ static_cast<Builder*>(this)->add_padding();
+ }
+
+ void add_node_ref(const NodeRef& node_ref) {
+ new (static_cast<Builder*>(this)->reserve_space_for<osmium::NodeRef>()) osmium::NodeRef(node_ref);
+ static_cast<Builder*>(this)->add_size(sizeof(osmium::NodeRef));
+ }
+
+ void add_node_ref(const object_id_type ref, const osmium::Location location=Location()) {
+ add_node_ref(NodeRef(ref, location));
+ }
+
+ }; // class NodeRefListBuilder
+
+ typedef NodeRefListBuilder<WayNodeList> WayNodeListBuilder;
+ typedef NodeRefListBuilder<OuterRing> OuterRingBuilder;
+ typedef NodeRefListBuilder<InnerRing> InnerRingBuilder;
+
+ class RelationMemberListBuilder : public ObjectBuilder<RelationMemberList> {
+
+ /**
+ * Add role to buffer.
+ *
+ * @param member Relation member object where the length of the role
+ * will be set.
+ * @param role The role.
+ * @param length Length of role string including \0 termination.
+ */
+ void add_role(osmium::RelationMember& member, const char* role, const string_size_type length) {
+ member.set_role_size(length);
+ add_size(append(role, length));
+ add_padding(true);
+ }
+
+ /**
+ * Add role to buffer.
+ *
+ * @param member Relation member object where the length of the role
+ * will be set.
+ * @param role \0-terminated role.
+ */
+ void add_role(osmium::RelationMember& member, const char* role) {
+ add_role(member, role, static_cast_with_assert<string_size_type>(std::strlen(role) + 1));
+ }
+
+ /**
+ * Add role to buffer.
+ *
+ * @param member Relation member object where the length of the role
+ * will be set.
+ * @param role Role.
+ */
+ void add_role(osmium::RelationMember& member, const std::string& role) {
+ add_role(member, role.data(), static_cast_with_assert<string_size_type>(role.size() + 1));
+ }
+
+ public:
+
+ explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+ ObjectBuilder<RelationMemberList>(buffer, parent) {
+ }
+
+ ~RelationMemberListBuilder() {
+ add_padding();
+ }
+
+ /**
+ * Add a member to the relation.
+ *
+ * @param type The type (node, way, or relation).
+ * @param ref The ID of the member.
+ * @param role The role of the member.
+ * @param full_member Optional pointer to the member object. If it
+ * is available a copy will be added to the
+ * relation.
+ */
+ void add_member(osmium::item_type type, object_id_type ref, const char* role, const osmium::OSMObject* full_member = nullptr) {
+ osmium::RelationMember* member = reserve_space_for<osmium::RelationMember>();
+ new (member) osmium::RelationMember(ref, type, full_member != nullptr);
+ add_size(sizeof(RelationMember));
+ add_role(*member, role);
+ if (full_member) {
+ add_item(full_member);
+ }
+ }
+
+ /**
+ * Add a member to the relation.
+ *
+ * @param type The type (node, way, or relation).
+ * @param ref The ID of the member.
+ * @param role The role of the member.
+ * @param full_member Optional pointer to the member object. If it
+ * is available a copy will be added to the
+ * relation.
+ */
+ void add_member(osmium::item_type type, object_id_type ref, const std::string& role, const osmium::OSMObject* full_member = nullptr) {
+ osmium::RelationMember* member = reserve_space_for<osmium::RelationMember>();
+ new (member) osmium::RelationMember(ref, type, full_member != nullptr);
+ add_size(sizeof(RelationMember));
+ add_role(*member, role);
+ if (full_member) {
+ add_item(full_member);
+ }
+ }
+
+ }; // class RelationMemberListBuilder
+
+ template <class T>
+ class OSMObjectBuilder : public ObjectBuilder<T> {
+
+ public:
+
+ 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));
+ }
+
+ void add_tags(const std::initializer_list<std::pair<const char*, const char*>>& tags) {
+ osmium::builder::TagListBuilder tl_builder(static_cast<Builder*>(this)->buffer(), this);
+ for (const auto& p : tags) {
+ tl_builder.add_tag(p.first, p.second);
+ }
+ }
+
+ }; // class OSMObjectBuilder
+
+ typedef OSMObjectBuilder<osmium::Node> NodeBuilder;
+ typedef OSMObjectBuilder<osmium::Relation> RelationBuilder;
+
+ class WayBuilder : public OSMObjectBuilder<osmium::Way> {
+
+ public:
+
+ explicit WayBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+ OSMObjectBuilder<osmium::Way>(buffer, parent) {
+ }
+
+ void add_node_refs(const std::initializer_list<osmium::NodeRef>& nodes) {
+ osmium::builder::WayNodeListBuilder builder(buffer(), this);
+ for (const auto& node_ref : nodes) {
+ builder.add_node_ref(node_ref);
+ }
+ }
+
+ }; // class WayBuilder
+
+ class AreaBuilder : public OSMObjectBuilder<osmium::Area> {
+
+ public:
+
+ explicit AreaBuilder(osmium::memory::Buffer& buffer, Builder* parent=nullptr) :
+ OSMObjectBuilder<osmium::Area>(buffer, parent) {
+ }
+
+ /**
+ * Initialize area attributes from the attributes of the given object.
+ */
+ void initialize_from_object(const osmium::OSMObject& source) {
+ osmium::Area& area = object();
+ area.set_id(osmium::object_id_to_area_id(source.id(), source.type()));
+ area.set_version(source.version());
+ area.set_changeset(source.changeset());
+ area.set_timestamp(source.timestamp());
+ area.set_visible(source.visible());
+ area.set_uid(source.uid());
+
+ add_user(source.user());
+ }
+
+ }; // class AreaBuilder
+
+ typedef ObjectBuilder<osmium::Changeset> ChangesetBuilder;
+
+ } // namespace builder
+
+} // namespace osmium
+
+#endif // OSMIUM_BUILDER_OSM_OBJECT_BUILDER_HPP
diff --git a/third_party/osmium/config/constexpr.hpp b/third_party/osmium/config/constexpr.hpp
new file mode 100644
index 0000000..3eddc84
--- /dev/null
+++ b/third_party/osmium/config/constexpr.hpp
@@ -0,0 +1,43 @@
+#ifndef OSMIUM_CONFIG_CONSTEXPR_HPP
+#define OSMIUM_CONFIG_CONSTEXPR_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.
+
+*/
+
+// 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
diff --git a/third_party/osmium/diff_handler.hpp b/third_party/osmium/diff_handler.hpp
new file mode 100644
index 0000000..9864df5
--- /dev/null
+++ b/third_party/osmium/diff_handler.hpp
@@ -0,0 +1,67 @@
+#ifndef OSMIUM_DIFF_HANDLER_HPP
+#define OSMIUM_DIFF_HANDLER_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 <osmium/osm/diff_object.hpp>
+
+namespace osmium {
+
+ /**
+ * @brief Osmium diff handlers provide access to differences between OSM object versions
+ */
+ namespace diff_handler {
+
+ class DiffHandler {
+
+ public:
+
+ DiffHandler() {
+ }
+
+ void node(const osmium::DiffNode&) const {
+ }
+
+ void way(const osmium::DiffWay&) const {
+ }
+
+ void relation(const osmium::DiffRelation&) const {
+ }
+
+ }; // class DiffHandler
+
+ } // namespace diff_handler
+
+} // namespace osmium
+
+#endif // OSMIUM_DIFF_HANDLER_HPP
diff --git a/third_party/osmium/diff_iterator.hpp b/third_party/osmium/diff_iterator.hpp
new file mode 100644
index 0000000..576834c
--- /dev/null
+++ b/third_party/osmium/diff_iterator.hpp
@@ -0,0 +1,129 @@
+#ifndef OSMIUM_DIFF_ITERATOR_HPP
+#define OSMIUM_DIFF_ITERATOR_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 <iterator>
+#include <type_traits>
+
+#include <osmium/osm/diff_object.hpp>
+
+namespace osmium {
+
+ class OSMObject;
+
+ template <class TBasicIterator>
+ class DiffIterator : public std::iterator<std::input_iterator_tag, const osmium::DiffObject> {
+
+ static_assert(std::is_base_of<osmium::OSMObject, typename TBasicIterator::value_type>::value, "TBasicIterator::value_type must derive from osmium::OSMObject");
+
+ TBasicIterator m_prev;
+ TBasicIterator m_curr;
+ TBasicIterator m_next;
+
+ const TBasicIterator m_end;
+
+ mutable osmium::DiffObject m_diff;
+
+ void set_diff() const {
+ assert(m_curr != m_end);
+
+ TBasicIterator prev = m_prev;
+ if (prev->type() != m_curr->type() || prev->id() != m_curr->id()) {
+ prev = m_curr;
+ }
+
+ TBasicIterator next = m_next;
+ if (next == m_end || next->type() != m_curr->type() || next->id() != m_curr->id()) {
+ next = m_curr;
+ }
+
+ m_diff = osmium::DiffObject(*prev, *m_curr, *next);
+ }
+
+ public:
+
+ explicit DiffIterator(TBasicIterator begin, TBasicIterator end) :
+ m_prev(begin),
+ m_curr(begin),
+ m_next(begin == end ? begin : ++begin),
+ m_end(end) {
+ }
+
+ DiffIterator(const DiffIterator&) = default;
+ DiffIterator& operator=(const DiffIterator&) = default;
+
+ DiffIterator(DiffIterator&&) = default;
+ DiffIterator& operator=(DiffIterator&&) = default;
+
+ DiffIterator& operator++() {
+ m_prev = std::move(m_curr);
+ m_curr = m_next;
+
+ if (m_next != m_end) {
+ ++m_next;
+ }
+
+ return *this;
+ }
+
+ DiffIterator operator++(int) {
+ DiffIterator tmp(*this);
+ operator++();
+ return tmp;
+ }
+
+ bool operator==(const DiffIterator& rhs) const {
+ return m_curr == rhs.m_curr && m_end == rhs.m_end;
+ }
+
+ bool operator!=(const DiffIterator& rhs) const {
+ return !(*this == rhs);
+ }
+
+ reference operator*() const {
+ set_diff();
+ return m_diff;
+ }
+
+ pointer operator->() const {
+ set_diff();
+ return &m_diff;
+ }
+
+ }; // class DiffIterator
+
+} // namespace osmium
+
+#endif // OSMIUM_DIFF_ITERATOR_HPP
diff --git a/third_party/osmium/diff_visitor.hpp b/third_party/osmium/diff_visitor.hpp
new file mode 100644
index 0000000..b8db697
--- /dev/null
+++ b/third_party/osmium/diff_visitor.hpp
@@ -0,0 +1,104 @@
+#ifndef OSMIUM_DIFF_VISITOR_HPP
+#define OSMIUM_DIFF_VISITOR_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 <osmium/diff_iterator.hpp>
+#include <osmium/io/input_iterator.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/diff_object.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+ namespace detail {
+
+ template <class THandler>
+ inline void apply_diff_iterator_recurse(const osmium::DiffObject& diff, THandler& handler) {
+ switch (diff.type()) {
+ case osmium::item_type::node:
+ handler.node(static_cast<const osmium::DiffNode&>(diff));
+ break;
+ case osmium::item_type::way:
+ handler.way(static_cast<const osmium::DiffWay&>(diff));
+ break;
+ case osmium::item_type::relation:
+ handler.relation(static_cast<const osmium::DiffRelation&>(diff));
+ break;
+ default:
+ throw osmium::unknown_type();
+ }
+ }
+
+ template <class THandler, class ...TRest>
+ inline void apply_diff_iterator_recurse(const osmium::DiffObject& diff, THandler& handler, TRest&... more) {
+ apply_diff_iterator_recurse(diff, handler);
+ apply_diff_iterator_recurse(diff, more...);
+ }
+
+ } // namespace detail
+
+ template <class TIterator, class ...THandlers>
+ inline void apply_diff(TIterator it, TIterator end, THandlers&... handlers) {
+ typedef osmium::DiffIterator<TIterator> diff_iterator;
+
+ diff_iterator dit(it, end);
+ diff_iterator dend(end, end);
+
+ for (; dit != dend; ++dit) {
+ detail::apply_diff_iterator_recurse(*dit, handlers...);
+ }
+ }
+
+ class OSMObject;
+
+ template <class TSource, class ...THandlers>
+ inline void apply_diff(TSource& source, THandlers&... handlers) {
+ apply_diff(osmium::io::InputIterator<TSource, osmium::OSMObject> {source},
+ osmium::io::InputIterator<TSource, osmium::OSMObject> {},
+ handlers...);
+ }
+
+ template <class ...THandlers>
+ inline void apply_diff(osmium::memory::Buffer& buffer, THandlers&... handlers) {
+ apply_diff(buffer.begin(), buffer.end(), handlers...);
+ }
+
+ template <class ...THandlers>
+ inline void apply_diff(const osmium::memory::Buffer& buffer, THandlers&... handlers) {
+ apply_diff(buffer.cbegin(), buffer.cend(), handlers...);
+ }
+
+} // namespace osmium
+
+#endif // OSMIUM_DIFF_VISITOR_HPP
diff --git a/third_party/osmium/dynamic_handler.hpp b/third_party/osmium/dynamic_handler.hpp
new file mode 100644
index 0000000..bc59313
--- /dev/null
+++ b/third_party/osmium/dynamic_handler.hpp
@@ -0,0 +1,195 @@
+#ifndef OSMIUM_DYNAMIC_HANDLER_HPP
+#define OSMIUM_DYNAMIC_HANDLER_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 <memory>
+#include <utility>
+
+#include <osmium/handler.hpp>
+
+namespace osmium {
+
+ class Node;
+ class Way;
+ class Relation;
+ class Area;
+ class Changeset;
+
+ namespace handler {
+
+ namespace detail {
+
+ class HandlerWrapperBase {
+
+ public:
+
+ virtual ~HandlerWrapperBase() {
+ }
+
+ virtual void node(const osmium::Node&) {
+ }
+
+ virtual void way(const osmium::Way&) {
+ }
+
+ virtual void relation(const osmium::Relation&) {
+ }
+
+ virtual void area(const osmium::Area&) {
+ }
+
+ virtual void changeset(const osmium::Changeset&) {
+ }
+
+ virtual void flush() {
+ }
+
+ }; // class HandlerWrapperBase
+
+
+ // The following uses trick from
+ // http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence
+ // to either call handler style functions or visitor style operator().
+
+#define OSMIUM_DYNAMIC_HANDLER_DISPATCH(_name_, _type_) \
+template <class THandler> \
+auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, int) -> decltype(handler._name_(object), void()) { \
+ handler._name_(object); \
+} \
+template <class THandler> \
+auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) -> decltype(handler(object), void()) { \
+ handler(object); \
+}
+
+ OSMIUM_DYNAMIC_HANDLER_DISPATCH(node, Node)
+ OSMIUM_DYNAMIC_HANDLER_DISPATCH(way, Way)
+ OSMIUM_DYNAMIC_HANDLER_DISPATCH(relation, Relation)
+ OSMIUM_DYNAMIC_HANDLER_DISPATCH(changeset, Changeset)
+ OSMIUM_DYNAMIC_HANDLER_DISPATCH(area, Area)
+
+ template <class THandler>
+ auto flush_dispatch(THandler& handler, int) -> decltype(handler.flush(), void()) {
+ handler.flush();
+ }
+
+ template <class THandler>
+ void flush_dispatch(THandler&, long) {}
+
+ template <class THandler>
+ class HandlerWrapper : public HandlerWrapperBase {
+
+ THandler m_handler;
+
+ public:
+
+ template <class... TArgs>
+ HandlerWrapper(TArgs&&... args) :
+ m_handler(std::forward<TArgs>(args)...) {
+ }
+
+ void node(const osmium::Node& node) override final {
+ node_dispatch(m_handler, node, 0);
+ }
+
+ void way(const osmium::Way& way) override final {
+ way_dispatch(m_handler, way, 0);
+ }
+
+ void relation(const osmium::Relation& relation) override final {
+ relation_dispatch(m_handler, relation, 0);
+ }
+
+ void area(const osmium::Area& area) override final {
+ area_dispatch(m_handler, area, 0);
+ }
+
+ void changeset(const osmium::Changeset& changeset) override final {
+ changeset_dispatch(m_handler, changeset, 0);
+ }
+
+ void flush() override final {
+ flush_dispatch(m_handler, 0);
+ }
+
+ }; // class HandlerWrapper
+
+ } // namespace detail
+
+ class DynamicHandler : public osmium::handler::Handler {
+
+ typedef std::unique_ptr<osmium::handler::detail::HandlerWrapperBase> impl_ptr;
+ impl_ptr m_impl;
+
+ public:
+
+ DynamicHandler() :
+ m_impl(impl_ptr(new osmium::handler::detail::HandlerWrapperBase)) {
+ }
+
+ template <class THandler, class... TArgs>
+ void set(TArgs&&... args) {
+ m_impl = impl_ptr(new osmium::handler::detail::HandlerWrapper<THandler>(std::forward<TArgs>(args)...));
+ }
+
+ void node(const osmium::Node& node) {
+ m_impl->node(node);
+ }
+
+ void way(const osmium::Way& way) {
+ m_impl->way(way);
+ }
+
+ void relation(const osmium::Relation& relation) {
+ m_impl->relation(relation);
+ }
+
+ void area(const osmium::Area& area) {
+ m_impl->area(area);
+ }
+
+ void changeset(const osmium::Changeset& changeset) {
+ m_impl->changeset(changeset);
+ }
+
+ void flush() {
+ m_impl->flush();
+ }
+
+ }; // class DynamicHandler
+
+ } // namspace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_DYNAMIC_HANDLER_HPP
diff --git a/third_party/osmium/experimental/flex_reader.hpp b/third_party/osmium/experimental/flex_reader.hpp
new file mode 100644
index 0000000..8dca152
--- /dev/null
+++ b/third_party/osmium/experimental/flex_reader.hpp
@@ -0,0 +1,131 @@
+#ifndef OSMIUM_EXPERIMENTAL_FLEX_READER_HPP
+#define OSMIUM_EXPERIMENTAL_FLEX_READER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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 <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/visitor.hpp>
+#include <osmium/area/multipolygon_collector.hpp>
+#include <osmium/area/assembler.hpp>
+
+namespace osmium {
+
+ /**
+ * Experimental code that is not "officially" supported.
+ */
+ namespace experimental {
+
+ template <class TLocationHandler>
+ class FlexReader {
+
+ 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;
+
+ osmium::io::Reader m_reader;
+ osmium::area::Assembler::config_type m_assembler_config;
+ osmium::area::MultipolygonCollector<osmium::area::Assembler> m_collector;
+
+ 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),
+ 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_reader(file, m_entities),
+ m_assembler_config(),
+ m_collector(m_assembler_config)
+ {
+ m_location_handler.ignore_errors();
+ if (m_with_areas) {
+ osmium::io::Reader reader(file, osmium::osm_entity_bits::relation);
+ m_collector.read_relations(reader);
+ reader.close();
+ }
+ }
+
+ 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 char* filename, osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::nwr) :
+ FlexReader(osmium::io::File(filename), entities) {
+ }
+
+ std::vector<osmium::memory::Buffer> read() {
+ std::vector<osmium::memory::Buffer> buffers;
+
+ 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));
+ }));
+ } else if (m_entities & (osmium::osm_entity_bits::node | osmium::osm_entity_bits::way)) {
+ osmium::apply(buffers[0], m_location_handler);
+ }
+ }
+
+ return buffers;
+ }
+
+ osmium::io::Header header() const {
+ return m_reader.header();
+ }
+
+ void close() {
+ return m_reader.close();
+ }
+
+ bool eof() const {
+ return m_reader.eof();
+ }
+
+ const osmium::area::MultipolygonCollector<osmium::area::Assembler>& collector() const {
+ return m_collector;
+ }
+
+ }; // class FlexReader
+
+ } // namespace experimental
+
+} // namespace osmium
+
+#endif // OSMIUM_EXPERIMENTAL_FLEX_READER_HPP
diff --git a/third_party/osmium/geom/coordinates.hpp b/third_party/osmium/geom/coordinates.hpp
new file mode 100644
index 0000000..1ff27fe
--- /dev/null
+++ b/third_party/osmium/geom/coordinates.hpp
@@ -0,0 +1,97 @@
+#ifndef OSMIUM_GEOM_COORDINATES_HPP
+#define OSMIUM_GEOM_COORDINATES_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 <cstddef>
+#include <iosfwd>
+#include <string>
+
+#include <osmium/osm/location.hpp>
+#include <osmium/util/double.hpp>
+
+namespace osmium {
+
+ namespace geom {
+
+ struct Coordinates {
+
+ double x;
+ double y;
+
+ explicit Coordinates(double cx, double cy) noexcept : x(cx), y(cy) {
+ }
+
+ Coordinates(const osmium::Location& location) : x(location.lon()), y(location.lat()) {
+ }
+
+ void append_to_string(std::string& s, const char infix, int precision) const {
+ osmium::util::double2string(s, x, precision);
+ s += infix;
+ osmium::util::double2string(s, y, precision);
+ }
+
+ void append_to_string(std::string& s, const char prefix, const char infix, const char suffix, int precision) const {
+ s += prefix;
+ append_to_string(s, infix, precision);
+ s += suffix;
+ }
+
+ }; // struct coordinates
+
+ /**
+ * Compare whether two Coordinates are identical. Might not give the
+ * right result if the coordinates have been the result of some
+ * calculation that introduced rounding errors.
+ */
+ inline bool operator==(const Coordinates& lhs, const Coordinates& rhs) noexcept {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+ return lhs.x == rhs.x && lhs.y == rhs.y;
+#pragma GCC diagnostic pop
+ }
+
+ inline bool operator!=(const Coordinates& lhs, const Coordinates& rhs) noexcept {
+ return ! operator==(lhs, rhs);
+ }
+
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const Coordinates& c) {
+ return out << '(' << c.x << ',' << c.y << ')';
+ }
+
+ } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_COORDINATES_HPP
diff --git a/third_party/osmium/geom/factory.hpp b/third_party/osmium/geom/factory.hpp
new file mode 100644
index 0000000..4097b5d
--- /dev/null
+++ b/third_party/osmium/geom/factory.hpp
@@ -0,0 +1,328 @@
+#ifndef OSMIUM_GEOM_FACTORY_HPP
+#define OSMIUM_GEOM_FACTORY_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 <cstddef>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/area.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+ /**
+ * Exception thrown when an invalid geometry is encountered. An example
+ * would be a linestring with less than two points.
+ */
+ struct geometry_error : public std::runtime_error {
+
+ geometry_error(const std::string& what) :
+ std::runtime_error(what) {
+ }
+
+ geometry_error(const char* what) :
+ std::runtime_error(what) {
+ }
+
+ }; // struct geometry_error
+
+ /**
+ * @brief Everything related to geometry handling.
+ */
+ namespace geom {
+
+ /**
+ * Which nodes of a way to use for a linestring.
+ */
+ enum class use_nodes : bool {
+ unique = true, ///< Remove consecutive nodes with same location.
+ all = false ///< Use all nodes.
+ }; // enum class use_nodes
+
+ /**
+ * Which direction the linestring created from a way
+ * should have.
+ */
+ enum class direction : bool {
+ backward = true, ///< Linestring has reverse direction.
+ forward = false ///< Linestring has same direction as way.
+ }; // enum class direction
+
+ /**
+ * This pseudo projection just returns its WGS84 input unchanged.
+ * Used as a template parameter if a real projection is not needed.
+ */
+ class IdentityProjection {
+
+ public:
+
+ Coordinates operator()(osmium::Location location) const {
+ return Coordinates{location.lon(), location.lat()};
+ }
+
+ int epsg() const noexcept {
+ return 4326;
+ }
+
+ std::string proj_string() const {
+ return "+proj=longlat +datum=WGS84 +no_defs";
+ }
+
+ }; // class IdentityProjection
+
+ /**
+ * Geometry factory.
+ */
+ template <class TGeomImpl, class TProjection = IdentityProjection>
+ class GeometryFactory {
+
+ /**
+ * Add all points of an outer or inner ring to a multipolygon.
+ */
+ void add_points(const osmium::OuterRing& nodes) {
+ osmium::Location last_location;
+ for (const osmium::NodeRef& node_ref : nodes) {
+ if (last_location != node_ref.location()) {
+ last_location = node_ref.location();
+ m_impl.multipolygon_add_location(m_projection(last_location));
+ }
+ }
+ }
+
+ TProjection m_projection;
+ TGeomImpl m_impl;
+
+ public:
+
+ /**
+ * Constructor for default initialized projection.
+ */
+ template <class... TArgs>
+ GeometryFactory<TGeomImpl, TProjection>(TArgs&&... args) :
+ m_projection(),
+ m_impl(std::forward<TArgs>(args)...) {
+ }
+
+ /**
+ * Constructor for explicitly initialized projection. Note that the
+ * projection is moved into the GeometryFactory.
+ */
+ template <class... TArgs>
+ GeometryFactory<TGeomImpl, TProjection>(TProjection&& projection, TArgs&&... args) :
+ m_projection(std::move(projection)),
+ m_impl(std::forward<TArgs>(args)...) {
+ }
+
+ typedef typename TGeomImpl::point_type point_type;
+ typedef typename TGeomImpl::linestring_type linestring_type;
+ typedef typename TGeomImpl::polygon_type polygon_type;
+ typedef typename TGeomImpl::multipolygon_type multipolygon_type;
+ typedef typename TGeomImpl::ring_type ring_type;
+
+ int epsg() const {
+ return m_projection.epsg();
+ }
+
+ std::string proj_string() const {
+ return m_projection.proj_string();
+ }
+
+ /* Point */
+
+ point_type create_point(const osmium::Location location) const {
+ return m_impl.make_point(m_projection(location));
+ }
+
+ point_type create_point(const osmium::Node& node) {
+ return create_point(node.location());
+ }
+
+ point_type create_point(const osmium::NodeRef& node_ref) {
+ return create_point(node_ref.location());
+ }
+
+ /* LineString */
+
+ void linestring_start() {
+ m_impl.linestring_start();
+ }
+
+ template <class TIter>
+ size_t fill_linestring(TIter it, TIter end) {
+ size_t num_points = 0;
+ for (; it != end; ++it, ++num_points) {
+ m_impl.linestring_add_location(m_projection(it->location()));
+ }
+ return num_points;
+ }
+
+ template <class TIter>
+ size_t fill_linestring_unique(TIter it, TIter end) {
+ size_t num_points = 0;
+ osmium::Location last_location;
+ for (; it != end; ++it) {
+ if (last_location != it->location()) {
+ last_location = it->location();
+ m_impl.linestring_add_location(m_projection(last_location));
+ ++num_points;
+ }
+ }
+ return num_points;
+ }
+
+ linestring_type linestring_finish(size_t num_points) {
+ 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_start();
+ size_t num_points = 0;
+
+ if (un == use_nodes::unique) {
+ osmium::Location last_location;
+ switch (dir) {
+ case direction::forward:
+ num_points = fill_linestring_unique(wnl.cbegin(), wnl.cend());
+ break;
+ case direction::backward:
+ num_points = fill_linestring_unique(wnl.crbegin(), wnl.crend());
+ break;
+ }
+ } else {
+ switch (dir) {
+ case direction::forward:
+ num_points = fill_linestring(wnl.cbegin(), wnl.cend());
+ break;
+ case direction::backward:
+ num_points = fill_linestring(wnl.crbegin(), wnl.crend());
+ break;
+ }
+ }
+
+ if (num_points < 2) {
+ throw osmium::geometry_error("not enough points for linestring");
+ }
+
+ return linestring_finish(num_points);
+ }
+
+ linestring_type create_linestring(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir=direction::forward) {
+ return create_linestring(way.nodes(), un, dir);
+ }
+
+ /* Polygon */
+
+ void polygon_start() {
+ m_impl.polygon_start();
+ }
+
+ template <class TIter>
+ size_t fill_polygon(TIter it, TIter end) {
+ size_t num_points = 0;
+ for (; it != end; ++it, ++num_points) {
+ m_impl.polygon_add_location(m_projection(it->location()));
+ }
+ return num_points;
+ }
+
+ template <class TIter>
+ size_t fill_polygon_unique(TIter it, TIter end) {
+ size_t num_points = 0;
+ osmium::Location last_location;
+ for (; it != end; ++it) {
+ if (last_location != it->location()) {
+ last_location = it->location();
+ m_impl.polygon_add_location(m_projection(last_location));
+ ++num_points;
+ }
+ }
+ return num_points;
+ }
+
+ polygon_type polygon_finish(size_t num_points) {
+ return m_impl.polygon_finish(num_points);
+ }
+
+ /* MultiPolygon */
+
+ multipolygon_type create_multipolygon(const osmium::Area& area) {
+ size_t num_polygons = 0;
+ size_t num_rings = 0;
+ m_impl.multipolygon_start();
+
+ for (auto it = area.cbegin(); it != area.cend(); ++it) {
+ const osmium::OuterRing& ring = static_cast<const osmium::OuterRing&>(*it);
+ if (it->type() == osmium::item_type::outer_ring) {
+ if (num_polygons > 0) {
+ m_impl.multipolygon_polygon_finish();
+ }
+ m_impl.multipolygon_polygon_start();
+ m_impl.multipolygon_outer_ring_start();
+ add_points(ring);
+ m_impl.multipolygon_outer_ring_finish();
+ ++num_rings;
+ ++num_polygons;
+ } else if (it->type() == osmium::item_type::inner_ring) {
+ m_impl.multipolygon_inner_ring_start();
+ add_points(ring);
+ m_impl.multipolygon_inner_ring_finish();
+ ++num_rings;
+ }
+ }
+
+ // if there are no rings, this area is invalid
+ if (num_rings == 0) {
+ throw osmium::geometry_error("invalid area");
+ }
+
+ m_impl.multipolygon_polygon_finish();
+ return m_impl.multipolygon_finish();
+ }
+
+ }; // class GeometryFactory
+
+ } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_FACTORY_HPP
diff --git a/third_party/osmium/geom/geojson.hpp b/third_party/osmium/geom/geojson.hpp
new file mode 100644
index 0000000..f6d7ee6
--- /dev/null
+++ b/third_party/osmium/geom/geojson.hpp
@@ -0,0 +1,152 @@
+#ifndef OSMIUM_GEOM_GEOJSON_HPP
+#define OSMIUM_GEOM_GEOJSON_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 <string>
+#include <utility>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/factory.hpp>
+
+namespace osmium {
+
+ namespace geom {
+
+ namespace detail {
+
+ class GeoJSONFactoryImpl {
+
+ std::string m_str;
+ int m_precision;
+
+ public:
+
+ typedef std::string point_type;
+ typedef std::string linestring_type;
+ typedef std::string polygon_type;
+ typedef std::string multipolygon_type;
+ typedef std::string ring_type;
+
+ GeoJSONFactoryImpl(int precision = 7) :
+ m_precision(precision) {
+ }
+
+ /* Point */
+
+ // { "type": "Point", "coordinates": [100.0, 0.0] }
+ point_type make_point(const osmium::geom::Coordinates& xy) const {
+ std::string str {"{\"type\":\"Point\",\"coordinates\":"};
+ xy.append_to_string(str, '[', ',', ']', m_precision);
+ str += "}";
+ return str;
+ }
+
+ /* LineString */
+
+ // { "type": "LineString", "coordinates": [ [100.0, 0.0], [101.0, 1.0] ] }
+ void linestring_start() {
+ m_str = "{\"type\":\"LineString\",\"coordinates\":[";
+ }
+
+ void linestring_add_location(const osmium::geom::Coordinates& xy) {
+ xy.append_to_string(m_str, '[', ',', ']', m_precision);
+ m_str += ',';
+ }
+
+ linestring_type linestring_finish(size_t /* num_points */) {
+ assert(!m_str.empty());
+ std::string str;
+ std::swap(str, m_str);
+ str.back() = ']';
+ str += "}";
+ return str;
+ }
+
+ /* MultiPolygon */
+
+ void multipolygon_start() {
+ m_str = "{\"type\":\"MultiPolygon\",\"coordinates\":[";
+ }
+
+ void multipolygon_polygon_start() {
+ m_str += '[';
+ }
+
+ void multipolygon_polygon_finish() {
+ m_str += "],";
+ }
+
+ void multipolygon_outer_ring_start() {
+ m_str += '[';
+ }
+
+ void multipolygon_outer_ring_finish() {
+ assert(!m_str.empty());
+ m_str.back() = ']';
+ }
+
+ void multipolygon_inner_ring_start() {
+ m_str += ",[";
+ }
+
+ void multipolygon_inner_ring_finish() {
+ assert(!m_str.empty());
+ m_str.back() = ']';
+ }
+
+ void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+ xy.append_to_string(m_str, '[', ',', ']', m_precision);
+ m_str += ',';
+ }
+
+ multipolygon_type multipolygon_finish() {
+ assert(!m_str.empty());
+ m_str.back() = ']';
+ m_str += "}";
+ return std::move(m_str);
+ }
+
+ }; // class GeoJSONFactoryImpl
+
+ } // namespace detail
+
+ template <class TProjection = IdentityProjection>
+ using GeoJSONFactory = GeometryFactory<osmium::geom::detail::GeoJSONFactoryImpl, TProjection>;
+
+ } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_GEOJSON_HPP
diff --git a/third_party/osmium/geom/geos.hpp b/third_party/osmium/geom/geos.hpp
new file mode 100644
index 0000000..877520b
--- /dev/null
+++ b/third_party/osmium/geom/geos.hpp
@@ -0,0 +1,224 @@
+#ifndef OSMIUM_GEOM_GEOS_HPP
+#define OSMIUM_GEOM_GEOS_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.
+
+*/
+
+#define OSMIUM_COMPILE_WITH_CFLAGS_GEOS `geos-config --cflags`
+#define OSMIUM_LINK_WITH_LIBS_GEOS `geos-config --libs`
+
+#include <utility>
+
+#include <geos/geom/Coordinate.h>
+#include <geos/geom/CoordinateSequence.h>
+#include <geos/geom/CoordinateSequenceFactory.h>
+#include <geos/geom/GeometryFactory.h>
+#include <geos/geom/LinearRing.h>
+#include <geos/geom/MultiPolygon.h>
+#include <geos/geom/Point.h>
+#include <geos/geom/Polygon.h>
+#include <geos/geom/PrecisionModel.h>
+#include <geos/util/GEOSException.h>
+
+#include <osmium/geom/factory.hpp>
+#include <osmium/geom/coordinates.hpp>
+
+// MSVC doesn't support throw_with_nested yet
+#ifdef _MSC_VER
+# define THROW throw
+#else
+# define THROW std::throw_with_nested
+#endif
+
+namespace osmium {
+
+ struct geos_geometry_error : public geometry_error {
+
+ geos_geometry_error() :
+ geometry_error("geometry creation failed in GEOS library, see nested exception for details") {
+ }
+
+ }; // struct geos_geometry_error
+
+ namespace geom {
+
+ namespace detail {
+
+ class GEOSFactoryImpl {
+
+ geos::geom::PrecisionModel m_precision_model;
+ geos::geom::GeometryFactory m_geos_factory;
+
+ std::unique_ptr<geos::geom::CoordinateSequence> m_coordinate_sequence;
+ std::vector<std::unique_ptr<geos::geom::LinearRing>> m_rings;
+ std::vector<std::unique_ptr<geos::geom::Polygon>> m_polygons;
+
+ public:
+
+ typedef std::unique_ptr<geos::geom::Point> point_type;
+ typedef std::unique_ptr<geos::geom::LineString> linestring_type;
+ typedef std::unique_ptr<geos::geom::Polygon> polygon_type;
+ typedef std::unique_ptr<geos::geom::MultiPolygon> multipolygon_type;
+ typedef std::unique_ptr<geos::geom::LinearRing> ring_type;
+
+ explicit GEOSFactoryImpl(int srid = -1) :
+ m_precision_model(),
+ m_geos_factory(&m_precision_model, srid) {
+ }
+
+ /* Point */
+
+ point_type make_point(const osmium::geom::Coordinates& xy) const {
+ try {
+ return point_type(m_geos_factory.createPoint(geos::geom::Coordinate(xy.x, xy.y)));
+ } catch (geos::util::GEOSException&) {
+ THROW(osmium::geos_geometry_error());
+ }
+ }
+
+ /* LineString */
+
+ void linestring_start() {
+ try {
+ m_coordinate_sequence.reset(m_geos_factory.getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
+ } catch (geos::util::GEOSException&) {
+ THROW(osmium::geos_geometry_error());
+ }
+ }
+
+ void linestring_add_location(const osmium::geom::Coordinates& xy) {
+ try {
+ m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
+ } catch (geos::util::GEOSException&) {
+ THROW(osmium::geos_geometry_error());
+ }
+ }
+
+ linestring_type linestring_finish(size_t /* num_points */) {
+ try {
+ return linestring_type(m_geos_factory.createLineString(m_coordinate_sequence.release()));
+ } catch (geos::util::GEOSException&) {
+ THROW(osmium::geos_geometry_error());
+ }
+ }
+
+ /* MultiPolygon */
+
+ void multipolygon_start() {
+ m_polygons.clear();
+ }
+
+ void multipolygon_polygon_start() {
+ m_rings.clear();
+ }
+
+ void multipolygon_polygon_finish() {
+ try {
+ assert(!m_rings.empty());
+ auto inner_rings = new std::vector<geos::geom::Geometry*>;
+ std::transform(std::next(m_rings.begin(), 1), m_rings.end(), std::back_inserter(*inner_rings), [](std::unique_ptr<geos::geom::LinearRing>& r) {
+ return r.release();
+ });
+ m_polygons.emplace_back(m_geos_factory.createPolygon(m_rings[0].release(), inner_rings));
+ m_rings.clear();
+ } catch (geos::util::GEOSException&) {
+ THROW(osmium::geos_geometry_error());
+ }
+ }
+
+ void multipolygon_outer_ring_start() {
+ try {
+ m_coordinate_sequence.reset(m_geos_factory.getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
+ } catch (geos::util::GEOSException&) {
+ THROW(osmium::geos_geometry_error());
+ }
+ }
+
+ void multipolygon_outer_ring_finish() {
+ try {
+ m_rings.emplace_back(m_geos_factory.createLinearRing(m_coordinate_sequence.release()));
+ } catch (geos::util::GEOSException&) {
+ THROW(osmium::geos_geometry_error());
+ }
+ }
+
+ void multipolygon_inner_ring_start() {
+ try {
+ m_coordinate_sequence.reset(m_geos_factory.getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
+ } catch (geos::util::GEOSException&) {
+ THROW(osmium::geos_geometry_error());
+ }
+ }
+
+ void multipolygon_inner_ring_finish() {
+ try {
+ m_rings.emplace_back(m_geos_factory.createLinearRing(m_coordinate_sequence.release()));
+ } catch (geos::util::GEOSException&) {
+ THROW(osmium::geos_geometry_error());
+ }
+ }
+
+ void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+ try {
+ m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
+ } catch (geos::util::GEOSException&) {
+ THROW(osmium::geos_geometry_error());
+ }
+ }
+
+ multipolygon_type multipolygon_finish() {
+ try {
+ auto polygons = new std::vector<geos::geom::Geometry*>;
+ std::transform(m_polygons.begin(), m_polygons.end(), std::back_inserter(*polygons), [](std::unique_ptr<geos::geom::Polygon>& p) {
+ return p.release();
+ });
+ m_polygons.clear();
+ return multipolygon_type(m_geos_factory.createMultiPolygon(polygons));
+ } catch (geos::util::GEOSException&) {
+ THROW(osmium::geos_geometry_error());
+ }
+ }
+
+ }; // class GEOSFactoryImpl
+
+ } // namespace detail
+
+ template <class TProjection = IdentityProjection>
+ using GEOSFactory = GeometryFactory<osmium::geom::detail::GEOSFactoryImpl, TProjection>;
+
+ } // namespace geom
+
+} // namespace osmium
+
+#undef THROW
+
+#endif // OSMIUM_GEOM_GEOS_HPP
diff --git a/third_party/osmium/geom/haversine.hpp b/third_party/osmium/geom/haversine.hpp
new file mode 100644
index 0000000..b8d0134
--- /dev/null
+++ b/third_party/osmium/geom/haversine.hpp
@@ -0,0 +1,94 @@
+#ifndef OSMIUM_GEOM_HAVERSINE_HPP
+#define OSMIUM_GEOM_HAVERSINE_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 <cmath>
+#include <iterator>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/util.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+ namespace geom {
+
+ /**
+ * @brief Functions to calculate arc distance on Earth using the haversine formula.
+ *
+ * See http://en.wikipedia.org/wiki/Haversine_formula
+ *
+ * Implementation derived from
+ * http://blog.julien.cayzac.name/2008/10/arc-and-distance-between-two-points-on.html
+ */
+ namespace haversine {
+
+ /// @brief Earth's quadratic mean radius for WGS84
+ constexpr double EARTH_RADIUS_IN_METERS = 6372797.560856;
+
+ /**
+ * Calculate distance in meters between two sets of coordinates.
+ */
+ inline double distance(const osmium::geom::Coordinates& c1, const osmium::geom::Coordinates& c2) {
+ double lonh = sin(deg_to_rad(c1.x - c2.x) * 0.5);
+ lonh *= lonh;
+ double lath = sin(deg_to_rad(c1.y - c2.y) * 0.5);
+ lath *= lath;
+ const double tmp = cos(deg_to_rad(c1.y)) * cos(deg_to_rad(c2.y));
+ return 2.0 * EARTH_RADIUS_IN_METERS * asin(sqrt(lath + tmp*lonh));
+ }
+
+ /**
+ * Calculate length of way.
+ */
+ inline double distance(const osmium::WayNodeList& wnl) {
+ double sum_length=0;
+
+ for (auto it = wnl.begin(); it != wnl.end(); ++it) {
+ if (std::next(it) != wnl.end()) {
+ sum_length += distance(it->location(), std::next(it)->location());
+ }
+ }
+
+ return sum_length;
+ }
+
+ } // namespace haversine
+
+ } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_HAVERSINE_HPP
diff --git a/third_party/osmium/geom/mercator_projection.hpp b/third_party/osmium/geom/mercator_projection.hpp
new file mode 100644
index 0000000..d170017
--- /dev/null
+++ b/third_party/osmium/geom/mercator_projection.hpp
@@ -0,0 +1,109 @@
+#ifndef OSMIUM_GEOM_MERCATOR_PROJECTION_HPP
+#define OSMIUM_GEOM_MERCATOR_PROJECTION_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 <cmath>
+#include <string>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/util.hpp>
+#include <osmium/osm/location.hpp>
+
+namespace osmium {
+
+ namespace geom {
+
+ namespace detail {
+
+ constexpr double earth_radius_for_epsg3857 = 6378137.0;
+
+ constexpr inline double lon_to_x(double lon) {
+ return earth_radius_for_epsg3857 * deg_to_rad(lon);
+ }
+
+ inline double lat_to_y(double lat) { // not constexpr because math functions aren't
+ return earth_radius_for_epsg3857 * std::log(std::tan(osmium::geom::PI/4 + deg_to_rad(lat)/2));
+ }
+
+ constexpr inline double x_to_lon(double x) {
+ return rad_to_deg(x) / earth_radius_for_epsg3857;
+ }
+
+ inline double y_to_lat(double y) { // not constexpr because math functions aren't
+ return rad_to_deg(2 * std::atan(std::exp(y / earth_radius_for_epsg3857)) - osmium::geom::PI/2);
+ }
+
+ } // namespace detail
+
+ /**
+ * The maximum latitude that can be projected with the Web Mercator
+ * (EPSG:3857) projection.
+ */
+ constexpr double MERCATOR_MAX_LAT = 85.0511288;
+
+ inline Coordinates lonlat_to_mercator(const Coordinates& c) {
+ return Coordinates(detail::lon_to_x(c.x), detail::lat_to_y(c.y));
+ }
+
+ inline Coordinates mercator_to_lonlat(const Coordinates& c) {
+ return Coordinates(detail::x_to_lon(c.x), detail::y_to_lat(c.y));
+ }
+
+ /**
+ * Functor that does projection from WGS84 (EPSG:4326) to "Web
+ * Mercator" (EPSG:3857)
+ */
+ class MercatorProjection {
+
+ public:
+
+ Coordinates operator()(osmium::Location location) const {
+ return Coordinates {detail::lon_to_x(location.lon()), detail::lat_to_y(location.lat())};
+ }
+
+ int epsg() const noexcept {
+ return 3857;
+ }
+
+ std::string proj_string() const {
+ return "+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";
+ }
+
+ }; // class MercatorProjection
+
+ } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_MERCATOR_PROJECTION_HPP
diff --git a/third_party/osmium/geom/ogr.hpp b/third_party/osmium/geom/ogr.hpp
new file mode 100644
index 0000000..2727f2f
--- /dev/null
+++ b/third_party/osmium/geom/ogr.hpp
@@ -0,0 +1,179 @@
+#ifndef OSMIUM_GEOM_OGR_HPP
+#define OSMIUM_GEOM_OGR_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.
+
+*/
+
+#define OSMIUM_COMPILE_WITH_CFLAGS_OGR `gdal-config --cflags`
+#define OSMIUM_LINK_WITH_LIBS_OGR `gdal-config --libs`
+
+#include <cassert>
+#include <cstddef>
+#include <memory>
+#include <utility>
+
+#pragma GCC diagnostic push
+#ifdef __clang__
+# pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
+#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>
+
+namespace osmium {
+
+ namespace geom {
+
+ namespace detail {
+
+ class OGRFactoryImpl {
+
+ public:
+
+ typedef std::unique_ptr<OGRPoint> point_type;
+ typedef std::unique_ptr<OGRLineString> linestring_type;
+ typedef std::unique_ptr<OGRPolygon> polygon_type;
+ typedef std::unique_ptr<OGRMultiPolygon> multipolygon_type;
+ typedef std::unique_ptr<OGRLinearRing> ring_type;
+
+ private:
+
+ linestring_type m_linestring;
+ multipolygon_type m_multipolygon;
+ polygon_type m_polygon;
+ ring_type m_ring;
+
+ public:
+
+ OGRFactoryImpl() = default;
+
+ /* Point */
+
+ point_type make_point(const osmium::geom::Coordinates& xy) const {
+ return point_type(new OGRPoint(xy.x, xy.y));
+ }
+
+ /* LineString */
+
+ void linestring_start() {
+ m_linestring = std::unique_ptr<OGRLineString>(new OGRLineString());
+ }
+
+ void linestring_add_location(const osmium::geom::Coordinates& xy) {
+ assert(!!m_linestring);
+ m_linestring->addPoint(xy.x, xy.y);
+ }
+
+ linestring_type linestring_finish(size_t /* num_points */) {
+ return std::move(m_linestring);
+ }
+
+ /* Polygon */
+
+ void polygon_start() {
+ m_ring = std::unique_ptr<OGRLinearRing>(new OGRLinearRing());
+ }
+
+ void polygon_add_location(const osmium::geom::Coordinates& xy) {
+ assert(!!m_ring);
+ m_ring->addPoint(xy.x, xy.y);
+ }
+
+ polygon_type polygon_finish(size_t /* num_points */) {
+ std::unique_ptr<OGRPolygon> polygon = std::unique_ptr<OGRPolygon>(new OGRPolygon());
+ polygon->addRingDirectly(m_ring.release());
+ return polygon;
+ }
+
+ /* MultiPolygon */
+
+ void multipolygon_start() {
+ m_multipolygon.reset(new OGRMultiPolygon());
+ }
+
+ void multipolygon_polygon_start() {
+ m_polygon.reset(new OGRPolygon());
+ }
+
+ void multipolygon_polygon_finish() {
+ assert(!!m_multipolygon);
+ assert(!!m_polygon);
+ m_multipolygon->addGeometryDirectly(m_polygon.release());
+ }
+
+ void multipolygon_outer_ring_start() {
+ m_ring.reset(new OGRLinearRing());
+ }
+
+ void multipolygon_outer_ring_finish() {
+ assert(!!m_polygon);
+ assert(!!m_ring);
+ m_polygon->addRingDirectly(m_ring.release());
+ }
+
+ void multipolygon_inner_ring_start() {
+ m_ring.reset(new OGRLinearRing());
+ }
+
+ void multipolygon_inner_ring_finish() {
+ assert(!!m_polygon);
+ assert(!!m_ring);
+ m_polygon->addRingDirectly(m_ring.release());
+ }
+
+ void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+ assert(!!m_polygon);
+ assert(!!m_ring);
+ m_ring->addPoint(xy.x, xy.y);
+ }
+
+ multipolygon_type multipolygon_finish() {
+ assert(!!m_multipolygon);
+ return std::move(m_multipolygon);
+ }
+
+ }; // class OGRFactoryImpl
+
+ } // namespace detail
+
+ template <class TProjection = IdentityProjection>
+ using OGRFactory = GeometryFactory<osmium::geom::detail::OGRFactoryImpl, TProjection>;
+
+ } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_OGR_HPP
diff --git a/third_party/osmium/geom/projection.hpp b/third_party/osmium/geom/projection.hpp
new file mode 100644
index 0000000..72ff945
--- /dev/null
+++ b/third_party/osmium/geom/projection.hpp
@@ -0,0 +1,159 @@
+#ifndef OSMIUM_GEOM_PROJECTION_HPP
+#define OSMIUM_GEOM_PROJECTION_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.
+
+*/
+
+#define OSMIUM_LINK_WITH_LIBS_PROJ -lproj
+
+#include <memory>
+#include <string>
+
+#include <proj_api.h>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/util.hpp>
+#include <osmium/osm/location.hpp>
+
+namespace osmium {
+
+ namespace geom {
+
+ /**
+ * C++ wrapper for a Coordinate Reference System of the proj library.
+ */
+ class CRS {
+
+ struct ProjCRSDeleter {
+ void operator()(void* crs) {
+ pj_free(crs);
+ }
+ }; // struct ProjCRSDeleter
+
+ std::unique_ptr<void, ProjCRSDeleter> m_crs;
+
+ projPJ get() const {
+ return m_crs.get();
+ }
+
+ public:
+
+ CRS(const std::string& crs) :
+ m_crs(pj_init_plus(crs.c_str()), ProjCRSDeleter()) {
+ if (!m_crs) {
+ throw osmium::projection_error(std::string("creation of CRS failed: ") + pj_strerrno(*pj_get_errno_ref()));
+ }
+ }
+
+ CRS(int epsg) :
+ CRS(std::string("+init=epsg:") + std::to_string(epsg)) {
+ }
+
+ bool is_latlong() const {
+ return pj_is_latlong(m_crs.get());
+ }
+
+ bool is_geocent() const {
+ return pj_is_geocent(m_crs.get());
+ }
+
+ /**
+ * Transform coordinates from one CRS into another. Wraps the same function
+ * of the proj library.
+ *
+ * Coordinates have to be in radians and are produced in radians.
+ *
+ * @throws osmmium::projection_error if the projection fails
+ */
+ friend Coordinates transform(const CRS& src, const CRS& dest, Coordinates c) {
+ int result = pj_transform(src.get(), dest.get(), 1, 1, &c.x, &c.y, nullptr);
+ if (result != 0) {
+ throw osmium::projection_error(std::string("projection failed: ") + pj_strerrno(result));
+ }
+ return c;
+ }
+
+ }; // class CRS
+
+ /**
+ * Functor that does projection from WGS84 (EPSG:4326) in to the given
+ * CRS.
+ */
+ class Projection {
+
+ int m_epsg;
+ std::string m_proj_string;
+ CRS m_crs_wgs84 {4326};
+ CRS m_crs_user;
+
+ public:
+
+ Projection(const std::string& proj_string) :
+ m_epsg(-1),
+ m_proj_string(proj_string),
+ m_crs_user(proj_string) {
+ }
+
+ Projection(int epsg) :
+ m_epsg(epsg),
+ m_proj_string(std::string("+init=epsg:") + std::to_string(epsg)),
+ m_crs_user(epsg) {
+ }
+
+ 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())));
+ if (m_crs_user.is_latlong()) {
+ c.x = rad_to_deg(c.x);
+ c.y = rad_to_deg(c.y);
+ }
+ return c;
+ }
+ }
+
+ int epsg() const noexcept {
+ return m_epsg;
+ }
+
+ std::string proj_string() const {
+ return m_proj_string;
+ }
+
+ }; // class Projection
+
+ } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_PROJECTION_HPP
diff --git a/third_party/osmium/geom/relations.hpp b/third_party/osmium/geom/relations.hpp
new file mode 100644
index 0000000..e57e2f4
--- /dev/null
+++ b/third_party/osmium/geom/relations.hpp
@@ -0,0 +1,57 @@
+#ifndef OSMIUM_GEOM_RELATIONS_HPP
+#define OSMIUM_GEOM_RELATIONS_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 <osmium/osm/box.hpp>
+#include <osmium/osm/location.hpp>
+
+namespace osmium {
+
+ namespace geom {
+
+ /**
+ * Check whether one geometry contains another.
+ */
+ inline bool contains(const osmium::Box& a, const osmium::Box& b) {
+ return ((a.bottom_left().x() >= b.bottom_left().x()) &&
+ (a.top_right().x() <= b.top_right().x()) &&
+ (a.bottom_left().y() >= b.bottom_left().y()) &&
+ (a.top_right().y() <= b.top_right().y()));
+ }
+
+ } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_RELATIONS_HPP
diff --git a/third_party/osmium/geom/util.hpp b/third_party/osmium/geom/util.hpp
new file mode 100644
index 0000000..1f1a50d
--- /dev/null
+++ b/third_party/osmium/geom/util.hpp
@@ -0,0 +1,75 @@
+#ifndef OSMIUM_GEOM_UTIL_HPP
+#define OSMIUM_GEOM_UTIL_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 <stdexcept>
+#include <string>
+
+namespace osmium {
+
+ /**
+ * Exception thrown when a projection object can not be initialized or the
+ * projection of some coordinates can not be calculated.
+ */
+ struct projection_error : public std::runtime_error {
+
+ projection_error(const std::string& what) :
+ std::runtime_error(what) {
+ }
+
+ projection_error(const char* what) :
+ std::runtime_error(what) {
+ }
+
+ }; // struct projection_error
+
+ namespace geom {
+
+ constexpr double PI = 3.14159265358979323846;
+
+ /// Convert angle from degrees to radians.
+ inline constexpr double deg_to_rad(double degree) noexcept {
+ return degree * (PI / 180.0);
+ }
+
+ /// Convert angle from radians to degrees.
+ inline constexpr double rad_to_deg(double radians) noexcept {
+ return radians * (180.0 / PI);
+ }
+
+ } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_UTIL_HPP
diff --git a/third_party/osmium/geom/wkb.hpp b/third_party/osmium/geom/wkb.hpp
new file mode 100644
index 0000000..0748ede
--- /dev/null
+++ b/third_party/osmium/geom/wkb.hpp
@@ -0,0 +1,279 @@
+#ifndef OSMIUM_GEOM_WKB_HPP
+#define OSMIUM_GEOM_WKB_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 <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <string>
+
+// Windows is only available for little endian architectures
+// http://stackoverflow.com/questions/6449468/can-i-safely-assume-that-windows-installations-will-always-be-little-endian
+#if !defined(_WIN32) && !defined(__APPLE__)
+# include <endian.h>
+#else
+# define __LITTLE_ENDIAN 1234
+# define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/factory.hpp>
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+ namespace geom {
+
+ enum class wkb_type : bool {
+ wkb = false,
+ ewkb = true
+ }; // enum class wkb_type
+
+ enum class out_type : bool {
+ binary = false,
+ hex = true
+ }; // enum class out_type
+
+ namespace detail {
+
+ template <typename T>
+ 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));
+ }
+
+ inline std::string convert_to_hex(std::string& str) {
+ static const char* lookup_hex = "0123456789ABCDEF";
+ std::string out;
+
+ for (char c : str) {
+ out += lookup_hex[(c >> 4) & 0xf];
+ out += lookup_hex[c & 0xf];
+ }
+
+ return out;
+ }
+
+ class WKBFactoryImpl {
+
+ /// OSM data always uses SRID 4326 (WGS84).
+ static constexpr uint32_t srid = 4326;
+
+ /**
+ * Type of WKB geometry.
+ * These definitions are from
+ * 99-049_OpenGIS_Simple_Features_Specification_For_SQL_Rev_1.1.pdf (for WKB)
+ * and http://trac.osgeo.org/postgis/browser/trunk/doc/ZMSgeoms.txt (for EWKB).
+ * They are used to encode geometries into the WKB format.
+ */
+ enum wkbGeometryType : uint32_t {
+ wkbPoint = 1,
+ wkbLineString = 2,
+ wkbPolygon = 3,
+ wkbMultiPoint = 4,
+ wkbMultiLineString = 5,
+ wkbMultiPolygon = 6,
+ wkbGeometryCollection = 7,
+
+ // SRID-presence flag (EWKB)
+ wkbSRID = 0x20000000
+ }; // enum wkbGeometryType
+
+ /**
+ * Byte order marker in WKB geometry.
+ */
+ enum class wkb_byte_order_type : uint8_t {
+ XDR = 0, // Big Endian
+ NDR = 1 // Little Endian
+ }; // enum class wkb_byte_order_type
+
+ std::string m_data;
+ uint32_t m_points {0};
+ wkb_type m_wkb_type;
+ out_type m_out_type;
+
+ size_t m_linestring_size_offset = 0;
+ size_t m_polygons = 0;
+ size_t m_rings = 0;
+ size_t m_multipolygon_size_offset = 0;
+ size_t m_polygon_size_offset = 0;
+ size_t m_ring_size_offset = 0;
+
+ size_t header(std::string& str, wkbGeometryType type, bool add_length) const {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ str_push(str, wkb_byte_order_type::NDR);
+#else
+ str_push(str, wkb_byte_order_type::XDR);
+#endif
+ if (m_wkb_type == wkb_type::ewkb) {
+ str_push(str, type | wkbSRID);
+ str_push(str, srid);
+ } else {
+ str_push(str, type);
+ }
+ size_t offset = str.size();
+ if (add_length) {
+ str_push(str, static_cast<uint32_t>(0));
+ }
+ return offset;
+ }
+
+ 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));
+ }
+
+ public:
+
+ typedef std::string point_type;
+ typedef std::string linestring_type;
+ typedef std::string polygon_type;
+ typedef std::string multipolygon_type;
+ typedef std::string ring_type;
+
+ explicit WKBFactoryImpl(wkb_type wtype=wkb_type::wkb, out_type otype=out_type::binary) :
+ m_wkb_type(wtype),
+ m_out_type(otype) {
+ }
+
+ /* Point */
+
+ point_type make_point(const osmium::geom::Coordinates& xy) const {
+ std::string data;
+ header(data, wkbPoint, false);
+ str_push(data, xy.x);
+ str_push(data, xy.y);
+
+ if (m_out_type == out_type::hex) {
+ return convert_to_hex(data);
+ } else {
+ return data;
+ }
+ }
+
+ /* LineString */
+
+ void linestring_start() {
+ m_data.clear();
+ m_linestring_size_offset = header(m_data, wkbLineString, true);
+ }
+
+ void linestring_add_location(const osmium::geom::Coordinates& xy) {
+ str_push(m_data, xy.x);
+ str_push(m_data, xy.y);
+ }
+
+ linestring_type linestring_finish(size_t num_points) {
+ set_size(m_linestring_size_offset, num_points);
+ std::string data;
+ std::swap(data, m_data);
+
+ if (m_out_type == out_type::hex) {
+ return convert_to_hex(data);
+ } else {
+ return data;
+ }
+ }
+
+ /* MultiPolygon */
+
+ void multipolygon_start() {
+ m_data.clear();
+ m_polygons = 0;
+ m_multipolygon_size_offset = header(m_data, wkbMultiPolygon, true);
+ }
+
+ void multipolygon_polygon_start() {
+ ++m_polygons;
+ m_rings = 0;
+ m_polygon_size_offset = header(m_data, wkbPolygon, true);
+ }
+
+ void multipolygon_polygon_finish() {
+ set_size(m_polygon_size_offset, m_rings);
+ }
+
+ void multipolygon_outer_ring_start() {
+ ++m_rings;
+ m_points = 0;
+ m_ring_size_offset = m_data.size();
+ str_push(m_data, static_cast<uint32_t>(0));
+ }
+
+ void multipolygon_outer_ring_finish() {
+ set_size(m_ring_size_offset, m_points);
+ }
+
+ void multipolygon_inner_ring_start() {
+ ++m_rings;
+ m_points = 0;
+ m_ring_size_offset = m_data.size();
+ str_push(m_data, static_cast<uint32_t>(0));
+ }
+
+ void multipolygon_inner_ring_finish() {
+ set_size(m_ring_size_offset, m_points);
+ }
+
+ void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+ str_push(m_data, xy.x);
+ str_push(m_data, xy.y);
+ ++m_points;
+ }
+
+ multipolygon_type multipolygon_finish() {
+ set_size(m_multipolygon_size_offset, m_polygons);
+ std::string data;
+ std::swap(data, m_data);
+
+ if (m_out_type == out_type::hex) {
+ return convert_to_hex(data);
+ } else {
+ return data;
+ }
+ }
+
+ }; // class WKBFactoryImpl
+
+ } // namespace detail
+
+ template <class TProjection = IdentityProjection>
+ using WKBFactory = GeometryFactory<osmium::geom::detail::WKBFactoryImpl, TProjection>;
+
+ } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_WKB_HPP
diff --git a/third_party/osmium/geom/wkt.hpp b/third_party/osmium/geom/wkt.hpp
new file mode 100644
index 0000000..0ef304a
--- /dev/null
+++ b/third_party/osmium/geom/wkt.hpp
@@ -0,0 +1,148 @@
+#ifndef OSMIUM_GEOM_WKT_HPP
+#define OSMIUM_GEOM_WKT_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 <cstddef>
+#include <string>
+#include <utility>
+
+#include <osmium/geom/coordinates.hpp>
+#include <osmium/geom/factory.hpp>
+
+namespace osmium {
+
+ namespace geom {
+
+ namespace detail {
+
+ class WKTFactoryImpl {
+
+ std::string m_str;
+ int m_precision;
+
+ public:
+
+ typedef std::string point_type;
+ typedef std::string linestring_type;
+ typedef std::string polygon_type;
+ typedef std::string multipolygon_type;
+ typedef std::string ring_type;
+
+ WKTFactoryImpl(int precision = 7) :
+ m_precision(precision) {
+ }
+
+ /* Point */
+
+ point_type make_point(const osmium::geom::Coordinates& xy) const {
+ std::string str {"POINT"};
+ xy.append_to_string(str, '(', ' ', ')', m_precision);
+ return str;
+ }
+
+ /* LineString */
+
+ void linestring_start() {
+ m_str = "LINESTRING(";
+ }
+
+ void linestring_add_location(const osmium::geom::Coordinates& xy) {
+ xy.append_to_string(m_str, ' ', m_precision);
+ m_str += ',';
+ }
+
+ linestring_type linestring_finish(size_t /* num_points */) {
+ assert(!m_str.empty());
+ std::string str;
+ std::swap(str, m_str);
+ str.back() = ')';
+ return str;
+ }
+
+ /* MultiPolygon */
+
+ void multipolygon_start() {
+ m_str = "MULTIPOLYGON(";
+ }
+
+ void multipolygon_polygon_start() {
+ m_str += '(';
+ }
+
+ void multipolygon_polygon_finish() {
+ m_str += "),";
+ }
+
+ void multipolygon_outer_ring_start() {
+ m_str += '(';
+ }
+
+ void multipolygon_outer_ring_finish() {
+ assert(!m_str.empty());
+ m_str.back() = ')';
+ }
+
+ void multipolygon_inner_ring_start() {
+ m_str += ",(";
+ }
+
+ void multipolygon_inner_ring_finish() {
+ assert(!m_str.empty());
+ m_str.back() = ')';
+ }
+
+ void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
+ xy.append_to_string(m_str, ' ', m_precision);
+ m_str += ',';
+ }
+
+ multipolygon_type multipolygon_finish() {
+ assert(!m_str.empty());
+ m_str.back() = ')';
+ return std::move(m_str);
+ }
+
+ }; // class WKTFactoryImpl
+
+ } // namespace detail
+
+ template <class TProjection = IdentityProjection>
+ using WKTFactory = GeometryFactory<osmium::geom::detail::WKTFactoryImpl, TProjection>;
+
+ } // namespace geom
+
+} // namespace osmium
+
+#endif // OSMIUM_GEOM_WKT_HPP
diff --git a/third_party/osmium/handler.hpp b/third_party/osmium/handler.hpp
new file mode 100644
index 0000000..62e59f8
--- /dev/null
+++ b/third_party/osmium/handler.hpp
@@ -0,0 +1,101 @@
+#ifndef OSMIUM_HANDLER_HPP
+#define OSMIUM_HANDLER_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.
+
+*/
+
+namespace osmium {
+
+ class OSMObject;
+ class Node;
+ class Way;
+ class Relation;
+ class Area;
+ class Changeset;
+ class TagList;
+ class WayNodeList;
+ class RelationMemberList;
+ class OuterRing;
+ class InnerRing;
+
+ /**
+ * @brief Osmium handlers provide callbacks for OSM objects
+ */
+ namespace handler {
+
+ class Handler {
+
+ public:
+
+ void osm_object(const osmium::OSMObject&) const {
+ }
+
+ void node(const osmium::Node&) const {
+ }
+
+ void way(const osmium::Way&) const {
+ }
+
+ void relation(const osmium::Relation&) const {
+ }
+
+ void area(const osmium::Area&) const {
+ }
+
+ void changeset(const osmium::Changeset&) const {
+ }
+
+ void tag_list(const osmium::TagList&) const {
+ }
+
+ void way_node_list(const osmium::WayNodeList&) const {
+ }
+
+ void relation_member_list(const osmium::RelationMemberList&) const {
+ }
+
+ void outer_ring(const osmium::OuterRing&) const {
+ }
+
+ void inner_ring(const osmium::InnerRing&) const {
+ }
+
+ void flush() const {
+ }
+
+ }; // class Handler
+
+ } // namspace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_HPP
diff --git a/third_party/osmium/handler/chain.hpp b/third_party/osmium/handler/chain.hpp
new file mode 100644
index 0000000..868632d
--- /dev/null
+++ b/third_party/osmium/handler/chain.hpp
@@ -0,0 +1,128 @@
+#ifndef OSMIUM_HANDLER_CHAIN_HPP
+#define OSMIUM_HANDLER_CHAIN_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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 <tuple>
+
+#include <osmium/handler.hpp>
+
+#define OSMIUM_CHAIN_HANDLER_CALL(_func_, _type_) \
+ template <int N, int SIZE, class THandlers> \
+ struct call_ ## _func_ { \
+ void operator()(THandlers& handlers, osmium::_type_& object) { \
+ std::get<N>(handlers)._func_(object); \
+ call_ ## _func_<N+1, SIZE, THandlers>()(handlers, object); \
+ } \
+ }; \
+ template <int SIZE, class THandlers> \
+ struct call_ ## _func_<SIZE, SIZE, THandlers> { \
+ void operator()(THandlers&, osmium::_type_&) {} \
+ };
+
+namespace osmium {
+
+ class Node;
+ class Way;
+ class Relation;
+ class Area;
+ class Changeset;
+
+ namespace handler {
+
+ /**
+ * This handler allows chaining of any number of handlers into a single
+ * handler.
+ */
+ template <class ...THandler>
+ class ChainHandler : public osmium::handler::Handler {
+
+ typedef std::tuple<THandler&...> handlers_type;
+ handlers_type m_handlers;
+
+ template <int N, int SIZE, class THandlers>
+ struct call_flush {
+ void operator()(THandlers& handlers) {
+ std::get<N>(handlers).flush();
+ call_flush<N+1, SIZE, THandlers>()(handlers);
+ }
+ }; // struct call_flush
+
+ template <int SIZE, class THandlers>
+ struct call_flush<SIZE, SIZE, THandlers> {
+ void operator()(THandlers&) {}
+ }; // struct call_flush
+
+ OSMIUM_CHAIN_HANDLER_CALL(node, Node)
+ OSMIUM_CHAIN_HANDLER_CALL(way, Way)
+ OSMIUM_CHAIN_HANDLER_CALL(relation, Relation)
+ OSMIUM_CHAIN_HANDLER_CALL(changeset, Changeset)
+ OSMIUM_CHAIN_HANDLER_CALL(area, Area)
+
+ public:
+
+ explicit ChainHandler(THandler&... handlers) :
+ m_handlers(handlers...) {
+ }
+
+ void node(osmium::Node& node) {
+ call_node<0, sizeof...(THandler), handlers_type>()(m_handlers, node);
+ }
+
+ void way(osmium::Way& way) {
+ call_way<0, sizeof...(THandler), handlers_type>()(m_handlers, way);
+ }
+
+ void relation(osmium::Relation& relation) {
+ call_relation<0, sizeof...(THandler), handlers_type>()(m_handlers, relation);
+ }
+
+ void changeset( osmium::Changeset& changeset) {
+ call_changeset<0, sizeof...(THandler), handlers_type>()(m_handlers, changeset);
+ }
+
+ void area(osmium::Area& area) {
+ call_area<0, sizeof...(THandler), handlers_type>()(m_handlers, area);
+ }
+
+ void flush() {
+ call_flush<0, sizeof...(THandler), handlers_type>()(m_handlers);
+ }
+
+ }; // class ChainHandler
+
+ } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_CHAIN_HPP
diff --git a/third_party/osmium/handler/disk_store.hpp b/third_party/osmium/handler/disk_store.hpp
new file mode 100644
index 0000000..2b7ffcf
--- /dev/null
+++ b/third_party/osmium/handler/disk_store.hpp
@@ -0,0 +1,111 @@
+#ifndef OSMIUM_HANDLER_DISK_STORE_HPP
+#define OSMIUM_HANDLER_DISK_STORE_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 <cstddef>
+
+#include <osmium/handler.hpp>
+#include <osmium/index/map.hpp>
+#include <osmium/io/detail/read_write.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/item_iterator.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+ namespace handler {
+
+ /**
+ *
+ * Note: This handler will only work if either all object IDs are
+ * positive or all object IDs are negative.
+ */
+ class DiskStore : public osmium::handler::Handler {
+
+ typedef osmium::index::map::Map<unsigned_object_id_type, size_t> offset_index_type;
+
+ size_t m_offset = 0;
+ int m_data_fd;
+
+ offset_index_type& m_node_index;
+ offset_index_type& m_way_index;
+ offset_index_type& m_relation_index;
+
+ public:
+
+ explicit DiskStore(int data_fd, offset_index_type& node_index, offset_index_type& way_index, offset_index_type& relation_index) :
+ m_data_fd(data_fd),
+ m_node_index(node_index),
+ m_way_index(way_index),
+ m_relation_index(relation_index) {
+ }
+
+ DiskStore(const DiskStore&) = delete;
+ DiskStore& operator=(const DiskStore&) = delete;
+
+ ~DiskStore() noexcept = default;
+
+ void node(const osmium::Node& node) {
+ m_node_index.set(node.positive_id(), m_offset);
+ m_offset += node.byte_size();
+ }
+
+ void way(const osmium::Way& way) {
+ m_way_index.set(way.positive_id(), m_offset);
+ m_offset += way.byte_size();
+ }
+
+ void relation(const osmium::Relation& relation) {
+ m_relation_index.set(relation.positive_id(), m_offset);
+ m_offset += relation.byte_size();
+ }
+
+ // XXX
+ void operator()(const osmium::memory::Buffer& buffer) {
+ osmium::io::detail::reliable_write(m_data_fd, buffer.data(), buffer.committed());
+
+ osmium::apply(buffer.begin(), buffer.end(), *this);
+ }
+
+ }; // class DiskStore
+
+ } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_DISK_STORE_HPP
diff --git a/third_party/osmium/handler/dump.hpp b/third_party/osmium/handler/dump.hpp
new file mode 100644
index 0000000..e62c4b0
--- /dev/null
+++ b/third_party/osmium/handler/dump.hpp
@@ -0,0 +1,294 @@
+#ifndef OSMIUM_HANDLER_DUMP_HPP
+#define OSMIUM_HANDLER_DUMP_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 <iomanip>
+#include <iostream>
+#include <string>
+
+#include <osmium/handler.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/area.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/changeset.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+ namespace handler {
+
+ class Dump : public osmium::handler::Handler {
+
+ std::ostream* m_out;
+ bool m_with_size;
+ std::string m_prefix;
+
+ void print_title(const char* title, const osmium::memory::Item& item) {
+ *m_out << m_prefix
+ << title
+ << ":";
+
+ if (m_with_size) {
+ *m_out << " ["
+ << item.byte_size()
+ << "]";
+ }
+
+ *m_out << "\n";
+ }
+
+ void print_meta(const osmium::OSMObject& object) {
+ *m_out << m_prefix
+ << " id="
+ << object.id()
+ << "\n";
+ *m_out << m_prefix
+ << " version="
+ << object.version()
+ << "\n";
+ *m_out << m_prefix
+ << " uid="
+ << object.uid()
+ << "\n";
+ *m_out << m_prefix
+ << " user=|"
+ << object.user()
+ << "|\n";
+ *m_out << m_prefix
+ << " changeset="
+ << object.changeset()
+ << "\n";
+ *m_out << m_prefix
+ << " timestamp="
+ << object.timestamp().to_iso()
+ << "\n";
+ *m_out << m_prefix
+ << " visible="
+ << (object.visible() ? "yes" : "no")
+ << "\n";
+
+ Dump dump(*m_out, m_with_size, m_prefix + " ");
+ osmium::apply(object.cbegin(), object.cend(), dump);
+ }
+
+ void print_location(const osmium::Node& node) {
+ const osmium::Location& location = node.location();
+
+ if (location) {
+ *m_out << m_prefix
+ << " lon="
+ << std::fixed
+ << std::setprecision(7)
+ << location.lon_without_check()
+ << "\n";
+ *m_out << m_prefix
+ << " lat="
+ << location.lat_without_check()
+ << "\n";
+ } else {
+ *m_out << m_prefix
+ << " lon=\n"
+ << m_prefix
+ << " lat=\n";
+ }
+ }
+
+ public:
+
+ explicit Dump(std::ostream& out, bool with_size=true, const std::string& prefix="") :
+ m_out(&out),
+ m_with_size(with_size),
+ m_prefix(prefix) {
+ }
+
+ void tag_list(const osmium::TagList& tags) {
+ print_title("TAGS", tags);
+ for (const auto& tag : tags) {
+ *m_out << m_prefix
+ << " k=|"
+ << tag.key()
+ << "| v=|"
+ << tag.value()
+ << "|"
+ << "\n";
+ }
+ }
+
+ void way_node_list(const osmium::WayNodeList& wnl) {
+ print_title("NODES", wnl);
+ for (const auto& node_ref : wnl) {
+ *m_out << m_prefix
+ << " ref="
+ << node_ref.ref();
+ if (node_ref.location()) {
+ *m_out << " pos="
+ << node_ref.location();
+ }
+ *m_out << "\n";
+ }
+ }
+
+ void relation_member_list(const osmium::RelationMemberList& rml) {
+ print_title("MEMBERS", rml);
+ for (const auto& member : rml) {
+ *m_out << m_prefix
+ << " type="
+ << item_type_to_name(member.type())
+ << " ref="
+ << member.ref()
+ << " role=|"
+ << member.role()
+ << "|\n";
+ if (member.full_member()) {
+ Dump dump(*m_out, m_with_size, m_prefix + " | ");
+ osmium::apply_item(member.get_object(), dump);
+ }
+ }
+ }
+
+ void outer_ring(const osmium::OuterRing& ring) {
+ print_title("OUTER RING", ring);
+ for (const auto& node_ref : ring) {
+ *m_out << m_prefix
+ << " ref="
+ << node_ref.ref();
+ if (node_ref.location()) {
+ *m_out << " pos="
+ << node_ref.location();
+ }
+ *m_out << "\n";
+ }
+ }
+
+ void inner_ring(const osmium::InnerRing& ring) {
+ print_title("INNER RING", ring);
+ for (const auto& node_ref : ring) {
+ *m_out << m_prefix
+ << " ref="
+ << node_ref.ref();
+ if (node_ref.location()) {
+ *m_out << " pos="
+ << node_ref.location();
+ }
+ *m_out << "\n";
+ }
+ }
+
+ void node(const osmium::Node& node) {
+ print_title("NODE", node);
+ print_meta(node);
+ print_location(node);
+ }
+
+ void way(const osmium::Way& way) {
+ print_title("WAY", way);
+ print_meta(way);
+ }
+
+ void relation(const osmium::Relation& relation) {
+ print_title("RELATION", relation);
+ print_meta(relation);
+ }
+
+ void area(const osmium::Area& area) {
+ print_title("AREA", area);
+ print_meta(area);
+ }
+
+ void changeset(const osmium::Changeset& changeset) {
+ print_title("CHANGESET", changeset);
+ *m_out << m_prefix
+ << " id="
+ << changeset.id()
+ << "\n";
+ *m_out << m_prefix
+ << " num_changes="
+ << changeset.num_changes()
+ << "\n";
+ *m_out << m_prefix
+ << " uid="
+ << changeset.uid()
+ << "\n";
+ *m_out << m_prefix
+ << " user=|"
+ << changeset.user()
+ << "|\n";
+ *m_out << m_prefix
+ << " created_at="
+ << changeset.created_at().to_iso()
+ << "\n";
+ *m_out << m_prefix
+ << " closed_at="
+ << changeset.closed_at().to_iso()
+ << "\n";
+ *m_out << m_prefix
+ << " bounds=";
+
+ if (changeset.bounds()) {
+ *m_out << '('
+ << changeset.bounds().bottom_left().lon_without_check()
+ << ','
+ << changeset.bounds().bottom_left().lat_without_check()
+ << ','
+ << changeset.bounds().top_right().lon_without_check()
+ << ','
+ << changeset.bounds().top_right().lat_without_check()
+ << ')';
+ } else {
+ *m_out << "(undefined)";
+ }
+
+ *m_out << "\n";
+
+ Dump dump(*m_out, m_with_size, m_prefix + " ");
+ osmium::apply(changeset.cbegin(), changeset.cend(), dump);
+ }
+
+ }; // class Dump
+
+ } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_DUMP_HPP
diff --git a/third_party/osmium/handler/node_locations_for_ways.hpp b/third_party/osmium/handler/node_locations_for_ways.hpp
new file mode 100644
index 0000000..a273082
--- /dev/null
+++ b/third_party/osmium/handler/node_locations_for_ways.hpp
@@ -0,0 +1,177 @@
+#ifndef OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_HPP
+#define OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_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 <type_traits>
+
+#include <osmium/handler.hpp>
+#include <osmium/index/index.hpp>
+#include <osmium/index/map/dummy.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+ namespace handler {
+
+ typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> dummy_type;
+
+ /**
+ * Handler to retrieve locations from nodes and add them to ways.
+ *
+ * @tparam TStoragePosIDs Class that handles the actual storage of the node locations
+ * (for positive IDs). It must support the set(id, value) and
+ * get(id) methods.
+ * @tparam TStorageNegIDs Same but for negative IDs.
+ */
+ 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>, TStorageNegIDs>::value,
+ "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
+
+ public:
+
+ typedef TStoragePosIDs index_pos_type;
+ typedef TStorageNegIDs index_neg_type;
+
+ private:
+
+ /// Object that handles the actual storage of the node locations (with positive IDs).
+ TStoragePosIDs& m_storage_pos;
+
+ /// Object that handles the actual storage of the node locations (with negative IDs).
+ TStorageNegIDs& m_storage_neg;
+
+ bool m_ignore_errors {false};
+
+ bool m_must_sort {false};
+
+ // It is okay to have this static dummy instance, even when using several threads,
+ // because it is read-only.
+ static dummy_type& get_dummy() {
+ static dummy_type instance;
+ return instance;
+ }
+
+ public:
+
+ explicit NodeLocationsForWays(TStoragePosIDs& storage_pos,
+ TStorageNegIDs& storage_neg = get_dummy()) :
+ m_storage_pos(storage_pos),
+ m_storage_neg(storage_neg) {
+ }
+
+ NodeLocationsForWays(const NodeLocationsForWays&) = delete;
+ NodeLocationsForWays& operator=(const NodeLocationsForWays&) = delete;
+
+ ~NodeLocationsForWays() noexcept = default;
+
+ void ignore_errors() {
+ m_ignore_errors = true;
+ }
+
+ /**
+ * Store the location of the node in the storage.
+ */
+ void node(const osmium::Node& node) {
+ m_must_sort = true;
+ const osmium::object_id_type id = node.id();
+ if (id >= 0) {
+ m_storage_pos.set(static_cast<osmium::unsigned_object_id_type>( id), node.location());
+ } else {
+ m_storage_neg.set(static_cast<osmium::unsigned_object_id_type>(-id), node.location());
+ }
+ }
+
+ /**
+ * Get location of node with given id.
+ */
+ osmium::Location get_node_location(const osmium::object_id_type id) const {
+ if (id >= 0) {
+ return m_storage_pos.get(static_cast<osmium::unsigned_object_id_type>( id));
+ } else {
+ return m_storage_neg.get(static_cast<osmium::unsigned_object_id_type>(-id));
+ }
+ }
+
+ /**
+ * Retrieve locations of all nodes in the way from storage and add
+ * them to the way object.
+ */
+ void way(osmium::Way& way) {
+ if (m_must_sort) {
+ m_storage_pos.sort();
+ m_storage_neg.sort();
+ m_must_sort = false;
+ }
+ bool error = false;
+ for (auto& node_ref : way.nodes()) {
+ try {
+ node_ref.set_location(get_node_location(node_ref.ref()));
+ if (!node_ref.location()) {
+ error = true;
+ }
+ } catch (osmium::not_found&) {
+ error = true;
+ }
+ }
+ if (error && !m_ignore_errors) {
+ throw osmium::not_found("location for one or more nodes not found in node location index");
+ }
+ }
+
+ /**
+ * Call clear on the location indexes. Makes the
+ * NodeLocationsForWays handler unusable. Used to explicitly free
+ * memory if thats needed.
+ */
+ void clear() {
+ m_storage_pos.clear();
+ m_storage_neg.clear();
+ }
+
+ }; // class NodeLocationsForWays
+
+ } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_NODE_LOCATIONS_FOR_WAYS_HPP
diff --git a/third_party/osmium/handler/object_relations.hpp b/third_party/osmium/handler/object_relations.hpp
new file mode 100644
index 0000000..e73ce87
--- /dev/null
+++ b/third_party/osmium/handler/object_relations.hpp
@@ -0,0 +1,106 @@
+#ifndef OSMIUM_HANDLER_OBJECT_RELATIONS_HPP
+#define OSMIUM_HANDLER_OBJECT_RELATIONS_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 <osmium/handler.hpp>
+#include <osmium/index/multimap.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+ namespace handler {
+
+ /**
+ *
+ * Note: This handler will only work if either all object IDs are
+ * positive or all object IDs are negative.
+ */
+ class ObjectRelations : public osmium::handler::Handler {
+
+ typedef osmium::index::multimap::Multimap<unsigned_object_id_type, unsigned_object_id_type> index_type;
+
+ index_type& m_index_n2w;
+ index_type& m_index_n2r;
+ index_type& m_index_w2r;
+ index_type& m_index_r2r;
+
+ public:
+
+ explicit ObjectRelations(index_type& n2w, index_type& n2r, index_type& w2r, index_type& r2r) :
+ m_index_n2w(n2w),
+ m_index_n2r(n2r),
+ m_index_w2r(w2r),
+ m_index_r2r(r2r) {
+ }
+
+ ObjectRelations(const ObjectRelations&) = delete;
+ ObjectRelations& operator=(const ObjectRelations&) = delete;
+
+ ~ObjectRelations() noexcept = default;
+
+ void way(const osmium::Way& way) {
+ for (const auto& node_ref : way.nodes()) {
+ m_index_n2w.set(node_ref.positive_ref(), way.positive_id());
+ }
+ }
+
+ void relation(const osmium::Relation& relation) {
+ for (const auto& member : relation.members()) {
+ switch (member.type()) {
+ case osmium::item_type::node:
+ m_index_n2r.set(member.positive_ref(), relation.positive_id());
+ break;
+ case osmium::item_type::way:
+ m_index_w2r.set(member.positive_ref(), relation.positive_id());
+ break;
+ case osmium::item_type::relation:
+ m_index_r2r.set(member.positive_ref(), relation.positive_id());
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ }; // class ObjectRelations
+
+ } // namespace handler
+
+} // namespace osmium
+
+#endif // OSMIUM_HANDLER_OBJECT_RELATIONS_HPP
diff --git a/third_party/osmium/index/detail/mmap_vector_anon.hpp b/third_party/osmium/index/detail/mmap_vector_anon.hpp
new file mode 100644
index 0000000..f066961
--- /dev/null
+++ b/third_party/osmium/index/detail/mmap_vector_anon.hpp
@@ -0,0 +1,78 @@
+#ifndef OSMIUM_DETAIL_MMAP_VECTOR_ANON_HPP
+#define OSMIUM_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).
+
+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 <cstddef>
+
+#include <osmium/index/detail/typed_mmap.hpp>
+#include <osmium/index/detail/mmap_vector_base.hpp>
+
+namespace osmium {
+
+ namespace detail {
+
+ /**
+ * 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> {
+
+ public:
+
+ mmap_vector_anon() :
+ mmap_vector_base<T, osmium::detail::mmap_vector_anon>(
+ -1,
+ osmium::detail::mmap_vector_size_increment,
+ 0,
+ osmium::detail::typed_mmap<T>::map(osmium::detail::mmap_vector_size_increment)) {
+ }
+
+ void reserve(size_t new_capacity) {
+ if (new_capacity > this->capacity()) {
+ this->data(osmium::detail::typed_mmap<T>::remap(this->data(), this->capacity(), new_capacity));
+ this->m_capacity = new_capacity;
+ }
+ }
+
+ }; // class mmap_vector_anon
+
+ } // namespace detail
+
+} // namespace osmium
+
+#endif // __linux__
+
+#endif // OSMIUM_DETAIL_MMAP_VECTOR_ANON_HPP
diff --git a/third_party/osmium/index/detail/mmap_vector_base.hpp b/third_party/osmium/index/detail/mmap_vector_base.hpp
new file mode 100644
index 0000000..fc96b27
--- /dev/null
+++ b/third_party/osmium/index/detail/mmap_vector_base.hpp
@@ -0,0 +1,183 @@
+#ifndef OSMIUM_DETAIL_MMAP_VECTOR_BASE_HPP
+#define OSMIUM_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).
+
+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 <cstddef>
+#include <new>
+#include <stdexcept>
+
+#include <osmium/index/detail/typed_mmap.hpp>
+
+namespace osmium {
+
+ namespace detail {
+
+ constexpr size_t mmap_vector_size_increment = 1024 * 1024;
+
+ /**
+ * This is a base class for implementing classes that look like
+ * STL vector but use mmap internally. This class can not be used
+ * on it's own. Use the derived classes mmap_vector_anon or
+ * mmap_vector_file.
+ */
+ template <typename T, template <typename> class TDerived>
+ class mmap_vector_base {
+
+ protected:
+
+ int m_fd;
+ size_t m_capacity;
+ size_t m_size;
+ T* m_data;
+
+ explicit mmap_vector_base(int fd, size_t capacity, size_t size, T* data) noexcept :
+ m_fd(fd),
+ m_capacity(capacity),
+ m_size(size),
+ m_data(data) {
+ }
+
+ explicit mmap_vector_base(int fd, size_t capacity, size_t size) :
+ m_fd(fd),
+ m_capacity(capacity),
+ m_size(size),
+ m_data(osmium::detail::typed_mmap<T>::grow_and_map(capacity, m_fd)) {
+ }
+
+ void data(T* data) {
+ m_data = data;
+ }
+
+ public:
+
+ typedef T value_type;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T* iterator;
+ typedef const T* const_iterator;
+
+ ~mmap_vector_base() {
+ osmium::detail::typed_mmap<T>::unmap(m_data, m_capacity);
+ }
+
+ size_t capacity() const noexcept {
+ return m_capacity;
+ }
+
+ size_t size() const noexcept {
+ return m_size;
+ }
+
+ bool empty() const noexcept {
+ return m_size == 0;
+ }
+
+ const T* data() const noexcept {
+ return m_data;
+ }
+
+ T* data() noexcept {
+ return m_data;
+ }
+
+ T& operator[](size_t n) {
+ return m_data[n];
+ }
+
+ T at(size_t n) const {
+ if (n >= m_size) {
+ throw std::out_of_range("out of range");
+ }
+ return m_data[n];
+ }
+
+ void clear() noexcept {
+ m_size = 0;
+ }
+
+ void shrink_to_fit() {
+ // XXX do something here
+ }
+
+ void push_back(const T& value) {
+ if (m_size >= m_capacity) {
+ resize(m_size+1);
+ }
+ m_data[m_size] = value;
+ ++m_size;
+ }
+
+ void resize(size_t new_size) {
+ if (new_size > capacity()) {
+ static_cast<TDerived<T>*>(this)->reserve(new_size + osmium::detail::mmap_vector_size_increment);
+ }
+ if (new_size > size()) {
+ new (data() + size()) T[new_size - size()];
+ }
+ m_size = new_size;
+ }
+
+ iterator begin() noexcept {
+ return m_data;
+ }
+
+ iterator end() noexcept {
+ return m_data + m_size;
+ }
+
+ const_iterator begin() const noexcept {
+ return m_data;
+ }
+
+ const_iterator end() const noexcept {
+ return m_data + m_size;
+ }
+
+ const_iterator cbegin() noexcept {
+ return m_data;
+ }
+
+ const_iterator cend() noexcept {
+ return m_data + m_size;
+ }
+
+ }; // class mmap_vector_base
+
+ } // namespace detail
+
+} // namespace osmium
+
+#endif // OSMIUM_DETAIL_MMAP_VECTOR_BASE_HPP
diff --git a/third_party/osmium/index/detail/mmap_vector_file.hpp b/third_party/osmium/index/detail/mmap_vector_file.hpp
new file mode 100644
index 0000000..ca8f0eb
--- /dev/null
+++ b/third_party/osmium/index/detail/mmap_vector_file.hpp
@@ -0,0 +1,82 @@
+#ifndef OSMIUM_DETAIL_MMAP_VECTOR_FILE_HPP
+#define OSMIUM_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).
+
+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 <cstddef>
+
+#include <osmium/index/detail/typed_mmap.hpp>
+#include <osmium/index/detail/mmap_vector_base.hpp>
+#include <osmium/index/detail/tmpfile.hpp>
+
+namespace osmium {
+
+ namespace detail {
+
+ /**
+ * 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> {
+
+ public:
+
+ explicit mmap_vector_file() :
+ mmap_vector_base<T, osmium::detail::mmap_vector_file>(
+ osmium::detail::create_tmp_file(),
+ osmium::detail::mmap_vector_size_increment,
+ 0) {
+ }
+
+ 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)) {
+ }
+
+ 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));
+ this->m_capacity = new_capacity;
+ }
+ }
+
+ }; // class mmap_vector_file
+
+ } // namespace detail
+
+} // namespace osmium
+
+#endif // OSMIUM_DETAIL_MMAP_VECTOR_FILE_HPP
diff --git a/third_party/osmium/index/detail/tmpfile.hpp b/third_party/osmium/index/detail/tmpfile.hpp
new file mode 100644
index 0000000..3d00c50
--- /dev/null
+++ b/third_party/osmium/index/detail/tmpfile.hpp
@@ -0,0 +1,62 @@
+#ifndef OSMIUM_DETAIL_TMPFILE_HPP
+#define OSMIUM_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).
+
+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 <cerrno>
+#include <cstdio>
+#include <system_error>
+
+namespace osmium {
+
+ namespace detail {
+
+ /**
+ * Create and open a temporary file. It is removed after opening.
+ *
+ * @returns File descriptor of temporary file.
+ * @throws std::system_error if something went wrong.
+ */
+ inline int create_tmp_file() {
+ FILE* file = ::tmpfile();
+ if (!file) {
+ throw std::system_error(errno, std::system_category(), "tempfile failed");
+ }
+ return fileno(file);
+ }
+
+ } // namespace detail
+
+} // namespace osmium
+
+#endif // OSMIUM_DETAIL_TMPFILE
diff --git a/third_party/osmium/index/detail/typed_mmap.hpp b/third_party/osmium/index/detail/typed_mmap.hpp
new file mode 100644
index 0000000..8a952a4
--- /dev/null
+++ b/third_party/osmium/index/detail/typed_mmap.hpp
@@ -0,0 +1,229 @@
+#ifndef OSMIUM_DETAIL_TYPED_MMAP_HPP
+#define OSMIUM_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).
+
+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 <cerrno>
+#include <cstddef>
+#include <stdexcept>
+#include <system_error>
+
+#include <sys/stat.h>
+
+#ifndef _WIN32
+# include <sys/mman.h>
+#else
+# include <mmap_for_windows.hpp>
+#endif
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#else
+# define ftruncate _chsize
+#endif
+
+// for bsd systems
+#ifndef MAP_ANONYMOUS
+# define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+ /**
+ * @brief Namespace for Osmium internal use
+ */
+ namespace detail {
+
+ /**
+ * This is a helper class for working with memory mapped files and
+ * anonymous shared memory. It wraps the necessary system calls
+ * adding:
+ * - error checking: all functions throw exceptions where needed
+ * - internal casts and size calculations allow use with user defined
+ * type T instead of void*
+ *
+ * This class only contains static functions. It should never be
+ * instantiated.
+ *
+ * @tparam T Type of objects we want to store.
+ */
+ template <typename T>
+ class typed_mmap {
+
+ public:
+
+ /**
+ * Create anonymous private memory mapping with enough space for size
+ * objects of type T.
+ *
+ * Note that no constructor is called for any of the objects in this memory!
+ *
+ * @param size Number of objects of type T that should fit into this memory
+ * @returns Pointer to mapped memory
+ * @throws std::system_error If mmap(2) failed
+ */
+ static T* map(size_t size) {
+ void* addr = ::mmap(nullptr, sizeof(T) * size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+ if (addr == MAP_FAILED) {
+ throw std::system_error(errno, std::system_category(), "mmap failed");
+ }
+#pragma GCC diagnostic pop
+ return reinterpret_cast<T*>(addr);
+ }
+
+ /**
+ * Create shared memory mapping of a file with enough space for size
+ * objects of type T. The file must already have at least the
+ * required size.
+ *
+ * Note that no constructor is called for any of the objects in this memory!
+ *
+ * @param size Number of objects of type T that should fit into this memory
+ * @param fd File descriptor
+ * @param write True if data should be writable
+ * @returns Pointer to mapped memory
+ * @throws std::system_error If mmap(2) failed
+ */
+ static T* map(size_t size, int fd, bool write = false) {
+ int prot = PROT_READ;
+ if (write) {
+ prot |= PROT_WRITE;
+ }
+ void* addr = ::mmap(nullptr, sizeof(T) * size, prot, MAP_SHARED, fd, 0);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+ if (addr == MAP_FAILED) {
+ throw std::system_error(errno, std::system_category(), "mmap failed");
+ }
+#pragma GCC diagnostic pop
+ return reinterpret_cast<T*>(addr);
+ }
+
+// mremap(2) is only available on linux systems
+#ifdef __linux__
+ /**
+ * Grow memory mapping created with map().
+ *
+ * Note that no constructor is called for any of the objects in this memory!
+ *
+ * @param data Pointer to current mapping (as returned by typed_mmap())
+ * @param old_size Number of objects currently stored in this memory
+ * @param new_size Number of objects we want to have space for
+ * @throws std::system_error If mremap(2) call failed
+ */
+ static T* remap(T* data, size_t old_size, size_t new_size) {
+ void* addr = ::mremap(reinterpret_cast<void*>(data), sizeof(T) * old_size, sizeof(T) * new_size, MREMAP_MAYMOVE);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+ if (addr == MAP_FAILED) {
+ throw std::system_error(errno, std::system_category(), "mremap failed");
+ }
+#pragma GCC diagnostic pop
+ return reinterpret_cast<T*>(addr);
+ }
+#endif
+
+ /**
+ * Release memory from map() call.
+ *
+ * Note that no destructor is called for the objects in this memory!
+ *
+ * @param data Pointer to the data
+ * @param size Number of objects of type T stored
+ * @throws std::system_error If munmap(2) call failed
+ */
+ static void unmap(T* data, size_t size) {
+ if (::munmap(reinterpret_cast<void*>(data), sizeof(T) * size) != 0) {
+ throw std::system_error(errno, std::system_category(), "munmap failed");
+ }
+ }
+
+ /**
+ * Get number of objects of type T that would fit into a file.
+ *
+ * @param fd File descriptor
+ * @returns Number of objects of type T in this file
+ * @throws std::system_error If fstat(2) call failed
+ * @throws std::length_error If size of the file isn't a multiple of sizeof(T)
+ */
+ static size_t file_size(int fd) {
+ struct stat s;
+ if (fstat(fd, &s) < 0) {
+ throw std::system_error(errno, std::system_category(), "fstat failed");
+ }
+ if (static_cast<size_t>(s.st_size) % sizeof(T) != 0) {
+ throw std::length_error("file size has to be multiple of object size");
+ }
+ return static_cast<size_t>(s.st_size) / sizeof(T);
+ }
+
+ /**
+ * Grow file so there is enough space for at least new_size objects
+ * of type T. If the file is large enough already, nothing is done.
+ * The file is never shrunk.
+ *
+ * @param new_size Number of objects of type T that should fit into this file
+ * @param fd File descriptor
+ * @throws std::system_error If ftruncate(2) call failed
+ */
+ static void grow_file(size_t new_size, int fd) {
+ if (file_size(fd) < new_size) {
+ if (::ftruncate(fd, static_cast_with_assert<off_t>(sizeof(T) * new_size)) < 0) {
+ throw std::system_error(errno, std::system_category(), "ftruncate failed");
+ }
+ }
+ }
+
+ /**
+ * Grow file to given size (if it is smaller) and mmap it.
+ *
+ * @param size Number of objects of type T that should fit into this file
+ * @param fd File descriptor
+ * @throws Errors thrown by grow_file() or map()
+ */
+ static T* grow_and_map(size_t size, int fd) {
+ grow_file(size, fd);
+ return map(size, fd, true);
+ }
+
+ }; // class typed_mmap
+
+ } // namespace detail
+
+} // namespace osmium
+
+#endif // OSMIUM_DETAIL_TYPED_MMAP_HPP
diff --git a/third_party/osmium/index/index.hpp b/third_party/osmium/index/index.hpp
new file mode 100644
index 0000000..ece8ec4
--- /dev/null
+++ b/third_party/osmium/index/index.hpp
@@ -0,0 +1,100 @@
+#ifndef OSMIUM_INDEX_INDEX_HPP
+#define OSMIUM_INDEX_INDEX_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 <cstddef>
+#include <limits>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+ /**
+ * Exception signaling that an element could not be
+ * found in an index.
+ */
+ struct not_found : public std::runtime_error {
+
+ not_found(const std::string& what) :
+ std::runtime_error(what) {
+ }
+
+ not_found(const char* what) :
+ std::runtime_error(what) {
+ }
+
+ }; // struct not_found
+
+ /**
+ * @brief Indexing of OSM data, Locations, etc.
+ */
+ namespace index {
+
+ template <typename TKey>
+ OSMIUM_NORETURN void not_found_error(TKey key) {
+ std::stringstream s;
+ s << "id " << key << " no found";
+ throw not_found(s.str());
+ }
+
+ /**
+ * Some of the index classes need an "empty" value that can
+ * never appear in real data. This function must return this
+ * empty value for any class used as a value in an index.
+ * The default implementation returns a default constructed
+ * object, but it can be specialized.
+ */
+ template <typename T>
+ inline constexpr T empty_value() {
+ return T{};
+ }
+
+ /**
+ * The size_t value in indexes is usually used for offsets
+ * into a buffer or file. It is unlikely that we ever need
+ * the full range, so the max value is a good "empty" value.
+ */
+ template <>
+ inline OSMIUM_CONSTEXPR size_t empty_value<size_t>() {
+ return std::numeric_limits<size_t>::max();
+ }
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_INDEX_HPP
diff --git a/third_party/osmium/index/map.hpp b/third_party/osmium/index/map.hpp
new file mode 100644
index 0000000..92b880f
--- /dev/null
+++ b/third_party/osmium/index/map.hpp
@@ -0,0 +1,155 @@
+#ifndef OSMIUM_INDEX_MAP_HPP
+#define OSMIUM_INDEX_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).
+
+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 <cstddef>
+#include <type_traits>
+
+#include <osmium/index/index.hpp> // IWYU pragma: export
+
+namespace osmium {
+
+ namespace index {
+
+ /**
+ * @brief Key-value containers with unique integer values for a key
+ */
+ namespace map {
+
+ /**
+ * This abstract class defines an interface to storage classes
+ * intended for storing small pieces of data (such as coordinates)
+ * indexed by a positive integer (such as an object ID). The
+ * storage must be very space efficient and able to scale to billions
+ * of objects.
+ *
+ * Subclasses have different implementations that store the
+ * data in different ways in memory and/or on disk. Some storage
+ * classes are better suited when working with the whole planet,
+ * some are better for data extracts.
+ *
+ * Note that these classes are not required to track "empty" fields.
+ * When reading data you have to be sure you have put something in
+ * there before.
+ *
+ * A typical use for this and derived classes is storage of node
+ * locations indexed by node ID. These indexes will only work
+ * on 64 bit systems if used in this case. 32 bit systems just
+ * can't address that much memory!
+ *
+ * @tparam TId Id type, usually osmium::unsigned_object_id_type,
+ * must be an unsigned integral type.
+ * @tparam TValue Value type, usually osmium::Location or size_t.
+ * Copied by value, so should be "small" type.
+ */
+ 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");
+
+ Map(const Map&) = delete;
+ Map& operator=(const Map&) = delete;
+
+ protected:
+
+ Map(Map&&) = default;
+ Map& operator=(Map&&) = default;
+
+ public:
+
+ /// The "key" type, usually osmium::unsigned_object_id_type.
+ typedef TId key_type;
+
+ /// The "value" type, usually a Location or size_t.
+ typedef TValue value_type;
+
+ Map() = default;
+
+ virtual ~Map() = default;
+
+ virtual void reserve(const size_t) {
+ // default implementation is empty
+ }
+
+ /// Set the field with id to value.
+ virtual void set(const TId id, const TValue value) = 0;
+
+ /// Retrieve value by id. Does not check for overflow or empty fields.
+ virtual const TValue get(const TId id) const = 0;
+
+ /**
+ * Get the approximate number of items in the storage. The storage
+ * might allocate memory in blocks, so this size might not be
+ * accurate. You can not use this to find out how much memory the
+ * storage uses. Use used_memory() for that.
+ */
+ virtual size_t size() const = 0;
+
+ /**
+ * Get the memory used for this storage in bytes. Note that this
+ * is not necessarily entirely accurate but an approximation.
+ * For storage classes that store the data in memory, this is
+ * the main memory used, for storage classes storing data on disk
+ * this is the memory used on disk.
+ */
+ virtual size_t used_memory() const = 0;
+
+ /**
+ * Clear memory used for this storage. After this you can not
+ * use the storage container any more.
+ */
+ virtual void clear() = 0;
+
+ /**
+ * Sort data in map. Call this after writing all data and
+ * before reading. Not all implementations need this.
+ */
+ virtual void sort() {
+ // default implementation is empty
+ }
+
+ virtual void dump_as_list(int /*fd*/) const {
+ std::runtime_error("can't dump as list");
+ }
+
+ }; // class Map
+
+ } // namespace map
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_HPP
diff --git a/third_party/osmium/index/map/dummy.hpp b/third_party/osmium/index/map/dummy.hpp
new file mode 100644
index 0000000..bafb810
--- /dev/null
+++ b/third_party/osmium/index/map/dummy.hpp
@@ -0,0 +1,87 @@
+#ifndef OSMIUM_INDEX_MAP_DUMMY_HPP
+#define OSMIUM_INDEX_MAP_DUMMY_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 <cstddef>
+
+#include <osmium/index/map.hpp>
+
+namespace osmium {
+
+ namespace index {
+
+ namespace map {
+
+ /**
+ * Pseudo map.
+ * Use this class if you don't need a map, but you
+ * need an object that behaves like one.
+ */
+ template <typename TId, typename TValue>
+ class Dummy : public osmium::index::map::Map<TId, TValue> {
+
+ public:
+
+ Dummy() = default;
+
+ ~Dummy() override final = default;
+
+ void set(const TId, const TValue) override final {
+ // intentionally left blank
+ }
+
+ const TValue get(const TId id) const override final {
+ not_found_error(id);
+ }
+
+ size_t size() const override final {
+ return 0;
+ }
+
+ size_t used_memory() const override final {
+ return 0;
+ }
+
+ void clear() override final {
+ }
+
+ }; // class Dummy
+
+ } // namespace map
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_DUMMY_HPP
diff --git a/third_party/osmium/index/map/mmap_vector_anon.hpp b/third_party/osmium/index/map/mmap_vector_anon.hpp
new file mode 100644
index 0000000..a62e99a
--- /dev/null
+++ b/third_party/osmium/index/map/mmap_vector_anon.hpp
@@ -0,0 +1,61 @@
+#ifndef OSMIUM_INDEX_MAP_MMAP_VECTOR_ANON_HPP
+#define OSMIUM_INDEX_MAP_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).
+
+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 <osmium/index/map/vector.hpp>
+#include <osmium/index/detail/mmap_vector_anon.hpp>
+
+namespace osmium {
+
+ namespace index {
+
+ 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>;
+
+ } // namespace map
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // __linux__
+
+#endif // OSMIUM_INDEX_MAP_MMAP_VECTOR_ANON_HPP
diff --git a/third_party/osmium/index/map/mmap_vector_file.hpp b/third_party/osmium/index/map/mmap_vector_file.hpp
new file mode 100644
index 0000000..7ea76fa
--- /dev/null
+++ b/third_party/osmium/index/map/mmap_vector_file.hpp
@@ -0,0 +1,57 @@
+#ifndef OSMIUM_INDEX_MAP_MMAP_VECTOR_FILE_HPP
+#define OSMIUM_INDEX_MAP_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).
+
+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/vector.hpp>
+#include <osmium/index/detail/mmap_vector_file.hpp>
+
+namespace osmium {
+
+ namespace index {
+
+ 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>;
+
+ } // namespace map
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_MMAP_VECTOR_FILE_HPP
diff --git a/third_party/osmium/index/map/sparse_table.hpp b/third_party/osmium/index/map/sparse_table.hpp
new file mode 100644
index 0000000..704e33e
--- /dev/null
+++ b/third_party/osmium/index/map/sparse_table.hpp
@@ -0,0 +1,140 @@
+#ifndef OSMIUM_INDEX_MAP_SPARSE_TABLE_HPP
+#define OSMIUM_INDEX_MAP_SPARSE_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).
+
+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 <cstddef>
+#include <stdexcept>
+#include <utility>
+#include <vector>
+
+#include <google/sparsetable>
+
+#include <osmium/index/map.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+namespace osmium {
+
+ namespace index {
+
+ namespace map {
+
+ /**
+ * The SparseTable 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.
+ *
+ * Use this index if the ID space is only sparsly
+ * populated, such as when working with smaller OSM files (like
+ * country extracts).
+ *
+ * This will only work on 64 bit machines.
+ */
+ template <typename TId, typename TValue>
+ class SparseTable : public osmium::index::map::Map<TId, TValue> {
+
+ TId m_grow_size;
+
+ google::sparsetable<TValue> m_elements;
+
+ static_assert(sizeof(typename google::sparsetable<TValue>::size_type) >= 8, "google::sparsetable needs 64bit machine");
+
+ public:
+
+ /**
+ * Constructor.
+ *
+ * @param grow_size The initial size of the index (ie number of
+ * elements that fit into the index).
+ * The storage will grow by at least this size
+ * every time it runs out of space.
+ */
+ explicit SparseTable(const TId grow_size=10000) :
+ m_grow_size(grow_size),
+ m_elements(grow_size) {
+ }
+
+ ~SparseTable() override final = default;
+
+ void set(const TId id, const TValue value) override final {
+ if (id >= m_elements.size()) {
+ m_elements.resize(id + m_grow_size);
+ }
+ m_elements[id] = value;
+ }
+
+ const TValue get(const TId id) const override final {
+ if (id >= m_elements.size()) {
+ not_found_error(id);
+ }
+ if (m_elements[id] == osmium::index::empty_value<TValue>()) {
+ not_found_error(id);
+ }
+ return m_elements[id];
+ }
+
+ size_t size() const override final {
+ return m_elements.size();
+ }
+
+ size_t used_memory() const override final {
+ // unused elements use 1 bit, used elements sizeof(TValue) bytes
+ // http://google-sparsehash.googlecode.com/svn/trunk/doc/sparsetable.html
+ return (m_elements.size() / 8) + (m_elements.num_nonempty() * sizeof(TValue));
+ }
+
+ void clear() override final {
+ m_elements.clear();
+ }
+
+ void dump_as_list(const int fd) const override final {
+ std::vector<std::pair<TId, TValue>> v;
+ int n=0;
+ for (const TValue value : m_elements) {
+ if (value != osmium::index::empty_value<TValue>()) {
+ v.emplace_back(n, value);
+ }
+ ++n;
+ }
+ osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(std::pair<TId, TValue>) * v.size());
+ }
+
+ }; // class SparseTable
+
+ } // namespace map
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_BYID_SPARSE_TABLE_HPP
diff --git a/third_party/osmium/index/map/stl_map.hpp b/third_party/osmium/index/map/stl_map.hpp
new file mode 100644
index 0000000..d2781a7
--- /dev/null
+++ b/third_party/osmium/index/map/stl_map.hpp
@@ -0,0 +1,112 @@
+#ifndef OSMIUM_INDEX_MAP_STL_MAP_HPP
+#define OSMIUM_INDEX_MAP_STL_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).
+
+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 <algorithm>
+#include <cstddef>
+#include <iterator>
+#include <map>
+#include <stdexcept>
+#include <vector>
+
+#include <osmium/index/map.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+namespace osmium {
+
+ namespace index {
+
+ namespace map {
+
+ /**
+ * This implementation uses std::map internally. It uses rather a
+ * lot of memory, but might make sense for small maps.
+ */
+ template <typename TId, typename TValue>
+ class StlMap : 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,
+ // and parent plus some overhead for color of red-black-tree
+ // or similar).
+ static constexpr size_t element_size = sizeof(TId) + sizeof(TValue) + sizeof(void*) * 4;
+
+ std::map<TId, TValue> m_elements;
+
+ public:
+
+ StlMap() = default;
+
+ ~StlMap() override final = default;
+
+ void set(const TId id, const TValue value) override final {
+ m_elements[id] = value;
+ }
+
+ const TValue get(const TId id) const override final {
+ try {
+ return m_elements.at(id);
+ } catch (std::out_of_range&) {
+ not_found_error(id);
+ }
+ }
+
+ size_t size() const override final {
+ return m_elements.size();
+ }
+
+ size_t used_memory() const override final {
+ return element_size * m_elements.size();
+ }
+
+ void clear() override final {
+ m_elements.clear();
+ }
+
+ void dump_as_list(const int fd) const 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
+
+ } // namespace map
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_STL_MAP_HPP
diff --git a/third_party/osmium/index/map/stl_vector.hpp b/third_party/osmium/index/map/stl_vector.hpp
new file mode 100644
index 0000000..238e9af
--- /dev/null
+++ b/third_party/osmium/index/map/stl_vector.hpp
@@ -0,0 +1,61 @@
+#ifndef OSMIUM_INDEX_MAP_STL_VECTOR_HPP
+#define OSMIUM_INDEX_MAP_STL_VECTOR_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 <vector>
+
+#include <osmium/index/map/vector.hpp>
+
+namespace osmium {
+
+ namespace index {
+
+ 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>;
+
+ } // namespace map
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_STL_VECTOR_HPP
diff --git a/third_party/osmium/index/map/vector.hpp b/third_party/osmium/index/map/vector.hpp
new file mode 100644
index 0000000..7e47ccf
--- /dev/null
+++ b/third_party/osmium/index/map/vector.hpp
@@ -0,0 +1,208 @@
+#ifndef OSMIUM_INDEX_MAP_VECTOR_HPP
+#define OSMIUM_INDEX_MAP_VECTOR_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 <algorithm>
+#include <cstddef>
+#include <stdexcept>
+#include <utility>
+
+#include <osmium/index/map.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+namespace osmium {
+
+ namespace index {
+
+ namespace map {
+
+ template <class TVector, typename TId, typename TValue>
+ class VectorBasedDenseMap : public Map<TId, TValue> {
+
+ TVector m_vector;
+
+ public:
+
+ VectorBasedDenseMap() :
+ m_vector() {
+ }
+
+ explicit VectorBasedDenseMap(int fd) :
+ m_vector(fd) {
+ }
+
+ ~VectorBasedDenseMap() {}
+
+ void reserve(const size_t size) override final {
+ m_vector.reserve(size);
+ }
+
+ void set(const TId id, const TValue value) override final {
+ if (size() <= id) {
+ m_vector.resize(id+1);
+ }
+ m_vector[id] = value;
+ }
+
+ const TValue get(const TId id) const override final {
+ try {
+ const TValue& value = m_vector.at(id);
+ if (value == osmium::index::empty_value<TValue>()) {
+ not_found_error(id);
+ }
+ return value;
+ } catch (std::out_of_range&) {
+ not_found_error(id);
+ }
+ }
+
+ size_t size() const override final {
+ return m_vector.size();
+ }
+
+ size_t used_memory() const override final {
+ return sizeof(TValue) * size();
+ }
+
+ void clear() override final {
+ m_vector.clear();
+ m_vector.shrink_to_fit();
+ }
+
+ }; // class VectorBasedDenseMap
+
+
+ template <typename TId, typename TValue, template<typename...> class TVector>
+ class VectorBasedSparseMap : public Map<TId, TValue> {
+
+ public:
+
+ typedef typename std::pair<TId, TValue> element_type;
+ typedef TVector<element_type> vector_type;
+ typedef typename vector_type::iterator iterator;
+ typedef typename vector_type::const_iterator const_iterator;
+
+ private:
+
+ vector_type m_vector;
+
+ public:
+
+ VectorBasedSparseMap() :
+ m_vector() {
+ }
+
+ VectorBasedSparseMap(int fd) :
+ m_vector(fd) {
+ }
+
+ ~VectorBasedSparseMap() override final = default;
+
+ void set(const TId id, const TValue value) override final {
+ m_vector.push_back(element_type(id, value));
+ }
+
+ const TValue get(const TId id) const override final {
+ const element_type element {
+ id,
+ osmium::index::empty_value<TValue>()
+ };
+ const auto result = std::lower_bound(m_vector.begin(), m_vector.end(), element, [](const element_type& a, const element_type& b) {
+ return a.first < b.first;
+ });
+ if (result == m_vector.end() || result->first != id) {
+ not_found_error(id);
+ } else {
+ return result->second;
+ }
+ }
+
+ size_t size() const override final {
+ return m_vector.size();
+ }
+
+ size_t byte_size() const {
+ return m_vector.size() * sizeof(element_type);
+ }
+
+ size_t used_memory() const override final {
+ return sizeof(element_type) * size();
+ }
+
+ void clear() override final {
+ m_vector.clear();
+ m_vector.shrink_to_fit();
+ }
+
+ void sort() override final {
+ std::sort(m_vector.begin(), m_vector.end());
+ }
+
+ void dump_as_list(int fd) const override final {
+ osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size());
+ }
+
+ 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 VectorBasedSparseMap
+
+ } // namespace map
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MAP_VECTOR_HPP
diff --git a/third_party/osmium/index/multimap.hpp b/third_party/osmium/index/multimap.hpp
new file mode 100644
index 0000000..f76c65d
--- /dev/null
+++ b/third_party/osmium/index/multimap.hpp
@@ -0,0 +1,129 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_HPP
+#define OSMIUM_INDEX_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).
+
+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 <cstddef>
+#include <type_traits>
+#include <utility>
+
+#include <osmium/index/index.hpp> // IWYU pragma: export
+
+namespace osmium {
+
+ namespace index {
+
+ /**
+ * @brief Key-value containers with multiple values for an integer key
+ */
+ namespace multimap {
+
+ 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");
+
+ typedef typename std::pair<TId, TValue> element_type;
+
+ Multimap(const Multimap&) = delete;
+ Multimap& operator=(const Multimap&) = delete;
+
+ protected:
+
+ Multimap(Multimap&&) = default;
+ Multimap& operator=(Multimap&&) = default;
+
+ public:
+
+ /// The "key" type, usually osmium::unsigned_object_id_type.
+ typedef TId key_type;
+
+ /// The "value" type, usually a Location or size_t.
+ typedef TValue value_type;
+
+ Multimap() = default;
+
+ virtual ~Multimap() noexcept = default;
+
+ /// Set the field with id to value.
+ virtual void set(const TId id, const TValue value) = 0;
+
+ typedef element_type* iterator;
+
+// virtual std::pair<iterator, iterator> get_all(const TId id) const = 0;
+
+ /**
+ * Get the approximate number of items in the storage. The storage
+ * might allocate memory in blocks, so this size might not be
+ * accurate. You can not use this to find out how much memory the
+ * storage uses. Use used_memory() for that.
+ */
+ virtual size_t size() const = 0;
+
+ /**
+ * Get the memory used for this storage in bytes. Note that this
+ * is not necessarily entirely accurate but an approximation.
+ * For storage classes that store the data in memory, this is
+ * the main memory used, for storage classes storing data on disk
+ * this is the memory used on disk.
+ */
+ virtual size_t used_memory() const = 0;
+
+ /**
+ * Clear memory used for this storage. After this you can not
+ * use the storage container any more.
+ */
+ virtual void clear() = 0;
+
+ /**
+ * Sort data in map. Call this after writing all data and
+ * before reading. Not all implementations need this.
+ */
+ virtual void sort() {
+ // default implementation is empty
+ }
+
+ virtual void dump_as_list(int /*fd*/) const {
+ std::runtime_error("can't dump as list");
+ }
+
+ }; // class Multimap
+
+ } // namespace map
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_HPP
diff --git a/third_party/osmium/index/multimap/hybrid.hpp b/third_party/osmium/index/multimap/hybrid.hpp
new file mode 100644
index 0000000..abaf31e
--- /dev/null
+++ b/third_party/osmium/index/multimap/hybrid.hpp
@@ -0,0 +1,199 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_HYBRID_HPP
+#define OSMIUM_INDEX_MULTIMAP_HYBRID_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 <cstddef>
+#include <utility>
+
+#include <osmium/index/multimap.hpp>
+#include <osmium/index/multimap/stl_vector.hpp>
+#include <osmium/index/multimap/stl_multimap.hpp>
+
+namespace osmium {
+
+ namespace index {
+
+ namespace multimap {
+
+ template <typename TId, typename TValue>
+ class HybridIterator {
+
+ typedef SparseMultimapMem<TId, TValue> main_map_type;
+ typedef StlMultimap<TId, TValue> extra_map_type;
+
+ typedef typename std::pair<TId, TValue> element_type;
+
+ typename main_map_type::iterator m_begin_main;
+ typename main_map_type::iterator m_end_main;
+ typename extra_map_type::iterator m_begin_extra;
+ typename extra_map_type::iterator m_end_extra;
+
+ public:
+
+ explicit HybridIterator(typename main_map_type::iterator begin_main,
+ typename main_map_type::iterator end_main,
+ typename extra_map_type::iterator begin_extra,
+ typename extra_map_type::iterator end_extra) :
+ m_begin_main(begin_main),
+ m_end_main(end_main),
+ m_begin_extra(begin_extra),
+ m_end_extra(end_extra) {
+ }
+
+ HybridIterator& operator++() {
+ if (m_begin_main == m_end_main) {
+ ++m_begin_extra;
+ } else {
+ ++m_begin_main;
+ while (m_begin_main != m_end_main && m_begin_main->second == osmium::index::empty_value<TValue>()) { // ignore removed elements
+ ++m_begin_main;
+ }
+ }
+ return *this;
+ }
+
+ HybridIterator<TId, TValue> operator++(int) {
+ auto tmp(*this);
+ operator++();
+ return tmp;
+ }
+
+ bool operator==(const HybridIterator& rhs) const {
+ return m_begin_main == rhs.m_begin_main &&
+ m_end_main == rhs.m_end_main &&
+ m_begin_extra == rhs.m_begin_extra &&
+ m_end_extra == rhs.m_end_extra;
+ }
+
+ bool operator!=(const HybridIterator& rhs) const {
+ return ! operator==(rhs);
+ }
+
+ const element_type& operator*() {
+ if (m_begin_main == m_end_main) {
+ return *m_begin_extra;
+ } else {
+ return *m_begin_main;
+ }
+ }
+
+ const element_type* operator->() {
+ return &operator*();
+ }
+
+ }; // class HybridIterator
+
+ 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;
+
+ main_map_type m_main;
+ extra_map_type m_extra;
+
+ public:
+
+ typedef HybridIterator<TId, TValue> iterator;
+ typedef const HybridIterator<TId, TValue> const_iterator;
+
+ Hybrid() :
+ m_main(),
+ m_extra() {
+ }
+
+ size_t size() const override final {
+ return m_main.size() + m_extra.size();
+ }
+
+ size_t used_memory() const override final {
+ return m_main.used_memory() + m_extra.used_memory();
+ }
+
+ void reserve(const size_t size) {
+ m_main.reserve(size);
+ }
+
+ void unsorted_set(const TId id, const TValue value) {
+ m_main.set(id, value);
+ }
+
+ void set(const TId id, const TValue value) override final {
+ m_extra.set(id, value);
+ }
+
+ std::pair<iterator, iterator> get_all(const TId id) {
+ auto result_main = m_main.get_all(id);
+ auto result_extra = m_extra.get_all(id);
+ return std::make_pair(iterator(result_main.first, result_main.second, result_extra.first, result_extra.second),
+ iterator(result_main.second, result_main.second, result_extra.second, result_extra.second));
+ }
+
+ void remove(const TId id, const TValue value) {
+ m_main.remove(id, value);
+ m_extra.remove(id, value);
+ }
+
+ void consolidate() {
+ m_main.erase_removed();
+ for (const auto& element : m_extra) {
+ m_main.set(element.first, element.second);
+ }
+ m_extra.clear();
+ m_main.sort();
+ }
+
+ void dump_as_list(int fd) override final {
+ consolidate();
+ m_main.dump_as_list(fd);
+ }
+
+ void clear() override final {
+ m_main.clear();
+ m_extra.clear();
+ }
+
+ void sort() override final {
+ m_main.sort();
+ }
+
+ }; // class Hybrid
+
+ } // namespace multimap
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_HYBRID_HPP
diff --git a/third_party/osmium/index/multimap/mmap_vector_anon.hpp b/third_party/osmium/index/multimap/mmap_vector_anon.hpp
new file mode 100644
index 0000000..b9de34a
--- /dev/null
+++ b/third_party/osmium/index/multimap/mmap_vector_anon.hpp
@@ -0,0 +1,58 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_ANON_HPP
+#define OSMIUM_INDEX_MULTIMAP_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).
+
+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 <osmium/index/multimap/vector.hpp>
+#include <osmium/index/detail/mmap_vector_anon.hpp>
+
+namespace osmium {
+
+ namespace index {
+
+ namespace multimap {
+
+ template <typename TId, typename TValue>
+ using SparseMultimapMmap = VectorBasedSparseMultimap<TId, TValue, osmium::detail::mmap_vector_anon>;
+
+ } // namespace multimap
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // __linux__
+
+#endif // OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_ANON_HPP
diff --git a/third_party/osmium/index/multimap/mmap_vector_file.hpp b/third_party/osmium/index/multimap/mmap_vector_file.hpp
new file mode 100644
index 0000000..0a925b4
--- /dev/null
+++ b/third_party/osmium/index/multimap/mmap_vector_file.hpp
@@ -0,0 +1,54 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_FILE_HPP
+#define OSMIUM_INDEX_MULTIMAP_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).
+
+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/multimap/vector.hpp>
+#include <osmium/index/detail/mmap_vector_file.hpp>
+
+namespace osmium {
+
+ namespace index {
+
+ namespace multimap {
+
+ template <typename TId, typename TValue>
+ using SparseMultimapFile = VectorBasedSparseMultimap<TId, TValue, osmium::detail::mmap_vector_file>;
+
+ } // namespace multimap
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_MMAP_VECTOR_FILE_HPP
diff --git a/third_party/osmium/index/multimap/stl_multimap.hpp b/third_party/osmium/index/multimap/stl_multimap.hpp
new file mode 100644
index 0000000..3df07ab
--- /dev/null
+++ b/third_party/osmium/index/multimap/stl_multimap.hpp
@@ -0,0 +1,151 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_STL_MULTIMAP_HPP
+#define OSMIUM_INDEX_MULTIMAP_STL_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).
+
+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 <algorithm>
+#include <cstddef>
+#include <map>
+#include <utility>
+#include <vector>
+
+#include <osmium/index/multimap.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+namespace osmium {
+
+ namespace index {
+
+ namespace multimap {
+
+ /**
+ * This implementation uses std::multimap internally. It uses rather a
+ * lot of memory, but might make sense for small maps.
+ */
+ template <typename TId, typename TValue>
+ class StlMultimap : 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,
+ // and parent plus some overhead for color of red-black-tree
+ // or similar).
+ static constexpr size_t element_size = sizeof(TId) + sizeof(TValue) + sizeof(void*) * 4;
+
+ public:
+
+ typedef typename std::multimap<const TId, TValue> collection_type;
+ typedef typename collection_type::iterator iterator;
+ typedef typename collection_type::const_iterator const_iterator;
+ typedef typename collection_type::value_type value_type;
+
+ typedef typename std::pair<TId, TValue> element_type;
+
+ private:
+
+ collection_type m_elements;
+
+ public:
+
+ StlMultimap() = default;
+
+ ~StlMultimap() noexcept override final = default;
+
+ void unsorted_set(const TId id, const TValue value) {
+ m_elements.emplace(id, value);
+ }
+
+ void set(const TId id, const TValue value) override final {
+ m_elements.emplace(id, value);
+ }
+
+ std::pair<iterator, iterator> get_all(const TId id) {
+ return m_elements.equal_range(id);
+ }
+
+ std::pair<const_iterator, const_iterator> get_all(const TId id) const {
+ return m_elements.equal_range(id);
+ }
+
+ void remove(const TId id, const TValue value) {
+ std::pair<iterator, iterator> r = get_all(id);
+ for (iterator it = r.first; it != r.second; ++it) {
+ if (it->second == value) {
+ m_elements.erase(it);
+ return;
+ }
+ }
+ }
+
+ iterator begin() {
+ return m_elements.begin();
+ }
+
+ iterator end() {
+ return m_elements.end();
+ }
+
+ size_t size() const override final {
+ return m_elements.size();
+ }
+
+ size_t used_memory() const override final {
+ return element_size * m_elements.size();
+ }
+
+ void clear() override final {
+ m_elements.clear();
+ }
+
+ void consolidate() {
+ // intentionally left blank
+ }
+
+ void dump_as_list(const int fd) const override final {
+ std::vector<element_type> v;
+ for (const auto& element : m_elements) {
+ v.emplace_back(element.first, element.second);
+ }
+// std::copy(m_elements.cbegin(), m_elements.cend(), std::back_inserter(v));
+ std::sort(v.begin(), v.end());
+ osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(element_type) * v.size());
+ }
+
+ }; // class StlMultimap
+
+ } // namespace multimap
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_STL_MULTIMAP_HPP
diff --git a/third_party/osmium/index/multimap/stl_vector.hpp b/third_party/osmium/index/multimap/stl_vector.hpp
new file mode 100644
index 0000000..2102824
--- /dev/null
+++ b/third_party/osmium/index/multimap/stl_vector.hpp
@@ -0,0 +1,58 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_STL_VECTOR_HPP
+#define OSMIUM_INDEX_MULTIMAP_STL_VECTOR_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 <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 index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_STL_VECTOR_HPP
diff --git a/third_party/osmium/index/multimap/vector.hpp b/third_party/osmium/index/multimap/vector.hpp
new file mode 100644
index 0000000..b9dae43
--- /dev/null
+++ b/third_party/osmium/index/multimap/vector.hpp
@@ -0,0 +1,151 @@
+#ifndef OSMIUM_INDEX_MULTIMAP_VECTOR_HPP
+#define OSMIUM_INDEX_MULTIMAP_VECTOR_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 <algorithm>
+#include <cstddef>
+#include <utility>
+
+#include <osmium/index/multimap.hpp>
+#include <osmium/io/detail/read_write.hpp>
+
+namespace osmium {
+
+ namespace index {
+
+ namespace multimap {
+
+ template <typename TId, typename TValue, template<typename...> class TVector>
+ class VectorBasedSparseMultimap : public Multimap<TId, TValue> {
+
+ public:
+
+ typedef typename std::pair<TId, TValue> element_type;
+ typedef TVector<element_type> vector_type;
+ typedef typename vector_type::iterator iterator;
+ typedef typename vector_type::const_iterator const_iterator;
+
+ private:
+
+ vector_type m_vector;
+
+ static bool is_removed(element_type& element) {
+ return element.second == osmium::index::empty_value<TValue>();
+ }
+
+ public:
+
+ void set(const TId id, const TValue value) override final {
+ m_vector.push_back(element_type(id, value));
+ }
+
+ void unsorted_set(const TId id, const TValue value) {
+ m_vector.push_back(element_type(id, value));
+ }
+
+ std::pair<iterator, iterator> get_all(const TId id) {
+ const element_type element {
+ id,
+ osmium::index::empty_value<TValue>()
+ };
+ return std::equal_range(m_vector.begin(), m_vector.end(), element, [](const element_type& a, const element_type& b) {
+ return a.first < b.first;
+ });
+ }
+
+ std::pair<const_iterator, const_iterator> get_all(const TId id) const {
+ const element_type element {
+ id,
+ osmium::index::empty_value<TValue>()
+ };
+ return std::equal_range(m_vector.cbegin(), m_vector.cend(), element, [](const element_type& a, const element_type& b) {
+ return a.first < b.first;
+ });
+ }
+
+ size_t size() const override final {
+ return m_vector.size();
+ }
+
+ size_t byte_size() const {
+ return m_vector.size() * sizeof(element_type);
+ }
+
+ size_t used_memory() const override final {
+ return sizeof(element_type) * size();
+ }
+
+ void clear() override final {
+ m_vector.clear();
+ m_vector.shrink_to_fit();
+ }
+
+ void sort() override final {
+ std::sort(m_vector.begin(), m_vector.end());
+ }
+
+ void remove(const TId id, const TValue value) {
+ auto r = get_all(id);
+ for (auto it = r.first; it != r.second; ++it) {
+ if (it->second == value) {
+ it->second = 0;
+ return;
+ }
+ }
+ }
+
+ void consolidate() {
+ std::sort(m_vector.begin(), m_vector.end());
+ }
+
+ void erase_removed() {
+ m_vector.erase(
+ std::remove_if(m_vector.begin(), m_vector.end(), is_removed),
+ m_vector.end()
+ );
+ }
+
+ void dump_as_list(int fd) const override final {
+ osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size());
+ }
+
+ }; // class VectorBasedSparseMultimap
+
+ } // namespace multimap
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_MULTIMAP_VECTOR_HPP
diff --git a/third_party/osmium/io/any_compression.hpp b/third_party/osmium/io/any_compression.hpp
new file mode 100644
index 0000000..03ad5ce
--- /dev/null
+++ b/third_party/osmium/io/any_compression.hpp
@@ -0,0 +1,39 @@
+#ifndef OSMIUM_IO_ANY_COMPRESSION_HPP
+#define OSMIUM_IO_ANY_COMPRESSION_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 <osmium/io/bzip2_compression.hpp> // IWYU pragma: export
+#include <osmium/io/gzip_compression.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_ANY_COMPRESSION_HPP
diff --git a/third_party/osmium/io/any_input.hpp b/third_party/osmium/io/any_input.hpp
new file mode 100644
index 0000000..f60ff14
--- /dev/null
+++ b/third_party/osmium/io/any_input.hpp
@@ -0,0 +1,41 @@
+#ifndef OSMIUM_IO_ANY_INPUT_HPP
+#define OSMIUM_IO_ANY_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
+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/io/any_compression.hpp> // IWYU pragma: export
+
+#include <osmium/io/pbf_input.hpp> // IWYU pragma: export
+#include <osmium/io/xml_input.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_ANY_INPUT_HPP
diff --git a/third_party/osmium/io/any_output.hpp b/third_party/osmium/io/any_output.hpp
new file mode 100644
index 0000000..9d97d7d
--- /dev/null
+++ b/third_party/osmium/io/any_output.hpp
@@ -0,0 +1,42 @@
+#ifndef OSMIUM_IO_ANY_OUTPUT_HPP
+#define OSMIUM_IO_ANY_OUTPUT_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 <osmium/io/any_compression.hpp> // IWYU pragma: export
+
+#include <osmium/io/opl_output.hpp> // IWYU pragma: export
+#include <osmium/io/pbf_output.hpp> // IWYU pragma: export
+#include <osmium/io/xml_output.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_ANY_OUTPUT_HPP
diff --git a/third_party/osmium/io/bzip2_compression.hpp b/third_party/osmium/io/bzip2_compression.hpp
new file mode 100644
index 0000000..cbfaf9a
--- /dev/null
+++ b/third_party/osmium/io/bzip2_compression.hpp
@@ -0,0 +1,277 @@
+#ifndef OSMIUM_IO_BZIP2_COMPRESSION_HPP
+#define OSMIUM_IO_BZIP2_COMPRESSION_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.
+
+*/
+
+#define OSMIUM_LINK_WITH_LIBS_BZ2LIB -lbz2
+
+#include <cstdio>
+#include <stdexcept>
+#include <string>
+
+#include <bzlib.h>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/file_compression.hpp>
+#include <osmium/util/cast.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+ /**
+ * Exception thrown when there are problems compressing or
+ * decompressing bzip2 files.
+ */
+ struct bzip2_error : public std::runtime_error {
+
+ int bzip2_error_code;
+ int system_errno;
+
+ bzip2_error(const std::string& what, int error_code) :
+ std::runtime_error(what),
+ bzip2_error_code(error_code),
+ system_errno(error_code == BZ_IO_ERROR ? errno : 0) {
+ }
+
+ }; // struct bzip2_error
+
+ namespace io {
+
+ namespace detail {
+
+ OSMIUM_NORETURN inline void throw_bzip2_error(BZFILE* bzfile, const char* msg, int bzlib_error=0) {
+ std::string error("bzip2 error: ");
+ error += msg;
+ error += ": ";
+ int errnum = bzlib_error;
+ if (bzlib_error) {
+ error += std::to_string(bzlib_error);
+ } else {
+ error += ::BZ2_bzerror(bzfile, &errnum);
+ }
+ throw osmium::bzip2_error(error, errnum);
+ }
+
+ } // namespace detail
+
+ class Bzip2Compressor : public Compressor {
+
+ FILE* m_file;
+ int m_bzerror;
+ BZFILE* m_bzfile;
+
+ public:
+
+ explicit Bzip2Compressor(int fd) :
+ Compressor(),
+ m_file(fdopen(dup(fd), "wb")),
+ m_bzerror(BZ_OK),
+ m_bzfile(::BZ2_bzWriteOpen(&m_bzerror, m_file, 6, 0, 0)) {
+ if (!m_bzfile) {
+ detail::throw_bzip2_error(m_bzfile, "write open failed", m_bzerror);
+ }
+ }
+
+ ~Bzip2Compressor() override final {
+ close();
+ }
+
+ void write(const std::string& data) override final {
+ int error;
+ ::BZ2_bzWrite(&error, m_bzfile, const_cast<char*>(data.data()), static_cast_with_assert<int>(data.size()));
+ if (error != BZ_OK && error != BZ_STREAM_END) {
+ detail::throw_bzip2_error(m_bzfile, "write failed", error);
+ }
+ }
+
+ void close() override final {
+ if (m_bzfile) {
+ int error;
+ ::BZ2_bzWriteClose(&error, m_bzfile, 0, nullptr, nullptr);
+ m_bzfile = nullptr;
+ if (m_file) {
+ fclose(m_file);
+ }
+ if (error != BZ_OK) {
+ detail::throw_bzip2_error(m_bzfile, "write close failed", error);
+ }
+ }
+ }
+
+ }; // class Bzip2Compressor
+
+ class Bzip2Decompressor : public Decompressor {
+
+ FILE* m_file;
+ int m_bzerror;
+ BZFILE* m_bzfile;
+ bool m_stream_end {false};
+
+ public:
+
+ Bzip2Decompressor(int fd) :
+ Decompressor(),
+ m_file(fdopen(dup(fd), "rb")),
+ m_bzerror(BZ_OK),
+ m_bzfile(::BZ2_bzReadOpen(&m_bzerror, m_file, 0, 0, nullptr, 0)) {
+ if (!m_bzfile) {
+ detail::throw_bzip2_error(m_bzfile, "read open failed", m_bzerror);
+ }
+ }
+
+ ~Bzip2Decompressor() override final {
+ close();
+ }
+
+ 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);
+ }
+ } else {
+ m_stream_end = true;
+ }
+ }
+ buffer.resize(static_cast<std::string::size_type>(nread));
+ return buffer;
+ }
+
+ void close() override final {
+ if (m_bzfile) {
+ int error;
+ ::BZ2_bzReadClose(&error, m_bzfile);
+ m_bzfile = nullptr;
+ if (m_file) {
+ fclose(m_file);
+ }
+ if (error != BZ_OK) {
+ detail::throw_bzip2_error(m_bzfile, "read close failed", error);
+ }
+ }
+ }
+
+ }; // class Bzip2Decompressor
+
+ class Bzip2BufferDecompressor : public Decompressor {
+
+ const char* m_buffer;
+ size_t m_buffer_size;
+ bz_stream m_bzstream;
+
+ public:
+
+ Bzip2BufferDecompressor(const char* buffer, size_t size) :
+ m_buffer(buffer),
+ m_buffer_size(size),
+ m_bzstream() {
+ m_bzstream.next_in = const_cast<char*>(buffer);
+ m_bzstream.avail_in = static_cast_with_assert<unsigned int>(size);
+ int result = BZ2_bzDecompressInit(&m_bzstream, 0, 0);
+ if (result != BZ_OK) {
+ std::string message("bzip2 error: decompression init failed: ");
+ throw bzip2_error(message, result);
+ }
+ }
+
+ ~Bzip2BufferDecompressor() override final {
+ BZ2_bzDecompressEnd(&m_bzstream);
+ }
+
+ 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);
+
+ 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);
+ }
+
+ output.resize(static_cast<unsigned long>(m_bzstream.next_out - output.data()));
+ return output;
+ }
+
+ }; // class Bzip2BufferDecompressor
+
+ namespace {
+
+ const bool registered_bzip2_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::bzip2,
+ [](int fd) { return new osmium::io::Bzip2Compressor(fd); },
+ [](int fd) { return new osmium::io::Bzip2Decompressor(fd); },
+ [](const char* buffer, size_t size) { return new osmium::io::Bzip2BufferDecompressor(buffer, size); }
+ );
+
+ } // anonymous namespace
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_BZIP2_COMPRESSION_HPP
diff --git a/third_party/osmium/io/compression.hpp b/third_party/osmium/io/compression.hpp
new file mode 100644
index 0000000..5977640
--- /dev/null
+++ b/third_party/osmium/io/compression.hpp
@@ -0,0 +1,279 @@
+#ifndef OSMIUM_IO_COMPRESSION_HPP
+#define OSMIUM_IO_COMPRESSION_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 <cerrno>
+#include <functional>
+#include <map>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <system_error>
+#include <utility>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#else
+# include <io.h>
+#endif
+
+#include <osmium/io/detail/read_write.hpp>
+#include <osmium/io/file_compression.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+ namespace io {
+
+ class Compressor {
+
+ public:
+
+ Compressor() = default;
+
+ virtual ~Compressor() {
+ }
+
+ virtual void write(const std::string& data) = 0;
+
+ virtual void close() = 0;
+
+ }; // class Compressor
+
+ class Decompressor {
+
+ public:
+
+ static constexpr size_t input_buffer_size = 256 * 1024;
+
+ Decompressor() = default;
+
+ Decompressor(const Decompressor&) = delete;
+ Decompressor& operator=(const Decompressor&) = delete;
+
+ Decompressor(Decompressor&&) = delete;
+ Decompressor& operator=(Decompressor&&) = delete;
+
+ virtual ~Decompressor() {
+ }
+
+ virtual std::string read() = 0;
+
+ virtual void close() {
+ }
+
+ }; // class Decompressor
+
+ /**
+ * This singleton factory class is used to register compression
+ * algorithms used for reading and writing OSM files.
+ *
+ * For each algorithm we store two functions that construct
+ * a compressor and decompressor object, respectively.
+ */
+ class CompressionFactory {
+
+ public:
+
+ typedef std::function<osmium::io::Compressor*(int)> create_compressor_type;
+ typedef std::function<osmium::io::Decompressor*(int)> create_decompressor_type_fd;
+ typedef std::function<osmium::io::Decompressor*(const char*, size_t)> create_decompressor_type_buffer;
+
+ private:
+
+ typedef std::map<const osmium::io::file_compression, std::tuple<create_compressor_type, create_decompressor_type_fd, create_decompressor_type_buffer>> compression_map_type;
+
+ compression_map_type m_callbacks;
+
+ CompressionFactory() = default;
+
+ CompressionFactory(const CompressionFactory&) = delete;
+ CompressionFactory& operator=(const CompressionFactory&) = delete;
+
+ CompressionFactory(CompressionFactory&&) = delete;
+ CompressionFactory& operator=(CompressionFactory&&) = delete;
+
+ OSMIUM_NORETURN void error(osmium::io::file_compression compression) {
+ std::string error_message {"Support for compression '"};
+ error_message += as_string(compression);
+ error_message += "' not compiled into this binary.";
+ throw std::runtime_error(error_message);
+ }
+
+ public:
+
+ static CompressionFactory& instance() {
+ static CompressionFactory factory;
+ return factory;
+ }
+
+ bool register_compression(
+ osmium::io::file_compression compression,
+ create_compressor_type create_compressor,
+ create_decompressor_type_fd create_decompressor_fd,
+ create_decompressor_type_buffer create_decompressor_buffer) {
+
+ compression_map_type::value_type cc(compression, std::make_tuple(create_compressor, create_decompressor_fd, create_decompressor_buffer));
+ return m_callbacks.insert(cc).second;
+ }
+
+ std::unique_ptr<osmium::io::Compressor> create_compressor(osmium::io::file_compression compression, int fd) {
+ auto it = m_callbacks.find(compression);
+
+ if (it != m_callbacks.end()) {
+ return std::unique_ptr<osmium::io::Compressor>(std::get<0>(it->second)(fd));
+ }
+
+ error(compression);
+ }
+
+ std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, int fd) {
+ auto it = m_callbacks.find(compression);
+
+ if (it != m_callbacks.end()) {
+ return std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd));
+ }
+
+ error(compression);
+ }
+
+ std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, const char* buffer, size_t size) {
+ auto it = m_callbacks.find(compression);
+
+ if (it != m_callbacks.end()) {
+ return std::unique_ptr<osmium::io::Decompressor>(std::get<2>(it->second)(buffer, size));
+ }
+
+ error(compression);
+ }
+
+ }; // class CompressionFactory
+
+ class NoCompressor : public Compressor {
+
+ int m_fd;
+
+ public:
+
+ NoCompressor(int fd) :
+ Compressor(),
+ m_fd(fd) {
+ }
+
+ ~NoCompressor() override final {
+ close();
+ }
+
+ void write(const std::string& data) override final {
+ osmium::io::detail::reliable_write(m_fd, data.data(), data.size());
+ }
+
+ void close() override final {
+ if (m_fd >= 0) {
+ ::close(m_fd);
+ m_fd = -1;
+ }
+ }
+
+ }; // class NoCompressor
+
+ class NoDecompressor : public Decompressor {
+
+ int m_fd;
+ const char *m_buffer;
+ size_t m_buffer_size;
+
+ public:
+
+ NoDecompressor(int fd) :
+ Decompressor(),
+ m_fd(fd),
+ m_buffer(nullptr),
+ m_buffer_size(0) {
+ }
+
+ NoDecompressor(const char* buffer, size_t size) :
+ Decompressor(),
+ m_fd(-1),
+ m_buffer(buffer),
+ m_buffer_size(size) {
+ }
+
+ ~NoDecompressor() override final {
+ close();
+ }
+
+ std::string read() override final {
+ if (m_buffer) {
+ if (m_buffer_size == 0) {
+ return std::string();
+ }
+ 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());
+ if (nread < 0) {
+ throw std::system_error(errno, std::system_category(), "Read failed");
+ }
+ buffer.resize(static_cast<size_t>(nread));
+ return buffer;
+ }
+ }
+
+ void close() override final {
+ if (m_fd >= 0) {
+ ::close(m_fd);
+ m_fd = -1;
+ }
+ }
+
+ }; // class NoDecompressor
+
+ namespace {
+
+ const bool registered_no_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::none,
+ [](int fd) { return new osmium::io::NoCompressor(fd); },
+ [](int fd) { return new osmium::io::NoDecompressor(fd); },
+ [](const char* buffer, size_t size) { return new osmium::io::NoDecompressor(buffer, size); }
+ );
+
+ } // anonymous namespace
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_COMPRESSION_HPP
diff --git a/third_party/osmium/io/detail/input_format.hpp b/third_party/osmium/io/detail/input_format.hpp
new file mode 100644
index 0000000..f88561b
--- /dev/null
+++ b/third_party/osmium/io/detail/input_format.hpp
@@ -0,0 +1,160 @@
+#ifndef OSMIUM_IO_DETAIL_INPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_INPUT_FORMAT_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 <functional>
+#include <map>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/entity_bits.hpp>
+
+namespace osmium {
+
+ namespace thread {
+ template <typename T> class Queue;
+ } // namespace thread
+
+ namespace io {
+
+ namespace detail {
+
+ /**
+ * Virtual base class for all classes reading OSM files in different
+ * formats.
+ *
+ * Do not use this class or derived classes directly. Use the
+ * osmium::io::Reader class instead.
+ */
+ class InputFormat {
+
+ protected:
+
+ 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) :
+ m_file(file),
+ m_read_which_entities(read_which_entities),
+ m_input_queue(input_queue) {
+ m_header.set_has_multiple_object_versions(m_file.has_multiple_object_versions());
+ }
+
+ InputFormat(const InputFormat&) = delete;
+ InputFormat(InputFormat&&) = delete;
+
+ InputFormat& operator=(const InputFormat&) = delete;
+ InputFormat& operator=(InputFormat&&) = delete;
+
+ public:
+
+ virtual ~InputFormat() {
+ }
+
+ virtual osmium::memory::Buffer read() = 0;
+
+ virtual void close() {
+ }
+
+ virtual osmium::io::Header header() {
+ return m_header;
+ }
+
+ }; // class InputFormat
+
+ /**
+ * This factory class is used to create objects that read OSM data
+ * written in a specified format.
+ *
+ * Do not use this class directly. Instead use the osmium::io::Reader
+ * class.
+ */
+ class InputFormatFactory {
+
+ public:
+
+ typedef std::function<osmium::io::detail::InputFormat*(const osmium::io::File&, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>&)> create_input_type;
+
+ private:
+
+ typedef std::map<osmium::io::file_format, create_input_type> map_type;
+
+ map_type m_callbacks;
+
+ InputFormatFactory() :
+ m_callbacks() {
+ }
+
+ public:
+
+ static InputFormatFactory& instance() {
+ static InputFormatFactory factory;
+ return factory;
+ }
+
+ bool register_input_format(osmium::io::file_format format, create_input_type create_function) {
+ if (! m_callbacks.insert(map_type::value_type(format, create_function)).second) {
+ return false;
+ }
+ return true;
+ }
+
+ std::unique_ptr<osmium::io::detail::InputFormat> create_input(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) {
+ file.check();
+
+ auto it = m_callbacks.find(file.format());
+ if (it != m_callbacks.end()) {
+ return std::unique_ptr<osmium::io::detail::InputFormat>((it->second)(file, read_which_entities, input_queue));
+ }
+
+ throw std::runtime_error(std::string("Support for input format '") + as_string(file.format()) + "' not compiled into this binary.");
+ }
+
+ }; // class InputFormatFactory
+
+ } // namespace detail
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_INPUT_FORMAT_HPP
diff --git a/third_party/osmium/io/detail/opl_output_format.hpp b/third_party/osmium/io/detail/opl_output_format.hpp
new file mode 100644
index 0000000..b21d118
--- /dev/null
+++ b/third_party/osmium/io/detail/opl_output_format.hpp
@@ -0,0 +1,315 @@
+#ifndef OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_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 <cinttypes>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <future>
+#include <iterator>
+#include <memory>
+#include <ratio>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <boost/version.hpp>
+
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wmissing-noreturn"
+# pragma clang diagnostic ignored "-Wsign-conversion"
+#endif
+
+#if BOOST_VERSION >= 104800
+# include <boost/regex/pending/unicode_iterator.hpp>
+#else
+# include <boost_unicode_iterator.hpp>
+#endif
+
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif
+
+#include <osmium/handler.hpp>
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/changeset.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/thread/pool.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+ namespace io {
+
+ class File;
+
+ namespace detail {
+
+ /**
+ * Writes out one buffer with OSM data in OPL format.
+ */
+ class OPLOutputBlock : public osmium::handler::Handler {
+
+ static constexpr size_t tmp_buffer_size = 100;
+
+ osmium::memory::Buffer m_input_buffer;
+
+ std::string m_out;
+
+ char m_tmp_buffer[tmp_buffer_size+1];
+
+ template <typename... TArgs>
+ void output_formatted(const char* format, TArgs&&... args) {
+#ifndef NDEBUG
+ int len =
+#endif
+#ifndef _MSC_VER
+ snprintf(m_tmp_buffer, tmp_buffer_size, format, std::forward<TArgs>(args)...);
+#else
+ _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;
+ }
+
+ 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));
+
+ for (; it != end; ++it) {
+ uint32_t c = *it;
+
+ // This is a list of Unicode code points that we let
+ // through instead of escaping them. It is incomplete
+ // and can be extended later.
+ // Generally we don't want to let through any character
+ // that has special meaning in the OPL format such as
+ // space, comma, @, etc. and any non-printing characters.
+ if ((0x0021 <= c && c <= 0x0024) ||
+ (0x0026 <= c && c <= 0x002b) ||
+ (0x002d <= c && c <= 0x003c) ||
+ (0x003e <= c && c <= 0x003f) ||
+ (0x0041 <= c && c <= 0x007e) ||
+ (0x00a1 <= c && c <= 0x00ac) ||
+ (0x00ae <= c && c <= 0x05ff)) {
+ *oit = c;
+ } else {
+ m_out += '%';
+ output_formatted("%04x", c);
+ }
+ }
+ }
+
+ void write_meta(const osmium::OSMObject& object) {
+ output_formatted("%" PRId64 " v%d d", object.id(), object.version());
+ m_out += (object.visible() ? 'V' : 'D');
+ output_formatted(" c%d t", object.changeset());
+ m_out += object.timestamp().to_iso();
+ output_formatted(" i%d u", object.uid());
+ append_encoded_string(object.user());
+ m_out += " T";
+ bool first = true;
+ for (const auto& tag : object.tags()) {
+ if (first) {
+ first = false;
+ } else {
+ m_out += ',';
+ }
+ append_encoded_string(tag.key());
+ m_out += '=';
+ append_encoded_string(tag.value());
+ }
+ }
+
+ void write_location(const osmium::Location location, const char x, const char y) {
+ 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;
+ }
+ }
+
+ public:
+
+ explicit OPLOutputBlock(osmium::memory::Buffer&& buffer) :
+ m_input_buffer(std::move(buffer)),
+ m_out(),
+ m_tmp_buffer() {
+ }
+
+ OPLOutputBlock(const OPLOutputBlock&) = delete;
+ OPLOutputBlock& operator=(const OPLOutputBlock&) = delete;
+
+ OPLOutputBlock(OPLOutputBlock&&) = default;
+ OPLOutputBlock& operator=(OPLOutputBlock&&) = default;
+
+ std::string operator()() {
+ osmium::apply(m_input_buffer.cbegin(), m_input_buffer.cend(), *this);
+
+ std::string out;
+ std::swap(out, m_out);
+ return out;
+ }
+
+ void node(const osmium::Node& node) {
+ m_out += 'n';
+ write_meta(node);
+ write_location(node.location(), 'x', 'y');
+ m_out += '\n';
+ }
+
+ void way(const osmium::Way& way) {
+ m_out += 'w';
+ write_meta(way);
+
+ m_out += " N";
+ bool first = true;
+ for (const auto& node_ref : way.nodes()) {
+ if (first) {
+ first = false;
+ } else {
+ m_out += ',';
+ }
+ output_formatted("n%" PRId64, node_ref.ref());
+ }
+ m_out += '\n';
+ }
+
+ void relation(const osmium::Relation& relation) {
+ m_out += 'r';
+ write_meta(relation);
+
+ m_out += " M";
+ bool first = true;
+ for (const auto& member : relation.members()) {
+ if (first) {
+ first = false;
+ } else {
+ m_out += ',';
+ }
+ m_out += item_type_to_char(member.type());
+ output_formatted("%" PRId64 "@", member.ref());
+ m_out += member.role();
+ }
+ 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();
+ 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";
+ bool first = true;
+ for (const auto& tag : changeset.tags()) {
+ if (first) {
+ first = false;
+ } else {
+ m_out += ',';
+ }
+ append_encoded_string(tag.key());
+ m_out += '=';
+ append_encoded_string(tag.value());
+ }
+
+ m_out += '\n';
+ }
+
+ }; // OPLOutputBlock
+
+ class OPLOutputFormat : public osmium::io::detail::OutputFormat {
+
+ OPLOutputFormat(const OPLOutputFormat&) = delete;
+ OPLOutputFormat& operator=(const OPLOutputFormat&) = delete;
+
+ public:
+
+ OPLOutputFormat(const osmium::io::File& file, data_queue_type& output_queue) :
+ OutputFormat(file, output_queue) {
+ }
+
+ void write_buffer(osmium::memory::Buffer&& buffer) override final {
+ m_output_queue.push(osmium::thread::Pool::instance().submit(OPLOutputBlock{std::move(buffer)}));
+ }
+
+ void close() override final {
+ std::string out;
+ std::promise<std::string> promise;
+ m_output_queue.push(promise.get_future());
+ promise.set_value(out);
+ }
+
+ }; // class OPLOutputFormat
+
+ namespace {
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-variable"
+ const bool registered_opl_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::opl,
+ [](const osmium::io::File& file, data_queue_type& output_queue) {
+ return new osmium::io::detail::OPLOutputFormat(file, output_queue);
+ });
+#pragma GCC diagnostic pop
+
+ } // anonymous namespace
+
+ } // namespace detail
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_HPP
diff --git a/third_party/osmium/io/detail/output_format.hpp b/third_party/osmium/io/detail/output_format.hpp
new file mode 100644
index 0000000..ad9e702
--- /dev/null
+++ b/third_party/osmium/io/detail/output_format.hpp
@@ -0,0 +1,156 @@
+#ifndef OSMIUM_IO_DETAIL_OUTPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_OUTPUT_FORMAT_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 <functional>
+#include <future>
+#include <map>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/thread/queue.hpp>
+
+namespace osmium {
+
+ namespace memory {
+ class Buffer;
+ }
+
+ namespace io {
+
+ namespace detail {
+
+ typedef osmium::thread::Queue<std::future<std::string>> data_queue_type;
+
+ /**
+ * Virtual base class for all classes writing OSM files in different
+ * formats.
+ *
+ * Do not use this class or derived classes directly. Use the
+ * osmium::io::Writer class instead.
+ */
+ class OutputFormat {
+
+ protected:
+
+ osmium::io::File m_file;
+ data_queue_type& m_output_queue;
+
+ public:
+
+ explicit OutputFormat(const osmium::io::File& file, data_queue_type& output_queue) :
+ m_file(file),
+ m_output_queue(output_queue) {
+ }
+
+ OutputFormat(const OutputFormat&) = delete;
+ OutputFormat(OutputFormat&&) = delete;
+
+ OutputFormat& operator=(const OutputFormat&) = delete;
+ OutputFormat& operator=(OutputFormat&&) = delete;
+
+ virtual ~OutputFormat() {
+ }
+
+ virtual void write_header(const osmium::io::Header&) {
+ }
+
+ virtual void write_buffer(osmium::memory::Buffer&&) = 0;
+
+ virtual void close() = 0;
+
+ }; // class OutputFormat
+
+ /**
+ * This factory class is used to create objects that write OSM data
+ * into a specified output format.
+ *
+ * Do not use this class directly. Instead use the osmium::io::Writer
+ * class.
+ */
+ class OutputFormatFactory {
+
+ public:
+
+ typedef std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, data_queue_type&)> create_output_type;
+
+ private:
+
+ typedef std::map<osmium::io::file_format, create_output_type> map_type;
+
+ map_type m_callbacks;
+
+ OutputFormatFactory() :
+ m_callbacks() {
+ }
+
+ public:
+
+ static OutputFormatFactory& instance() {
+ static OutputFormatFactory factory;
+ return factory;
+ }
+
+ bool register_output_format(osmium::io::file_format format, create_output_type create_function) {
+ if (! m_callbacks.insert(map_type::value_type(format, create_function)).second) {
+ return false;
+ }
+ return true;
+ }
+
+ std::unique_ptr<osmium::io::detail::OutputFormat> create_output(const osmium::io::File& file, data_queue_type& output_queue) {
+ file.check();
+
+ auto it = m_callbacks.find(file.format());
+ if (it != m_callbacks.end()) {
+ return std::unique_ptr<osmium::io::detail::OutputFormat>((it->second)(file, output_queue));
+ }
+
+ throw std::runtime_error(std::string("Support for output format '") + as_string(file.format()) + "' not compiled into this binary.");
+ }
+
+ }; // class OutputFormatFactory
+
+ } // namespace detail
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_OUTPUT_FORMAT_HPP
diff --git a/third_party/osmium/io/detail/pbf.hpp b/third_party/osmium/io/detail/pbf.hpp
new file mode 100644
index 0000000..9814bd4
--- /dev/null
+++ b/third_party/osmium/io/detail/pbf.hpp
@@ -0,0 +1,100 @@
+#ifndef OSMIUM_IO_DETAIL_PBF_HPP
+#define OSMIUM_IO_DETAIL_PBF_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.
+
+*/
+
+#define OSMIUM_LINK_WITH_LIBS_PBF -pthread -lz -lprotobuf-lite -losmpbf
+
+#include <stdexcept>
+
+#include <osmpbf/osmpbf.h>
+
+// needed for htonl and ntohl
+#ifndef _WIN32
+# include <netinet/in.h>
+#else
+# include <winsock2.h>
+#endif
+
+#include <osmium/io/error.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+// avoid g++ false positive
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreturn-type"
+ inline item_type osmpbf_membertype_to_item_type(const OSMPBF::Relation::MemberType mt) {
+ switch (mt) {
+ case OSMPBF::Relation::NODE:
+ return item_type::node;
+ case OSMPBF::Relation::WAY:
+ return item_type::way;
+ case OSMPBF::Relation::RELATION:
+ return item_type::relation;
+ }
+ }
+#pragma GCC diagnostic pop
+
+ inline OSMPBF::Relation::MemberType item_type_to_osmpbf_membertype(const item_type type) {
+ switch (type) {
+ case item_type::node:
+ return OSMPBF::Relation::NODE;
+ case item_type::way:
+ return OSMPBF::Relation::WAY;
+ case item_type::relation:
+ return OSMPBF::Relation::RELATION;
+ default:
+ throw std::runtime_error("Unknown relation member type");
+ }
+ }
+
+ /**
+ * Exception thrown when there was a problem with parsing the PBF format of
+ * a file.
+ */
+ struct pbf_error : public io_error {
+
+ pbf_error(const std::string& what) :
+ io_error(std::string("PBF error: ") + what) {
+ }
+
+ pbf_error(const char* what) :
+ io_error(std::string("PBF error: ") + what) {
+ }
+
+ }; // struct pbf_error
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_PBF_HPP
diff --git a/third_party/osmium/io/detail/pbf_input_format.hpp b/third_party/osmium/io/detail/pbf_input_format.hpp
new file mode 100644
index 0000000..3491bed
--- /dev/null
+++ b/third_party/osmium/io/detail/pbf_input_format.hpp
@@ -0,0 +1,240 @@
+#ifndef OSMIUM_IO_DETAIL_PBF_INPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_PBF_INPUT_FORMAT_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 <algorithm>
+#include <atomic>
+#include <cassert>
+#include <chrono>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <future>
+#include <memory>
+#include <ratio>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <thread>
+#include <type_traits>
+
+#include <osmium/io/detail/input_format.hpp>
+#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
+#include <osmium/io/detail/pbf_parser.hpp>
+#include <osmium/io/error.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/thread/pool.hpp>
+#include <osmium/thread/queue.hpp>
+#include <osmium/thread/util.hpp>
+#include <osmium/util/cast.hpp>
+#include <osmium/util/config.hpp>
+
+namespace osmium {
+
+ namespace io {
+
+ class File;
+
+ namespace detail {
+
+ typedef osmium::thread::Queue<std::future<osmium::memory::Buffer>> queue_type;
+
+ /**
+ * Class for parsing PBF files.
+ */
+ class PBFInputFormat : public osmium::io::detail::InputFormat {
+
+ bool m_use_thread_pool;
+ queue_type m_queue;
+ std::atomic<bool> m_done;
+ std::thread m_reader;
+ osmium::thread::Queue<std::string>& m_input_queue;
+ std::string m_input_buffer;
+
+ /**
+ * Read the given number of bytes from the input queue.
+ *
+ * @param size Number of bytes to read
+ * @returns String with the data
+ * @throws osmium::pbf_error If size bytes can't be read
+ */
+ std::string read_from_input_queue(size_t size) {
+ while (m_input_buffer.size() < size) {
+ std::string new_data;
+ m_input_queue.wait_and_pop(new_data);
+ if (new_data.empty()) {
+ throw osmium::pbf_error("truncated data (EOF encountered)");
+ }
+ m_input_buffer += new_data;
+ }
+
+ std::string output { m_input_buffer.substr(size) };
+ m_input_buffer.resize(size);
+ std::swap(output, m_input_buffer);
+ return output;
+ }
+
+ /**
+ * Read BlobHeader by first reading the size and then the
+ * BlobHeader. The BlobHeader contains a type field (which is
+ * checked against the expected type) and a size field.
+ *
+ * @param expected_type Expected type of data ("OSMHeader" or
+ * "OSMData").
+ * @returns Size of the data read from BlobHeader (0 on EOF).
+ */
+ size_t read_blob_header(const char* expected_type) {
+ uint32_t size_in_network_byte_order;
+
+ try {
+ std::string input_data = read_from_input_queue(sizeof(size_in_network_byte_order));
+ size_in_network_byte_order = *reinterpret_cast<const uint32_t*>(input_data.data());
+ } catch (osmium::pbf_error&) {
+ return 0; // EOF
+ }
+
+ uint32_t size = ntohl(size_in_network_byte_order);
+ if (size > static_cast<uint32_t>(OSMPBF::max_blob_header_size)) {
+ throw osmium::pbf_error("invalid BlobHeader size (> max_blob_header_size)");
+ }
+
+ OSMPBF::BlobHeader blob_header;
+ if (!blob_header.ParseFromString(read_from_input_queue(size))) {
+ throw osmium::pbf_error("failed to parse BlobHeader");
+ }
+
+ if (blob_header.type() != expected_type) {
+ throw osmium::pbf_error("blob does not have expected type (OSMHeader in first blob, OSMData in following blobs)");
+ }
+
+ return static_cast<size_t>(blob_header.datasize());
+ }
+
+ void parse_osm_data(osmium::osm_entity_bits::type read_types) {
+ osmium::thread::set_thread_name("_osmium_pbf_in");
+ int n=0;
+ while (auto size = read_blob_header("OSMData")) {
+
+ if (m_use_thread_pool) {
+ m_queue.push(osmium::thread::Pool::instance().submit(DataBlobParser{read_from_input_queue(size), read_types}));
+ } else {
+ std::promise<osmium::memory::Buffer> promise;
+ m_queue.push(promise.get_future());
+ DataBlobParser data_blob_parser{read_from_input_queue(size), read_types};
+ promise.set_value(data_blob_parser());
+ }
+ ++n;
+
+ if (m_done) {
+ return;
+ }
+ }
+ m_done = true;
+ }
+
+ public:
+
+ /**
+ * Instantiate PBF Parser
+ *
+ * @param file osmium::io::File instance describing file to be read from.
+ * @param read_which_entities Which types of OSM entities (nodes, ways, relations, changesets) should be parsed?
+ * @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),
+ m_use_thread_pool(osmium::config::use_pool_threads_for_pbf_parsing()),
+ m_queue(20, "pbf_parser_results"), // XXX
+ m_done(false),
+ m_input_queue(input_queue),
+ m_input_buffer() {
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ // handle OSMHeader
+ auto size = read_blob_header("OSMHeader");
+ m_header = parse_header_blob(read_from_input_queue(size));
+
+ if (m_read_which_entities != osmium::osm_entity_bits::nothing) {
+ m_reader = std::thread(&PBFInputFormat::parse_osm_data, this, m_read_which_entities);
+ }
+ }
+
+ ~PBFInputFormat() {
+ m_done = true;
+ 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 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());
+ }
+
+ return osmium::memory::Buffer();
+ }
+
+ }; // class PBFInputFormat
+
+ namespace {
+
+ const bool registered_pbf_input = osmium::io::detail::InputFormatFactory::instance().register_input_format(osmium::io::file_format::pbf,
+ [](const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) {
+ return new osmium::io::detail::PBFInputFormat(file, read_which_entities, input_queue);
+ });
+
+ } // anonymous namespace
+
+ } // namespace detail
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_PBF_INPUT_FORMAT_HPP
diff --git a/third_party/osmium/io/detail/pbf_output_format.hpp b/third_party/osmium/io/detail/pbf_output_format.hpp
new file mode 100644
index 0000000..44f8ffb
--- /dev/null
+++ b/third_party/osmium/io/detail/pbf_output_format.hpp
@@ -0,0 +1,944 @@
+#ifndef OSMIUM_IO_DETAIL_PBF_OUTPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_PBF_OUTPUT_FORMAT_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.
+
+*/
+
+/*
+
+About the .osm.pbf file format
+This is an excerpt of <http://wiki.openstreetmap.org/wiki/PBF_Format>
+
+The .osm.pbf format and it's derived formats (.osh.pbf and .osc.pbf) are encoded
+using googles protobuf library for the low-level storage. They are constructed
+by nesting data on two levels:
+
+On the lower level the file is constructed using BlobHeaders and Blobs. A .osm.pbf
+file contains multiple sequences of
+ 1. a 4-byte header size, stored in network-byte-order
+ 2. a BlobHeader of exactly this size
+ 3. a Blob
+
+The BlobHeader tells the reader about the type and size of the following Blob. The
+Blob can contain data in raw or zlib-compressed form. After uncompressing the blob
+it is treated differently depending on the type specified in the BlobHeader.
+
+The contents of the Blob belongs to the higher level. It contains either an HeaderBlock
+(type="OSMHeader") or an PrimitiveBlock (type="OSMData"). The file needs to have
+at least one HeaderBlock before the first PrimitiveBlock.
+
+The HeaderBlock contains meta-information like the writing program or a bbox. It may
+also contain multiple "required features" that describe what kinds of input a
+reading program needs to handle in order to fully understand the files' contents.
+
+The PrimitiveBlock can store multiple types of objects (i.e. 5 nodes, 2 ways and
+1 relation). It contains one or more PrimitiveGroup which in turn contain multiple
+nodes, ways or relations. A PrimitiveGroup should only contain one kind of object.
+
+There's a special kind of "object type" called dense-nodes. It is used to store nodes
+in a very dense format, avoiding message overheads and using delta-encoding for nearly
+all ids.
+
+All Strings are stored as indexes to rows in a StringTable. The StringTable contains
+one row for each used string, so strings that are used multiple times need to be
+stored only once. The StringTable is sorted by usage-count, so the most often used
+string is stored at index 1.
+
+A simple outline of a .osm.pbf file could look like this:
+
+ 4-bytes header size
+ BlobHeader
+ Blob
+ HeaderBlock
+ 4-bytes header size
+ BlobHeader
+ Blob
+ PrimitiveBlock
+ StringTable
+ PrimitiveGroup
+ 5 nodes
+ PrimitiveGroup
+ 2 ways
+ PrimitiveGroup
+ 1 relation
+
+More complete outlines of real .osm.pbf files can be created using the osmpbf-outline tool:
+ <https://github.com/MaZderMind/OSM-binary/tree/osmpbf-outline>
+*/
+
+#include <algorithm>
+#include <chrono>
+#include <cmath>
+#include <cstdint>
+#include <cstdlib>
+#include <future>
+#include <iostream>
+#include <memory>
+#include <ratio>
+#include <string>
+#include <thread>
+#include <time.h>
+#include <utility>
+
+#include <osmium/handler.hpp>
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
+#include <osmium/io/detail/pbf_stringtable.hpp>
+#include <osmium/io/detail/zlib.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/util/cast.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+ namespace io {
+
+ namespace detail {
+
+ namespace {
+
+ /**
+ * Serialize a protobuf message into a Blob, optionally apply compression
+ * and return it together with a BlobHeader ready to be written to a file.
+ *
+ * @param type Type-string used in the BlobHeader.
+ * @param msg Protobuf-message.
+ * @param use_compression Should the output be compressed using zlib?
+ */
+ std::string serialize_blob(const std::string& type, const google::protobuf::MessageLite& msg, bool use_compression) {
+ OSMPBF::Blob pbf_blob;
+
+ {
+ std::string content;
+ msg.SerializeToString(&content);
+
+ pbf_blob.set_raw_size(static_cast_with_assert<::google::protobuf::int32>(content.size()));
+
+ if (use_compression) {
+ pbf_blob.set_zlib_data(osmium::io::detail::zlib_compress(content));
+ } else {
+ pbf_blob.set_raw(content);
+ }
+ }
+
+ std::string blob_data;
+ pbf_blob.SerializeToString(&blob_data);
+
+ OSMPBF::BlobHeader pbf_blob_header;
+ pbf_blob_header.set_type(type);
+ pbf_blob_header.set_datasize(static_cast_with_assert<::google::protobuf::int32>(blob_data.size()));
+
+ std::string blob_header_data;
+ pbf_blob_header.SerializeToString(&blob_header_data);
+
+ uint32_t sz = htonl(static_cast_with_assert<uint32_t>(blob_header_data.size()));
+
+ // write to output: the 4-byte BlobHeader-Size followed by the BlobHeader followed by the Blob
+ std::string output;
+ output.reserve(sizeof(sz) + blob_header_data.size() + blob_data.size());
+ output.append(reinterpret_cast<const char*>(&sz), sizeof(sz));
+ output.append(blob_header_data);
+ output.append(blob_data);
+
+ return output;
+ }
+
+ } // anonymous namespace
+
+ class PBFOutputFormat : public osmium::io::detail::OutputFormat, public osmium::handler::Handler {
+
+ /**
+ * This class models a variable that keeps track of the value
+ * it was last set to and returns the delta between old and
+ * new value from the update() call.
+ */
+ template <typename T>
+ class Delta {
+
+ T m_value;
+
+ public:
+
+ Delta() :
+ m_value(0) {
+ }
+
+ void clear() {
+ m_value = 0;
+ }
+
+ T update(T new_value) {
+ using std::swap;
+ swap(m_value, new_value);
+ return m_value - new_value;
+ }
+
+ }; // class Delta
+
+ /**
+ * Maximum number of items in a primitive block.
+ *
+ * The uncompressed length of a Blob *should* be less
+ * than 16 megabytes and *must* be less than 32 megabytes.
+ *
+ * A block may contain any number of entities, as long as
+ * the size limits for the surrounding blob are obeyed.
+ * However, for simplicity, the current Osmosis (0.38)
+ * as well as Osmium implementation always
+ * uses at most 8k entities in a block.
+ */
+ static constexpr uint32_t max_block_contents = 8000;
+
+ /**
+ * The output buffer (block) will be filled to about
+ * 95% and then written to disk. This leaves more than
+ * enough space for the string table (which typically
+ * needs about 0.1 to 0.3% of the block size).
+ */
+ static constexpr int64_t buffer_fill_percent = 95;
+
+ /**
+ * protobuf-struct of a HeaderBlock
+ */
+ OSMPBF::HeaderBlock pbf_header_block;
+
+ /**
+ * protobuf-struct of a PrimitiveBlock
+ */
+ OSMPBF::PrimitiveBlock pbf_primitive_block;
+
+ /**
+ * pointer to PrimitiveGroups inside the current PrimitiveBlock,
+ * used for writing nodes, ways or relations
+ */
+ OSMPBF::PrimitiveGroup* pbf_nodes;
+ OSMPBF::PrimitiveGroup* pbf_ways;
+ OSMPBF::PrimitiveGroup* pbf_relations;
+
+ /**
+ * To flexibly handle multiple resolutions, the granularity, or
+ * resolution used for representing locations is adjustable in
+ * multiples of 1 nanodegree. The default scaling factor is 100
+ * nanodegrees, corresponding to about ~1cm at the equator.
+ * This is the current resolution of the OSM database.
+ */
+ int m_location_granularity;
+
+ /**
+ * The granularity used for representing timestamps is also adjustable in
+ * multiples of 1 millisecond. The default scaling factor is 1000
+ * milliseconds, which is the current resolution of the OSM database.
+ */
+ int m_date_granularity;
+
+ /**
+ * should nodes be serialized into the dense format?
+ *
+ * nodes can be encoded one of two ways, as a Node
+ * (m_use_dense_nodes = false) and a special dense format.
+ * In the dense format, all information is stored 'column wise',
+ * as an array of ID's, array of latitudes, and array of
+ * longitudes. Each column is delta-encoded. This reduces
+ * header overheads and allows delta-coding to work very effectively.
+ */
+ bool m_use_dense_nodes {true};
+
+ /**
+ * should the PBF blobs contain zlib compressed data?
+ *
+ * the zlib compression is optional, it's possible to store the
+ * blobs in raw format. Disabling the compression can improve the
+ * writing speed a little but the output will be 2x to 3x bigger.
+ */
+ bool m_use_compression {true};
+
+ /**
+ * While the .osm.pbf-format is able to carry all meta information, it is
+ * also able to omit this information to reduce size.
+ */
+ bool m_should_add_metadata {true};
+
+ /**
+ * Should the visible flag be added on objects?
+ */
+ bool m_add_visible;
+
+ /**
+ * counter used to quickly check the number of objects stored inside
+ * the current PrimitiveBlock. When the counter reaches max_block_contents
+ * the PrimitiveBlock is serialized into a Blob and flushed to the file.
+ *
+ * this check is performed in check_block_contents_counter() which is
+ * called once for each object.
+ */
+ uint16_t primitive_block_contents;
+ int primitive_block_size;
+
+ // StringTable management
+ StringTable string_table;
+
+ /**
+ * These variables are used to calculate the
+ * delta-encoding while storing dense-nodes. It holds the last seen values
+ * from which the difference is stored into the protobuf.
+ */
+ Delta<int64_t> m_delta_id;
+ Delta<int64_t> m_delta_lat;
+ Delta<int64_t> m_delta_lon;
+ Delta<int64_t> m_delta_timestamp;
+ Delta<int64_t> m_delta_changeset;
+ Delta<int64_t> m_delta_uid;
+ Delta<::google::protobuf::int32> m_delta_user_sid;
+
+ bool debug;
+
+ bool has_debug_level(int) {
+ return false;
+ }
+
+ ///// Blob writing /////
+
+ /**
+ * 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.
+ *
+ * This function needs to know about the concrete structure of all item types to find
+ * all occurrences of string-ids.
+ */
+ void map_string_ids() {
+ // 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) {
+ map_common_string_ids(pbf_nodes->mutable_nodes(i));
+ }
+
+ // test, if the node-block has a densenodes structure
+ if (pbf_nodes->has_dense()) {
+ // get a pointer to the densenodes structure
+ OSMPBF::DenseNodes* dense = pbf_nodes->mutable_dense();
+
+ // 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) {
+ // map interim string-ids > 0 to real string ids
+ auto sid = dense->keys_vals(i);
+ if (sid > 0) {
+ dense->set_keys_vals(i, string_table.map_string_id(sid));
+ }
+ }
+
+ // test if the densenodes block has meta infos
+ if (dense->has_denseinfo()) {
+ // get a pointer to the denseinfo structure
+ OSMPBF::DenseInfo* denseinfo = dense->mutable_denseinfo();
+
+ // iterate over all username string-ids
+ 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));
+
+ // delta encode the string-id
+ denseinfo->set_user_sid(i, m_delta_user_sid.update(user_sid));
+ }
+ }
+ }
+ }
+
+ // 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) {
+ map_common_string_ids(pbf_ways->mutable_ways(i));
+ }
+ }
+
+ // 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) {
+ // get a pointer to the relation
+ OSMPBF::Relation* relation = pbf_relations->mutable_relations(i);
+
+ // pass them to the map_common_string_ids function
+ map_common_string_ids(relation);
+
+ // 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) {
+ relation->set_roles_sid(mi, string_table.map_string_id(relation->roles_sid(mi)));
+ }
+ }
+ }
+ }
+
+ /**
+ * a helper function used in map_string_ids to map common interim string-ids of the
+ * user name and all tags to real string ids.
+ *
+ * TPBFObject is either OSMPBF::Node, OSMPBF::Way or OSMPBF::Relation.
+ */
+ template <class TPBFObject>
+ void map_common_string_ids(TPBFObject* in) {
+ // if the object has meta-info attached
+ if (in->has_info()) {
+ // map the interim-id of the user name to a real id
+ OSMPBF::Info* info = in->mutable_info();
+ info->set_user_sid(string_table.map_string_id(info->user_sid()));
+ }
+
+ // 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) {
+ in->set_keys(i, string_table.map_string_id(in->keys(i)));
+ in->set_vals(i, string_table.map_string_id(in->vals(i)));
+ }
+ }
+
+
+ ///// MetaData helper /////
+
+ /**
+ * convert a double lat or lon value to an int, respecting the current blocks granularity
+ */
+ int64_t lonlat2int(double lonlat) {
+ return static_cast<int64_t>(std::round(lonlat * OSMPBF::lonlat_resolution / location_granularity()));
+ }
+
+ /**
+ * convert a timestamp to an int, respecting the current blocks granularity
+ */
+ int64_t timestamp2int(time_t timestamp) {
+ return static_cast<int64_t>(std::round(timestamp * (1000.0 / date_granularity())));
+ }
+
+ /**
+ * helper function used in the write()-calls to apply common information from an osmium-object
+ * onto a pbf-object.
+ *
+ * TPBFObject is either OSMPBF::Node, OSMPBF::Way or OSMPBF::Relation.
+ */
+ template <class TPBFObject>
+ void apply_common_info(const osmium::OSMObject& in, TPBFObject* out) {
+ // set the object-id
+ out->set_id(in.id());
+
+ // iterate over all tags and set the keys and vals, recording the strings in the
+ // interim StringTable and storing the interim ids
+ for (const auto& tag : in.tags()) {
+ out->add_keys(string_table.record_string(tag.key()));
+ out->add_vals(string_table.record_string(tag.value()));
+ }
+
+ if (m_should_add_metadata) {
+ // add an info-section to the pbf object and set the meta-info on it
+ OSMPBF::Info* out_info = out->mutable_info();
+ if (m_add_visible) {
+ out_info->set_visible(in.visible());
+ }
+ out_info->set_version(static_cast<::google::protobuf::int32>(in.version()));
+ out_info->set_timestamp(timestamp2int(in.timestamp()));
+ out_info->set_changeset(in.changeset());
+ out_info->set_uid(static_cast<::google::protobuf::int32>(in.uid()));
+ out_info->set_user_sid(string_table.record_string(in.user()));
+ }
+ }
+
+
+ ///// High-Level Block writing /////
+
+ /**
+ * store the current pbf_header_block into a Blob and clear this struct afterwards.
+ */
+ void store_header_block() {
+ if (debug && has_debug_level(1)) {
+ std::cerr << "storing header block" << std::endl;
+ }
+
+ std::promise<std::string> promise;
+ m_output_queue.push(promise.get_future());
+ promise.set_value(serialize_blob("OSMHeader", pbf_header_block, m_use_compression));
+
+ pbf_header_block.Clear();
+ }
+
+ /**
+ * store the interim StringTable to the current pbf_primitive_block, map all interim string ids
+ * to real StringTable ids and then store the current pbf_primitive_block into a Blob and clear
+ * this struct and all related pointers and maps afterwards.
+ */
+ void store_primitive_block() {
+ if (debug && has_debug_level(1)) {
+ std::cerr << "storing primitive block with " << primitive_block_contents << " items" << std::endl;
+ }
+
+ // set the granularity
+ 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());
+
+ // map all interim string ids to real ids
+ map_string_ids();
+
+ std::promise<std::string> promise;
+ m_output_queue.push(promise.get_future());
+ promise.set_value(serialize_blob("OSMData", pbf_primitive_block, m_use_compression));
+
+ // clear the PrimitiveBlock struct
+ pbf_primitive_block.Clear();
+
+ // clear the interim StringTable and its id map
+ string_table.clear();
+
+ // reset the delta variables
+ m_delta_id.clear();
+ m_delta_lat.clear();
+ m_delta_lon.clear();
+ m_delta_timestamp.clear();
+ m_delta_changeset.clear();
+ m_delta_uid.clear();
+ m_delta_user_sid.clear();
+
+ // reset the contents-counter to zero
+ primitive_block_contents = 0;
+ primitive_block_size = 0;
+
+ // reset the node/way/relation pointers to nullptr
+ pbf_nodes = nullptr;
+ pbf_ways = nullptr;
+ pbf_relations = nullptr;
+ }
+
+ /**
+ * this little function checks primitive_block_contents counter against its maximum and calls
+ * store_primitive_block to flush the block to the disk when it's reached. It's also responsible
+ * for increasing this counter.
+ *
+ * this function also checks the estimated size of the current block and calls store_primitive_block
+ * when the estimated size reaches buffer_fill_percent of the maximum uncompressed blob size.
+ */
+ void check_block_contents_counter() {
+ if (primitive_block_contents >= max_block_contents) {
+ store_primitive_block();
+ } else if (primitive_block_size > OSMPBF::max_uncompressed_blob_size * buffer_fill_percent / 100) {
+ if (debug && has_debug_level(1)) {
+ std::cerr << "storing primitive_block with only " << primitive_block_contents << " items, because its ByteSize (" << primitive_block_size << ") reached " <<
+ (static_cast<float>(primitive_block_size) / static_cast<float>(OSMPBF::max_uncompressed_blob_size) * 100.0) << "% of the maximum blob-size" << std::endl;
+ }
+
+ store_primitive_block();
+ }
+
+ ++primitive_block_contents;
+ }
+
+
+ ///// Block content writing /////
+
+ /**
+ * Add a node to the block.
+ *
+ * @param node The node to add.
+ */
+ void write_node(const osmium::Node& node) {
+ // add a way to the group
+ OSMPBF::Node* pbf_node = pbf_nodes->add_nodes();
+
+ // copy the common meta-info from the osmium-object to the pbf-object
+ apply_common_info(node, pbf_node);
+
+ // modify lat & lon to integers, respecting the block's granularity and copy
+ // the ints to the pbf-object
+ pbf_node->set_lon(lonlat2int(node.location().lon_without_check()));
+ pbf_node->set_lat(lonlat2int(node.location().lat_without_check()));
+ }
+
+ /**
+ * Add a node to the block using DenseNodes.
+ *
+ * @param node The node to add.
+ */
+ void write_dense_node(const osmium::Node& node) {
+ // add a DenseNodes-Section to the PrimitiveGroup
+ OSMPBF::DenseNodes* dense = pbf_nodes->mutable_dense();
+
+ // copy the id, delta encoded
+ dense->add_id(m_delta_id.update(node.id()));
+
+ // copy the longitude, delta encoded
+ dense->add_lon(m_delta_lon.update(lonlat2int(node.location().lon_without_check())));
+
+ // copy the latitude, delta encoded
+ dense->add_lat(m_delta_lat.update(lonlat2int(node.location().lat_without_check())));
+
+ // 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)
+ // so for three nodes the keys_vals array may look like this: 3 5 2 1 0 0 8 5
+ // the first node has two tags (3=>5 and 2=>1), the second node does not
+ // have any tags and the third node has a single tag (8=>5)
+ for (const auto& tag : node.tags()) {
+ dense->add_keys_vals(string_table.record_string(tag.key()));
+ dense->add_keys_vals(string_table.record_string(tag.value()));
+ }
+ dense->add_keys_vals(0);
+
+ if (m_should_add_metadata) {
+ // add a DenseInfo-Section to the PrimitiveGroup
+ OSMPBF::DenseInfo* denseinfo = dense->mutable_denseinfo();
+
+ denseinfo->add_version(static_cast<::google::protobuf::int32>(node.version()));
+
+ if (m_add_visible) {
+ denseinfo->add_visible(node.visible());
+ }
+
+ // copy the timestamp, delta encoded
+ denseinfo->add_timestamp(m_delta_timestamp.update(timestamp2int(node.timestamp())));
+
+ // copy the changeset, delta encoded
+ denseinfo->add_changeset(m_delta_changeset.update(node.changeset()));
+
+ // copy the user id, delta encoded
+ denseinfo->add_uid(static_cast<::google::protobuf::int32>(m_delta_uid.update(node.uid())));
+
+ // record the user-name to the interim stringtable and copy the
+ // interim string-id to the pbf-object
+ denseinfo->add_user_sid(string_table.record_string(node.user()));
+ }
+ }
+
+ /**
+ * Add a way to the block.
+ *
+ * @param way The way to add.
+ */
+ void write_way(const osmium::Way& way) {
+ // add a way to the group
+ OSMPBF::Way* pbf_way = pbf_ways->add_ways();
+
+ // copy the common meta-info from the osmium-object to the pbf-object
+ apply_common_info(way, pbf_way);
+
+ // last way-node-id used for delta-encoding
+ Delta<int64_t> delta_id;
+
+ for (const auto& node_ref : way.nodes()) {
+ // copy the way-node-id, delta encoded
+ pbf_way->add_refs(delta_id.update(node_ref.ref()));
+ }
+
+ // count up blob size by the size of the Way
+ primitive_block_size += pbf_way->ByteSize();
+ }
+
+ /**
+ * Add a relation to the block.
+ *
+ * @param relation The relation to add.
+ */
+ void write_relation(const osmium::Relation& relation) {
+ // add a relation to the group
+ OSMPBF::Relation* pbf_relation = pbf_relations->add_relations();
+
+ // copy the common meta-info from the osmium-object to the pbf-object
+ apply_common_info(relation, pbf_relation);
+
+ Delta<int64_t> delta_id;
+
+ for (const auto& member : relation.members()) {
+ // record the relation-member role to the interim stringtable and copy the
+ // interim string-id to the pbf-object
+ pbf_relation->add_roles_sid(string_table.record_string(member.role()));
+
+ // copy the relation-member-id, delta encoded
+ pbf_relation->add_memids(delta_id.update(member.ref()));
+
+ // copy the relation-member-type, mapped to the OSMPBF enum
+ pbf_relation->add_types(item_type_to_osmpbf_membertype(member.type()));
+ }
+
+ // count up blob size by the size of the Relation
+ primitive_block_size += pbf_relation->ByteSize();
+ }
+
+ // objects of this class can't be copied
+ PBFOutputFormat(const PBFOutputFormat&) = delete;
+ PBFOutputFormat& operator=(const PBFOutputFormat&) = delete;
+
+ public:
+
+ /**
+ * Create PBFOutputFormat object from File.
+ */
+ explicit PBFOutputFormat(const osmium::io::File& file, data_queue_type& output_queue) :
+ OutputFormat(file, output_queue),
+ pbf_header_block(),
+ pbf_primitive_block(),
+ pbf_nodes(nullptr),
+ pbf_ways(nullptr),
+ pbf_relations(nullptr),
+ m_location_granularity(pbf_primitive_block.granularity()),
+ m_date_granularity(pbf_primitive_block.date_granularity()),
+ m_add_visible(file.has_multiple_object_versions()),
+ primitive_block_contents(0),
+ primitive_block_size(0),
+ string_table(),
+ m_delta_id(),
+ m_delta_lat(),
+ m_delta_lon(),
+ m_delta_timestamp(),
+ m_delta_changeset(),
+ m_delta_uid(),
+ m_delta_user_sid(),
+ debug(true) {
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+ if (file.get("pbf_dense_nodes") == "false") {
+ m_use_dense_nodes = false;
+ }
+ if (file.get("pbf_compression") == "none" || file.get("pbf_compression") == "false") {
+ m_use_compression = false;
+ }
+ if (file.get("pbf_add_metadata") == "false") {
+ m_should_add_metadata = false;
+ }
+ }
+
+ void write_buffer(osmium::memory::Buffer&& buffer) override final {
+ osmium::apply(buffer.cbegin(), buffer.cend(), *this);
+ }
+
+
+ /**
+ * getter to access the granularity
+ */
+ int location_granularity() const {
+ return m_location_granularity;
+ }
+
+ /**
+ * setter to set the granularity
+ */
+ PBFOutputFormat& location_granularity(int g) {
+ m_location_granularity = g;
+ return *this;
+ }
+
+
+ /**
+ * getter to access the date_granularity
+ */
+ int date_granularity() const {
+ return m_date_granularity;
+ }
+
+ /**
+ * Set date granularity.
+ */
+ PBFOutputFormat& date_granularity(int g) {
+ m_date_granularity = g;
+ return *this;
+ }
+
+
+ /**
+ * Initialize the writing process.
+ *
+ * This initializes the header-block, sets the required-features and
+ * the writing-program and adds the obligatory StringTable-Index 0.
+ */
+ void write_header(const osmium::io::Header& header) override final {
+ // add the schema version as required feature to the HeaderBlock
+ pbf_header_block.add_required_features("OsmSchema-V0.6");
+
+ // when the densenodes-feature is used, add DenseNodes as required feature
+ if (m_use_dense_nodes) {
+ pbf_header_block.add_required_features("DenseNodes");
+ }
+
+ // when the resulting file will carry history information, add
+ // HistoricalInformation as required feature
+ if (m_file.has_multiple_object_versions()) {
+ pbf_header_block.add_required_features("HistoricalInformation");
+ }
+
+ // set the writing program
+ pbf_header_block.set_writingprogram(header.get("generator"));
+
+ if (!header.boxes().empty()) {
+ OSMPBF::HeaderBBox* pbf_bbox = pbf_header_block.mutable_bbox();
+ osmium::Box box = header.joined_boxes();
+ pbf_bbox->set_left(static_cast<::google::protobuf::int64>(box.bottom_left().lon() * OSMPBF::lonlat_resolution));
+ pbf_bbox->set_bottom(static_cast<::google::protobuf::int64>(box.bottom_left().lat() * OSMPBF::lonlat_resolution));
+ pbf_bbox->set_right(static_cast<::google::protobuf::int64>(box.top_right().lon() * OSMPBF::lonlat_resolution));
+ pbf_bbox->set_top(static_cast<::google::protobuf::int64>(box.top_right().lat() * OSMPBF::lonlat_resolution));
+ }
+
+ std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp");
+ if (!osmosis_replication_timestamp.empty()) {
+ osmium::Timestamp ts(osmosis_replication_timestamp.c_str());
+ pbf_header_block.set_osmosis_replication_timestamp(ts);
+ }
+
+ std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number");
+ if (!osmosis_replication_sequence_number.empty()) {
+ pbf_header_block.set_osmosis_replication_sequence_number(std::atoll(osmosis_replication_sequence_number.c_str()));
+ }
+
+ std::string osmosis_replication_base_url = header.get("osmosis_replication_base_url");
+ if (!osmosis_replication_base_url.empty()) {
+ pbf_header_block.set_osmosis_replication_base_url(osmosis_replication_base_url);
+ }
+
+ store_header_block();
+ }
+
+ /**
+ * Add a node to the pbf.
+ *
+ * A call to this method won't write the node to the file directly but
+ * cache it for later bulk-writing. Calling final() ensures that everything
+ * gets written and every file pointer is closed.
+ */
+ void node(const osmium::Node& node) {
+ // first of we check the contents-counter which may flush the cached nodes to
+ // disk if the limit is reached. This call also increases the contents-counter
+ check_block_contents_counter();
+
+ if (debug && has_debug_level(2)) {
+ std::cerr << "node " << node.id() << " v" << node.version() << std::endl;
+ }
+
+ // if no PrimitiveGroup for nodes has been added, add one and save the pointer
+ if (!pbf_nodes) {
+ pbf_nodes = pbf_primitive_block.add_primitivegroup();
+ }
+
+ if (m_use_dense_nodes) {
+ write_dense_node(node);
+ } else {
+ write_node(node);
+ }
+ }
+
+ /**
+ * Add a way to the pbf.
+ *
+ * A call to this method won't write the way to the file directly but
+ * cache it for later bulk-writing. Calling final() ensures that everything
+ * gets written and every file pointer is closed.
+ */
+ void way(const osmium::Way& way) {
+ // first of we check the contents-counter which may flush the cached ways to
+ // disk if the limit is reached. This call also increases the contents-counter
+ check_block_contents_counter();
+
+ // if no PrimitiveGroup for nodes has been added, add one and save the pointer
+ if (!pbf_ways) {
+ pbf_ways = pbf_primitive_block.add_primitivegroup();
+ }
+
+ write_way(way);
+ }
+
+ /**
+ * Add a relation to the pbf.
+ *
+ * A call to this method won't write the way to the file directly but
+ * cache it for later bulk-writing. Calling final() ensures that everything
+ * gets written and every file pointer is closed.
+ */
+ void relation(const osmium::Relation& relation) {
+ // first of we check the contents-counter which may flush the cached relations to
+ // disk if the limit is reached. This call also increases the contents-counter
+ check_block_contents_counter();
+
+ // if no PrimitiveGroup for relations has been added, add one and save the pointer
+ if (!pbf_relations) {
+ pbf_relations = pbf_primitive_block.add_primitivegroup();
+ }
+
+ write_relation(relation);
+ }
+
+ /**
+ * Finalize the writing process, flush any open primitive blocks to the file and
+ * close the file.
+ */
+ void close() override final {
+ if (debug && has_debug_level(1)) {
+ std::cerr << "finishing" << std::endl;
+ }
+
+ // if the current block contains any elements, flush it to the protobuf
+ if (primitive_block_contents > 0) {
+ store_primitive_block();
+ }
+
+ std::promise<std::string> promise;
+ m_output_queue.push(promise.get_future());
+ promise.set_value(std::string());
+ }
+
+ }; // class PBFOutputFormat
+
+ namespace {
+
+ const bool registered_pbf_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::pbf,
+ [](const osmium::io::File& file, data_queue_type& output_queue) {
+ return new osmium::io::detail::PBFOutputFormat(file, output_queue);
+ });
+
+ } // anonymous namespace
+
+ } // namespace detail
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_PBF_OUTPUT_FORMAT_HPP
diff --git a/third_party/osmium/io/detail/pbf_parser.hpp b/third_party/osmium/io/detail/pbf_parser.hpp
new file mode 100644
index 0000000..201c57c
--- /dev/null
+++ b/third_party/osmium/io/detail/pbf_parser.hpp
@@ -0,0 +1,449 @@
+#ifndef OSMIUM_IO_DETAIL_PBF_PRIMITIVE_BLOCK_PARSER_HPP
+#define OSMIUM_IO_DETAIL_PBF_PRIMITIVE_BLOCK_PARSER_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 <cstddef>
+#include <cstdint>
+#include <algorithm>
+
+#include <osmpbf/osmpbf.h>
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
+#include <osmium/io/detail/zlib.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+ namespace io {
+
+ namespace detail {
+
+ class PBFPrimitiveBlockParser {
+
+ static constexpr size_t initial_buffer_size = 2 * 1024 * 1024;
+
+ const std::string& m_data;
+
+ const OSMPBF::StringTable* m_stringtable;
+ int64_t m_lon_offset;
+ int64_t m_lat_offset;
+ int64_t m_date_factor;
+ int32_t m_granularity;
+
+ osmium::osm_entity_bits::type m_read_types;
+
+ osmium::memory::Buffer m_buffer;
+
+ PBFPrimitiveBlockParser(const PBFPrimitiveBlockParser&) = delete;
+ PBFPrimitiveBlockParser(PBFPrimitiveBlockParser&&) = delete;
+
+ PBFPrimitiveBlockParser& operator=(const PBFPrimitiveBlockParser&) = delete;
+ PBFPrimitiveBlockParser& operator=(PBFPrimitiveBlockParser&&) = delete;
+
+ public:
+
+ explicit PBFPrimitiveBlockParser(const std::string& data, osmium::osm_entity_bits::type read_types) :
+ m_data(data),
+ m_stringtable(nullptr),
+ m_lon_offset(0),
+ m_lat_offset(0),
+ m_date_factor(1000),
+ m_granularity(100),
+ m_read_types(read_types),
+ m_buffer(initial_buffer_size) {
+ }
+
+ ~PBFPrimitiveBlockParser() = default;
+
+ osmium::memory::Buffer operator()() {
+ OSMPBF::PrimitiveBlock pbf_primitive_block;
+ if (!pbf_primitive_block.ParseFromString(m_data)) {
+ throw osmium::pbf_error("failed to parse PrimitiveBlock");
+ }
+
+ m_stringtable = &pbf_primitive_block.stringtable();
+ m_lon_offset = pbf_primitive_block.lon_offset();
+ m_lat_offset = pbf_primitive_block.lat_offset();
+ 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) {
+ const OSMPBF::PrimitiveGroup& group = pbf_primitive_block.primitivegroup(i);
+
+ if (group.has_dense()) {
+ if (m_read_types & osmium::osm_entity_bits::node) parse_dense_node_group(group);
+ } else if (group.ways_size() != 0) {
+ if (m_read_types & osmium::osm_entity_bits::way) parse_way_group(group);
+ } else if (group.relations_size() != 0) {
+ if (m_read_types & osmium::osm_entity_bits::relation) parse_relation_group(group);
+ } else if (group.nodes_size() != 0) {
+ if (m_read_types & osmium::osm_entity_bits::node) parse_node_group(group);
+ } else {
+ throw osmium::pbf_error("group of unknown type");
+ }
+ }
+
+ return std::move(m_buffer);
+ }
+
+ private:
+
+ template <class TBuilder, class TPBFObject>
+ void parse_attributes(TBuilder& builder, const TPBFObject& pbf_object) {
+ auto& object = builder.object();
+
+ object.set_id(pbf_object.id());
+
+ if (pbf_object.has_info()) {
+ object.set_version(static_cast_with_assert<object_version_type>(pbf_object.info().version()))
+ .set_changeset(static_cast_with_assert<changeset_id_type>(pbf_object.info().changeset()))
+ .set_timestamp(pbf_object.info().timestamp() * m_date_factor)
+ .set_uid_from_signed(pbf_object.info().uid());
+ if (pbf_object.info().has_visible()) {
+ object.set_visible(pbf_object.info().visible());
+ }
+ builder.add_user(m_stringtable->s(static_cast_with_assert<int>(pbf_object.info().user_sid())));
+ } else {
+ builder.add_user("", 1);
+ }
+ }
+
+ void parse_node_group(const OSMPBF::PrimitiveGroup& group) {
+ 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);
+
+ if (builder.object().visible()) {
+ builder.object().set_location(osmium::Location(
+ (pbf_node.lon() * m_granularity + m_lon_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision),
+ (pbf_node.lat() * m_granularity + m_lat_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision)));
+ }
+
+ if (pbf_node.keys_size() > 0) {
+ osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
+ 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))));
+ }
+ }
+
+ m_buffer.commit();
+ }
+ }
+
+ void parse_way_group(const OSMPBF::PrimitiveGroup& group) {
+ 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);
+
+ 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) {
+ ref += pbf_way.refs(n);
+ wnl_builder.add_node_ref(ref);
+ }
+ }
+
+ if (pbf_way.keys_size() > 0) {
+ osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
+ 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))));
+ }
+ }
+
+ m_buffer.commit();
+ }
+ }
+
+ void parse_relation_group(const OSMPBF::PrimitiveGroup& group) {
+ 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);
+
+ 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) {
+ 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)));
+ }
+ }
+
+ if (pbf_relation.keys_size() > 0) {
+ osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
+ 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))));
+ }
+ }
+
+ m_buffer.commit();
+ }
+ }
+
+ int add_tags(const OSMPBF::DenseNodes& dense, int n, osmium::builder::NodeBuilder* builder) {
+ if (n >= dense.keys_vals_size()) {
+ return n;
+ }
+
+ if (dense.keys_vals(n) == 0) {
+ return n+1;
+ }
+
+ osmium::builder::TagListBuilder tl_builder(m_buffer, builder);
+
+ while (n < dense.keys_vals_size()) {
+ int tag_key_pos = dense.keys_vals(n++);
+
+ if (tag_key_pos == 0) {
+ break;
+ }
+
+ tl_builder.add_tag(m_stringtable->s(tag_key_pos),
+ m_stringtable->s(dense.keys_vals(n)));
+
+ ++n;
+ }
+
+ return n;
+ }
+
+ void parse_dense_node_group(const OSMPBF::PrimitiveGroup& group) {
+ int64_t last_dense_id = 0;
+ int64_t last_dense_latitude = 0;
+ int64_t last_dense_longitude = 0;
+ int64_t last_dense_uid = 0;
+ int64_t last_dense_user_sid = 0;
+ int64_t last_dense_changeset = 0;
+ int64_t last_dense_timestamp = 0;
+ int last_dense_tag = 0;
+
+ const OSMPBF::DenseNodes& dense = group.dense();
+
+ for (int i=0; i < dense.id_size(); ++i) {
+ bool visible = true;
+
+ last_dense_id += dense.id(i);
+ last_dense_latitude += dense.lat(i);
+ last_dense_longitude += dense.lon(i);
+
+ if (dense.has_denseinfo()) {
+ last_dense_changeset += dense.denseinfo().changeset(i);
+ last_dense_timestamp += dense.denseinfo().timestamp(i);
+ last_dense_uid += dense.denseinfo().uid(i);
+ last_dense_user_sid += dense.denseinfo().user_sid(i);
+ if (dense.denseinfo().visible_size() > 0) {
+ visible = dense.denseinfo().visible(i);
+ }
+ assert(last_dense_changeset >= 0);
+ assert(last_dense_timestamp >= 0);
+ assert(last_dense_uid >= -1);
+ assert(last_dense_user_sid >= 0);
+ }
+
+ osmium::builder::NodeBuilder builder(m_buffer);
+ osmium::Node& node = builder.object();
+
+ node.set_id(last_dense_id);
+
+ if (dense.has_denseinfo()) {
+ auto v = dense.denseinfo().version(i);
+ assert(v > 0);
+ node.set_version(static_cast<osmium::object_version_type>(v));
+ node.set_changeset(static_cast<osmium::changeset_id_type>(last_dense_changeset));
+ node.set_timestamp(last_dense_timestamp * m_date_factor);
+ node.set_uid_from_signed(static_cast<osmium::signed_user_id_type>(last_dense_uid));
+ node.set_visible(visible);
+ builder.add_user(m_stringtable->s(static_cast<int>(last_dense_user_sid)));
+ } else {
+ builder.add_user("", 1);
+ }
+
+ if (visible) {
+ builder.object().set_location(osmium::Location(
+ (last_dense_longitude * m_granularity + m_lon_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision),
+ (last_dense_latitude * m_granularity + m_lat_offset) / (OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision)));
+ }
+
+ last_dense_tag = add_tags(dense, last_dense_tag, &builder);
+ m_buffer.commit();
+ }
+ }
+
+ }; // class PBFPrimitiveBlockParser
+
+ /**
+ * PBF blobs can optionally be packed with the zlib algorithm.
+ * This function returns the raw data (if it was unpacked) or
+ * the unpacked data (if it was packed).
+ *
+ * @param input_data Reference to input data.
+ * @returns Unpacked data
+ * @throws osmium::pbf_error If there was a problem parsing the PBF
+ */
+ inline std::unique_ptr<const std::string> unpack_blob(const std::string& input_data) {
+ OSMPBF::Blob pbf_blob;
+ if (!pbf_blob.ParseFromString(input_data)) {
+ throw osmium::pbf_error("failed to parse blob");
+ }
+
+ if (pbf_blob.has_raw()) {
+ return std::unique_ptr<std::string>(pbf_blob.release_raw());
+ } else if (pbf_blob.has_zlib_data()) {
+ auto raw_size = pbf_blob.raw_size();
+ assert(raw_size >= 0);
+ assert(raw_size <= OSMPBF::max_uncompressed_blob_size);
+ return osmium::io::detail::zlib_uncompress(pbf_blob.zlib_data(), static_cast<unsigned long>(raw_size));
+ } else if (pbf_blob.has_lzma_data()) {
+ throw osmium::pbf_error("lzma blobs not implemented");
+ } else {
+ throw osmium::pbf_error("blob contains no data");
+ }
+ }
+
+ /**
+ * Parse blob as a HeaderBlock.
+ *
+ * @param input_buffer Blob data
+ * @returns Header object
+ * @throws osmium::pbf_error If there was a parsing error
+ */
+ inline osmium::io::Header parse_header_blob(const std::string& input_buffer) {
+ const std::unique_ptr<const std::string> data = unpack_blob(input_buffer);
+
+ OSMPBF::HeaderBlock pbf_header_block;
+ if (!pbf_header_block.ParseFromString(*data)) {
+ throw osmium::pbf_error("failed to parse HeaderBlock");
+ }
+
+ osmium::io::Header header;
+ 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;
+ if (feature == "DenseNodes") {
+ header.set("pbf_dense_nodes", true);
+ continue;
+ }
+ if (feature == "HistoricalInformation") {
+ header.set_has_multiple_object_versions(true);
+ continue;
+ }
+
+ throw osmium::pbf_error(std::string("required feature not supported: ") + feature);
+ }
+
+ 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);
+ }
+
+ if (pbf_header_block.has_writingprogram()) {
+ header.set("generator", pbf_header_block.writingprogram());
+ }
+
+ if (pbf_header_block.has_bbox()) {
+ const OSMPBF::HeaderBBox& pbf_bbox = pbf_header_block.bbox();
+ const int64_t resolution_convert = OSMPBF::lonlat_resolution / osmium::Location::coordinate_precision;
+ osmium::Box box;
+ box.extend(osmium::Location(pbf_bbox.left() / resolution_convert, pbf_bbox.bottom() / resolution_convert));
+ box.extend(osmium::Location(pbf_bbox.right() / resolution_convert, pbf_bbox.top() / resolution_convert));
+ header.add_box(box);
+ }
+
+ if (pbf_header_block.has_osmosis_replication_timestamp()) {
+ header.set("osmosis_replication_timestamp", osmium::Timestamp(pbf_header_block.osmosis_replication_timestamp()).to_iso());
+ }
+
+ if (pbf_header_block.has_osmosis_replication_sequence_number()) {
+ header.set("osmosis_replication_sequence_number", std::to_string(pbf_header_block.osmosis_replication_sequence_number()));
+ }
+
+ if (pbf_header_block.has_osmosis_replication_base_url()) {
+ header.set("osmosis_replication_base_url", pbf_header_block.osmosis_replication_base_url());
+ }
+
+ return header;
+ }
+
+ class DataBlobParser {
+
+ 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_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& operator=(const DataBlobParser&) = delete;
+
+ osmium::memory::Buffer operator()() {
+ const std::unique_ptr<const std::string> data = unpack_blob(m_input_buffer);
+ PBFPrimitiveBlockParser parser(*data, m_read_types);
+ return std::move(parser());
+ }
+
+ }; // class DataBlobParser
+
+ } // namespace detail
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_PBF_PRIMITIVE_BLOCK_PARSER_HPP
diff --git a/third_party/osmium/io/detail/pbf_stringtable.hpp b/third_party/osmium/io/detail/pbf_stringtable.hpp
new file mode 100644
index 0000000..6f6c54c
--- /dev/null
+++ b/third_party/osmium/io/detail/pbf_stringtable.hpp
@@ -0,0 +1,204 @@
+#ifndef OSMIUM_IO_DETAIL_PBF_STRINGTABLE_HPP
+#define OSMIUM_IO_DETAIL_PBF_STRINGTABLE_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 <algorithm>
+#include <cstdint>
+#include <iterator>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <osmpbf/osmpbf.h>
+
+#include <osmium/util/cast.hpp>
+
+namespace osmium {
+
+ namespace io {
+
+ namespace detail {
+
+ /**
+ * StringTable management for PBF writer
+ *
+ * All strings are stored as indexes to rows in a StringTable. The StringTable contains
+ * one row for each used string, so strings that are used multiple times need to be
+ * stored only once. The StringTable is sorted by usage-count, so the most often used
+ * string is stored at index 1.
+ */
+ class StringTable {
+
+ public:
+
+ /// type for string IDs (interim and final)
+ typedef uint16_t string_id_type;
+
+ private:
+
+ /**
+ * this is the struct used to build the StringTable. It is stored as
+ * the value-part in the strings-map.
+ *
+ * when a new string is added to the map, its count is set to 0 and
+ * the interim_id is set to the current size of the map. This interim_id
+ * is then stored into the pbf-objects.
+ *
+ * before the PrimitiveBlock is serialized, the map is sorted by count
+ * and stored into the pbf-StringTable. Afterwards the interim-ids are
+ * mapped to the "real" id in the StringTable.
+ *
+ * this way often used strings get lower ids in the StringTable. As the
+ * protobuf-serializer stores numbers in variable bit-lengths, lower
+ * IDs means less used space in the resulting file.
+ */
+ struct string_info {
+
+ /// number of occurrences of this string
+ uint16_t count;
+
+ /// an intermediate-id
+ string_id_type interim_id;
+
+ }; // struct string_info
+
+ /**
+ * Interim StringTable, storing all strings that should be written to
+ * the StringTable once the block is written to disk.
+ */
+ typedef std::map<std::string, string_info> string2string_info_type;
+ string2string_info_type m_strings;
+
+ /**
+ * This vector is used to map the interim IDs to real StringTable IDs after
+ * writing all strings to the StringTable.
+ */
+ typedef std::vector<string_id_type> interim_id2id_type;
+ interim_id2id_type m_id2id_map;
+
+ size_t m_size = 0;
+
+ public:
+
+ StringTable() {
+ }
+
+ friend bool operator<(const string_info& lhs, const string_info& rhs) {
+ return lhs.count > rhs.count;
+ }
+
+ /**
+ * record a string in the interim StringTable if it's missing, otherwise just increase its counter,
+ * return the interim-id assigned to the string.
+ */
+ string_id_type record_string(const std::string& string) {
+ string_info& info = m_strings[string];
+ if (info.interim_id == 0) {
+ ++m_size;
+ info.interim_id = static_cast_with_assert<string_id_type>(m_size);
+ } else {
+ info.count++;
+ }
+ return info.interim_id;
+ }
+
+ /**
+ * Sort the interim StringTable and store it to the real protobuf StringTable.
+ * while storing to the real table, this function fills the id2id_map with
+ * pairs, mapping the interim-ids to final and real StringTable ids.
+ *
+ * Note that the m_strings table is a std::map and as such is sorted lexicographically.
+ * When the transformation into the sortedby multimap is done, it gets sorted by
+ * the count. The end result (at least with the glibc standard container/algorithm
+ * 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) {
+ // 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;
+
+ 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);
+ });
+
+ 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);
+
+ // store the mapping from the interim-id to the real id
+ m_id2id_map[mapping.first.interim_id] = ++n;
+ }
+ }
+
+ /**
+ * Map from an interim ID to a real string ID.
+ */
+ string_id_type map_string_id(const string_id_type interim_id) const {
+ return m_id2id_map[interim_id];
+ }
+
+ template <typename T>
+ string_id_type map_string_id(const T interim_id) const {
+ return map_string_id(static_cast_with_assert<string_id_type>(interim_id));
+ }
+
+ /**
+ * Clear the stringtable, preparing for the next block.
+ */
+ void clear() {
+ m_strings.clear();
+ m_id2id_map.clear();
+ m_size = 0;
+ }
+
+ }; // class StringTable
+
+ } // namespace detail
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_PBF_STRINGTABLE_HPP
diff --git a/third_party/osmium/io/detail/read_thread.hpp b/third_party/osmium/io/detail/read_thread.hpp
new file mode 100644
index 0000000..7c37139
--- /dev/null
+++ b/third_party/osmium/io/detail/read_thread.hpp
@@ -0,0 +1,106 @@
+#ifndef OSMIUM_IO_DETAIL_READ_THREAD_HPP
+#define OSMIUM_IO_DETAIL_READ_THREAD_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 <atomic>
+#include <chrono>
+#include <ratio>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <osmium/io/compression.hpp>
+#include <osmium/thread/queue.hpp>
+#include <osmium/thread/util.hpp>
+
+namespace osmium {
+
+ namespace io {
+
+ namespace detail {
+
+ class ReadThread {
+
+ osmium::thread::Queue<std::string>& m_queue;
+ osmium::io::Decompressor* m_decompressor;
+
+ // If this is set in the main thread, we have to wrap up at the
+ // next possible moment.
+ std::atomic<bool>& m_done;
+
+ public:
+
+ explicit ReadThread(osmium::thread::Queue<std::string>& queue, osmium::io::Decompressor* decompressor, std::atomic<bool>& done) :
+ m_queue(queue),
+ m_decompressor(decompressor),
+ m_done(done) {
+ }
+
+ bool operator()() {
+ osmium::thread::set_thread_name("_osmium_input");
+
+ try {
+ while (!m_done) {
+ std::string data {m_decompressor->read()};
+ if (data.empty()) {
+ m_queue.push(std::move(data));
+ break;
+ }
+ m_queue.push(std::move(data));
+ while (m_queue.size() > 10 && !m_done) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ }
+
+ m_decompressor->close();
+ } catch (...) {
+ // If there is an exception in this thread, we make sure
+ // to push an empty string onto the queue to signal the
+ // end-of-data to the reading thread so that it will not
+ // hang. Then we re-throw the exception.
+ m_queue.push(std::string());
+ throw;
+ }
+ return true;
+ }
+
+ }; // class ReadThread
+
+ } // namespace detail
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_READ_THREAD_HPP
diff --git a/third_party/osmium/io/detail/read_write.hpp b/third_party/osmium/io/detail/read_write.hpp
new file mode 100644
index 0000000..a949296
--- /dev/null
+++ b/third_party/osmium/io/detail/read_write.hpp
@@ -0,0 +1,156 @@
+#ifndef OSMIUM_IO_DETAIL_READ_WRITE_HPP
+#define OSMIUM_IO_DETAIL_READ_WRITE_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 <cerrno>
+#include <cstddef>
+#include <fcntl.h>
+#include <string>
+#include <system_error>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#else
+# include <io.h>
+typedef int ssize_t;
+#endif
+
+#include <osmium/io/overwrite.hpp>
+
+namespace osmium {
+
+ namespace io {
+
+ /**
+ * @brief Namespace for Osmium internal use
+ */
+ namespace detail {
+
+ /**
+ * Open file for writing. If the file exists, it is truncated, if
+ * not, it is created. If the file name is empty or "-", no file
+ * is opened and the stdout file descriptor (1) is returned.
+ *
+ * @param filename Name of file to be opened.
+ * @param allow_overwrite If the file exists, should it be overwritten?
+ * @returns File descriptor of open file.
+ * @throws system_error if the file can't be opened.
+ */
+ inline int open_for_writing(const std::string& filename, osmium::io::overwrite allow_overwrite = osmium::io::overwrite::no) {
+ if (filename == "" || filename == "-") {
+ return 1; // stdout
+ } else {
+ int flags = O_WRONLY | O_CREAT;
+ if (allow_overwrite == osmium::io::overwrite::allow) {
+ flags |= O_TRUNC;
+ } else {
+ flags |= O_EXCL;
+ }
+#ifdef _WIN32
+ flags |= O_BINARY;
+#endif
+ int fd = ::open(filename.c_str(), flags, 0666);
+ if (fd < 0) {
+ throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
+ }
+ return fd;
+ }
+ }
+
+ /**
+ * Open file for reading. If the file name is empty or "-", no file
+ * is opened and the stdin file descriptor (0) is returned.
+ *
+ * @param filename Name of file to be opened.
+ * @returns File descriptor of open file.
+ * @throws system_error if the file can't be opened.
+ */
+ inline int open_for_reading(const std::string& filename) {
+ if (filename == "" || filename == "-") {
+ return 0; // stdin
+ } else {
+ int flags = O_RDONLY;
+#ifdef _WIN32
+ flags |= O_BINARY;
+#endif
+ int fd = ::open(filename.c_str(), flags);
+ if (fd < 0) {
+ throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
+ }
+ return fd;
+ }
+ }
+
+ /**
+ * Writes the given number of bytes from the output_buffer to the file descriptor.
+ * This is just a wrapper around write(2), because write(2) can write less than
+ * the given number of bytes.
+ *
+ * @param fd File descriptor.
+ * @param output_buffer Buffer with data to be written. Must be at least size bytes long.
+ * @param size Number of bytes to write.
+ * @throws std::system_error On error.
+ */
+ inline void reliable_write(const int fd, const unsigned char* output_buffer, const size_t size) {
+ size_t offset = 0;
+ do {
+ ssize_t length = ::write(fd, output_buffer + offset, size - offset);
+ if (length < 0) {
+ throw std::system_error(errno, std::system_category(), "Write failed");
+ }
+ offset += static_cast<size_t>(length);
+ } while (offset < size);
+ }
+
+ /**
+ * Writes the given number of bytes from the output_buffer to the file descriptor.
+ * This is just a wrapper around write(2), because write(2) can write less than
+ * the given number of bytes.
+ *
+ * @param fd File descriptor.
+ * @param output_buffer Buffer with data to be written. Must be at least size bytes long.
+ * @param size Number of bytes to write.
+ * @throws std::system_error On error.
+ */
+ inline void reliable_write(const int fd, const char* output_buffer, const size_t size) {
+ reliable_write(fd, reinterpret_cast<const unsigned char*>(output_buffer), size);
+ }
+
+ } // namespace detail
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_READ_WRITE_HPP
diff --git a/third_party/osmium/io/detail/write_thread.hpp b/third_party/osmium/io/detail/write_thread.hpp
new file mode 100644
index 0000000..49b7b5d
--- /dev/null
+++ b/third_party/osmium/io/detail/write_thread.hpp
@@ -0,0 +1,86 @@
+#ifndef OSMIUM_IO_DETAIL_WRITE_THREAD_HPP
+#define OSMIUM_IO_DETAIL_WRITE_THREAD_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 <future>
+#include <string>
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/thread/util.hpp>
+
+namespace osmium {
+
+ namespace io {
+
+ namespace detail {
+
+ class WriteThread {
+
+ typedef osmium::io::detail::data_queue_type data_queue_type;
+
+ data_queue_type& m_input_queue;
+ osmium::io::Compressor* m_compressor;
+
+ public:
+
+ explicit WriteThread(data_queue_type& input_queue, osmium::io::Compressor* compressor) :
+ m_input_queue(input_queue),
+ m_compressor(compressor) {
+ }
+
+ bool operator()() {
+ osmium::thread::set_thread_name("_osmium_output");
+
+ std::future<std::string> data_future;
+ std::string data;
+ do {
+ m_input_queue.wait_and_pop(data_future);
+ data = data_future.get();
+ m_compressor->write(data);
+ } while (!data.empty());
+
+ m_compressor->close();
+ return true;
+ }
+
+ }; // class WriteThread
+
+ } // namespace detail
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_WRITE_THREAD_HPP
diff --git a/third_party/osmium/io/detail/xml_input_format.hpp b/third_party/osmium/io/detail/xml_input_format.hpp
new file mode 100644
index 0000000..1564b78
--- /dev/null
+++ b/third_party/osmium/io/detail/xml_input_format.hpp
@@ -0,0 +1,726 @@
+#ifndef OSMIUM_IO_DETAIL_XML_INPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_XML_INPUT_FORMAT_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.
+
+*/
+
+#define OSMIUM_LINK_WITH_LIBS_EXPAT -lexpat
+
+#include <atomic>
+#include <cassert>
+#include <chrono>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <exception>
+#include <future>
+#include <iostream>
+#include <memory>
+#include <ratio>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <expat.h>
+
+#include <osmium/builder/builder.hpp>
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/io/detail/input_format.hpp>
+#include <osmium/io/error.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/thread/queue.hpp>
+#include <osmium/thread/util.hpp>
+#include <osmium/util/cast.hpp>
+
+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.
+ */
+ struct xml_error : public io_error {
+
+ unsigned long line;
+ unsigned long column;
+ XML_Error error_code;
+ std::string error_string;
+
+ xml_error(XML_Parser parser) :
+ io_error(std::string("XML parsing error at line ")
+ + std::to_string(XML_GetCurrentLineNumber(parser))
+ + ", column "
+ + std::to_string(XML_GetCurrentColumnNumber(parser))
+ + ": "
+ + XML_ErrorString(XML_GetErrorCode(parser))),
+ line(XML_GetCurrentLineNumber(parser)),
+ column(XML_GetCurrentColumnNumber(parser)),
+ error_code(XML_GetErrorCode(parser)),
+ error_string(XML_ErrorString(error_code)) {
+ }
+
+ }; // struct xml_error
+
+ struct format_version_error : public io_error {
+
+ std::string version;
+
+ explicit format_version_error() :
+ io_error("Can not read file without version (missing version attribute on osm element)."),
+ version() {
+ }
+
+ explicit format_version_error(const char* v) :
+ io_error(std::string("Can not read file with version ") + v),
+ version(v) {
+ }
+
+ }; // struct format_version_error
+
+ namespace io {
+
+ class File;
+
+ namespace detail {
+
+ /**
+ * Once the header is fully parsed this exception will be thrown if
+ * the caller is not interested in anything else except the header.
+ * It will break off the parsing at this point.
+ *
+ * This exception is never seen by user code, it is caught internally.
+ */
+ class ParserIsDone : std::exception {
+ };
+
+ class XMLParser {
+
+ static constexpr int buffer_size = 10 * 1000 * 1000;
+
+ enum class context {
+ root,
+ top,
+ node,
+ way,
+ relation,
+ changeset,
+ ignored_node,
+ ignored_way,
+ ignored_relation,
+ ignored_changeset,
+ in_object
+ }; // enum class context
+
+ context m_context;
+ context m_last_context;
+
+ /**
+ * This is used only for change files which contain create, modify,
+ * and delete sections.
+ */
+ bool m_in_delete_section;
+
+ osmium::io::Header m_header;
+
+ osmium::memory::Buffer m_buffer;
+
+ std::unique_ptr<osmium::builder::NodeBuilder> m_node_builder;
+ std::unique_ptr<osmium::builder::WayBuilder> m_way_builder;
+ std::unique_ptr<osmium::builder::RelationBuilder> m_relation_builder;
+ std::unique_ptr<osmium::builder::ChangesetBuilder> m_changeset_builder;
+
+ std::unique_ptr<osmium::builder::TagListBuilder> m_tl_builder;
+ std::unique_ptr<osmium::builder::WayNodeListBuilder> m_wnl_builder;
+ std::unique_ptr<osmium::builder::RelationMemberListBuilder> m_rml_builder;
+
+ osmium::thread::Queue<std::string>& m_input_queue;
+ osmium::thread::Queue<osmium::memory::Buffer>& m_queue;
+ std::promise<osmium::io::Header>& m_header_promise;
+
+ osmium::osm_entity_bits::type m_read_types;
+
+ std::atomic<bool>& m_done;
+
+ /**
+ * A C++ wrapper for the Expat parser that makes sure no memory is leaked.
+ */
+ template <class T>
+ class ExpatXMLParser {
+
+ XML_Parser m_parser;
+
+ static void XMLCALL start_element_wrapper(void* data, const XML_Char* element, const XML_Char** attrs) {
+ static_cast<XMLParser*>(data)->start_element(element, attrs);
+ }
+
+ static void XMLCALL end_element_wrapper(void* data, const XML_Char* element) {
+ static_cast<XMLParser*>(data)->end_element(element);
+ }
+
+ public:
+
+ ExpatXMLParser(T* callback_object) :
+ m_parser(XML_ParserCreate(nullptr)) {
+ if (!m_parser) {
+ throw osmium::io_error("Internal error: Can not create parser");
+ }
+ XML_SetUserData(m_parser, callback_object);
+ XML_SetElementHandler(m_parser, start_element_wrapper, end_element_wrapper);
+ }
+
+ ExpatXMLParser(const ExpatXMLParser&) = delete;
+ ExpatXMLParser(ExpatXMLParser&&) = delete;
+
+ ExpatXMLParser& operator=(const ExpatXMLParser&) = delete;
+ ExpatXMLParser& operator=(ExpatXMLParser&&) = delete;
+
+ ~ExpatXMLParser() {
+ XML_ParserFree(m_parser);
+ }
+
+ void operator()(const std::string& data, bool last) {
+ if (XML_Parse(m_parser, data.data(), static_cast_with_assert<int>(data.size()), last) == XML_STATUS_ERROR) {
+ throw osmium::xml_error(m_parser);
+ }
+ }
+
+ }; // class ExpatXMLParser
+
+ /**
+ * A helper class that makes sure a promise is kept. It stores
+ * a reference to some piece of data and to a promise and, on
+ * destruction, sets the value of the promise from the data.
+ */
+ template <class T>
+ class PromiseKeeper {
+
+ T& m_data;
+ std::promise<T>& m_promise;
+
+ public:
+
+ PromiseKeeper(T& data, std::promise<T>& promise) :
+ m_data(data),
+ m_promise(promise) {
+ }
+
+ ~PromiseKeeper() {
+ m_promise.set_value(m_data);
+ }
+
+ }; // class PromiseKeeper
+
+ public:
+
+ explicit XMLParser(osmium::thread::Queue<std::string>& input_queue, osmium::thread::Queue<osmium::memory::Buffer>& queue, std::promise<osmium::io::Header>& header_promise, osmium::osm_entity_bits::type read_types, std::atomic<bool>& done) :
+ m_context(context::root),
+ m_last_context(context::root),
+ m_in_delete_section(false),
+ m_header(),
+ m_buffer(buffer_size),
+ m_node_builder(),
+ m_way_builder(),
+ m_relation_builder(),
+ m_changeset_builder(),
+ m_tl_builder(),
+ m_wnl_builder(),
+ m_rml_builder(),
+ m_input_queue(input_queue),
+ m_queue(queue),
+ m_header_promise(header_promise),
+ m_read_types(read_types),
+ m_done(done) {
+ }
+
+ /**
+ * The copy constructor is needed for storing XMLParser in a std::function.
+ * The copy will look the same as if it has been initialized with the
+ * same parameters as the original. Any state changes in the original will
+ * not be reflected in the copy.
+ */
+ XMLParser(const XMLParser& other) :
+ m_context(context::root),
+ m_last_context(context::root),
+ m_in_delete_section(false),
+ m_header(),
+ m_buffer(buffer_size),
+ m_node_builder(),
+ m_way_builder(),
+ m_relation_builder(),
+ m_changeset_builder(),
+ m_tl_builder(),
+ m_wnl_builder(),
+ m_rml_builder(),
+ m_input_queue(other.m_input_queue),
+ m_queue(other.m_queue),
+ m_header_promise(other.m_header_promise),
+ m_read_types(other.m_read_types),
+ m_done(other.m_done) {
+ }
+
+ XMLParser(XMLParser&&) = default;
+
+ XMLParser& operator=(const XMLParser&) = delete;
+
+ XMLParser& operator=(XMLParser&&) = default;
+
+ ~XMLParser() = default;
+
+ bool operator()() {
+ ExpatXMLParser<XMLParser> parser(this);
+ PromiseKeeper<osmium::io::Header> promise_keeper(m_header, m_header_promise);
+ bool last;
+ do {
+ std::string data;
+ m_input_queue.wait_and_pop(data);
+ last = data.empty();
+ try {
+ parser(data, last);
+ } catch (ParserIsDone&) {
+ return true;
+ } catch (...) {
+ m_queue.push(osmium::memory::Buffer()); // empty buffer to signify eof
+ throw;
+ }
+ } while (!last && !m_done);
+ if (m_buffer.committed() > 0) {
+ m_queue.push(std::move(m_buffer));
+ }
+ m_queue.push(osmium::memory::Buffer()); // empty buffer to signify eof
+ return true;
+ }
+
+ private:
+
+ const char* init_object(osmium::OSMObject& object, const XML_Char** attrs) {
+ static const char* empty = "";
+ const char* user = empty;
+
+ if (m_in_delete_section) {
+ object.set_visible(false);
+ }
+
+ osmium::Location location;
+ for (int count = 0; attrs[count]; count += 2) {
+ if (!strcmp(attrs[count], "lon")) {
+ location.set_lon(std::atof(attrs[count+1])); // XXX doesn't detect garbage after the number
+ } else if (!strcmp(attrs[count], "lat")) {
+ location.set_lat(std::atof(attrs[count+1])); // XXX doesn't detect garbage after the number
+ } else if (!strcmp(attrs[count], "user")) {
+ user = attrs[count+1];
+ } else {
+ object.set_attribute(attrs[count], attrs[count+1]);
+ }
+ }
+
+ if (location && object.type() == osmium::item_type::node) {
+ static_cast<osmium::Node&>(object).set_location(location);
+ }
+
+ return user;
+ }
+
+ void init_changeset(osmium::builder::ChangesetBuilder* builder, const XML_Char** attrs) {
+ static const char* empty = "";
+ const char* user = empty;
+ osmium::Changeset& new_changeset = builder->object();
+
+ osmium::Location min;
+ osmium::Location max;
+ for (int count = 0; attrs[count]; count += 2) {
+ if (!strcmp(attrs[count], "min_lon")) {
+ min.set_lon(atof(attrs[count+1]));
+ } else if (!strcmp(attrs[count], "min_lat")) {
+ min.set_lat(atof(attrs[count+1]));
+ } else if (!strcmp(attrs[count], "max_lon")) {
+ max.set_lon(atof(attrs[count+1]));
+ } else if (!strcmp(attrs[count], "max_lat")) {
+ max.set_lat(atof(attrs[count+1]));
+ } else if (!strcmp(attrs[count], "user")) {
+ user = attrs[count+1];
+ } else {
+ new_changeset.set_attribute(attrs[count], attrs[count+1]);
+ }
+ }
+
+ new_changeset.bounds().extend(min);
+ new_changeset.bounds().extend(max);
+
+ builder->add_user(user);
+ }
+
+ void check_tag(osmium::builder::Builder* builder, const XML_Char* element, const XML_Char** attrs) {
+ if (!strcmp(element, "tag")) {
+ m_wnl_builder.reset();
+ m_rml_builder.reset();
+
+ const char* key = "";
+ const char* value = "";
+ for (int count = 0; attrs[count]; count += 2) {
+ if (attrs[count][0] == 'k' && attrs[count][1] == 0) {
+ key = attrs[count+1];
+ } else if (attrs[count][0] == 'v' && attrs[count][1] == 0) {
+ value = attrs[count+1];
+ }
+ }
+ if (!m_tl_builder) {
+ m_tl_builder = std::unique_ptr<osmium::builder::TagListBuilder>(new osmium::builder::TagListBuilder(m_buffer, builder));
+ }
+ m_tl_builder->add_tag(key, value);
+ }
+ }
+
+ void header_is_done() {
+ if (m_read_types == osmium::osm_entity_bits::nothing) {
+ throw ParserIsDone();
+ }
+ }
+
+ void start_element(const XML_Char* element, const XML_Char** attrs) {
+ switch (m_context) {
+ case context::root:
+ if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) {
+ if (!strcmp(element, "osmChange")) {
+ m_header.set_has_multiple_object_versions(true);
+ }
+ for (int count = 0; attrs[count]; count += 2) {
+ if (!strcmp(attrs[count], "version")) {
+ m_header.set("version", attrs[count+1]);
+ if (strcmp(attrs[count+1], "0.6")) {
+ throw osmium::format_version_error(attrs[count+1]);
+ }
+ } else if (!strcmp(attrs[count], "generator")) {
+ m_header.set("generator", attrs[count+1]);
+ }
+ }
+ if (m_header.get("version") == "") {
+ throw osmium::format_version_error();
+ }
+ }
+ m_context = context::top;
+ break;
+ case context::top:
+ assert(!m_tl_builder);
+ if (!strcmp(element, "node")) {
+ header_is_done();
+ if (m_read_types & osmium::osm_entity_bits::node) {
+ m_node_builder = std::unique_ptr<osmium::builder::NodeBuilder>(new osmium::builder::NodeBuilder(m_buffer));
+ m_node_builder->add_user(init_object(m_node_builder->object(), attrs));
+ m_context = context::node;
+ } else {
+ m_context = context::ignored_node;
+ }
+ } else if (!strcmp(element, "way")) {
+ header_is_done();
+ if (m_read_types & osmium::osm_entity_bits::way) {
+ m_way_builder = std::unique_ptr<osmium::builder::WayBuilder>(new osmium::builder::WayBuilder(m_buffer));
+ m_way_builder->add_user(init_object(m_way_builder->object(), attrs));
+ m_context = context::way;
+ } else {
+ m_context = context::ignored_way;
+ }
+ } else if (!strcmp(element, "relation")) {
+ header_is_done();
+ if (m_read_types & osmium::osm_entity_bits::relation) {
+ m_relation_builder = std::unique_ptr<osmium::builder::RelationBuilder>(new osmium::builder::RelationBuilder(m_buffer));
+ m_relation_builder->add_user(init_object(m_relation_builder->object(), attrs));
+ m_context = context::relation;
+ } else {
+ m_context = context::ignored_relation;
+ }
+ } else if (!strcmp(element, "changeset")) {
+ header_is_done();
+ if (m_read_types & osmium::osm_entity_bits::changeset) {
+ m_changeset_builder = std::unique_ptr<osmium::builder::ChangesetBuilder>(new osmium::builder::ChangesetBuilder(m_buffer));
+ init_changeset(m_changeset_builder.get(), attrs);
+ m_context = context::changeset;
+ } else {
+ m_context = context::ignored_changeset;
+ }
+ } else if (!strcmp(element, "bounds")) {
+ osmium::Location min;
+ osmium::Location max;
+ for (int count = 0; attrs[count]; count += 2) {
+ if (!strcmp(attrs[count], "minlon")) {
+ min.set_lon(atof(attrs[count+1]));
+ } else if (!strcmp(attrs[count], "minlat")) {
+ min.set_lat(atof(attrs[count+1]));
+ } else if (!strcmp(attrs[count], "maxlon")) {
+ max.set_lon(atof(attrs[count+1]));
+ } else if (!strcmp(attrs[count], "maxlat")) {
+ max.set_lat(atof(attrs[count+1]));
+ }
+ }
+ osmium::Box box;
+ box.extend(min).extend(max);
+ m_header.add_box(box);
+ } else if (!strcmp(element, "delete")) {
+ m_in_delete_section = true;
+ }
+ break;
+ case context::node:
+ m_last_context = context::node;
+ m_context = context::in_object;
+ check_tag(m_node_builder.get(), element, attrs);
+ break;
+ case context::way:
+ m_last_context = context::way;
+ m_context = context::in_object;
+ if (!strcmp(element, "nd")) {
+ m_tl_builder.reset();
+
+ if (!m_wnl_builder) {
+ m_wnl_builder = std::unique_ptr<osmium::builder::WayNodeListBuilder>(new osmium::builder::WayNodeListBuilder(m_buffer, m_way_builder.get()));
+ }
+
+ for (int count = 0; attrs[count]; count += 2) {
+ if (!strcmp(attrs[count], "ref")) {
+ m_wnl_builder->add_node_ref(osmium::string_to_object_id(attrs[count+1]));
+ }
+ }
+ } else {
+ check_tag(m_way_builder.get(), element, attrs);
+ }
+ break;
+ case context::relation:
+ m_last_context = context::relation;
+ m_context = context::in_object;
+ if (!strcmp(element, "member")) {
+ m_tl_builder.reset();
+
+ if (!m_rml_builder) {
+ m_rml_builder = std::unique_ptr<osmium::builder::RelationMemberListBuilder>(new osmium::builder::RelationMemberListBuilder(m_buffer, m_relation_builder.get()));
+ }
+
+ char type = 'x';
+ object_id_type ref = 0;
+ const char* role = "";
+ for (int count = 0; attrs[count]; count += 2) {
+ if (!strcmp(attrs[count], "type")) {
+ type = static_cast<char>(attrs[count+1][0]);
+ } else if (!strcmp(attrs[count], "ref")) {
+ ref = osmium::string_to_object_id(attrs[count+1]);
+ } else if (!strcmp(attrs[count], "role")) {
+ role = static_cast<const char*>(attrs[count+1]);
+ }
+ }
+ // XXX assert type, ref, role are set
+ m_rml_builder->add_member(char_to_item_type(type), ref, role);
+ } else {
+ check_tag(m_relation_builder.get(), element, attrs);
+ }
+ break;
+ case context::changeset:
+ m_last_context = context::changeset;
+ m_context = context::in_object;
+ check_tag(m_changeset_builder.get(), element, attrs);
+ break;
+ case context::ignored_node:
+ break;
+ case context::ignored_way:
+ break;
+ case context::ignored_relation:
+ break;
+ case context::ignored_changeset:
+ break;
+ case context::in_object:
+ assert(false); // should never be here
+ break;
+ }
+ }
+
+ void end_element(const XML_Char* element) {
+ switch (m_context) {
+ case context::root:
+ assert(false); // should never be here
+ break;
+ case context::top:
+ if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) {
+ header_is_done();
+ m_context = context::root;
+ } else if (!strcmp(element, "delete")) {
+ m_in_delete_section = false;
+ }
+ break;
+ case context::node:
+ assert(!strcmp(element, "node"));
+ m_tl_builder.reset();
+ m_node_builder.reset();
+ m_buffer.commit();
+ m_context = context::top;
+ flush_buffer();
+ break;
+ case context::way:
+ assert(!strcmp(element, "way"));
+ m_tl_builder.reset();
+ m_wnl_builder.reset();
+ m_way_builder.reset();
+ m_buffer.commit();
+ m_context = context::top;
+ flush_buffer();
+ break;
+ case context::relation:
+ assert(!strcmp(element, "relation"));
+ m_tl_builder.reset();
+ m_rml_builder.reset();
+ m_relation_builder.reset();
+ m_buffer.commit();
+ m_context = context::top;
+ flush_buffer();
+ break;
+ case context::changeset:
+ assert(!strcmp(element, "changeset"));
+ m_tl_builder.reset();
+ m_changeset_builder.reset();
+ m_buffer.commit();
+ m_context = context::top;
+ flush_buffer();
+ break;
+ case context::in_object:
+ m_context = m_last_context;
+ break;
+ case context::ignored_node:
+ if (!strcmp(element, "node")) {
+ m_context = context::top;
+ }
+ break;
+ case context::ignored_way:
+ if (!strcmp(element, "way")) {
+ m_context = context::top;
+ }
+ break;
+ case context::ignored_relation:
+ if (!strcmp(element, "relation")) {
+ m_context = context::top;
+ }
+ break;
+ case context::ignored_changeset:
+ if (!strcmp(element, "changeset")) {
+ m_context = context::top;
+ }
+ break;
+ }
+ }
+
+ void flush_buffer() {
+ if (m_buffer.capacity() - m_buffer.committed() < 1000 * 1000) {
+ m_queue.push(std::move(m_buffer));
+ osmium::memory::Buffer buffer(buffer_size);
+ std::swap(m_buffer, buffer);
+ }
+ }
+
+ }; // class XMLParser
+
+ class XMLInputFormat : public osmium::io::detail::InputFormat {
+
+ static constexpr size_t max_queue_size = 100;
+
+ osmium::thread::Queue<osmium::memory::Buffer> m_queue;
+ std::atomic<bool> m_done;
+ std::promise<osmium::io::Header> m_header_promise;
+ std::future<bool> m_parser_future;
+
+ public:
+
+ /**
+ * Instantiate XML Parser
+ *
+ * @param file osmium::io::File instance describing file to be read from.
+ * @param read_which_entities Which types of OSM entities (nodes, ways, relations, changesets) should be parsed?
+ * @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),
+ m_queue(max_queue_size, "xml_parser_results"),
+ m_done(false),
+ m_header_promise(),
+ m_parser_future(std::async(std::launch::async, XMLParser(input_queue, m_queue, m_header_promise, read_which_entities, m_done))) {
+ }
+
+ ~XMLInputFormat() {
+ try {
+ close();
+ } catch (...) {
+ // ignore any exceptions at this point because destructor should not throw
+ }
+ }
+
+ virtual osmium::io::Header header() override final {
+ osmium::thread::check_for_exception(m_parser_future);
+ return m_header_promise.get_future().get();
+ }
+
+ osmium::memory::Buffer read() override {
+ osmium::memory::Buffer buffer;
+ if (!m_done || !m_queue.empty()) {
+ m_queue.wait_and_pop(buffer);
+ }
+
+ osmium::thread::check_for_exception(m_parser_future);
+ return buffer;
+ }
+
+ void close() {
+ m_done = true;
+ osmium::thread::wait_until_done(m_parser_future);
+ }
+
+ }; // class XMLInputFormat
+
+ namespace {
+
+ const bool registered_xml_input = osmium::io::detail::InputFormatFactory::instance().register_input_format(osmium::io::file_format::xml,
+ [](const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities, osmium::thread::Queue<std::string>& input_queue) {
+ return new osmium::io::detail::XMLInputFormat(file, read_which_entities, input_queue);
+ });
+
+ } // anonymous namespace
+
+ } // namespace detail
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_XML_INPUT_FORMAT_HPP
diff --git a/third_party/osmium/io/detail/xml_output_format.hpp b/third_party/osmium/io/detail/xml_output_format.hpp
new file mode 100644
index 0000000..c8c7a38
--- /dev/null
+++ b/third_party/osmium/io/detail/xml_output_format.hpp
@@ -0,0 +1,481 @@
+#ifndef OSMIUM_IO_DETAIL_XML_OUTPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_XML_OUTPUT_FORMAT_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 <chrono>
+#include <cinttypes>
+#include <cstddef>
+#include <cstdio>
+#include <future>
+#include <iterator>
+#include <memory>
+#include <ratio>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <osmium/handler.hpp>
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/collection.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/changeset.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/thread/pool.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+ namespace io {
+
+ namespace detail {
+
+ struct XMLWriteError {};
+
+ namespace {
+
+ void xml_string(std::string& out, const char* in) {
+ for (; *in != '\0'; ++in) {
+ switch(*in) {
+ case '&': out += "&"; break;
+ case '\"': out += """; break;
+ case '\'': out += "'"; break;
+ case '<': out += "<"; break;
+ case '>': out += ">"; break;
+ default: out += *in; break;
+ }
+ }
+ }
+
+ const size_t tmp_buffer_size = 100;
+
+ template <typename T>
+ void oprintf(std::string& out, const char* format, T value) {
+ char buffer[tmp_buffer_size+1];
+ size_t max_size = sizeof(buffer)/sizeof(char);
+#ifndef NDEBUG
+ int len =
+#endif
+#ifndef _MSC_VER
+ snprintf(buffer, max_size, format, value);
+#else
+ _snprintf(buffer, max_size, format, value);
+#endif
+ assert(len > 0 && static_cast<size_t>(len) < max_size);
+ out += buffer;
+ }
+
+ } // anonymous namespace
+
+ class XMLOutputBlock : public osmium::handler::Handler {
+
+ // operation (create, modify, delete) for osc files
+ enum class operation {
+ op_none = 0,
+ op_create = 1,
+ op_modify = 2,
+ op_delete = 3
+ }; // enum class operation
+
+ osmium::memory::Buffer m_input_buffer;
+
+ std::string m_out;
+
+ operation m_last_op {operation::op_none};
+
+ const bool m_write_visible_flag;
+ const bool m_write_change_ops;
+
+ void write_spaces(int num) {
+ for (; num!=0; --num) {
+ m_out += ' ';
+ }
+ }
+
+ void write_prefix() {
+ if (m_write_change_ops) {
+ write_spaces(4);
+ } else {
+ write_spaces(2);
+ }
+ }
+
+ void write_meta(const osmium::OSMObject& object) {
+ oprintf(m_out, " id=\"%" PRId64 "\"", object.id());
+
+ if (object.version()) {
+ oprintf(m_out, " version=\"%d\"", object.version());
+ }
+
+ if (object.timestamp()) {
+ 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 += "\"";
+ }
+
+ if (object.changeset()) {
+ oprintf(m_out, " changeset=\"%d\"", object.changeset());
+ }
+
+ if (m_write_visible_flag) {
+ if (object.visible()) {
+ m_out += " visible=\"true\"";
+ } else {
+ m_out += " visible=\"false\"";
+ }
+ }
+ }
+
+ 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";
+ }
+ }
+
+ void open_close_op_tag(const operation op = operation::op_none) {
+ if (op == m_last_op) {
+ return;
+ }
+
+ switch (m_last_op) {
+ case operation::op_none:
+ break;
+ case operation::op_create:
+ m_out += " </create>\n";
+ break;
+ case operation::op_modify:
+ m_out += " </modify>\n";
+ break;
+ case operation::op_delete:
+ m_out += " </delete>\n";
+ break;
+ }
+
+ switch (op) {
+ case operation::op_none:
+ break;
+ case operation::op_create:
+ m_out += " <create>\n";
+ break;
+ case operation::op_modify:
+ m_out += " <modify>\n";
+ break;
+ case operation::op_delete:
+ m_out += " <delete>\n";
+ break;
+ }
+
+ m_last_op = op;
+ }
+
+ public:
+
+ explicit XMLOutputBlock(osmium::memory::Buffer&& buffer, bool write_visible_flag, bool write_change_ops) :
+ m_input_buffer(std::move(buffer)),
+ 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(XMLOutputBlock&&) = default;
+ XMLOutputBlock& operator=(XMLOutputBlock&&) = default;
+
+ std::string operator()() {
+ 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);
+ return out;
+ }
+
+ void node(const osmium::Node& node) {
+ if (m_write_change_ops) {
+ open_close_op_tag(node.visible() ? (node.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
+ }
+
+ write_prefix();
+ 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 += "\"";
+ }
+
+ if (node.tags().empty()) {
+ m_out += "/>\n";
+ return;
+ }
+
+ m_out += ">\n";
+
+ write_tags(node.tags());
+
+ write_prefix();
+ m_out += "</node>\n";
+ }
+
+ void way(const osmium::Way& way) {
+ if (m_write_change_ops) {
+ open_close_op_tag(way.visible() ? (way.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
+ }
+
+ write_prefix();
+ m_out += "<way";
+ write_meta(way);
+
+ if (way.tags().empty() && way.nodes().empty()) {
+ m_out += "/>\n";
+ return;
+ }
+
+ m_out += ">\n";
+
+ for (const auto& node_ref : way.nodes()) {
+ write_prefix();
+ oprintf(m_out, " <nd ref=\"%" PRId64 "\"/>\n", node_ref.ref());
+ }
+
+ write_tags(way.tags());
+
+ write_prefix();
+ m_out += "</way>\n";
+ }
+
+ void relation(const osmium::Relation& relation) {
+ if (m_write_change_ops) {
+ open_close_op_tag(relation.visible() ? (relation.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete);
+ }
+
+ write_prefix();
+ m_out += "<relation";
+ write_meta(relation);
+
+ if (relation.tags().empty() && relation.members().empty()) {
+ m_out += "/>\n";
+ return;
+ }
+
+ 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";
+ }
+
+ write_tags(relation.tags());
+
+ write_prefix();
+ m_out += "</relation>\n";
+ }
+
+ void changeset(const osmium::Changeset& changeset) {
+ write_prefix();
+ m_out += "<changeset";
+
+ oprintf(m_out, " id=\"%" PRId32 "\"", changeset.id());
+
+ if (changeset.created_at()) {
+ m_out += " created_at=\"";
+ m_out += changeset.created_at().to_iso();
+ m_out += "\"";
+ }
+
+ 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\"";
+ } else {
+ 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());
+ }
+
+ if (!changeset.user_is_anonymous()) {
+ m_out += " user=\"";
+ xml_string(m_out, changeset.user());
+ oprintf(m_out, "\" uid=\"%d\"", changeset.uid());
+ }
+
+ if (changeset.tags().empty()) {
+ m_out += "/>\n";
+ return;
+ }
+
+ m_out += ">\n";
+
+ write_tags(changeset.tags());
+
+ write_prefix();
+ m_out += "</changeset>\n";
+ }
+
+ }; // class XMLOutputBlock
+
+ class XMLOutputFormat : public osmium::io::detail::OutputFormat, public osmium::handler::Handler {
+
+ bool m_write_visible_flag;
+
+ public:
+
+ XMLOutputFormat(const osmium::io::File& file, data_queue_type& output_queue) :
+ OutputFormat(file, output_queue),
+ m_write_visible_flag(file.has_multiple_object_versions() || m_file.is_true("force_visible_flag")) {
+ }
+
+ XMLOutputFormat(const XMLOutputFormat&) = delete;
+ XMLOutputFormat& operator=(const XMLOutputFormat&) = delete;
+
+ ~XMLOutputFormat() override final {
+ }
+
+ void write_buffer(osmium::memory::Buffer&& buffer) override final {
+ m_output_queue.push(osmium::thread::Pool::instance().submit(XMLOutputBlock{std::move(buffer), m_write_visible_flag, m_file.is_true("xml_change_format")}));
+ }
+
+ void write_header(const osmium::io::Header& header) override final {
+ std::string out = "<?xml version='1.0' encoding='UTF-8'?>\n";
+
+ if (m_file.is_true("xml_change_format")) {
+ out += "<osmChange version=\"0.6\" generator=\"";
+ xml_string(out, header.get("generator").c_str());
+ out += "\">\n";
+ } else {
+ out += "<osm version=\"0.6\"";
+
+ std::string xml_josm_upload = header.get("xml_josm_upload");
+ if (xml_josm_upload == "true" || xml_josm_upload == "false") {
+ out += " upload=\"";
+ out += xml_josm_upload;
+ out += "\"";
+ }
+ out += " generator=\"";
+ xml_string(out, header.get("generator").c_str());
+ out += "\">\n";
+ }
+
+ for (const auto& box : header.boxes()) {
+ out += " <bounds";
+ oprintf(out, " minlon=\"%.7f\"", box.bottom_left().lon());
+ oprintf(out, " minlat=\"%.7f\"", box.bottom_left().lat());
+ oprintf(out, " maxlon=\"%.7f\"", box.top_right().lon());
+ oprintf(out, " maxlat=\"%.7f\"/>\n", box.top_right().lat());
+ }
+
+ std::promise<std::string> promise;
+ m_output_queue.push(promise.get_future());
+ promise.set_value(std::move(out));
+ }
+
+ void close() override final {
+ {
+ std::string out;
+ if (m_file.is_true("xml_change_format")) {
+ out += "</osmChange>\n";
+ } else {
+ out += "</osm>\n";
+ }
+
+ std::promise<std::string> promise;
+ m_output_queue.push(promise.get_future());
+ promise.set_value(std::move(out));
+ }
+
+ std::promise<std::string> promise;
+ m_output_queue.push(promise.get_future());
+ promise.set_value(std::string());
+ }
+
+ }; // class XMLOutputFormat
+
+ namespace {
+
+ const bool registered_xml_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::xml,
+ [](const osmium::io::File& file, data_queue_type& output_queue) {
+ return new osmium::io::detail::XMLOutputFormat(file, output_queue);
+ });
+
+ } // anonymous namespace
+
+ } // namespace detail
+
+ } // namespace output
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_XML_OUTPUT_FORMAT_HPP
diff --git a/third_party/osmium/io/detail/zlib.hpp b/third_party/osmium/io/detail/zlib.hpp
new file mode 100644
index 0000000..84ab86c
--- /dev/null
+++ b/third_party/osmium/io/detail/zlib.hpp
@@ -0,0 +1,99 @@
+#ifndef OSMIUM_IO_DETAIL_ZLIB_HPP
+#define OSMIUM_IO_DETAIL_ZLIB_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.
+
+*/
+
+#define OSMIUM_LINK_WITH_LIBS_ZLIB -lz
+
+#include <memory>
+#include <stdexcept>
+#include <string>
+
+#include <zlib.h>
+
+namespace osmium {
+
+ namespace io {
+
+ namespace detail {
+
+ /**
+ * Compress data using zlib.
+ *
+ * @param input Data to compress.
+ * @returns Compressed data.
+ */
+ inline std::string zlib_compress(const std::string& input) {
+ unsigned long output_size = ::compressBound(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");
+ }
+
+ output.resize(output_size);
+
+ return output;
+ }
+
+ /**
+ * Uncompress data using zlib.
+ *
+ * @param input Compressed input data.
+ * @param raw_size Size of uncompressed data.
+ * @returns Uncompressed data.
+ */
+ 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");
+ }
+
+ return output;
+ }
+
+ } // namespace detail
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_DETAIL_ZLIB_HPP
diff --git a/third_party/osmium/io/error.hpp b/third_party/osmium/io/error.hpp
new file mode 100644
index 0000000..8fb9f05
--- /dev/null
+++ b/third_party/osmium/io/error.hpp
@@ -0,0 +1,57 @@
+#ifndef OSMIUM_IO_ERROR_HPP
+#define OSMIUM_IO_ERROR_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 <stdexcept>
+
+namespace osmium {
+
+ /**
+ * Exception thrown when some kind of input/output operation failed.
+ */
+ struct io_error : public std::runtime_error {
+
+ io_error(const std::string& what) :
+ std::runtime_error(what) {
+ }
+
+ io_error(const char* what) :
+ std::runtime_error(what) {
+ }
+
+ }; // struct io_error
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_ERROR_HPP
diff --git a/third_party/osmium/io/file.hpp b/third_party/osmium/io/file.hpp
new file mode 100644
index 0000000..21469b8
--- /dev/null
+++ b/third_party/osmium/io/file.hpp
@@ -0,0 +1,343 @@
+#ifndef OSMIUM_IO_FILE_HPP
+#define OSMIUM_IO_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).
+
+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 <cstddef>
+#include <stdexcept>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <osmium/io/file_format.hpp>
+#include <osmium/io/file_compression.hpp>
+#include <osmium/util/options.hpp>
+
+namespace osmium {
+
+ /**
+ * @brief Everything related to input and output of OSM data.
+ */
+ namespace io {
+
+ namespace detail {
+
+ inline std::vector<std::string> split(const std::string& in, const char delim) {
+ std::vector<std::string> result;
+ std::stringstream ss(in);
+ std::string item;
+ while (std::getline(ss, item, delim)) {
+ result.push_back(item);
+ }
+ return result;
+ }
+
+ } // namespace detail
+
+ /**
+ * This class describes an OSM file in one of several different formats.
+ *
+ * If the filename is empty or "-", this means stdin or stdout is used.
+ */
+ class File : public osmium::util::Options {
+
+ private:
+
+ std::string m_filename;
+
+ const char* m_buffer;
+ size_t m_buffer_size;
+
+ std::string m_format_string;
+
+ file_format m_file_format {file_format::unknown};
+
+ file_compression m_file_compression {file_compression::none};
+
+ bool m_has_multiple_object_versions {false};
+
+ public:
+
+ /**
+ * Create File using type and encoding from filename or given
+ * format specification.
+ *
+ * @param filename Filename including suffix. The type and encoding
+ * of the file will be taken from the suffix.
+ * An empty filename or "-" means stdin or stdout.
+ * @param format File format as string. See the description of the
+ * parse_format() function for details.
+ */
+ explicit File(const std::string& filename = "", const std::string& format = "") :
+ Options(),
+ m_filename(filename),
+ m_buffer(nullptr),
+ m_buffer_size(0),
+ m_format_string(format) {
+
+ // stdin/stdout
+ if (filename == "" || filename == "-") {
+ m_filename = "";
+ default_settings_for_stdinout();
+ }
+
+ // filename is actually a URL
+ std::string protocol = m_filename.substr(0, m_filename.find_first_of(':'));
+ if (protocol == "http" || protocol == "https") {
+ default_settings_for_url();
+ }
+
+ detect_format_from_suffix(m_filename);
+
+ if (format != "") {
+ parse_format(format);
+ }
+ }
+
+ /**
+ * Create File using buffer pointer and size and type and encoding
+ * from given format specification.
+ *
+ * @param buffer Pointer to buffer with data.
+ * @param size Size of buffer.
+ * @param format File format as string. See the description of the
+ * parse_format() function for details.
+ */
+ explicit File(const char* buffer, size_t size, const std::string& format = "") :
+ Options(),
+ m_filename(),
+ m_buffer(buffer),
+ m_buffer_size(size),
+ m_format_string(format) {
+
+ default_settings_for_stdinout();
+
+ if (format != "") {
+ parse_format(format);
+ }
+ }
+
+ File(const File&) = default;
+ File& operator=(const File&) = default;
+
+ File(File&&) = default;
+ File& operator=(File&&) = default;
+
+ ~File() = default;
+
+ const char* buffer() const noexcept {
+ return m_buffer;
+ }
+
+ size_t buffer_size() const noexcept {
+ return m_buffer_size;
+ }
+
+ void parse_format(const std::string& format) {
+ std::vector<std::string> options = detail::split(format, ',');
+
+ // if the first item in the format list doesn't contain
+ // an equals sign, it is a format
+ if (!options.empty() && options[0].find_first_of('=') == std::string::npos) {
+ detect_format_from_suffix(options[0]);
+ options.erase(options.begin());
+ }
+
+ for (auto& option : options) {
+ size_t pos = option.find_first_of('=');
+ if (pos == std::string::npos) {
+ set(option, true);
+ } else {
+ std::string value = option.substr(pos+1);
+ option.erase(pos);
+ set(option, value);
+ }
+ }
+
+ if (get("history") == "true") {
+ m_has_multiple_object_versions = true;
+ } else if (get("history") == "false") {
+ m_has_multiple_object_versions = false;
+ }
+ }
+
+ void detect_format_from_suffix(const std::string& name) {
+ std::vector<std::string> suffixes = detail::split(name, '.');
+
+ if (suffixes.empty()) return;
+
+ // if the last suffix is one of a known set of compressions,
+ // set that compression
+ if (suffixes.back() == "gz") {
+ m_file_compression = file_compression::gzip;
+ suffixes.pop_back();
+ } else if (suffixes.back() == "bz2") {
+ m_file_compression = file_compression::bzip2;
+ suffixes.pop_back();
+ }
+
+ if (suffixes.empty()) return;
+
+ // if the last suffix is one of a known set of formats,
+ // set that format
+ if (suffixes.back() == "pbf") {
+ m_file_format = file_format::pbf;
+ suffixes.pop_back();
+ } else if (suffixes.back() == "xml") {
+ m_file_format = file_format::xml;
+ suffixes.pop_back();
+ } else if (suffixes.back() == "opl") {
+ m_file_format = file_format::opl;
+ suffixes.pop_back();
+ }
+
+ if (suffixes.empty()) return;
+
+ if (suffixes.back() == "osm") {
+ if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
+ suffixes.pop_back();
+ } else if (suffixes.back() == "osh") {
+ if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
+ m_has_multiple_object_versions = true;
+ suffixes.pop_back();
+ } else if (suffixes.back() == "osc") {
+ if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
+ m_has_multiple_object_versions = true;
+ set("xml_change_format", true);
+ suffixes.pop_back();
+ }
+ }
+
+ /**
+ * Check file format etc. for consistency and throw exception if there
+ * is a problem.
+ *
+ * @throws std::runtime_error
+ */
+ void check() const {
+ if (m_file_format == file_format::unknown) {
+ std::string msg = "Could not detect file format";
+ if (!m_format_string.empty()) {
+ msg += " from format string '";
+ msg += m_format_string;
+ msg += "'";
+ }
+ if (m_filename.empty()) {
+ msg += " for stdin/stdout";
+ } else {
+ msg += " for filename '";
+ msg += m_filename;
+ msg += "'";
+ }
+ msg += ".";
+ throw std::runtime_error(msg);
+ }
+ }
+
+ /**
+ * Set default settings for type and encoding when the filename is
+ * empty or "-". If you want to have a different default setting
+ * override this in a subclass.
+ */
+ void default_settings_for_stdinout() {
+ m_file_format = file_format::unknown;
+ m_file_compression = file_compression::none;
+ }
+
+ /**
+ * Set default settings for type and encoding when the filename is
+ * a normal file. If you want to have a different default setting
+ * override this in a subclass.
+ */
+ void default_settings_for_file() {
+ m_file_format = file_format::unknown;
+ m_file_compression = file_compression::none;
+ }
+
+ /**
+ * Set default settings for type and encoding when the filename is a URL.
+ * If you want to have a different default setting override this in a
+ * subclass.
+ */
+ void default_settings_for_url() {
+ m_file_format = file_format::xml;
+ m_file_compression = file_compression::none;
+ }
+
+ file_format format() const noexcept {
+ return m_file_format;
+ }
+
+ File& set_format(file_format format) noexcept {
+ m_file_format = format;
+ return *this;
+ }
+
+ file_compression compression() const noexcept {
+ return m_file_compression;
+ }
+
+ File& set_compression(file_compression compression) noexcept {
+ m_file_compression = compression;
+ return *this;
+ }
+
+ bool has_multiple_object_versions() const noexcept {
+ return m_has_multiple_object_versions;
+ }
+
+ File& set_has_multiple_object_versions(bool value) noexcept {
+ m_has_multiple_object_versions = value;
+ return *this;
+ }
+
+ File& filename(const std::string& filename) {
+ if (filename == "-") {
+ m_filename = "";
+ } else {
+ m_filename = filename;
+ }
+ return *this;
+ }
+
+ const std::string& filename() const noexcept {
+ return m_filename;
+ }
+
+ }; // class File
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_FILE_HPP
diff --git a/third_party/osmium/io/file_compression.hpp b/third_party/osmium/io/file_compression.hpp
new file mode 100644
index 0000000..c718715
--- /dev/null
+++ b/third_party/osmium/io/file_compression.hpp
@@ -0,0 +1,72 @@
+#ifndef OSMIUM_IO_FILE_COMPRESSION_HPP
+#define OSMIUM_IO_FILE_COMPRESSION_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 <iosfwd>
+
+namespace osmium {
+
+ namespace io {
+
+ enum class file_compression {
+ none = 0,
+ gzip = 1,
+ bzip2 = 2
+ };
+
+// avoid g++ false positive
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreturn-type"
+ inline const char* as_string(file_compression compression) {
+ switch (compression) {
+ case file_compression::none:
+ return "none";
+ case file_compression::gzip:
+ return "gzip";
+ case file_compression::bzip2:
+ return "bzip2";
+ }
+ }
+#pragma GCC diagnostic pop
+
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const file_compression compression) {
+ return out << as_string(compression);
+ }
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_FILE_COMPRESSION_HPP
diff --git a/third_party/osmium/io/file_format.hpp b/third_party/osmium/io/file_format.hpp
new file mode 100644
index 0000000..5a4aa5c
--- /dev/null
+++ b/third_party/osmium/io/file_format.hpp
@@ -0,0 +1,78 @@
+#ifndef OSMIUM_IO_FILE_FORMAT_HPP
+#define OSMIUM_IO_FILE_FORMAT_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 <iosfwd>
+
+namespace osmium {
+
+ namespace io {
+
+ enum class file_format {
+ unknown = 0,
+ xml = 1,
+ pbf = 2,
+ opl = 3,
+ json = 4
+ };
+
+// avoid g++ false positive
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreturn-type"
+ inline const char* as_string(file_format format) {
+ switch (format) {
+ case file_format::unknown:
+ return "unknown";
+ case file_format::xml:
+ return "XML";
+ case file_format::pbf:
+ return "PBF";
+ case file_format::opl:
+ return "OPL";
+ case file_format::json:
+ return "JSON";
+ }
+ }
+#pragma GCC diagnostic pop
+
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const file_format format) {
+ return out << as_string(format);
+ }
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_FILE_FORMAT_HPP
diff --git a/third_party/osmium/io/gzip_compression.hpp b/third_party/osmium/io/gzip_compression.hpp
new file mode 100644
index 0000000..db99acb
--- /dev/null
+++ b/third_party/osmium/io/gzip_compression.hpp
@@ -0,0 +1,238 @@
+#ifndef OSMIUM_IO_GZIP_COMPRESSION_HPP
+#define OSMIUM_IO_GZIP_COMPRESSION_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.
+
+*/
+
+#define OSMIUM_LINK_WITH_LIBS_ZLIB -lz
+
+#include <stdexcept>
+#include <string>
+
+#include <errno.h>
+#include <zlib.h>
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/file_compression.hpp>
+#include <osmium/util/cast.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+ /**
+ * Exception thrown when there are problems compressing or
+ * decompressing gzip files.
+ */
+ struct gzip_error : public std::runtime_error {
+
+ int gzip_error_code;
+ int system_errno;
+
+ gzip_error(const std::string& what, int error_code) :
+ std::runtime_error(what),
+ gzip_error_code(error_code),
+ system_errno(error_code == Z_ERRNO ? errno : 0) {
+ }
+
+ }; // struct gzip_error
+
+ namespace io {
+
+ namespace detail {
+
+ OSMIUM_NORETURN inline void throw_gzip_error(gzFile gzfile, const char* msg, int zlib_error=0) {
+ std::string error("gzip error: ");
+ error += msg;
+ error += ": ";
+ int errnum = zlib_error;
+ if (zlib_error) {
+ error += std::to_string(zlib_error);
+ } else {
+ error += ::gzerror(gzfile, &errnum);
+ }
+ throw osmium::gzip_error(error, errnum);
+ }
+
+ } // namespace detail
+
+ class GzipCompressor : public Compressor {
+
+ gzFile m_gzfile;
+
+ public:
+
+ explicit GzipCompressor(int fd) :
+ Compressor(),
+ m_gzfile(::gzdopen(fd, "w")) {
+ if (!m_gzfile) {
+ detail::throw_gzip_error(m_gzfile, "write initialization failed");
+ }
+ }
+
+ ~GzipCompressor() override final {
+ close();
+ }
+
+ void write(const std::string& data) override final {
+ if (!data.empty()) {
+ int nwrite = ::gzwrite(m_gzfile, data.data(), static_cast_with_assert<unsigned int>(data.size()));
+ if (nwrite == 0) {
+ detail::throw_gzip_error(m_gzfile, "write failed");
+ }
+ }
+ }
+
+ void close() override final {
+ if (m_gzfile) {
+ int result = ::gzclose(m_gzfile);
+ m_gzfile = nullptr;
+ if (result != Z_OK) {
+ detail::throw_gzip_error(m_gzfile, "write close failed", result);
+ }
+ }
+ }
+
+ }; // class GzipCompressor
+
+ class GzipDecompressor : public Decompressor {
+
+ gzFile m_gzfile;
+
+ public:
+
+ explicit GzipDecompressor(int fd) :
+ Decompressor(),
+ m_gzfile(::gzdopen(fd, "r")) {
+ if (!m_gzfile) {
+ detail::throw_gzip_error(m_gzfile, "read initialization failed");
+ }
+ }
+
+ ~GzipDecompressor() override final {
+ close();
+ }
+
+ std::string read() override final {
+ std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
+ int nread = ::gzread(m_gzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<unsigned int>(buffer.size()));
+ if (nread < 0) {
+ detail::throw_gzip_error(m_gzfile, "read failed");
+ }
+ buffer.resize(static_cast<std::string::size_type>(nread));
+ return buffer;
+ }
+
+ void close() override final {
+ if (m_gzfile) {
+ int result = ::gzclose(m_gzfile);
+ m_gzfile = nullptr;
+ if (result != Z_OK) {
+ detail::throw_gzip_error(m_gzfile, "read close failed", result);
+ }
+ }
+ }
+
+ }; // class GzipDecompressor
+
+ class GzipBufferDecompressor : public Decompressor {
+
+ const char* m_buffer;
+ size_t m_buffer_size;
+ z_stream m_zstream;
+
+ public:
+
+ GzipBufferDecompressor(const char* buffer, size_t size) :
+ m_buffer(buffer),
+ m_buffer_size(size),
+ m_zstream() {
+ m_zstream.next_in = reinterpret_cast<unsigned char*>(const_cast<char*>(buffer));
+ m_zstream.avail_in = static_cast_with_assert<unsigned int>(size);
+ int result = inflateInit2(&m_zstream, MAX_WBITS | 32);
+ if (result != Z_OK) {
+ std::string message("gzip error: decompression init failed: ");
+ if (m_zstream.msg) {
+ message.append(m_zstream.msg);
+ }
+ throw osmium::gzip_error(message, result);
+ }
+ }
+
+ ~GzipBufferDecompressor() override final {
+ inflateEnd(&m_zstream);
+ }
+
+ std::string read() override final {
+ if (!m_buffer) {
+ return std::string();
+ }
+
+ 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 (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);
+ }
+ throw osmium::gzip_error(message, result);
+ }
+
+ output.resize(static_cast<unsigned long>(m_zstream.next_out - reinterpret_cast<const unsigned char*>(output.data())));
+ return output;
+ }
+
+ }; // class GzipBufferDecompressor
+
+ namespace {
+
+ const bool registered_gzip_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::gzip,
+ [](int fd) { return new osmium::io::GzipCompressor(fd); },
+ [](int fd) { return new osmium::io::GzipDecompressor(fd); },
+ [](const char* buffer, size_t size) { return new osmium::io::GzipBufferDecompressor(buffer, size); }
+ );
+
+ } // anonymous namespace
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_GZIP_COMPRESSION_HPP
diff --git a/third_party/osmium/io/header.hpp b/third_party/osmium/io/header.hpp
new file mode 100644
index 0000000..0fdbf77
--- /dev/null
+++ b/third_party/osmium/io/header.hpp
@@ -0,0 +1,122 @@
+#ifndef OSMIUM_IO_HEADER_HPP
+#define OSMIUM_IO_HEADER_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 <initializer_list>
+#include <vector>
+
+#include <osmium/osm/box.hpp>
+#include <osmium/util/options.hpp>
+
+namespace osmium {
+
+ namespace io {
+
+ /**
+ * Meta information from the header of an OSM file.
+ */
+ class Header : public osmium::util::Options {
+
+ /// Bounding boxes
+ std::vector<osmium::Box> m_boxes;
+
+ /**
+ * Are there possibly multiple versions of the same object in this stream of objects?
+ * This is true for history files and for change files, but not for normal OSM files.
+ */
+ bool m_has_multiple_object_versions = false;
+
+ public:
+
+ Header() = default;
+
+ explicit Header(const std::initializer_list<osmium::util::Options::value_type>& values) :
+ Options(values) {
+ }
+
+ Header(const Header&) = default;
+ Header& operator=(const Header&) = default;
+
+ Header(Header&&) = default;
+ Header& operator=(Header&&) = default;
+
+ ~Header() = default;
+
+ std::vector<osmium::Box>& boxes() noexcept {
+ return m_boxes;
+ }
+
+ const std::vector<osmium::Box>& boxes() const noexcept {
+ return m_boxes;
+ }
+
+ Header& boxes(const std::vector<osmium::Box>& boxes) noexcept {
+ m_boxes = boxes;
+ return *this;
+ }
+
+ osmium::Box box() const {
+ return m_boxes.empty() ? osmium::Box() : m_boxes.front();
+ }
+
+ osmium::Box joined_boxes() const {
+ osmium::Box box;
+ for (const auto& b : m_boxes) {
+ box.extend(b.bottom_left());
+ box.extend(b.top_right());
+ }
+ return box;
+ }
+
+ Header& add_box(const osmium::Box& box) {
+ m_boxes.push_back(box);
+ return *this;
+ }
+
+ bool has_multiple_object_versions() const noexcept {
+ return m_has_multiple_object_versions;
+ }
+
+ Header& set_has_multiple_object_versions(bool value) noexcept {
+ m_has_multiple_object_versions = value;
+ return *this;
+ }
+
+ }; // class Header
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_HEADER_HPP
diff --git a/third_party/osmium/io/input_iterator.hpp b/third_party/osmium/io/input_iterator.hpp
new file mode 100644
index 0000000..a2e3b83
--- /dev/null
+++ b/third_party/osmium/io/input_iterator.hpp
@@ -0,0 +1,139 @@
+#ifndef OSMIUM_IO_INPUT_ITERATOR_HPP
+#define OSMIUM_IO_INPUT_ITERATOR_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 <cstddef>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/item.hpp>
+
+namespace osmium {
+
+ namespace io {
+
+ /**
+ * This iterator class allows you to iterate over all items from a
+ * source. It hides all the buffer handling and makes the contents of a
+ * source accessible as a normal STL input iterator.
+ */
+ template <class TSource, class TItem = osmium::memory::Item>
+ class InputIterator {
+
+ static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "TItem must derive from osmium::buffer::Item");
+
+ typedef typename osmium::memory::Buffer::t_iterator<TItem> item_iterator;
+
+ TSource* m_source;
+ std::shared_ptr<osmium::memory::Buffer> m_buffer;
+ item_iterator m_iter {};
+
+ void update_buffer() {
+ do {
+ m_buffer = std::make_shared<osmium::memory::Buffer>(std::move(m_source->read()));
+ if (!m_buffer || !*m_buffer) { // end of input
+ m_source = nullptr;
+ m_buffer.reset();
+ m_iter = item_iterator();
+ return;
+ }
+ m_iter = m_buffer->begin<TItem>();
+ } while (m_iter == m_buffer->end<TItem>());
+ }
+
+ public:
+
+ typedef std::input_iterator_tag iterator_category;
+ typedef TItem value_type;
+ typedef ptrdiff_t difference_type;
+ typedef TItem* pointer;
+ typedef TItem& reference;
+
+ explicit InputIterator(TSource& source) :
+ m_source(&source) {
+ update_buffer();
+ }
+
+ // end iterator
+ InputIterator() noexcept :
+ m_source(nullptr) {
+ }
+
+ InputIterator& operator++() {
+ assert(m_source);
+ assert(m_buffer);
+ assert(m_iter);
+ ++m_iter;
+ if (m_iter == m_buffer->end<TItem>()) {
+ update_buffer();
+ }
+ return *this;
+ }
+
+ InputIterator operator++(int) {
+ InputIterator tmp(*this);
+ operator++();
+ return tmp;
+ }
+
+ bool operator==(const InputIterator& rhs) const noexcept {
+ return m_source == rhs.m_source &&
+ m_buffer == rhs.m_buffer &&
+ m_iter == rhs.m_iter;
+ }
+
+ bool operator!=(const InputIterator& rhs) const noexcept {
+ return !(*this == rhs);
+ }
+
+ reference operator*() const {
+ assert(m_iter);
+ return static_cast<reference>(*m_iter);
+ }
+
+ pointer operator->() const {
+ assert(m_iter);
+ return &static_cast<reference>(*m_iter);
+ }
+
+ }; // class InputIterator
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_INPUT_ITERATOR_HPP
diff --git a/third_party/osmium/io/opl_output.hpp b/third_party/osmium/io/opl_output.hpp
new file mode 100644
index 0000000..46a1224
--- /dev/null
+++ b/third_party/osmium/io/opl_output.hpp
@@ -0,0 +1,39 @@
+#ifndef OSMIUM_IO_OPL_OUTPUT_HPP
+#define OSMIUM_IO_OPL_OUTPUT_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 <osmium/io/writer.hpp> // IWYU pragma: export
+#include <osmium/io/detail/opl_output_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_OPL_OUTPUT_HPP
diff --git a/third_party/osmium/io/output_iterator.hpp b/third_party/osmium/io/output_iterator.hpp
new file mode 100644
index 0000000..e6a9cc0
--- /dev/null
+++ b/third_party/osmium/io/output_iterator.hpp
@@ -0,0 +1,116 @@
+#ifndef OSMIUM_IO_OUTPUT_ITERATOR_HPP
+#define OSMIUM_IO_OUTPUT_ITERATOR_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 <cstddef>
+#include <iterator>
+#include <memory>
+#include <utility>
+
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/diff_object.hpp>
+
+namespace osmium {
+
+ namespace memory {
+ class Item;
+ } // namespace memory
+
+ namespace io {
+
+ template <class TDest>
+ class OutputIterator : public std::iterator<std::output_iterator_tag, osmium::memory::Item> {
+
+ struct buffer_wrapper {
+
+ osmium::memory::Buffer buffer;
+
+ buffer_wrapper(size_t buffer_size) :
+ buffer(buffer_size, osmium::memory::Buffer::auto_grow::no) {
+ }
+
+ }; // struct buffer_wrapper
+
+ static constexpr size_t default_buffer_size = 10 * 1024 * 1024;
+
+ TDest* m_destination;
+
+ std::shared_ptr<buffer_wrapper> m_buffer_wrapper;
+
+ public:
+
+ explicit OutputIterator(TDest& destination, const size_t buffer_size = default_buffer_size) :
+ m_destination(&destination),
+ m_buffer_wrapper(std::make_shared<buffer_wrapper>(buffer_size)) {
+ }
+
+ void flush() {
+ osmium::memory::Buffer buffer(m_buffer_wrapper->buffer.capacity(), osmium::memory::Buffer::auto_grow::no);
+ std::swap(m_buffer_wrapper->buffer, buffer);
+ (*m_destination)(std::move(buffer));
+ }
+
+ OutputIterator& operator=(const osmium::memory::Item& item) {
+ try {
+ m_buffer_wrapper->buffer.push_back(item);
+ } catch (osmium::buffer_is_full&) {
+ flush();
+ m_buffer_wrapper->buffer.push_back(item);
+ }
+ return *this;
+ }
+
+ OutputIterator& operator=(const osmium::DiffObject& diff) {
+ return this->operator=(diff.curr());
+ }
+
+ OutputIterator& operator*() {
+ return *this;
+ }
+
+ OutputIterator& operator++() {
+ return *this;
+ }
+
+ OutputIterator& operator++(int) {
+ return *this;
+ }
+
+ }; // class OutputIterator
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_OUTPUT_ITERATOR_HPP
diff --git a/third_party/osmium/io/overwrite.hpp b/third_party/osmium/io/overwrite.hpp
new file mode 100644
index 0000000..f29a932
--- /dev/null
+++ b/third_party/osmium/io/overwrite.hpp
@@ -0,0 +1,52 @@
+#ifndef OSMIUM_IO_OVERWRITE_HPP
+#define OSMIUM_IO_OVERWRITE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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.
+
+*/
+
+namespace osmium {
+
+ namespace io {
+
+ /**
+ * Allow overwriting of existing file.
+ */
+ enum class overwrite : bool {
+ no = false,
+ allow = true
+ };
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_OVERWRITE_HPP
diff --git a/third_party/osmium/io/pbf_input.hpp b/third_party/osmium/io/pbf_input.hpp
new file mode 100644
index 0000000..8426f6c
--- /dev/null
+++ b/third_party/osmium/io/pbf_input.hpp
@@ -0,0 +1,39 @@
+#ifndef OSMIUM_IO_PBF_INPUT_HPP
+#define OSMIUM_IO_PBF_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
+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/io/reader.hpp> // IWYU pragma: export
+#include <osmium/io/detail/pbf_input_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_PBF_INPUT_HPP
diff --git a/third_party/osmium/io/pbf_output.hpp b/third_party/osmium/io/pbf_output.hpp
new file mode 100644
index 0000000..9fd0396
--- /dev/null
+++ b/third_party/osmium/io/pbf_output.hpp
@@ -0,0 +1,39 @@
+#ifndef OSMIUM_IO_PBF_OUTPUT_HPP
+#define OSMIUM_IO_PBF_OUTPUT_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 <osmium/io/writer.hpp> // IWYU pragma: export
+#include <osmium/io/detail/pbf_output_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_PBF_OUTPUT_HPP
diff --git a/third_party/osmium/io/reader.hpp b/third_party/osmium/io/reader.hpp
new file mode 100644
index 0000000..a9b8b95
--- /dev/null
+++ b/third_party/osmium/io/reader.hpp
@@ -0,0 +1,303 @@
+#ifndef OSMIUM_IO_READER_HPP
+#define OSMIUM_IO_READER_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 <atomic>
+#include <cerrno>
+#include <cstdlib>
+#include <fcntl.h>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <thread>
+#include <utility>
+
+#ifndef _WIN32
+# include <sys/wait.h>
+#endif
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/detail/input_format.hpp>
+#include <osmium/io/detail/read_thread.hpp>
+#include <osmium/io/detail/read_write.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/thread/util.hpp>
+#include <osmium/thread/queue.hpp>
+
+namespace osmium {
+
+ namespace io {
+
+ /**
+ * This is the user-facing interface for reading OSM files. Instantiate
+ * an object of this class with a file name or osmium::io::File object
+ * and then call read() on it in a loop until it returns an invalid
+ * Buffer.
+ */
+ class Reader {
+
+ osmium::io::File m_file;
+ osmium::osm_entity_bits::type m_read_which_entities;
+ std::atomic<bool> m_input_done;
+ int m_childpid;
+
+ osmium::thread::Queue<std::string> m_input_queue;
+
+ std::unique_ptr<osmium::io::Decompressor> m_decompressor;
+ std::future<bool> m_read_future;
+
+ std::unique_ptr<osmium::io::detail::InputFormat> m_input;
+
+#ifndef _WIN32
+ /**
+ * Fork and execute the given command in the child.
+ * A pipe is created between the child and the parent.
+ * The child writes to the pipe, the parent reads from it.
+ * This function never returns in the child.
+ *
+ * @param command Command to execute in the child.
+ * @param filename Filename to give to command as argument.
+ * @returns File descriptor of pipe in the parent.
+ * @throws std::system_error if a system call fails.
+ */
+ static int execute(const std::string& command, const std::string& filename, int* childpid) {
+ int pipefd[2];
+ if (pipe(pipefd) < 0) {
+ throw std::system_error(errno, std::system_category(), "opening pipe failed");
+ }
+ pid_t pid = fork();
+ if (pid < 0) {
+ throw std::system_error(errno, std::system_category(), "fork failed");
+ }
+ if (pid == 0) { // child
+ // close all file descriptors except one end of the pipe
+ for (int i=0; i < 32; ++i) {
+ if (i != pipefd[1]) {
+ ::close(i);
+ }
+ }
+ if (dup2(pipefd[1], 1) < 0) { // put end of pipe as stdout/stdin
+ exit(1);
+ }
+
+ ::open("/dev/null", O_RDONLY); // stdin
+ ::open("/dev/null", O_WRONLY); // stderr
+ // hack: -g switches off globbing in curl which allows [] to be used in file names
+ // this is important for XAPI URLs
+ // in theory this execute() function could be used for other commands, but it is
+ // only used for curl at the moment, so this is okay.
+ if (::execlp(command.c_str(), command.c_str(), "-g", filename.c_str(), nullptr) < 0) {
+ exit(1);
+ }
+ }
+ // parent
+ *childpid = pid;
+ ::close(pipefd[1]);
+ return pipefd[0];
+ }
+#endif
+
+ /**
+ * Open File for reading. Handles URLs or normal files. URLs
+ * are opened by executing the "curl" program (which must be installed)
+ * and reading from its output.
+ *
+ * @returns File descriptor of open file or pipe.
+ * @throws std::system_error if a system call fails.
+ */
+ static int open_input_file_or_url(const std::string& filename, int* childpid) {
+ std::string protocol = filename.substr(0, filename.find_first_of(':'));
+ if (protocol == "http" || protocol == "https" || protocol == "ftp" || protocol == "file") {
+#ifndef _WIN32
+ return execute("curl", filename, childpid);
+#else
+ throw std::runtime_error("Reading OSM files from the network currently not supported on Windows.");
+#endif
+ } else {
+ return osmium::io::detail::open_for_reading(filename);
+ }
+ }
+
+ public:
+
+ /**
+ * Create new Reader object.
+ *
+ * @param file The file we want to open.
+ * @param read_which_entities Which OSM entities (nodes, ways, relations, and/or changesets)
+ * should be read from the input file. It can speed the read up
+ * significantly if objects that are not needed anyway are not
+ * parsed.
+ */
+ explicit Reader(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities = osmium::osm_entity_bits::all) :
+ m_file(file),
+ m_read_which_entities(read_which_entities),
+ m_input_done(false),
+ m_childpid(0),
+ m_input_queue(20, "raw_input"), // XXX
+ m_decompressor(m_file.buffer() ?
+ osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), m_file.buffer(), m_file.buffer_size()) :
+ osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), open_input_file_or_url(m_file.filename(), &m_childpid))),
+ m_read_future(std::async(std::launch::async, detail::ReadThread(m_input_queue, m_decompressor.get(), m_input_done))),
+ m_input(osmium::io::detail::InputFormatFactory::instance().create_input(m_file, m_read_which_entities, m_input_queue)) {
+ }
+
+ explicit Reader(const std::string& filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
+ Reader(osmium::io::File(filename), read_types) {
+ }
+
+ explicit Reader(const char* filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
+ Reader(osmium::io::File(filename), read_types) {
+ }
+
+ Reader(const Reader&) = delete;
+ Reader& operator=(const Reader&) = delete;
+
+ ~Reader() {
+ try {
+ close();
+ }
+ catch (...) {
+ }
+ }
+
+ /**
+ * Close down the Reader. A call to this is optional, because the
+ * destructor of Reader will also call this. But if you don't call
+ * this function first, the destructor might throw an exception
+ * which is not good.
+ *
+ * @throws Some form of std::runtime_error when there is a problem.
+ */
+ void close() {
+ // Signal to input child process that it should wrap up.
+ m_input_done = true;
+
+ m_input->close();
+
+#ifndef _WIN32
+ if (m_childpid) {
+ int status;
+ pid_t pid = ::waitpid(m_childpid, &status, 0);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+ if (pid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ throw std::system_error(errno, std::system_category(), "subprocess returned error");
+ }
+#pragma GCC diagnostic pop
+ m_childpid = 0;
+ }
+#endif
+
+ osmium::thread::wait_until_done(m_read_future);
+ }
+
+ /**
+ * Get the header data from the file.
+ */
+ osmium::io::Header header() const {
+ return m_input->header();
+ }
+
+ /**
+ * Reads the next buffer from the input. An invalid buffer signals
+ * end-of-file. After end-of-file all read() calls will return an
+ * invalid buffer. An invalid buffer is also always returned if
+ * osmium::osm_entity_bits::nothing was set when the Reader was
+ * constructed.
+ *
+ * @returns Buffer.
+ * @throws Some form of std::runtime_error if there is an error.
+ */
+ osmium::memory::Buffer read() {
+ // If an exception happened in the input thread, re-throw
+ // it in this (the main) thread.
+ osmium::thread::check_for_exception(m_read_future);
+
+ if (m_read_which_entities == osmium::osm_entity_bits::nothing || m_input_done) {
+ // If the caller didn't want anything but the header, it will
+ // always get an empty buffer here.
+ return osmium::memory::Buffer();
+ }
+
+ osmium::memory::Buffer buffer = m_input->read();
+ if (!buffer) {
+ m_input_done = true;
+ }
+ return buffer;
+ }
+
+ /**
+ * Has the end of file been reached? This is set after the last
+ * data has been read. It is also set by calling close().
+ */
+ bool eof() const {
+ return m_input_done;
+ }
+
+ }; // class Reader
+
+ /**
+ * Read contents of the given file into a buffer in one go. Takes
+ * the same arguments as any of the Reader constructors.
+ *
+ * The buffer can take up quite a lot of memory, so don't do this
+ * unless you are working with small OSM files and/or have lots of
+ * RAM.
+ */
+ template <class... TArgs>
+ osmium::memory::Buffer read_file(TArgs&&... args) {
+ osmium::memory::Buffer buffer(1024*1024, osmium::memory::Buffer::auto_grow::yes);
+
+ Reader reader(std::forward<TArgs>(args)...);
+ while (osmium::memory::Buffer read_buffer = reader.read()) {
+ buffer.add_buffer(read_buffer);
+ buffer.commit();
+ }
+
+ return buffer;
+ }
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_READER_HPP
diff --git a/third_party/osmium/io/reader_iterator.hpp b/third_party/osmium/io/reader_iterator.hpp
new file mode 100644
index 0000000..8d71418
--- /dev/null
+++ b/third_party/osmium/io/reader_iterator.hpp
@@ -0,0 +1,51 @@
+#ifndef OSMIUM_IO_READER_ITERATOR_HPP
+#define OSMIUM_IO_READER_ITERATOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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 <osmium/io/reader.hpp>
+#include <osmium/io/input_iterator.hpp>
+
+namespace std {
+
+ inline osmium::io::InputIterator<osmium::io::Reader> begin(osmium::io::Reader& reader) {
+ return osmium::io::InputIterator<osmium::io::Reader>(reader);
+ }
+
+ inline osmium::io::InputIterator<osmium::io::Reader> end(osmium::io::Reader&) {
+ return osmium::io::InputIterator<osmium::io::Reader>();
+ }
+
+} // namespace std
+
+#endif // OSMIUM_IO_READER_ITERATOR_HPP
diff --git a/third_party/osmium/io/writer.hpp b/third_party/osmium/io/writer.hpp
new file mode 100644
index 0000000..7e9bd13
--- /dev/null
+++ b/third_party/osmium/io/writer.hpp
@@ -0,0 +1,145 @@
+#ifndef OSMIUM_IO_WRITER_HPP
+#define OSMIUM_IO_WRITER_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 <memory>
+#include <string>
+#include <utility>
+
+#include <osmium/io/compression.hpp>
+#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/detail/read_write.hpp>
+#include <osmium/io/detail/write_thread.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/header.hpp>
+#include <osmium/io/overwrite.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/thread/util.hpp>
+
+namespace osmium {
+
+ namespace io {
+
+ /**
+ * This is the user-facing interface for writing OSM files. Instantiate
+ * an object of this class with a file name or osmium::io::File object
+ * and optionally the data for the header and then call operator() on it
+ * to write Buffers. Call close() to finish up.
+ */
+ class Writer {
+
+ osmium::io::File m_file;
+
+ osmium::io::detail::data_queue_type m_output_queue;
+
+ std::unique_ptr<osmium::io::detail::OutputFormat> m_output;
+
+ std::unique_ptr<osmium::io::Compressor> m_compressor;
+
+ std::future<bool> m_write_future;
+
+ public:
+
+ /**
+ * The constructor of the Writer object opens a file and writes the
+ * header to it.
+ *
+ * @param file File (contains name and format info) to open.
+ * @param header Optional header data. If this is not given sensible
+ * 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+
+ * (default).
+ *
+ * @throws std::runtime_error If the file could not be opened.
+ * @throws std::system_error If the file could not be opened.
+ */
+ explicit Writer(const osmium::io::File& file, const osmium::io::Header& header = osmium::io::Header(), overwrite allow_overwrite = overwrite::no) :
+ m_file(file),
+ m_output_queue(20, "raw_output"), // XXX
+ m_output(osmium::io::detail::OutputFormatFactory::instance().create_output(m_file, m_output_queue)),
+ m_compressor(osmium::io::CompressionFactory::instance().create_compressor(file.compression(), osmium::io::detail::open_for_writing(m_file.filename(), allow_overwrite))),
+ m_write_future(std::async(std::launch::async, detail::WriteThread(m_output_queue, m_compressor.get()))) {
+ assert(!m_file.buffer());
+ m_output->write_header(header);
+ }
+
+ explicit Writer(const std::string& filename, const osmium::io::Header& header = osmium::io::Header(), overwrite allow_overwrite = overwrite::no) :
+ Writer(osmium::io::File(filename), header, allow_overwrite) {
+ }
+
+ explicit Writer(const char* filename, const osmium::io::Header& header = osmium::io::Header(), overwrite allow_overwrite = overwrite::no) :
+ Writer(osmium::io::File(filename), header, allow_overwrite) {
+ }
+
+ Writer(const Writer&) = delete;
+ Writer& operator=(const Writer&) = delete;
+
+ ~Writer() {
+ close();
+ }
+
+ /**
+ * Write contents of a buffer to the output file.
+ *
+ * @throws Some form of std::runtime_error when there is a problem.
+ */
+ void operator()(osmium::memory::Buffer&& buffer) {
+ osmium::thread::check_for_exception(m_write_future);
+ if (buffer.committed() > 0) {
+ m_output->write_buffer(std::move(buffer));
+ }
+ }
+
+ /**
+ * Flush writes to output file and closes it. If you do not
+ * call this, the destructor of Writer will also do the same
+ * thing. But because this call might thrown an exception,
+ * it is better to call close() explicitly.
+ *
+ * @throws Some form of std::runtime_error when there is a problem.
+ */
+ void close() {
+ m_output->close();
+ osmium::thread::wait_until_done(m_write_future);
+ }
+
+ }; // class Writer
+
+ } // namespace io
+
+} // namespace osmium
+
+#endif // OSMIUM_IO_WRITER_HPP
diff --git a/third_party/osmium/io/xml_input.hpp b/third_party/osmium/io/xml_input.hpp
new file mode 100644
index 0000000..f33d37e
--- /dev/null
+++ b/third_party/osmium/io/xml_input.hpp
@@ -0,0 +1,39 @@
+#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
+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/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/osmium/io/xml_output.hpp b/third_party/osmium/io/xml_output.hpp
new file mode 100644
index 0000000..d5b839f
--- /dev/null
+++ b/third_party/osmium/io/xml_output.hpp
@@ -0,0 +1,39 @@
+#ifndef OSMIUM_IO_XML_OUTPUT_HPP
+#define OSMIUM_IO_XML_OUTPUT_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 <osmium/io/writer.hpp> // IWYU pragma: export
+#include <osmium/io/detail/xml_output_format.hpp> // IWYU pragma: export
+
+#endif // OSMIUM_IO_XML_OUTPUT_HPP
diff --git a/third_party/osmium/memory/buffer.hpp b/third_party/osmium/memory/buffer.hpp
new file mode 100644
index 0000000..fe040ca
--- /dev/null
+++ b/third_party/osmium/memory/buffer.hpp
@@ -0,0 +1,534 @@
+#ifndef OSMIUM_MEMORY_BUFFER_HPP
+#define OSMIUM_MEMORY_BUFFER_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 <cstddef>
+#include <cstring>
+#include <exception>
+#include <functional>
+#include <iterator>
+#include <stdexcept>
+#include <utility>
+#include <vector>
+
+#include <osmium/memory/item.hpp>
+#include <osmium/memory/item_iterator.hpp>
+#include <osmium/osm/entity.hpp>
+
+namespace osmium {
+
+ /**
+ * Exception thrown by the osmium::memory::Buffer class when somebody tries
+ * to write data into a buffer and it doesn't fit. Buffers with internal
+ * memory management will not throw this exception, but increase their size.
+ */
+ struct buffer_is_full : public std::runtime_error {
+
+ buffer_is_full() :
+ std::runtime_error("Osmium buffer is full") {
+ }
+
+ }; // struct buffer_is_full
+
+ /**
+ * @brief Memory management of items in buffers and iterators over this data.
+ */
+ namespace memory {
+
+ /**
+ * A memory area for storing OSM objects and other items. Each item stored
+ * has a type and a length. See the Item class for details.
+ *
+ * Data can be added to a buffer piece by piece using reserve_space() and
+ * add_item(). After all data that together forms an item is added, it must
+ * be committed using the commit() call. Usually this is done through the
+ * Builder class and its derived classes.
+ *
+ * You can iterate over all items in a buffer using the iterators returned
+ * by begin(), end(), cbegin(), and cend().
+ *
+ * Buffers exist in two flavours, those with external memory management and
+ * those with internal memory management. If you already have some memory
+ * with data in it (for instance read from disk), you create a Buffer with
+ * external memory managment. It is your job then to free the memory once
+ * the buffer isn't used any more. If you don't have memory already, you can
+ * create a Buffer object and have it manage the memory internally. It will
+ * dynamically allocate memory and free it again after use.
+ *
+ * By default, if a buffer gets full it will throw a buffer_is_full exception.
+ * You can use the set_full_callback() method to set a callback functor
+ * which will be called instead of throwing an exception.
+ */
+ class Buffer {
+
+ public:
+
+ enum class auto_grow : bool {
+ yes = true,
+ no = false
+ }; // enum class auto_grow
+
+ private:
+
+ std::vector<unsigned char> m_memory;
+ unsigned char* m_data;
+ size_t m_capacity;
+ size_t m_written;
+ size_t m_committed;
+ auto_grow m_auto_grow {auto_grow::no};
+ std::function<void(Buffer&)> m_full;
+
+ public:
+
+ typedef Item value_type;
+
+ /**
+ * The constructor without any parameters creates a non-initialized
+ * buffer, ie an empty hull of a buffer that has no actual memory
+ * associated with it. It can be used to signify end-of-input.
+ */
+ Buffer() noexcept :
+ m_memory(),
+ m_data(nullptr),
+ m_capacity(0),
+ m_written(0),
+ m_committed(0) {
+ }
+
+ /**
+ * Constructs an externally memory-managed buffer using the given
+ * memory and size.
+ *
+ * @param data A pointer to some already initialized data.
+ * @param size The size of the initialized data.
+ * @throws std::invalid_argument When the size isn't a multiple of the alignment.
+ */
+ explicit Buffer(unsigned char* data, size_t size) :
+ m_memory(),
+ m_data(data),
+ m_capacity(size),
+ m_written(size),
+ m_committed(size) {
+ if (size % align_bytes != 0) {
+ throw std::invalid_argument("buffer size needs to be multiple of alignment");
+ }
+ }
+
+ /**
+ * Constructs an externally memory-managed buffer with the given
+ * capacity that already contains 'committed' bytes of data.
+ *
+ * @param data A pointer to some (possibly initialized) data.
+ * @param capacity The size of the memory for this buffer.
+ * @param committed The size of the initialized data. If this is 0, the buffer startes out empty.
+ * @throws std::invalid_argument When the capacity or committed isn't a multiple of the alignment.
+ */
+ explicit Buffer(unsigned char* data, size_t capacity, size_t committed) :
+ m_memory(),
+ m_data(data),
+ m_capacity(capacity),
+ m_written(committed),
+ m_committed(committed) {
+ if (capacity % align_bytes != 0) {
+ throw std::invalid_argument("buffer capacity needs to be multiple of alignment");
+ }
+ if (committed % align_bytes != 0) {
+ throw std::invalid_argument("buffer parameter 'committed' needs to be multiple of alignment");
+ }
+ }
+
+ /**
+ * Create an internally memory-managed buffer with the given capacity.
+ * different in that it internally gets dynamic memory of the
+ * required size. The dynamic memory will be automatically
+ * freed when the Buffer is destroyed.
+ */
+ explicit Buffer(size_t capacity, auto_grow auto_grow = auto_grow::yes) :
+ m_memory(capacity),
+ m_data(m_memory.data()),
+ m_capacity(capacity),
+ m_written(0),
+ m_committed(0),
+ m_auto_grow(auto_grow) {
+ if (capacity % align_bytes != 0) {
+ throw std::invalid_argument("buffer capacity needs to be multiple of alignment");
+ }
+ }
+
+ // buffers can not be copied
+ Buffer(const Buffer&) = delete;
+ Buffer& operator=(const Buffer&) = delete;
+
+ // buffers can be moved
+ Buffer(Buffer&&) = default;
+ Buffer& operator=(Buffer&&) = default;
+
+ ~Buffer() = default;
+
+ /**
+ * Return a pointer to data inside the buffer.
+ */
+ unsigned char* data() const noexcept {
+ return m_data;
+ }
+
+ /**
+ * Returns the capacity of the buffer, ie how many bytes it can contain.
+ */
+ size_t capacity() const noexcept {
+ return m_capacity;
+ }
+
+ /**
+ * Returns the number of bytes already filled in this buffer.
+ */
+ size_t committed() const noexcept {
+ return m_committed;
+ }
+
+ /**
+ * Returns the number of bytes currently filled in this buffer that
+ * are not yet committed.
+ */
+ size_t written() const noexcept {
+ return m_written;
+ }
+
+ /**
+ * This tests if the current state of the buffer is aligned
+ * properly. Can be used for asserts.
+ */
+ bool is_aligned() const noexcept {
+ return (m_written % align_bytes == 0) && (m_committed % align_bytes == 0);
+ }
+
+ /**
+ * Set functor to be called whenever the buffer is full
+ * instead of throwing buffer_is_full.
+ */
+ void set_full_callback(std::function<void(Buffer&)> full) {
+ m_full = full;
+ }
+
+ /**
+ * Grow capacity of this buffer to the given size.
+ * This works only with internally memory-managed buffers.
+ * If the given size is not larger than the current capacity, nothing is done.
+ * Already written but not committed data is discarded.
+ *
+ * @param size New capacity.
+ */
+ void grow(size_t size) {
+ if (m_memory.empty()) {
+ throw std::logic_error("Can't grow Buffer if it doesn't use internal memory management.");
+ }
+ if (m_capacity < size) {
+ if (size % align_bytes != 0) {
+ throw std::invalid_argument("buffer capacity needs to be multiple of alignment");
+ }
+ m_memory.resize(size);
+ m_data = m_memory.data();
+ m_capacity = size;
+ }
+ }
+
+ /**
+ * Mark currently written bytes in the buffer as committed.
+ *
+ * @returns Last number of committed bytes before this commit.
+ */
+ size_t commit() {
+ assert(is_aligned());
+
+ const size_t offset = m_committed;
+ m_committed = m_written;
+ return offset;
+ }
+
+ /**
+ * Roll back changes in buffer to last committed state.
+ */
+ void rollback() {
+ m_written = m_committed;
+ }
+
+ /**
+ * Clear the buffer.
+ *
+ * @returns Number of bytes in the buffer before it was cleared.
+ */
+ size_t clear() {
+ const size_t committed = m_committed;
+ m_written = 0;
+ m_committed = 0;
+ return committed;
+ }
+
+ /**
+ * Get the data in the buffer at the given offset.
+ *
+ * @tparam T Type we want to the data to be interpreted as.
+ * @returns Reference of given type pointing to the data in the buffer.
+ */
+ template <class T>
+ T& get(const size_t offset) const {
+ return *reinterpret_cast<T*>(&m_data[offset]);
+ }
+
+ /**
+ * Reserve space of given size in buffer and return pointer to it.
+ * This is the only way of adding data to the buffer. You reserve
+ * the space and then fill it.
+ *
+ * Note that you have to eventually call commit() to actually
+ * commit this data.
+ *
+ * If there isn't enough space in the buffer, one of three things
+ * can happen:
+ *
+ * * If you have set a callback with set_full_callback(), it is
+ * called. After the call returns, you must have either grown
+ * the buffer or cleared it by calling buffer.clear().
+ * * If no callback is defined and this buffer uses internal
+ * memory management, the buffers capacity is grown, so that
+ * the new data will fit.
+ * * Else the buffer_is_full exception is thrown.
+ *
+ * @param size Number of bytes to reserve.
+ * @returns Pointer to reserved space. Note that this pointer is
+ * only guaranteed to be valid until the next call to
+ * reserve_space().
+ * @throws osmium::buffer_is_full Might be thrown if the buffer is full.
+ */
+ unsigned char* reserve_space(const size_t size) {
+ if (m_written + size > m_capacity) {
+ if (m_full) {
+ m_full(*this);
+ } else if (!m_memory.empty() && (m_auto_grow == auto_grow::yes)) {
+ // double buffer size until there is enough space
+ size_t new_capacity = m_capacity * 2;
+ while (m_written + size > new_capacity) {
+ new_capacity *= 2;
+ }
+ grow(new_capacity);
+ } else {
+ throw osmium::buffer_is_full();
+ }
+ }
+ unsigned char* data = &m_data[m_written];
+ m_written += size;
+ return data;
+ }
+
+ /**
+ * Add an item to the buffer. The size of the item is stored inside
+ * the item, so we know how much memory to copy.
+ *
+ * Note that you have to eventually call commit() to actually
+ * commit this data.
+ *
+ * @tparam T Class of the item to be copied.
+ * @param item Reference to the item to be copied.
+ * @returns Reference to newly copied data in the buffer.
+ */
+ 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);
+ }
+
+ /**
+ * Add committed contents of the given buffer to this buffer.
+ *
+ * Note that you have to eventually call commit() to actually
+ * commit this data.
+ */
+ void add_buffer(const Buffer& buffer) {
+ unsigned char* ptr = reserve_space(buffer.committed());
+ std::memcpy(ptr, buffer.data(), buffer.committed());
+ }
+
+ /**
+ * Add an item to the buffer. This function is provided so that
+ * you can use std::back_inserter.
+ */
+ void push_back(const osmium::memory::Item& item) {
+ add_item(item);
+ commit();
+ }
+
+ /**
+ * These iterators can be used to iterate over all items in
+ * a buffer.
+ */
+ template <class T>
+ using t_iterator = osmium::memory::ItemIterator<T>;
+
+ template <class T>
+ using t_const_iterator = osmium::memory::ItemIterator<const T>;
+
+ typedef t_iterator<osmium::OSMEntity> iterator;
+ typedef t_const_iterator<osmium::OSMEntity> const_iterator;
+
+ template <class T>
+ t_iterator<T> begin() {
+ return t_iterator<T>(m_data, m_data + m_committed);
+ }
+
+ iterator begin() {
+ return iterator(m_data, m_data + m_committed);
+ }
+
+ template <class T>
+ t_iterator<T> end() {
+ return t_iterator<T>(m_data + m_committed, m_data + m_committed);
+ }
+
+ iterator end() {
+ return iterator(m_data + m_committed, m_data + m_committed);
+ }
+
+ template <class T>
+ t_const_iterator<T> cbegin() const {
+ return t_const_iterator<T>(m_data, m_data + m_committed);
+ }
+
+ const_iterator cbegin() const {
+ return const_iterator(m_data, m_data + m_committed);
+ }
+
+ template <class T>
+ t_const_iterator<T> cend() const {
+ return t_const_iterator<T>(m_data + m_committed, m_data + m_committed);
+ }
+
+ const_iterator cend() const {
+ return const_iterator(m_data + m_committed, m_data + m_committed);
+ }
+
+ template <class T>
+ t_const_iterator<T> begin() const {
+ return cbegin<T>();
+ }
+
+ const_iterator begin() const {
+ return cbegin();
+ }
+
+ template <class T>
+ t_const_iterator<T> end() const {
+ return cend<T>();
+ }
+
+ const_iterator end() const {
+ return cend();
+ }
+
+ /**
+ * In a bool context any initialized buffer is true.
+ */
+ explicit operator bool() const {
+ return m_data != nullptr;
+ }
+
+ friend void swap(Buffer& lhs, Buffer& rhs) {
+ using std::swap;
+
+ swap(lhs.m_memory, rhs.m_memory);
+ swap(lhs.m_data, rhs.m_data);
+ swap(lhs.m_capacity, rhs.m_capacity);
+ swap(lhs.m_written, rhs.m_written);
+ swap(lhs.m_committed, rhs.m_committed);
+ }
+
+ /**
+ * Purge removed items from the buffer. This is done by moving all
+ * non-removed items forward in the buffer overwriting removed
+ * items and then correcting the m_written and m_committed numbers.
+ *
+ * Note that calling this function invalidates all iterators on this
+ * buffer and all offsets in this buffer.
+ *
+ * For every non-removed item that moves its position, the function
+ * 'moving_in_buffer' is called on the given callback object with
+ * the old and new offsets in the buffer where the object used to
+ * be and is now, respectively. This call can be used to update any
+ * indexes.
+ */
+ template <class TCallbackClass>
+ void purge_removed(TCallbackClass* callback) {
+ if (begin() == end()) {
+ return;
+ }
+
+ iterator it_write = begin();
+
+ iterator next;
+ for (iterator it_read = begin(); it_read != end(); it_read = next) {
+ next = std::next(it_read);
+ if (!it_read->removed()) {
+ if (it_read != it_write) {
+ assert(it_read.data() >= data());
+ assert(it_write.data() >= data());
+ size_t old_offset = static_cast<size_t>(it_read.data() - data());
+ size_t new_offset = static_cast<size_t>(it_write.data() - data());
+ callback->moving_in_buffer(old_offset, new_offset);
+ std::memmove(it_write.data(), it_read.data(), it_read->padded_size());
+ }
+ it_write.advance_once();
+ }
+ }
+
+ assert(it_write.data() >= data());
+ m_written = static_cast<size_t>(it_write.data() - data());
+ m_committed = m_written;
+ }
+
+ }; // class Buffer
+
+ inline bool operator==(const Buffer& lhs, const Buffer& rhs) noexcept {
+ return lhs.data() == rhs.data() && lhs.capacity() == rhs.capacity() && lhs.committed() == rhs.committed();
+ }
+
+ inline bool operator!=(const Buffer& lhs, const Buffer& rhs) noexcept {
+ return ! (lhs == rhs);
+ }
+
+ } // namespace memory
+
+} // namespace osmium
+
+#endif // OSMIUM_MEMORY_BUFFER_HPP
diff --git a/third_party/osmium/memory/collection.hpp b/third_party/osmium/memory/collection.hpp
new file mode 100644
index 0000000..b25dd64
--- /dev/null
+++ b/third_party/osmium/memory/collection.hpp
@@ -0,0 +1,153 @@
+#ifndef OSMIUM_MEMORY_COLLECTION_HPP
+#define OSMIUM_MEMORY_COLLECTION_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 <iterator>
+#include <iosfwd>
+#include <type_traits>
+
+#include <osmium/memory/item.hpp>
+
+namespace osmium {
+
+ namespace memory {
+
+ template <class TMember>
+ class CollectionIterator : public std::iterator<std::forward_iterator_tag, TMember> {
+
+ // This data_type is either 'unsigned char*' or 'const unsigned char*' depending
+ // on whether TMember is const. This allows this class to be used as an iterator and
+ // as a const_iterator.
+ typedef typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type data_type;
+
+ data_type m_data;
+
+ public:
+
+ CollectionIterator() noexcept :
+ m_data(nullptr) {
+ }
+
+ CollectionIterator(data_type data) noexcept :
+ m_data(data) {
+ }
+
+ CollectionIterator<TMember>& operator++() {
+ m_data = reinterpret_cast<TMember*>(m_data)->next();
+ return *static_cast<CollectionIterator<TMember>*>(this);
+ }
+
+ CollectionIterator<TMember> operator++(int) {
+ CollectionIterator<TMember> tmp(*this);
+ operator++();
+ return tmp;
+ }
+
+ bool operator==(const CollectionIterator<TMember>& rhs) const noexcept {
+ return m_data == rhs.m_data;
+ }
+
+ bool operator!=(const CollectionIterator<TMember>& rhs) const noexcept {
+ return m_data != rhs.m_data;
+ }
+
+ unsigned char* data() const noexcept {
+ return m_data;
+ }
+
+ TMember& operator*() const {
+ return *reinterpret_cast<TMember*>(m_data);
+ }
+
+ TMember* operator->() const {
+ return reinterpret_cast<TMember*>(m_data);
+ }
+
+ template <typename TChar, typename TTraits>
+ friend std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const CollectionIterator<TMember>& iter) {
+ return out << static_cast<const void*>(iter.m_data);
+ }
+
+ }; // class CollectionIterator
+
+ template <class TMember, osmium::item_type TCollectionItemType>
+ class Collection : public Item {
+
+ public:
+
+ typedef CollectionIterator<TMember> iterator;
+ typedef CollectionIterator<const TMember> const_iterator;
+ typedef TMember value_type;
+
+ static constexpr osmium::item_type itemtype = TCollectionItemType;
+
+ Collection() :
+ Item(sizeof(Collection<TMember, TCollectionItemType>), TCollectionItemType) {
+ }
+
+ bool empty() const {
+ return sizeof(Collection<TMember, TCollectionItemType>) == byte_size();
+ }
+
+ iterator begin() {
+ return iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
+ }
+
+ iterator end() {
+ return iterator(data() + byte_size());
+ }
+
+ const_iterator cbegin() const {
+ return const_iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
+ }
+
+ const_iterator cend() const {
+ return const_iterator(data() + byte_size());
+ }
+
+ const_iterator begin() const {
+ return cbegin();
+ }
+
+ const_iterator end() const {
+ return cend();
+ }
+
+ }; // class Collection
+
+ } // namespace memory
+
+} // namespace osmium
+
+#endif // OSMIUM_MEMORY_COLLECTION_HPP
diff --git a/third_party/osmium/memory/item.hpp b/third_party/osmium/memory/item.hpp
new file mode 100644
index 0000000..2d22f94
--- /dev/null
+++ b/third_party/osmium/memory/item.hpp
@@ -0,0 +1,179 @@
+#ifndef OSMIUM_MEMORY_ITEM_HPP
+#define OSMIUM_MEMORY_ITEM_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 <cstddef>
+#include <cstdint>
+#include <type_traits>
+
+namespace osmium {
+
+ // forward declaration, see osmium/osm/item_type.hpp for declaration
+ enum class item_type : uint16_t;
+
+ namespace builder {
+ class Builder;
+ }
+
+ namespace memory {
+
+ typedef uint32_t item_size_type;
+
+ // align datastructures to this many bytes
+ constexpr item_size_type align_bytes = 8;
+
+ 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");
+ return (length + align_bytes - 1) & ~(align_bytes - 1);
+ }
+
+ /**
+ * @brief Namespace for Osmium internal use
+ */
+ namespace detail {
+
+ /**
+ * This class contains only a helper method used in several
+ * other classes.
+ */
+ class ItemHelper {
+
+ protected:
+
+ ItemHelper() = default;
+
+ ~ItemHelper() = default;
+
+ ItemHelper(const ItemHelper&) = default;
+ ItemHelper(ItemHelper&&) = default;
+
+ ItemHelper& operator=(const ItemHelper&) = default;
+ ItemHelper& operator=(ItemHelper&&) = default;
+
+ public:
+
+ unsigned char* data() noexcept {
+ return reinterpret_cast<unsigned char*>(this);
+ }
+
+ const unsigned char* data() const noexcept {
+ return reinterpret_cast<const unsigned char*>(this);
+ }
+
+ }; // class ItemHelper
+
+ } // namespace detail
+
+ class Item : public osmium::memory::detail::ItemHelper {
+
+ item_size_type m_size;
+ item_type m_type;
+ uint16_t m_removed : 1;
+ uint16_t m_padding : 15;
+
+ template <class TMember>
+ friend class CollectionIterator;
+
+ template <class TMember>
+ friend class ItemIterator;
+
+ friend class osmium::builder::Builder;
+
+ Item& add_size(const item_size_type size) noexcept {
+ m_size += size;
+ return *this;
+ }
+
+ protected:
+
+ explicit Item(item_size_type size=0, item_type type=item_type()) noexcept :
+ m_size(size),
+ m_type(type),
+ m_removed(false),
+ m_padding(0) {
+ }
+
+ Item(const Item&) = delete;
+ Item(Item&&) = delete;
+
+ Item& operator=(const Item&) = delete;
+ Item& operator=(Item&&) = delete;
+
+ Item& set_type(const item_type item_type) noexcept {
+ m_type = item_type;
+ return *this;
+ }
+
+ public:
+
+ unsigned char* next() noexcept {
+ return data() + padded_size();
+ }
+
+ const unsigned char* next() const noexcept {
+ return data() + padded_size();
+ }
+
+ item_size_type byte_size() const noexcept {
+ return m_size;
+ }
+
+ item_size_type padded_size() const {
+ return padded_length(m_size);
+ }
+
+ item_type type() const noexcept {
+ return m_type;
+ }
+
+ bool removed() const noexcept {
+ return m_removed;
+ }
+
+ void set_removed(bool removed) noexcept {
+ m_removed = removed;
+ }
+
+ }; // class Item
+
+ static_assert(sizeof(Item) == 8, "Class osmium::Item has wrong size!");
+ static_assert(sizeof(Item) % align_bytes == 0, "Class osmium::Item has wrong size to be aligned properly!");
+
+ } // namespace memory
+
+} // namespace osmium
+
+#endif // OSMIUM_MEMORY_ITEM_HPP
diff --git a/third_party/osmium/memory/item_iterator.hpp b/third_party/osmium/memory/item_iterator.hpp
new file mode 100644
index 0000000..34ed600
--- /dev/null
+++ b/third_party/osmium/memory/item_iterator.hpp
@@ -0,0 +1,234 @@
+#ifndef OSMIUM_ITEM_ITERATOR_HPP
+#define OSMIUM_ITEM_ITERATOR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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 <iterator>
+#include <iosfwd>
+#include <type_traits>
+
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+ class Node;
+ class Way;
+ class Relation;
+ class Area;
+ class Changeset;
+ class OSMObject;
+ class OSMEntity;
+ class TagList;
+ class WayNodeList;
+ class RelationMemberList;
+ class InnerRing;
+ class OuterRing;
+
+ namespace memory {
+
+ namespace detail {
+
+ template <class T>
+ inline bool type_is_compatible(osmium::item_type) noexcept {
+ return true;
+ }
+
+ template <>
+ inline bool type_is_compatible<osmium::Node>(osmium::item_type t) noexcept {
+ return t == osmium::item_type::node;
+ }
+
+ template <>
+ inline bool type_is_compatible<osmium::Way>(osmium::item_type t) noexcept {
+ return t == osmium::item_type::way;
+ }
+
+ template <>
+ inline bool type_is_compatible<osmium::Relation>(osmium::item_type t) noexcept {
+ return t == osmium::item_type::relation;
+ }
+
+ template <>
+ inline bool type_is_compatible<osmium::Area>(osmium::item_type t) noexcept {
+ return t == osmium::item_type::area;
+ }
+
+ template <>
+ inline bool type_is_compatible<osmium::Changeset>(osmium::item_type t) noexcept {
+ return t == osmium::item_type::changeset;
+ }
+
+ template <>
+ inline bool type_is_compatible<osmium::OSMObject>(osmium::item_type t) noexcept {
+ return t == osmium::item_type::node || t == osmium::item_type::way || t == osmium::item_type::relation || t == osmium::item_type::area;
+ }
+
+ template <>
+ inline bool type_is_compatible<osmium::OSMEntity>(osmium::item_type t) noexcept {
+ return t == osmium::item_type::node || t == osmium::item_type::way || t == osmium::item_type::relation || t == osmium::item_type::area || t == osmium::item_type::changeset;
+ }
+
+ template <>
+ inline bool type_is_compatible<osmium::TagList>(osmium::item_type t) noexcept {
+ return t == osmium::item_type::tag_list;
+ }
+
+ template <>
+ inline bool type_is_compatible<osmium::WayNodeList>(osmium::item_type t) noexcept {
+ return t == osmium::item_type::way_node_list;
+ }
+
+ template <>
+ inline bool type_is_compatible<osmium::RelationMemberList>(osmium::item_type t) noexcept {
+ return t == osmium::item_type::relation_member_list || t == osmium::item_type::relation_member_list_with_full_members;
+ }
+
+ template <>
+ inline bool type_is_compatible<osmium::OuterRing>(osmium::item_type t) noexcept {
+ return t == osmium::item_type::outer_ring;
+ }
+
+ template <>
+ inline bool type_is_compatible<osmium::InnerRing>(osmium::item_type t) noexcept {
+ return t == osmium::item_type::inner_ring;
+ }
+
+ } // namespace detail
+
+ template <class TMember>
+ class ItemIterator : public std::iterator<std::forward_iterator_tag, TMember> {
+
+ static_assert(std::is_base_of<osmium::memory::Item, TMember>::value, "TMember must derive from osmium::memory::Item");
+
+ // This data_type is either 'unsigned char*' or 'const unsigned char*' depending
+ // on whether TMember is const. This allows this class to be used as an iterator and
+ // as a const_iterator.
+ typedef typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type data_type;
+
+ data_type m_data;
+ data_type m_end;
+
+ void advance_to_next_item_of_right_type() {
+ while (m_data != m_end &&
+ !detail::type_is_compatible<typename std::remove_const<TMember>::type>(reinterpret_cast<const osmium::memory::Item*>(m_data)->type())) {
+ m_data = reinterpret_cast<TMember*>(m_data)->next();
+ }
+ }
+
+ public:
+
+ ItemIterator() noexcept :
+ m_data(nullptr),
+ m_end(nullptr) {
+ }
+
+ ItemIterator(data_type data, data_type end) :
+ m_data(data),
+ m_end(end) {
+ advance_to_next_item_of_right_type();
+ }
+
+ template <class T>
+ ItemIterator<T> cast() const {
+ return ItemIterator<T>(m_data, m_end);
+ }
+
+ ItemIterator<TMember>& operator++() {
+ assert(m_data);
+ assert(m_data != m_end);
+ m_data = reinterpret_cast<TMember*>(m_data)->next();
+ advance_to_next_item_of_right_type();
+ return *static_cast<ItemIterator<TMember>*>(this);
+ }
+
+ /**
+ * Like operator++() but will NOT skip items of unwanted
+ * types. Do not use this unless you know what you are
+ * doing.
+ */
+ ItemIterator<TMember>& advance_once() {
+ assert(m_data);
+ assert(m_data != m_end);
+ m_data = reinterpret_cast<TMember*>(m_data)->next();
+ return *static_cast<ItemIterator<TMember>*>(this);
+ }
+
+ ItemIterator<TMember> operator++(int) {
+ ItemIterator<TMember> tmp(*this);
+ operator++();
+ return tmp;
+ }
+
+ bool operator==(const ItemIterator<TMember>& rhs) const {
+ return m_data == rhs.m_data && m_end == rhs.m_end;
+ }
+
+ bool operator!=(const ItemIterator<TMember>& rhs) const {
+ return !(*this == rhs);
+ }
+
+ unsigned char* data() const {
+ assert(m_data);
+ return m_data;
+ }
+
+ TMember& operator*() const {
+ assert(m_data);
+ assert(m_data != m_end);
+ return *reinterpret_cast<TMember*>(m_data);
+ }
+
+ TMember* operator->() const {
+ assert(m_data);
+ assert(m_data != m_end);
+ return reinterpret_cast<TMember*>(m_data);
+ }
+
+ explicit operator bool() const {
+ return m_data != nullptr;
+ }
+
+ template <typename TChar, typename TTraits>
+ friend std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const ItemIterator<TMember>& iter) {
+ return out << static_cast<void*>(iter.m_data);
+ }
+
+ }; // class ItemIterator
+
+ } // namespace memory
+
+} // namespace osmium
+
+#endif // OSMIUM_ITEM_ITERATOR_HPP
diff --git a/third_party/osmium/object_pointer_collection.hpp b/third_party/osmium/object_pointer_collection.hpp
new file mode 100644
index 0000000..22029a1
--- /dev/null
+++ b/third_party/osmium/object_pointer_collection.hpp
@@ -0,0 +1,112 @@
+#ifndef OSMIUM_OBJECT_POINTER_COLLECTION_HPP
+#define OSMIUM_OBJECT_POINTER_COLLECTION_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 <algorithm>
+#include <utility>
+#include <vector>
+
+#include <boost/iterator/indirect_iterator.hpp>
+
+#include <osmium/handler.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/object.hpp>
+
+// IWYU pragma: no_forward_declare osmium::OSMObject
+// IWYU pragma: no_forward_declare osmium::memory::Item
+
+namespace osmium {
+
+ /**
+ * A collection of pointers to OSM objects. The pointers can be easily
+ * and quickly sorted or otherwise manipulated, while the objects
+ * themselves or the buffers they are in, do not have to be changed.
+ *
+ * An iterator is provided that can iterate over the pointers but looks
+ * like it is iterating over the underlying OSM objects.
+ *
+ * This class implements the visitor pattern which makes it easy to
+ * populate the collection from a buffer of OSM objects:
+ *
+ * osmium::ObjectPointerCollection objects;
+ * osmium::memory::Buffer buffer = reader.read();
+ * osmium::apply(buffer, objects);
+ *
+ */
+ class ObjectPointerCollection : public osmium::handler::Handler {
+
+ std::vector<osmium::OSMObject*> m_objects;
+
+ public:
+
+ typedef boost::indirect_iterator<std::vector<osmium::OSMObject*>::iterator, osmium::OSMObject> iterator;
+ typedef boost::indirect_iterator<std::vector<osmium::OSMObject*>::const_iterator, const osmium::OSMObject> const_iterator;
+
+ ObjectPointerCollection() noexcept :
+ m_objects() {
+ }
+
+ void osm_object(osmium::OSMObject& object) {
+ m_objects.push_back(&object);
+ }
+
+ /**
+ * Sort objects according to the given order functor.
+ */
+ template <class TCompare>
+ void sort(TCompare&& compare) {
+ std::sort(m_objects.begin(), m_objects.end(), std::forward<TCompare>(compare));
+ }
+
+ iterator begin() {
+ return iterator { m_objects.begin() };
+ }
+
+ iterator end() {
+ return iterator { m_objects.end() };
+ }
+
+ const_iterator cbegin() const {
+ return const_iterator { m_objects.cbegin() };
+ }
+
+ const_iterator cend() const {
+ return const_iterator { m_objects.cend() };
+ }
+
+ }; // class ObjectPointerCollection
+
+} // namespace osmium
+
+#endif // OSMIUM_OBJECT_POINTER_COLLECTION_HPP
diff --git a/third_party/osmium/osm.hpp b/third_party/osmium/osm.hpp
new file mode 100644
index 0000000..bf21c19
--- /dev/null
+++ b/third_party/osmium/osm.hpp
@@ -0,0 +1,48 @@
+#ifndef OSMIUM_OSM_HPP
+#define OSMIUM_OSM_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 <osmium/osm/node.hpp> // IWYU pragma: export
+#include <osmium/osm/way.hpp> // IWYU pragma: export
+#include <osmium/osm/relation.hpp> // IWYU pragma: export
+#include <osmium/osm/area.hpp> // IWYU pragma: export
+#include <osmium/osm/changeset.hpp> // IWYU pragma: export
+
+/**
+ * @brief Namespace for everything in the Osmium library.
+ */
+namespace osmium {
+} // namespace osmium
+
+#endif // OSMIUM_OSM_HPP
diff --git a/third_party/osmium/osm/area.hpp b/third_party/osmium/osm/area.hpp
new file mode 100644
index 0000000..a388de2
--- /dev/null
+++ b/third_party/osmium/osm/area.hpp
@@ -0,0 +1,193 @@
+#ifndef OSMIUM_OSM_AREA_HPP
+#define OSMIUM_OSM_AREA_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 <cstdlib>
+#include <utility>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/node_ref_list.hpp>
+
+namespace osmium {
+
+ namespace builder {
+ template <class T> class ObjectBuilder;
+ }
+
+ /**
+ * An outer ring of an Area.
+ */
+ class OuterRing : public NodeRefList<osmium::item_type::outer_ring> {
+
+ public:
+
+ OuterRing():
+ NodeRefList<osmium::item_type::outer_ring>() {
+ }
+
+ }; // class OuterRing
+
+ static_assert(sizeof(OuterRing) % osmium::memory::align_bytes == 0, "Class osmium::OuterRing has wrong size to be aligned properly!");
+
+ /**
+ * An inner ring of an Area.
+ */
+ class InnerRing : public NodeRefList<osmium::item_type::inner_ring> {
+
+ public:
+
+ InnerRing():
+ NodeRefList<osmium::item_type::inner_ring>() {
+ }
+
+ }; // class InnerRing
+
+ static_assert(sizeof(InnerRing) % osmium::memory::align_bytes == 0, "Class osmium::InnerRing has wrong size to be aligned properly!");
+
+ /**
+ * Convert way or (multipolygon) relation id into unique area id.
+ *
+ * @param id Id of a way or relation
+ * @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) {
+ osmium::object_id_type area_id = std::abs(id) * 2;
+ if (type == osmium::item_type::relation) {
+ ++area_id;
+ }
+ return id < 0 ? -area_id : area_id;
+ }
+
+ /**
+ * Convert area id into id of the way or relation it was created from.
+ *
+ * @param id Area id
+ * @returns Way or Relation id.
+ */
+ inline osmium::object_id_type area_id_to_object_id(osmium::object_id_type id) {
+ return id / 2;
+ }
+
+ /**
+ * An OSM area created out of a closed way or a multipolygon relation.
+ */
+ class Area : public OSMObject {
+
+ friend class osmium::builder::ObjectBuilder<osmium::Area>;
+
+ Area() :
+ OSMObject(sizeof(Area), osmium::item_type::area) {
+ }
+
+ public:
+
+ static constexpr osmium::item_type itemtype = osmium::item_type::area;
+
+ /**
+ * Was this area created from a way? (In contrast to areas
+ * created from a relation and their members.)
+ */
+ bool from_way() const noexcept {
+ return (positive_id() & 0x1) == 0;
+ }
+
+ /**
+ * Return the Id of the way or relation this area was created from.
+ */
+ osmium::object_id_type orig_id() const {
+ return osmium::area_id_to_object_id(id());
+ }
+
+ /**
+ * Count the number of outer and inner rings of this area.
+ */
+ std::pair<int, int> num_rings() const {
+ std::pair<int, int> counter;
+
+ for (auto it = cbegin(); it != cend(); ++it) {
+ switch (it->type()) {
+ case osmium::item_type::outer_ring:
+ ++counter.first;
+ break;
+ case osmium::item_type::inner_ring:
+ ++counter.second;
+ break;
+ case osmium::item_type::tag_list:
+ // ignore tags
+ break;
+ case osmium::item_type::undefined:
+ case osmium::item_type::node:
+ case osmium::item_type::way:
+ case osmium::item_type::relation:
+ case osmium::item_type::area:
+ case osmium::item_type::changeset:
+ case osmium::item_type::way_node_list:
+ case osmium::item_type::relation_member_list:
+ case osmium::item_type::relation_member_list_with_full_members:
+ assert(false && "Children of Area can only be outer/inner_ring and tag_list.");
+ break;
+ }
+ }
+
+ return counter;
+ }
+
+ /**
+ * Is this area a multipolygon, ie. has it more than one outer ring?
+ */
+ bool is_multipolygon() const {
+ return num_rings().first > 1;
+ }
+
+ osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cbegin(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
+ return it.cast<const osmium::InnerRing>();
+ }
+
+ 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>();
+ }
+
+ }; // class Area
+
+ static_assert(sizeof(Area) % osmium::memory::align_bytes == 0, "Class osmium::Area has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_AREA_HPP
diff --git a/third_party/osmium/osm/box.hpp b/third_party/osmium/osm/box.hpp
new file mode 100644
index 0000000..2b761fe
--- /dev/null
+++ b/third_party/osmium/osm/box.hpp
@@ -0,0 +1,207 @@
+#ifndef OSMIUM_OSM_BOX_HPP
+#define OSMIUM_OSM_BOX_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 <iosfwd>
+
+#include <osmium/util/compatibility.hpp>
+#include <osmium/osm/location.hpp>
+
+namespace osmium {
+
+ /**
+ * Bounding box.
+ */
+ class Box {
+
+ osmium::Location m_bottom_left;
+ osmium::Location m_top_right;
+
+ public:
+
+ /**
+ * Create undefined Box. Use the extend() function
+ * to add actual bounds.
+ */
+ constexpr Box() noexcept :
+ m_bottom_left(),
+ m_top_right() {
+ }
+
+ Box(double minx, double miny, double maxx, double maxy) :
+ m_bottom_left(minx, miny),
+ m_top_right(maxx, maxy) {
+ }
+
+ Box(const osmium::Location& bottom_left, const osmium::Location& top_right) :
+ m_bottom_left(bottom_left),
+ m_top_right(top_right) {
+ }
+
+ Box(const Box&) = default;
+ Box(Box&&) = default;
+ Box& operator=(const Box&) = default;
+ Box& operator=(Box&&) = default;
+ ~Box() = default;
+
+ /**
+ * Extend this bounding box by the given location. If the
+ * location is undefined, the bounding box is unchanged.
+ */
+ Box& extend(const Location& location) noexcept {
+ if (location) {
+ if (m_bottom_left) {
+ if (location.x() < m_bottom_left.x()) {
+ m_bottom_left.set_x(location.x());
+ }
+ if (location.x() > m_top_right.x()) {
+ m_top_right.set_x(location.x());
+ }
+ if (location.y() < m_bottom_left.y()) {
+ m_bottom_left.set_y(location.y());
+ }
+ if (location.y() > m_top_right.y()) {
+ m_top_right.set_y(location.y());
+ }
+ } else {
+ m_bottom_left = location;
+ m_top_right = location;
+ }
+ }
+ return *this;
+ }
+
+ /**
+ * Extend this bounding box by the given box. If the
+ * box is undefined, the bounding box is unchanged.
+ */
+ Box& extend(const Box& box) noexcept {
+ extend(box.bottom_left());
+ extend(box.top_right());
+ return *this;
+ }
+
+ /**
+ * Box are defined, ie. contains defined coordinates.
+ */
+ explicit constexpr operator bool() const noexcept {
+ return static_cast<bool>(m_bottom_left);
+ }
+
+ /**
+ * Box are valid, ie. defined and inside usual bounds
+ * (-180<=lon<=180, -90<=lat<=90).
+ */
+ constexpr bool valid() const noexcept {
+ return bottom_left().valid() && top_right().valid();
+ }
+
+ /**
+ * Bottom-left location.
+ */
+ OSMIUM_CONSTEXPR Location bottom_left() const noexcept {
+ return m_bottom_left;
+ }
+
+ /**
+ * Bottom-left location.
+ */
+ Location& bottom_left() noexcept {
+ return m_bottom_left;
+ }
+
+ /**
+ * Top-right location.
+ */
+ OSMIUM_CONSTEXPR Location top_right() const noexcept {
+ return m_top_right;
+ }
+
+ /**
+ * Top-right location.
+ */
+ Location& top_right() noexcept {
+ return m_top_right;
+ }
+
+ /**
+ * Is the location inside the box?
+ */
+ bool contains(const osmium::Location& location) const {
+ return location.x() >= bottom_left().x() && location.y() >= bottom_left().y() &&
+ location.x() <= top_right().x() && location.y() <= top_right().y();
+ }
+
+ /**
+ * Calculate size of the box in square degrees.
+ *
+ * @throws osmium::invalid_location unless all coordinates are valid
+ */
+ double size() const {
+ return (m_top_right.lon() - m_bottom_left.lon()) *
+ (m_top_right.lat() - m_bottom_left.lat());
+ }
+
+ }; // class Box
+
+ /**
+ * Boxes are equal if both locations are 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();
+ }
+
+ /**
+ * Output a box to a stream.
+ */
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Box& box) {
+ if (box) {
+ out << '('
+ << box.bottom_left().lon()
+ << ','
+ << box.bottom_left().lat()
+ << ','
+ << box.top_right().lon()
+ << ','
+ << box.top_right().lat()
+ << ')';
+ } else {
+ out << "(undefined)";
+ }
+ return out;
+ }
+} // namespace osmium
+
+#endif // OSMIUM_OSM_BOX_HPP
diff --git a/third_party/osmium/osm/changeset.hpp b/third_party/osmium/osm/changeset.hpp
new file mode 100644
index 0000000..2b79fb5
--- /dev/null
+++ b/third_party/osmium/osm/changeset.hpp
@@ -0,0 +1,336 @@
+#ifndef OSMIUM_OSM_CHANGESET_HPP
+#define OSMIUM_OSM_CHANGESET_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 <cstdint>
+#include <cstring>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/entity.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+ namespace builder {
+ template <class T> class ObjectBuilder;
+ }
+
+ /**
+ * \brief An OSM Changeset, a group of changes made by a single user over
+ * a short period of time.
+ *
+ * You can not create Changeset objects directly. Use the ChangesetBuilder
+ * class to create Changesets in a Buffer.
+ */
+ class Changeset : public osmium::OSMEntity {
+
+ friend class osmium::builder::ObjectBuilder<osmium::Changeset>;
+
+ osmium::Timestamp m_created_at;
+ osmium::Timestamp m_closed_at;
+ osmium::Box m_bounds;
+ changeset_id_type m_id {0};
+ num_changes_type m_num_changes {0};
+ user_id_type m_uid {0};
+ string_size_type m_user_size;
+
+ Changeset() :
+ OSMEntity(sizeof(Changeset), osmium::item_type::changeset) {
+ }
+
+ void set_user_size(string_size_type size) {
+ m_user_size = size;
+ }
+
+ unsigned char* subitems_position() {
+ return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size);
+ }
+
+ const unsigned char* subitems_position() const {
+ return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size);
+ }
+
+ public:
+
+ /// Get ID of this changeset
+ changeset_id_type id() const noexcept {
+ return m_id;
+ }
+
+ /**
+ * Set ID of this changeset
+ *
+ * @param id The id.
+ * @returns Reference to changeset to make calls chainable.
+ */
+ Changeset& set_id(changeset_id_type id) noexcept {
+ m_id = id;
+ return *this;
+ }
+
+ /**
+ * Set ID of this changeset.
+ *
+ * @param id The id.
+ * @returns Reference to object to make calls chainable.
+ */
+ Changeset& set_id(const char* id) {
+ return set_id(osmium::string_to_changeset_id(id));
+ }
+
+ /// Get user id.
+ user_id_type uid() const noexcept {
+ return m_uid;
+ }
+
+ /**
+ * Set user id.
+ *
+ * @param uid The user id.
+ * @returns Reference to changeset to make calls chainable.
+ */
+ Changeset& set_uid(user_id_type uid) noexcept {
+ m_uid = uid;
+ return *this;
+ }
+
+ /**
+ * Set user id to given uid or to 0 (anonymous user) if the given
+ * uid is smaller than 0.
+ *
+ * @param uid The user id.
+ * @returns Reference to changeset to make calls chainable.
+ */
+ Changeset& set_uid_from_signed(signed_user_id_type uid) noexcept {
+ m_uid = uid < 0 ? 0 : static_cast<user_id_type>(uid);
+ return *this;
+ }
+
+ /**
+ * Set user id to given uid or to 0 (anonymous user) if the given
+ * uid is smaller than 0.
+ *
+ * @returns Reference to changeset to make calls chainable.
+ */
+ Changeset& set_uid(const char* uid) {
+ return set_uid_from_signed(string_to_user_id(uid));
+ }
+
+ /// Is this user anonymous?
+ bool user_is_anonymous() const noexcept {
+ return m_uid == 0;
+ }
+
+ /// Get timestamp when this changeset was created.
+ osmium::Timestamp created_at() const noexcept {
+ return m_created_at;
+ }
+
+ /**
+ * Get timestamp when this changeset was closed.
+ *
+ * @returns Timestamp. Will return the empty Timestamp when the
+ * changeset is not yet closed.
+ */
+ osmium::Timestamp closed_at() const noexcept {
+ return m_closed_at;
+ }
+
+ /// Is this changeset open?
+ bool open() const noexcept {
+ return m_closed_at == osmium::Timestamp();
+ }
+
+ /// Is this changeset closed?
+ bool closed() const noexcept {
+ return !open();
+ }
+
+ /**
+ * Set the timestamp when this changeset was created.
+ *
+ * @param timestamp Timestamp
+ * @returns Reference to changeset to make calls chainable.
+ */
+ Changeset& set_created_at(const osmium::Timestamp timestamp) {
+ m_created_at = timestamp;
+ return *this;
+ }
+
+ /**
+ * Set the timestamp when this changeset was closed.
+ *
+ * @param timestamp Timestamp
+ * @returns Reference to changeset to make calls chainable.
+ */
+ Changeset& set_closed_at(const osmium::Timestamp timestamp) {
+ m_closed_at = timestamp;
+ return *this;
+ }
+
+ /// Get the number of changes in this changeset
+ num_changes_type num_changes() const noexcept {
+ return m_num_changes;
+ }
+
+ /// Set the number of changes in this changeset
+ Changeset& set_num_changes(num_changes_type num_changes) noexcept {
+ m_num_changes = num_changes;
+ return *this;
+ }
+
+ /// Set the number of changes in this changeset
+ Changeset& set_num_changes(const char* num_changes) noexcept {
+ return set_num_changes(osmium::string_to_num_changes(num_changes));
+ }
+
+ /**
+ * Get the bounding box of this changeset.
+ *
+ * @returns Bounding box. Can be empty.
+ */
+ osmium::Box& bounds() noexcept {
+ return m_bounds;
+ }
+
+ /**
+ * Get the bounding box of this changeset.
+ *
+ * @returns Bounding box. Can be empty.
+ */
+ const osmium::Box& bounds() const noexcept {
+ return m_bounds;
+ }
+
+ /// Get user name.
+ const char* user() const {
+ return reinterpret_cast<const char*>(data() + sizeof(Changeset));
+ }
+
+ /// Get the list of tags.
+ const TagList& tags() const {
+ return osmium::detail::subitem_of_type<const TagList>(cbegin(), cend());
+ }
+
+ /**
+ * Set named attribute.
+ *
+ * @param attr Name of the attribute (must be one of "id", "version",
+ * "changeset", "timestamp", "uid", "visible")
+ * @param value Value of the attribute
+ */
+ void set_attribute(const char* attr, const char* value) {
+ if (!strcmp(attr, "id")) {
+ set_id(value);
+ } else if (!strcmp(attr, "num_changes")) {
+ set_num_changes(value);
+ } else if (!strcmp(attr, "created_at")) {
+ set_created_at(osmium::Timestamp(value));
+ } else if (!strcmp(attr, "closed_at")) {
+ set_closed_at(osmium::Timestamp(value));
+ } else if (!strcmp(attr, "uid")) {
+ set_uid(value);
+ }
+ }
+
+ typedef osmium::memory::CollectionIterator<Item> iterator;
+ typedef osmium::memory::CollectionIterator<const Item> const_iterator;
+
+ iterator begin() {
+ return iterator(subitems_position());
+ }
+
+ iterator end() {
+ return iterator(data() + padded_size());
+ }
+
+ const_iterator cbegin() const {
+ return const_iterator(subitems_position());
+ }
+
+ const_iterator cend() const {
+ return const_iterator(data() + padded_size());
+ }
+
+ const_iterator begin() const {
+ return cbegin();
+ }
+
+ const_iterator end() const {
+ return cend();
+ }
+
+ }; // class Changeset
+
+ 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.
+ */
+ inline bool operator==(const Changeset& lhs, const Changeset& rhs) {
+ return lhs.id() == rhs.id();
+ }
+
+ inline bool operator!=(const Changeset& lhs, const Changeset& rhs) {
+ return ! (lhs == rhs);
+ }
+
+ /**
+ * Changesets can be ordered by id.
+ */
+ inline bool operator<(const Changeset& lhs, const Changeset& rhs) {
+ return lhs.id() < rhs.id();
+ }
+
+ inline bool operator>(const Changeset& lhs, const Changeset& rhs) {
+ return rhs < lhs;
+ }
+
+ inline bool operator<=(const Changeset& lhs, const Changeset& rhs) {
+ return ! (rhs < lhs);
+ }
+
+ inline bool operator>=(const Changeset& lhs, const Changeset& rhs) {
+ return ! (lhs < rhs);
+ }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_CHANGESET_HPP
diff --git a/third_party/osmium/osm/diff_object.hpp b/third_party/osmium/osm/diff_object.hpp
new file mode 100644
index 0000000..a8f91ec
--- /dev/null
+++ b/third_party/osmium/osm/diff_object.hpp
@@ -0,0 +1,156 @@
+#ifndef OSMIUM_OSM_DIFF_OBJECT_HPP
+#define OSMIUM_OSM_DIFF_OBJECT_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 <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+ class Node;
+ class Way;
+ class Relation;
+
+ class DiffObject {
+
+ protected:
+
+ osmium::OSMObject* m_prev;
+ osmium::OSMObject* m_curr;
+ osmium::OSMObject* m_next;
+
+ public:
+
+ DiffObject() noexcept :
+ m_prev(nullptr),
+ m_curr(nullptr),
+ m_next(nullptr) {
+ }
+
+ explicit DiffObject(osmium::OSMObject& prev, osmium::OSMObject& curr, osmium::OSMObject& next) noexcept :
+ m_prev(&prev),
+ m_curr(&curr),
+ m_next(&next) {
+ }
+
+ DiffObject(const DiffObject&) = default;
+ DiffObject& operator=(const DiffObject&) = default;
+
+ DiffObject(DiffObject&&) = default;
+ DiffObject& operator=(DiffObject&&) = default;
+
+ const osmium::OSMObject& prev() const noexcept {
+ return *m_prev;
+ }
+
+ const osmium::OSMObject& curr() const noexcept {
+ return *m_curr;
+ }
+
+ const osmium::OSMObject& next() const noexcept {
+ return *m_next;
+ }
+
+ bool first() const noexcept {
+ return m_prev == m_curr;
+ }
+
+ bool last() const noexcept {
+ return m_curr == m_next;
+ }
+
+ osmium::item_type type() const noexcept {
+ return m_curr->type();
+ }
+
+ osmium::object_id_type id() const noexcept {
+ return m_curr->id();
+ }
+
+ osmium::object_version_type version() const noexcept {
+ return m_curr->version();
+ }
+
+ osmium::changeset_id_type changeset() const noexcept {
+ return m_curr->changeset();
+ }
+
+ const osmium::Timestamp start_time() const noexcept {
+ return m_curr->timestamp();
+ }
+
+ const osmium::Timestamp end_time() const noexcept {
+ return last() ? osmium::Timestamp() : m_next->timestamp();
+ }
+
+ }; // class DiffObject
+
+ template <class T>
+ class DiffObjectDerived : public DiffObject {
+
+ public:
+
+ DiffObjectDerived(T& prev, T& curr, T& next) noexcept :
+ DiffObject(prev, curr, next) {
+ }
+
+ DiffObjectDerived(const DiffObjectDerived&) = default;
+ DiffObjectDerived& operator=(const DiffObjectDerived&) = default;
+
+ DiffObjectDerived(DiffObjectDerived&&) = default;
+ DiffObjectDerived& operator=(DiffObjectDerived&&) = default;
+
+ const T& prev() const noexcept {
+ return *static_cast<const T*>(m_prev);
+ }
+
+ const T& curr() const noexcept {
+ return *static_cast<const T*>(m_curr);
+ }
+
+ const T& next() const noexcept {
+ return *static_cast<const T*>(m_next);
+ }
+
+ }; // class DiffObjectDerived
+
+ typedef DiffObjectDerived<osmium::Node> DiffNode;
+ typedef DiffObjectDerived<osmium::Way> DiffWay;
+ typedef DiffObjectDerived<osmium::Relation> DiffRelation;
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_DIFF_OBJECT_HPP
diff --git a/third_party/osmium/osm/entity.hpp b/third_party/osmium/osm/entity.hpp
new file mode 100644
index 0000000..e37ed4c
--- /dev/null
+++ b/third_party/osmium/osm/entity.hpp
@@ -0,0 +1,74 @@
+#ifndef OSMIUM_OSM_ENTITY_HPP
+#define OSMIUM_OSM_ENTITY_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 <osmium/memory/item.hpp>
+
+namespace osmium {
+
+ namespace detail {
+
+ template <class TSubitem, class TIter>
+ inline TSubitem& subitem_of_type(TIter it, TIter end) {
+ for (; it != end; ++it) {
+ if (it->type() == TSubitem::itemtype) {
+ return reinterpret_cast<TSubitem&>(*it);
+ }
+ }
+
+ // If no subitem of the TSubitem type was found,
+ // return a default constructed one.
+ static TSubitem subitem;
+ return subitem;
+ }
+
+ } // namespace detail
+
+ /**
+ * \brief OSMEntity is the abstract base class for the OSMObject and
+ * Changeset classes.
+ */
+ class OSMEntity : public osmium::memory::Item {
+
+ public:
+
+ explicit OSMEntity(osmium::memory::item_size_type size, osmium::item_type type) :
+ Item(size, type) {
+ }
+
+ }; // class OSMEntity
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_ENTITY_HPP
diff --git a/third_party/osmium/osm/entity_bits.hpp b/third_party/osmium/osm/entity_bits.hpp
new file mode 100644
index 0000000..2a4d964
--- /dev/null
+++ b/third_party/osmium/osm/entity_bits.hpp
@@ -0,0 +1,99 @@
+#ifndef OSMIUM_OSM_ENTITY_BITS_HPP
+#define OSMIUM_OSM_ENTITY_BITS_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.
+
+*/
+
+namespace osmium {
+
+ /**
+ * @brief Bitfield for OSM entity types.
+ */
+ namespace osm_entity_bits {
+
+ /**
+ * Describes zero or more OSM entities.
+ *
+ * Usage:
+ *
+ * @code{.cpp}
+ * osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::node | osmium::osm_entity_bits::way;
+ *
+ * entities |= osmium::osm_entity_bits::relation;
+ *
+ * assert(entities & osmium::osm_entity_bits::object);
+ *
+ * assert(! (entities & osmium::osm_entity_bits::changeset));
+ * @endcode
+ */
+ enum type : unsigned char {
+
+ nothing = 0x00,
+ node = 0x01,
+ way = 0x02,
+ relation = 0x04,
+ nwr = 0x07, ///< node, way, or relation object
+ area = 0x08,
+ nwra = 0x0f, ///< node, way, relation, or area object
+ object = 0x0f, ///< node, way, relation, or area object
+ changeset = 0x10,
+ all = 0x1f ///< object or changeset
+
+ }; // enum type
+
+ inline type operator|(const type lhs, const type rhs) noexcept {
+ return static_cast<type>(static_cast<int>(lhs) | static_cast<int> (rhs));
+ }
+
+ inline type& operator|=(type& lhs, const type rhs) noexcept {
+ lhs = lhs | rhs;
+ return lhs;
+ }
+
+ inline type operator&(const type lhs, const type rhs) noexcept {
+ return static_cast<type>(static_cast<int>(lhs) & static_cast<int> (rhs));
+ }
+
+ inline type operator~(const type value) noexcept {
+ return static_cast<type>(~static_cast<int>(value));
+ }
+
+ inline type operator&=(type& lhs, const type rhs) noexcept {
+ lhs = lhs & rhs;
+ return lhs;
+ }
+
+ } // namespace osm_entity_bits
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_ENTITY_BITS_HPP
diff --git a/third_party/osmium/osm/item_type.hpp b/third_party/osmium/osm/item_type.hpp
new file mode 100644
index 0000000..d277e06
--- /dev/null
+++ b/third_party/osmium/osm/item_type.hpp
@@ -0,0 +1,173 @@
+#ifndef OSMIUM_OSM_ITEM_TYPE_HPP
+#define OSMIUM_OSM_ITEM_TYPE_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 <cstdint> // IWYU pragma: keep
+#include <iosfwd>
+#include <stdexcept>
+
+namespace osmium {
+
+ enum class item_type : uint16_t {
+
+ undefined = 0x00,
+ node = 0x01,
+ way = 0x02,
+ relation = 0x03,
+ area = 0x04,
+ changeset = 0x05,
+ tag_list = 0x11,
+ way_node_list = 0x12,
+ relation_member_list = 0x13,
+ relation_member_list_with_full_members = 0x23,
+ outer_ring = 0x40,
+ inner_ring = 0x41
+
+ }; // enum class item_type
+
+ inline item_type char_to_item_type(const char c) noexcept {
+ switch (c) {
+ case 'X':
+ return item_type::undefined;
+ case 'n':
+ return item_type::node;
+ case 'w':
+ return item_type::way;
+ case 'r':
+ return item_type::relation;
+ case 'a':
+ return item_type::area;
+ case 'c':
+ return item_type::changeset;
+ case 'T':
+ return item_type::tag_list;
+ case 'N':
+ return item_type::way_node_list;
+ case 'M':
+ return item_type::relation_member_list;
+ case 'F':
+ return item_type::relation_member_list_with_full_members;
+ case 'O':
+ return item_type::outer_ring;
+ case 'I':
+ return item_type::inner_ring;
+ default:
+ return item_type::undefined;
+ }
+ }
+
+// avoid g++ false positive
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreturn-type"
+ inline char item_type_to_char(const item_type type) noexcept {
+ switch (type) {
+ case item_type::undefined:
+ return 'X';
+ case item_type::node:
+ return 'n';
+ case item_type::way:
+ return 'w';
+ case item_type::relation:
+ return 'r';
+ case item_type::area:
+ return 'a';
+ case item_type::changeset:
+ return 'c';
+ case item_type::tag_list:
+ return 'T';
+ case item_type::way_node_list:
+ return 'N';
+ case item_type::relation_member_list:
+ return 'M';
+ case item_type::relation_member_list_with_full_members:
+ return 'F';
+ case item_type::outer_ring:
+ return 'O';
+ case item_type::inner_ring:
+ return 'I';
+ }
+ }
+
+ inline const char* item_type_to_name(const item_type type) noexcept {
+ switch (type) {
+ case item_type::undefined:
+ return "undefined";
+ case item_type::node:
+ return "node";
+ case item_type::way:
+ return "way";
+ case item_type::relation:
+ return "relation";
+ case item_type::area:
+ return "area";
+ case item_type::changeset:
+ return "changeset";
+ case item_type::tag_list:
+ return "tag_list";
+ case item_type::way_node_list:
+ return "way_node_list";
+ case item_type::relation_member_list:
+ return "relation_member_list";
+ case item_type::relation_member_list_with_full_members:
+ return "relation_member_list_with_full_members";
+ case item_type::outer_ring:
+ return "outer_ring";
+ case item_type::inner_ring:
+ return "inner_ring";
+ }
+ }
+#pragma GCC diagnostic pop
+
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const item_type item_type) {
+ return out << item_type_to_char(item_type);
+ }
+
+ /**
+ * This exception is thrown when a visitor encounters an unknown item type.
+ * Under usual circumstance this should not happen. If it does happen, it
+ * probably means the buffer contains different kinds of objects than were
+ * expected or that there is some kind of data corruption.
+ */
+ struct unknown_type : public std::runtime_error {
+
+ unknown_type() :
+ std::runtime_error("unknown item type") {
+ }
+
+ }; // struct unknown_type
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_ITEM_TYPE_HPP
diff --git a/third_party/osmium/osm/location.hpp b/third_party/osmium/osm/location.hpp
new file mode 100644
index 0000000..cabecd5
--- /dev/null
+++ b/third_party/osmium/osm/location.hpp
@@ -0,0 +1,285 @@
+#ifndef OSMIUM_OSM_LOCATION_HPP
+#define OSMIUM_OSM_LOCATION_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 <cmath>
+#include <cstdint>
+#include <iosfwd>
+#include <stdexcept>
+#include <string>
+
+#include <iostream>
+
+#include <osmium/util/compatibility.hpp>
+#include <osmium/util/double.hpp>
+
+namespace osmium {
+
+ /**
+ * Exception signaling an invalid location, ie a location
+ * outside the -180 to 180 and -90 to 90 degree range.
+ */
+ struct invalid_location : public std::range_error {
+
+ invalid_location(const std::string& what) :
+ std::range_error(what) {
+ }
+
+ invalid_location(const char* what) :
+ std::range_error(what) {
+ }
+
+ }; // struct invalid_location
+
+ /**
+ * Locations define a place on earth.
+ *
+ * Locations are stored in 32 bit integers for the x and y
+ * coordinates, respectively. This gives you an accuracy of a few
+ * centimeters, good enough for OSM use. (The main OSM database
+ * uses the same scheme.)
+ *
+ * An undefined Location can be created by calling the constructor
+ * without parameters.
+ *
+ * Coordinates are never checked on whether they are inside bounds.
+ * Call valid() to check this.
+ */
+ class Location {
+
+ int32_t m_x;
+ int32_t m_y;
+
+ public:
+
+ // this value is used for a coordinate to mark it as undefined
+ // MSVC doesn't declare std::numeric_limits<int32_t>::max() as
+ // constexpr, so we hard code this for the time being.
+ // static constexpr int32_t undefined_coordinate = std::numeric_limits<int32_t>::max();
+ static constexpr int32_t undefined_coordinate = 2147483647;
+
+ static constexpr int coordinate_precision = 10000000;
+
+ static int32_t double_to_fix(const double c) noexcept {
+ return static_cast<int32_t>(std::round(c * coordinate_precision));
+ }
+
+ static OSMIUM_CONSTEXPR double fix_to_double(const int32_t c) noexcept {
+ return static_cast<double>(c) / coordinate_precision;
+ }
+
+ /**
+ * Create undefined Location.
+ */
+ explicit constexpr Location() noexcept :
+ m_x(undefined_coordinate),
+ m_y(undefined_coordinate) {
+ }
+
+ /**
+ * Create Location with given x and y coordinates.
+ * Note that these coordinates are coordinate_precision
+ * times larger than the real coordinates.
+ */
+ constexpr Location(const int32_t x, const int32_t y) noexcept :
+ m_x(x),
+ m_y(y) {
+ }
+
+ /**
+ * Create Location with given x and y coordinates.
+ * Note that these coordinates are coordinate_precision
+ * times larger than the real coordinates.
+ */
+ constexpr Location(const int64_t x, const int64_t y) noexcept :
+ m_x(static_cast<int32_t>(x)),
+ m_y(static_cast<int32_t>(y)) {
+ }
+
+ /**
+ * Create Location with given longitude and latitude.
+ */
+ Location(const double lon, const double lat) :
+ m_x(double_to_fix(lon)),
+ m_y(double_to_fix(lat)) {
+ }
+
+ Location(const Location&) = default;
+ Location(Location&&) = default;
+ Location& operator=(const Location&) = default;
+ Location& operator=(Location&&) = default;
+ ~Location() = default;
+
+ /**
+ * Check whether the coordinates of this location
+ * are defined.
+ */
+ explicit constexpr operator bool() const noexcept {
+ return m_x != undefined_coordinate && m_y != undefined_coordinate;
+ }
+
+ /**
+ * Check whether the coordinates are inside the
+ * usual bounds (-180<=lon<=180, -90<=lat<=90).
+ */
+ constexpr bool valid() const noexcept {
+ return m_x >= -180 * coordinate_precision
+ && m_x <= 180 * coordinate_precision
+ && m_y >= -90 * coordinate_precision
+ && m_y <= 90 * coordinate_precision;
+ }
+
+ constexpr int32_t x() const noexcept {
+ return m_x;
+ }
+
+ constexpr int32_t y() const noexcept {
+ return m_y;
+ }
+
+ Location& set_x(const int32_t x) noexcept {
+ m_x = x;
+ return *this;
+ }
+
+ Location& set_y(const int32_t y) noexcept {
+ m_y = y;
+ return *this;
+ }
+
+ /**
+ * Get longitude.
+ *
+ * @throws invalid_location if the location is invalid
+ */
+ double lon() const {
+ if (!valid()) {
+ throw osmium::invalid_location("invalid location");
+ }
+ return fix_to_double(m_x);
+ }
+
+ /**
+ * Get longitude without checking the validity.
+ */
+ double lon_without_check() const {
+ return fix_to_double(m_x);
+ }
+
+ /**
+ * Get latitude.
+ *
+ * @throws invalid_location if the location is invalid
+ */
+ double lat() const {
+ if (!valid()) {
+ throw osmium::invalid_location("invalid location");
+ }
+ return fix_to_double(m_y);
+ }
+
+ /**
+ * Get latitude without checking the validity.
+ */
+ double lat_without_check() const {
+ return fix_to_double(m_y);
+ }
+
+ Location& set_lon(double lon) noexcept {
+ m_x = double_to_fix(lon);
+ return *this;
+ }
+
+ Location& set_lat(double lat) noexcept {
+ m_y = double_to_fix(lat);
+ return *this;
+ }
+
+ template <typename T>
+ T as_string(T iterator, const char separator) const {
+ iterator = osmium::util::double2string(iterator, lon(), 7);
+ *iterator++ = separator;
+ return osmium::util::double2string(iterator, lat(), 7);
+ }
+
+ }; // class Location
+
+ /**
+ * Locations are equal if both coordinates are equal.
+ */
+ inline OSMIUM_CONSTEXPR bool operator==(const Location& lhs, const Location& rhs) noexcept {
+ return lhs.x() == rhs.x() && lhs.y() == rhs.y();
+ }
+
+ inline OSMIUM_CONSTEXPR bool operator!=(const Location& lhs, const Location& rhs) noexcept {
+ return ! (lhs == rhs);
+ }
+
+ /**
+ * Compare two locations by comparing first the x and then
+ * the y coordinate. If either of the locations is
+ * undefined the result is undefined.
+ */
+ inline OSMIUM_CONSTEXPR bool operator<(const Location& lhs, const Location& rhs) noexcept {
+ return (lhs.x() == rhs.x() && lhs.y() < rhs.y()) || lhs.x() < rhs.x();
+ }
+
+ inline OSMIUM_CONSTEXPR bool operator>(const Location& lhs, const Location& rhs) noexcept {
+ return rhs < lhs;
+ }
+
+ inline OSMIUM_CONSTEXPR bool operator<=(const Location& lhs, const Location& rhs) noexcept {
+ return ! (rhs < lhs);
+ }
+
+ inline OSMIUM_CONSTEXPR bool operator>=(const Location& lhs, const Location& rhs) noexcept {
+ return ! (lhs < rhs);
+ }
+
+ /**
+ * Output a location to a stream.
+ */
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Location& location) {
+ if (location) {
+ out << '(' << location.lon() << ',' << location.lat() << ')';
+ } else {
+ out << "(undefined,undefined)";
+ }
+ return out;
+ }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_LOCATION_HPP
diff --git a/third_party/osmium/osm/node.hpp b/third_party/osmium/osm/node.hpp
new file mode 100644
index 0000000..50146c5
--- /dev/null
+++ b/third_party/osmium/osm/node.hpp
@@ -0,0 +1,76 @@
+#ifndef OSMIUM_OSM_NODE_HPP
+#define OSMIUM_OSM_NODE_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 <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/object.hpp>
+
+namespace osmium {
+
+ namespace builder {
+ template <class T> class ObjectBuilder;
+ }
+
+ class Node : public OSMObject {
+
+ friend class osmium::builder::ObjectBuilder<osmium::Node>;
+
+ osmium::Location m_location;
+
+ Node() :
+ OSMObject(sizeof(Node), osmium::item_type::node) {
+ }
+
+ public:
+
+ static constexpr osmium::item_type itemtype = osmium::item_type::node;
+
+ osmium::Location location() const noexcept {
+ return m_location;
+ }
+
+ Node& set_location(const osmium::Location& location) {
+ m_location = location;
+ return *this;
+ }
+
+ }; // class Node
+
+ static_assert(sizeof(Node) % osmium::memory::align_bytes == 0, "Class osmium::Node has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_NODE_HPP
diff --git a/third_party/osmium/osm/node_ref.hpp b/third_party/osmium/osm/node_ref.hpp
new file mode 100644
index 0000000..ed50b9e
--- /dev/null
+++ b/third_party/osmium/osm/node_ref.hpp
@@ -0,0 +1,173 @@
+#ifndef OSMIUM_OSM_NODE_REF_HPP
+#define OSMIUM_OSM_NODE_REF_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 <cstdlib>
+#include <iosfwd>
+
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+ /**
+ * This reference to a node contains a node ID and a (possibly empty)
+ * location.
+ */
+ class NodeRef : public osmium::memory::detail::ItemHelper {
+
+ osmium::object_id_type m_ref;
+ osmium::Location m_location;
+
+ public:
+
+ NodeRef(const osmium::object_id_type ref=0, const osmium::Location& location=Location()) noexcept :
+ m_ref(ref),
+ m_location(location) {
+ }
+
+ osmium::object_id_type ref() const noexcept {
+ return m_ref;
+ }
+
+ osmium::unsigned_object_id_type positive_ref() const noexcept {
+ return static_cast<osmium::unsigned_object_id_type>(std::abs(m_ref));
+ }
+
+ /**
+ * Get reference to location in this NodeRef. Can be used to update it.
+ */
+ osmium::Location& location() noexcept {
+ return m_location;
+ }
+
+ osmium::Location location() const noexcept {
+ return m_location;
+ }
+
+ double lon() const {
+ return m_location.lon();
+ }
+
+ double lat() const {
+ return m_location.lat();
+ }
+
+ int32_t x() const noexcept {
+ return m_location.x();
+ }
+
+ int32_t y() const noexcept {
+ return m_location.y();
+ }
+
+ NodeRef& set_ref(const osmium::object_id_type ref) noexcept {
+ m_ref = ref;
+ return *this;
+ }
+
+ NodeRef& set_location(const osmium::Location& location) noexcept {
+ m_location = location;
+ return *this;
+ }
+
+ }; // class NodeRef
+
+ inline bool operator==(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+ return lhs.ref() == rhs.ref();
+ }
+
+ inline bool operator!=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+ return ! (lhs == rhs);
+ }
+
+ inline bool operator<(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+ return lhs.ref() < rhs.ref();
+ }
+
+ inline bool operator>(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+ return rhs < lhs;
+ }
+
+ inline bool operator<=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+ return ! (rhs < lhs);
+ }
+
+ inline bool operator>=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+ return ! (lhs < rhs);
+ }
+
+ /**
+ * Output a NodeRef to a stream.
+ */
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::NodeRef& nr) {
+ return out << "<" << nr.ref() << " " << nr.location() << ">";
+ }
+
+ /**
+ * Functor to compare NodeRefs by Location instead of id.
+ */
+ struct location_equal {
+
+ bool operator()(const NodeRef& lhs, const NodeRef& rhs) const noexcept {
+ return lhs.location() == rhs.location();
+ }
+
+ typedef NodeRef first_argument_type;
+ typedef NodeRef second_argument_type;
+ typedef bool result_type;
+
+ }; // struct location_equal
+
+ /**
+ * Functor to compare NodeRefs by Location instead of id.
+ */
+ struct location_less {
+
+ bool operator()(const NodeRef& lhs, const NodeRef& rhs) const noexcept {
+ return lhs.location() < rhs.location();
+ }
+
+ typedef NodeRef first_argument_type;
+ typedef NodeRef second_argument_type;
+ typedef bool result_type;
+
+ }; // struct location_less
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_NODE_REF_HPP
diff --git a/third_party/osmium/osm/node_ref_list.hpp b/third_party/osmium/osm/node_ref_list.hpp
new file mode 100644
index 0000000..321c952
--- /dev/null
+++ b/third_party/osmium/osm/node_ref_list.hpp
@@ -0,0 +1,135 @@
+#ifndef OSMIUM_OSM_NODE_REF_LIST_HPP
+#define OSMIUM_OSM_NODE_REF_LIST_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 <cstddef>
+#include <iterator>
+
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/node_ref.hpp>
+
+namespace osmium {
+
+ /**
+ * A vector of NodeRef objects. Usually this is not instatiated 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) {
+ }
+
+ bool empty() const noexcept {
+ return sizeof(NodeRefList) == byte_size();
+ }
+
+ 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 {
+ const NodeRef* node_ref = &*(cbegin());
+ return node_ref[n];
+ }
+
+ const NodeRef& front() const {
+ return operator[](0);
+ }
+
+ const NodeRef& back() const {
+ return operator[](size()-1);
+ }
+
+ bool is_closed() const {
+ return front().ref() == back().ref();
+ }
+
+ bool ends_have_same_id() const {
+ return front().ref() == back().ref();
+ }
+
+ bool ends_have_same_location() const {
+ return front().location() == back().location();
+ }
+
+ typedef NodeRef* iterator;
+ typedef const NodeRef* const_iterator;
+ typedef std::reverse_iterator<const NodeRef*> const_reverse_iterator;
+
+ iterator begin() {
+ return iterator(data() + sizeof(NodeRefList));
+ }
+
+ iterator end() {
+ return iterator(data() + byte_size());
+ }
+
+ const_iterator cbegin() const {
+ return const_iterator(data() + sizeof(NodeRefList));
+ }
+
+ const_iterator cend() const {
+ return const_iterator(data() + byte_size());
+ }
+
+ const_iterator begin() const {
+ return cbegin();
+ }
+
+ const_iterator end() const {
+ return cend();
+ }
+
+ const_reverse_iterator crbegin() const {
+ return const_reverse_iterator(cend());
+ }
+
+ const_reverse_iterator crend() const {
+ return const_reverse_iterator(cbegin());
+ }
+
+ }; // class NodeRefList
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_NODE_REF_LIST_HPP
diff --git a/third_party/osmium/osm/object.hpp b/third_party/osmium/osm/object.hpp
new file mode 100644
index 0000000..9c4d603
--- /dev/null
+++ b/third_party/osmium/osm/object.hpp
@@ -0,0 +1,437 @@
+#ifndef OSMIUM_OSM_OBJECT_HPP
+#define OSMIUM_OSM_OBJECT_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 <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <stdexcept>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/memory/item_iterator.hpp>
+#include <osmium/osm/entity.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+ /**
+ * OSMObject (Node, Way, Relation, or Area).
+ */
+ class OSMObject : public osmium::OSMEntity {
+
+ object_id_type m_id;
+ bool m_deleted : 1;
+ object_version_type m_version : 31;
+ osmium::Timestamp m_timestamp;
+ user_id_type m_uid;
+ changeset_id_type m_changeset;
+
+ size_t sizeof_object() const noexcept {
+ return sizeof(OSMObject) + (type() == item_type::node ? sizeof(osmium::Location) : 0) + sizeof(string_size_type);
+ }
+
+ unsigned char* user_position() noexcept {
+ return data() + sizeof_object() - sizeof(string_size_type);
+ }
+
+ const unsigned char* user_position() const noexcept {
+ return data() + sizeof_object() - sizeof(string_size_type);
+ }
+
+ string_size_type user_size() const noexcept {
+ return *reinterpret_cast<const string_size_type*>(user_position());
+ }
+
+ unsigned char* subitems_position() {
+ return data() + osmium::memory::padded_length(sizeof_object() + user_size());
+ }
+
+ const unsigned char* subitems_position() const {
+ return data() + osmium::memory::padded_length(sizeof_object() + user_size());
+ }
+
+ protected:
+
+ OSMObject(osmium::memory::item_size_type size, osmium::item_type type) :
+ OSMEntity(size, type),
+ m_id(0),
+ m_deleted(false),
+ m_version(0),
+ m_timestamp(),
+ m_uid(0),
+ m_changeset(0) {
+ }
+
+ void set_user_size(string_size_type size) {
+ *reinterpret_cast<string_size_type*>(user_position()) = size;
+ }
+
+ public:
+
+ /// Get ID of this object.
+ object_id_type id() const noexcept {
+ return m_id;
+ }
+
+ /// Get absolute value of the ID of this object.
+ unsigned_object_id_type positive_id() const noexcept {
+ return static_cast<unsigned_object_id_type>(std::abs(m_id));
+ }
+
+ /**
+ * Set ID of this object.
+ *
+ * @returns Reference to object to make calls chainable.
+ */
+ OSMObject& set_id(object_id_type id) noexcept {
+ m_id = id;
+ return *this;
+ }
+
+ /**
+ * Set ID of this object.
+ *
+ * @returns Reference to object to make calls chainable.
+ */
+ OSMObject& set_id(const char* id) {
+ return set_id(osmium::string_to_object_id(id));
+ }
+
+ /// Is this object marked as deleted?
+ bool deleted() const noexcept {
+ return m_deleted;
+ }
+
+ /// Is this object marked visible (ie not deleted)?
+ bool visible() const noexcept {
+ return !deleted();
+ }
+
+ /**
+ * Mark this object as deleted (or not).
+ *
+ * @returns Reference to object to make calls chainable.
+ */
+ OSMObject& set_deleted(bool deleted) noexcept {
+ m_deleted = deleted;
+ return *this;
+ }
+
+ /**
+ * Mark this object as visible (ie not deleted) (or not).
+ *
+ * @returns Reference to object to make calls chainable.
+ */
+ OSMObject& set_visible(bool visible) noexcept {
+ m_deleted = !visible;
+ return *this;
+ }
+
+ /**
+ * Mark this object as visible (ie not deleted) or deleted.
+ *
+ * @param visible Either "true" or "false"
+ * @returns Reference to object to make calls chainable.
+ */
+ OSMObject& set_visible(const char* visible) {
+ if (!strcmp("true", visible)) {
+ set_visible(true);
+ } else if (!strcmp("false", visible)) {
+ set_visible(false);
+ } else {
+ throw std::invalid_argument("Unknown value for visible attribute (allowed is 'true' or 'false')");
+ }
+ return *this;
+ }
+
+ /// Get version of this object.
+ object_version_type version() const noexcept {
+ return m_version;
+ }
+
+ /**
+ * Set object version.
+ *
+ * @returns Reference to object to make calls chainable.
+ */
+ OSMObject& set_version(object_version_type version) noexcept {
+ m_version = version;
+ return *this;
+ }
+
+ /**
+ * Set object version.
+ *
+ * @returns Reference to object to make calls chainable.
+ */
+ OSMObject& set_version(const char* version) {
+ return set_version(string_to_object_version(version));
+ }
+
+ /// Get changeset id of this object.
+ changeset_id_type changeset() const noexcept {
+ return m_changeset;
+ }
+
+ /**
+ * Set changeset id of this object.
+ *
+ * @returns Reference to object to make calls chainable.
+ */
+ OSMObject& set_changeset(changeset_id_type changeset) noexcept {
+ m_changeset = changeset;
+ return *this;
+ }
+
+ /**
+ * Set changeset id of this object.
+ *
+ * @returns Reference to object to make calls chainable.
+ */
+ OSMObject& set_changeset(const char* changeset) {
+ return set_changeset(string_to_changeset_id(changeset));
+ }
+
+ /// Get user id of this object.
+ user_id_type uid() const noexcept {
+ return m_uid;
+ }
+
+ /**
+ * Set user id of this object.
+ *
+ * @returns Reference to object to make calls chainable.
+ */
+ OSMObject& set_uid(user_id_type uid) noexcept {
+ m_uid = uid;
+ return *this;
+ }
+
+ /**
+ * Set user id of this object.
+ * Sets uid to 0 (anonymous) if the given uid is smaller than 0.
+ *
+ * @returns Reference to object to make calls chainable.
+ */
+ OSMObject& set_uid_from_signed(signed_user_id_type uid) noexcept {
+ m_uid = uid < 0 ? 0 : static_cast<user_id_type>(uid);
+ return *this;
+ }
+
+ /**
+ * Set user id of this object.
+ *
+ * @returns Reference to object to make calls chainable.
+ */
+ OSMObject& set_uid(const char* uid) {
+ return set_uid_from_signed(string_to_user_id(uid));
+ }
+
+ /// Is this user anonymous?
+ bool user_is_anonymous() const noexcept {
+ return m_uid == 0;
+ }
+
+ /// Get timestamp when this object last changed.
+ osmium::Timestamp timestamp() const noexcept {
+ return m_timestamp;
+ }
+
+ /**
+ * Set the timestamp when this object last changed.
+ *
+ * @param timestamp Timestamp
+ * @returns Reference to object to make calls chainable.
+ */
+ OSMObject& set_timestamp(const osmium::Timestamp timestamp) noexcept {
+ m_timestamp = timestamp;
+ return *this;
+ }
+
+ /// Get user name for this object.
+ const char* user() const noexcept {
+ return reinterpret_cast<const char*>(data() + sizeof_object());
+ }
+
+ /// Get the list of tags for this object.
+ const TagList& tags() const {
+ return osmium::detail::subitem_of_type<const TagList>(cbegin(), cend());
+ }
+
+ /**
+ * Get tag value by key.
+ *
+ * Convenience function that will forward to same function on TagList
+ * object.
+ */
+ const char* get_value_by_key(const char* key, const char* default_value = nullptr) const noexcept {
+ return tags().get_value_by_key(key, default_value);
+ }
+
+ /**
+ * Set named attribute.
+ *
+ * @param attr Name of the attribute (must be one of "id", "version", "changeset", "timestamp", "uid", "visible")
+ * @param value Value of the attribute
+ */
+ void set_attribute(const char* attr, const char* value) {
+ if (!strcmp(attr, "id")) {
+ set_id(value);
+ } else if (!strcmp(attr, "version")) {
+ set_version(value);
+ } else if (!strcmp(attr, "changeset")) {
+ set_changeset(value);
+ } else if (!strcmp(attr, "timestamp")) {
+ set_timestamp(osmium::Timestamp(value));
+ } else if (!strcmp(attr, "uid")) {
+ set_uid(value);
+ } else if (!strcmp(attr, "visible")) {
+ set_visible(value);
+ }
+ }
+
+ typedef osmium::memory::CollectionIterator<Item> iterator;
+ typedef osmium::memory::CollectionIterator<const Item> const_iterator;
+
+ iterator begin() {
+ return iterator(subitems_position());
+ }
+
+ iterator end() {
+ return iterator(next());
+ }
+
+ const_iterator cbegin() const {
+ return const_iterator(subitems_position());
+ }
+
+ const_iterator cend() const {
+ return const_iterator(next());
+ }
+
+ const_iterator begin() const {
+ return cbegin();
+ }
+
+ const_iterator end() const {
+ return cend();
+ }
+
+ template <class T>
+ using t_iterator = osmium::memory::ItemIterator<T>;
+
+ template <class T>
+ using t_const_iterator = osmium::memory::ItemIterator<const T>;
+
+ template <class T>
+ t_iterator<T> begin() {
+ return t_iterator<T>(subitems_position(), next());
+ }
+
+ template <class T>
+ t_iterator<T> end() {
+ return t_iterator<T>(next(), next());
+ }
+
+ template <class T>
+ t_const_iterator<T> cbegin() const {
+ return t_const_iterator<T>(subitems_position(), next());
+ }
+
+ template <class T>
+ t_const_iterator<T> cend() const {
+ return t_const_iterator<T>(next(), next());
+ }
+
+ template <class T>
+ t_const_iterator<T> begin() const {
+ return cbegin<T>();
+ }
+
+ template <class T>
+ t_const_iterator<T> end() const {
+ return cend<T>();
+ }
+
+ }; // class OSMObject
+
+ static_assert(sizeof(OSMObject) % osmium::memory::align_bytes == 0, "Class osmium::OSMObject has wrong size to be aligned properly!");
+
+ /**
+ * OSMObjects are equal if their type, id, and version are equal.
+ */
+ inline bool operator==(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+ return lhs.type() == rhs.type() &&
+ lhs.id() == rhs.id() &&
+ lhs.version() == rhs.version();
+ }
+
+ inline bool operator!=(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+ return ! (lhs == rhs);
+ }
+
+ /**
+ * OSMObjects can be ordered by type, id and version.
+ * Note that we use the absolute value of the id for a
+ * better ordering of objects with negative id.
+ */
+ inline bool operator<(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+ if (lhs.type() != rhs.type()) {
+ return lhs.type() < rhs.type();
+ }
+ return (lhs.id() == rhs.id() && lhs.version() < rhs.version()) ||
+ lhs.positive_id() < rhs.positive_id();
+ }
+
+ inline bool operator>(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+ return rhs < lhs;
+ }
+
+ inline bool operator<=(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+ return ! (rhs < lhs);
+ }
+
+ inline bool operator>=(const OSMObject& lhs, const OSMObject& rhs) noexcept {
+ return ! (lhs < rhs);
+ }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_OBJECT_HPP
diff --git a/third_party/osmium/osm/object_comparisons.hpp b/third_party/osmium/osm/object_comparisons.hpp
new file mode 100644
index 0000000..db11b0d
--- /dev/null
+++ b/third_party/osmium/osm/object_comparisons.hpp
@@ -0,0 +1,110 @@
+#ifndef OSMIUM_OSM_OBJECT_COMPARISONS_HPP
+#define OSMIUM_OSM_OBJECT_COMPARISONS_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 <osmium/osm/object.hpp>
+
+namespace osmium {
+
+ /**
+ * Function object class for comparing OSM objects for equality by type, id, and version.
+ */
+ struct object_equal_type_id_version {
+
+ bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
+ return lhs == rhs;
+ }
+
+ bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
+ return *lhs == *rhs;
+ }
+
+ }; // struct object_equal_type_id_version
+
+ /**
+ * Function object class for comparing OSM objects for equality by type and id,
+ * ignoring the version.
+ */
+ struct object_equal_type_id {
+
+ bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
+ return lhs.type() == rhs.type() &&
+ lhs.id() == rhs.id();
+ }
+
+ bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
+ return operator()(*lhs, *rhs);
+ }
+
+ }; // struct object_equal_type_id
+
+ /**
+ * Function object class for ordering OSM objects by type, id, and version.
+ */
+ struct object_order_type_id_version {
+
+ bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
+ return lhs < rhs;
+ }
+
+ bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
+ return *lhs < *rhs;
+ }
+
+ }; // struct object_order_type_id_version
+
+ /**
+ * Function object class for ordering OSM objects by type, id, and reverse version,
+ * ie objects are ordered by type and id, but later versions of an object are
+ * ordered before earlier versions of the same object.
+ */
+ struct object_order_type_id_reverse_version {
+
+ bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
+ if (lhs.type() != rhs.type()) {
+ return lhs.type() < rhs.type();
+ }
+ return (lhs.id() == rhs.id() && lhs.version() > rhs.version()) ||
+ lhs.positive_id() < rhs.positive_id();
+ }
+
+ bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
+ return operator()(*lhs, *rhs);
+ }
+
+ }; // struct object_order_type_id_reverse_version
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_OBJECT_COMPARISONS_HPP
diff --git a/third_party/osmium/osm/relation.hpp b/third_party/osmium/osm/relation.hpp
new file mode 100644
index 0000000..f5d0401
--- /dev/null
+++ b/third_party/osmium/osm/relation.hpp
@@ -0,0 +1,189 @@
+#ifndef OSMIUM_OSM_RELATION_HPP
+#define OSMIUM_OSM_RELATION_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 <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <iterator>
+
+#include <osmium/memory/collection.hpp> // IWYU pragma: keep
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+ namespace builder {
+ template <class> class ObjectBuilder;
+ class RelationMemberListBuilder;
+ }
+
+ class RelationMember : public osmium::memory::detail::ItemHelper {
+
+ friend class osmium::builder::RelationMemberListBuilder;
+
+ object_id_type m_ref;
+ item_type m_type;
+ uint16_t m_flags;
+ string_size_type m_role_size {0};
+
+ RelationMember(const RelationMember&) = delete;
+ RelationMember(RelationMember&&) = delete;
+
+ RelationMember& operator=(const RelationMember&) = delete;
+ RelationMember& operator=(RelationMember&&) = delete;
+
+ unsigned char* endpos() {
+ return data() + osmium::memory::padded_length(sizeof(RelationMember) + m_role_size);
+ }
+
+ const unsigned char* endpos() const {
+ return data() + osmium::memory::padded_length(sizeof(RelationMember) + m_role_size);
+ }
+
+ template <class TMember>
+ friend class osmium::memory::CollectionIterator;
+
+ unsigned char* next() {
+ if (full_member()) {
+ return endpos() + reinterpret_cast<osmium::memory::Item*>(endpos())->byte_size();
+ } else {
+ return endpos();
+ }
+ }
+
+ unsigned const char* next() const {
+ if (full_member()) {
+ return endpos() + reinterpret_cast<const osmium::memory::Item*>(endpos())->byte_size();
+ } else {
+ return endpos();
+ }
+ }
+
+ void set_role_size(string_size_type size) noexcept {
+ m_role_size = size;
+ }
+
+ public:
+
+ 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 :
+ m_ref(ref),
+ m_type(type),
+ m_flags(full ? 1 : 0) {
+ }
+
+ object_id_type ref() const noexcept {
+ return m_ref;
+ }
+
+ RelationMember& ref(object_id_type ref) noexcept {
+ m_ref = ref;
+ return *this;
+ }
+
+ unsigned_object_id_type positive_ref() const noexcept {
+ return static_cast<unsigned_object_id_type>(std::abs(m_ref));
+ }
+
+ item_type type() const noexcept {
+ return m_type;
+ }
+
+ bool full_member() const noexcept {
+ return m_flags == 1;
+ }
+
+ const char* role() const noexcept {
+ return reinterpret_cast<const char*>(data() + sizeof(RelationMember));
+ }
+
+ OSMObject& get_object() {
+ return *reinterpret_cast<OSMObject*>(endpos());
+ }
+
+ const OSMObject& get_object() const {
+ return *reinterpret_cast<const OSMObject*>(endpos());
+ }
+
+ }; // class RelationMember
+
+ class RelationMemberList : public osmium::memory::Collection<RelationMember, osmium::item_type::relation_member_list> {
+
+ public:
+
+ typedef size_t size_type;
+
+ RelationMemberList() :
+ osmium::memory::Collection<RelationMember, osmium::item_type::relation_member_list>() {
+ }
+
+ size_type size() const noexcept {
+ return static_cast<size_type>(std::distance(begin(), end()));
+ }
+
+ }; // class RelationMemberList
+
+ static_assert(sizeof(RelationMemberList) % osmium::memory::align_bytes == 0, "Class osmium::RelationMemberList has wrong size to be aligned properly!");
+
+ class Relation : public OSMObject {
+
+ friend class osmium::builder::ObjectBuilder<osmium::Relation>;
+
+ Relation() noexcept :
+ OSMObject(sizeof(Relation), osmium::item_type::relation) {
+ }
+
+ public:
+
+ static constexpr osmium::item_type itemtype = osmium::item_type::relation;
+
+ RelationMemberList& members() {
+ return osmium::detail::subitem_of_type<RelationMemberList>(begin(), end());
+ }
+
+ const RelationMemberList& members() const {
+ return osmium::detail::subitem_of_type<const RelationMemberList>(cbegin(), cend());
+ }
+
+ }; // class Relation
+
+ static_assert(sizeof(Relation) % osmium::memory::align_bytes == 0, "Class osmium::Relation has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_RELATION_HPP
diff --git a/third_party/osmium/osm/segment.hpp b/third_party/osmium/osm/segment.hpp
new file mode 100644
index 0000000..205036e
--- /dev/null
+++ b/third_party/osmium/osm/segment.hpp
@@ -0,0 +1,105 @@
+#ifndef OSMIUM_OSM_SEGMENT_HPP
+#define OSMIUM_OSM_SEGMENT_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 <iosfwd>
+#include <utility>
+
+#include <osmium/osm/location.hpp>
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+ /**
+ * A Segment is the directed connection between two Locations.
+ */
+ class Segment {
+
+ osmium::Location m_first;
+ osmium::Location m_second;
+
+ public:
+
+ explicit constexpr Segment(const osmium::Location& location1, const osmium::Location& location2) noexcept :
+ m_first(location1),
+ m_second(location2) {
+ }
+
+ constexpr Segment(const Segment&) = default;
+ constexpr Segment(Segment&&) = default;
+
+ Segment& operator=(const Segment&) = default;
+ Segment& operator=(Segment&&) = default;
+
+ ~Segment() = default;
+
+ /// Return first Location of Segment.
+ OSMIUM_CONSTEXPR osmium::Location first() const noexcept {
+ return m_first;
+ }
+
+ /// Return second Location of Segment.
+ OSMIUM_CONSTEXPR osmium::Location second() const noexcept {
+ return m_second;
+ }
+
+ protected:
+
+ void swap_locations() {
+ using std::swap;
+ swap(m_first, m_second);
+ }
+
+ }; // class Segment
+
+ /// Segments are equal if both their locations are equal
+ inline OSMIUM_CONSTEXPR bool operator==(const Segment& lhs, const Segment& rhs) noexcept {
+ return lhs.first() == rhs.first() && lhs.second() == rhs.second();
+ }
+
+ inline OSMIUM_CONSTEXPR bool operator!=(const Segment& lhs, const Segment& rhs) noexcept {
+ return ! (lhs == rhs);
+ }
+
+ /**
+ * Output Segment to a stream.
+ */
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Segment& segment) {
+ return out << segment.first() << "->" << segment.second();
+ }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_SEGMENT_HPP
diff --git a/third_party/osmium/osm/tag.hpp b/third_party/osmium/osm/tag.hpp
new file mode 100644
index 0000000..fe80de3
--- /dev/null
+++ b/third_party/osmium/osm/tag.hpp
@@ -0,0 +1,140 @@
+#ifndef OSMIUM_OSM_TAG_HPP
+#define OSMIUM_OSM_TAG_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 <algorithm>
+#include <cstddef>
+#include <cstring>
+#include <iosfwd>
+#include <iterator>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+ class Tag : public osmium::memory::detail::ItemHelper {
+
+ Tag(const Tag&) = delete;
+ Tag(Tag&&) = delete;
+
+ Tag& operator=(const Tag&) = delete;
+ Tag& operator=(Tag&&) = delete;
+
+ template <class TMember>
+ friend class osmium::memory::CollectionIterator;
+
+ static unsigned char* after_null(unsigned char* ptr) {
+ return reinterpret_cast<unsigned char*>(std::strchr(reinterpret_cast<char*>(ptr), 0) + 1);
+ }
+
+ static const unsigned char* after_null(const unsigned char* ptr) {
+ return reinterpret_cast<const unsigned char*>(std::strchr(reinterpret_cast<const char*>(ptr), 0) + 1);
+ }
+
+ unsigned char* next() {
+ return after_null(after_null(data()));
+ }
+
+ const unsigned char* next() const {
+ return after_null(after_null(data()));
+ }
+
+ public:
+
+ static constexpr item_type collection_type = item_type::tag_list;
+
+ const char* key() const noexcept {
+ return reinterpret_cast<const char*>(data());
+ }
+
+ const char* value() const {
+ return reinterpret_cast<const char*>(after_null(data()));
+ }
+
+ }; // class Tag
+
+ inline bool operator==(const Tag& a, const Tag& b) {
+ return !std::strcmp(a.key(), b.key()) && !strcmp(a.value(), b.value());
+ }
+
+ inline bool operator<(const Tag& a, const Tag& b) {
+ return (!std::strcmp(a.key(), b.key()) && (std::strcmp(a.value(), b.value()) < 0)) || (std::strcmp(a.key(), b.key()) < 0);
+ }
+
+ /**
+ * Output a Tag to a stream.
+ */
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const Tag& tag) {
+ return out << tag.key() << '=' << tag.value();
+ }
+
+ class TagList : public osmium::memory::Collection<Tag, osmium::item_type::tag_list> {
+
+ public:
+
+ typedef size_t size_type;
+
+ TagList() :
+ osmium::memory::Collection<Tag, osmium::item_type::tag_list>() {
+ }
+
+ size_type size() const noexcept {
+ return static_cast<size_type>(std::distance(begin(), end()));
+ }
+
+ const char* get_value_by_key(const char* key, const char* default_value = nullptr) const noexcept {
+ auto result = std::find_if(cbegin(), cend(), [key](const Tag& tag) {
+ return !strcmp(tag.key(), key);
+ });
+ if (result == cend()) {
+ return default_value;
+ } else {
+ return result->value();
+ }
+ }
+
+ const char* operator[](const char* key) const noexcept {
+ return get_value_by_key(key);
+ }
+
+ }; // class TagList
+
+ static_assert(sizeof(TagList) % osmium::memory::align_bytes == 0, "Class osmium::TagList has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_TAG_HPP
diff --git a/third_party/osmium/osm/timestamp.hpp b/third_party/osmium/osm/timestamp.hpp
new file mode 100644
index 0000000..662b61f
--- /dev/null
+++ b/third_party/osmium/osm/timestamp.hpp
@@ -0,0 +1,169 @@
+#ifndef OSMIUM_OSM_TIMESTAMP_HPP
+#define OSMIUM_OSM_TIMESTAMP_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 <cstdint>
+#include <ctime>
+#include <iosfwd>
+#include <limits>
+#include <stdexcept>
+#include <string>
+#include <time.h>
+
+#include <osmium/util/compatibility.hpp>
+
+namespace osmium {
+
+ /**
+ * A timestamp. Internal representation is an unsigned 32bit integer
+ * holding seconds since epoch, so this will overflow in 2038.
+ */
+ class Timestamp {
+
+ // length of ISO timestamp string yyyy-mm-ddThh:mm:ssZ\0
+ static constexpr int timestamp_length = 20 + 1;
+
+ /**
+ * The timestamp format for OSM timestamps in strftime(3) format.
+ * This is the ISO-Format yyyy-mm-ddThh:mm:ssZ
+ */
+ static const char* timestamp_format() {
+ static const char f[timestamp_length] = "%Y-%m-%dT%H:%M:%SZ";
+ return f;
+ }
+
+ uint32_t m_timestamp;
+
+ public:
+
+ constexpr Timestamp() noexcept :
+ m_timestamp(0) {
+ }
+
+ // Not "explicit" so that conversions from time_t work
+ // like in node.timestamp(123);
+ constexpr Timestamp(time_t timestamp) noexcept :
+ m_timestamp(static_cast<uint32_t>(timestamp)) {
+ }
+
+ /**
+ * Construct timestamp from ISO date/time string.
+ * Throws std::invalid_argument, if the timestamp can not be parsed.
+ */
+ explicit Timestamp(const char* timestamp) {
+#ifndef _WIN32
+ struct tm tm {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ if (strptime(timestamp, timestamp_format(), &tm) == nullptr) {
+ throw std::invalid_argument("can't parse timestamp");
+ }
+ m_timestamp = static_cast<uint32_t>(timegm(&tm));
+#else
+ struct tm tm;
+ int n = sscanf(timestamp, "%4d-%2d-%2dT%2d:%2d:%2dZ", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+ if (n != 6) {
+ throw std::invalid_argument("can't parse timestamp");
+ }
+ tm.tm_year -= 1900;
+ tm.tm_mon--;
+ tm.tm_wday = 0;
+ tm.tm_yday = 0;
+ tm.tm_isdst = 0;
+ m_timestamp = _mkgmtime(&tm);
+#endif
+ }
+
+ constexpr time_t seconds_since_epoch() const noexcept {
+ return static_cast<time_t>(m_timestamp);
+ }
+
+ constexpr operator time_t() const noexcept {
+ return static_cast<time_t>(m_timestamp);
+ }
+
+ template <typename T>
+ void operator+=(T time_difference) noexcept {
+ m_timestamp += time_difference;
+ }
+
+ template <typename T>
+ void operator-=(T time_difference) noexcept {
+ m_timestamp -= time_difference;
+ }
+
+ /**
+ * 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();
+#ifndef _MSC_VER
+ gmtime_r(&sse, &tm);
+#else
+ 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));
+ return s;
+ }
+
+ }; // class Timestamp
+
+ inline OSMIUM_CONSTEXPR Timestamp start_of_time() noexcept {
+ return Timestamp(1);
+ }
+
+ inline OSMIUM_CONSTEXPR Timestamp end_of_time() noexcept {
+ return Timestamp(std::numeric_limits<time_t>::max());
+ }
+
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, Timestamp timestamp) {
+ out << timestamp.to_iso();
+ return out;
+ }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_TIMESTAMP_HPP
diff --git a/third_party/osmium/osm/types.hpp b/third_party/osmium/osm/types.hpp
new file mode 100644
index 0000000..532b549
--- /dev/null
+++ b/third_party/osmium/osm/types.hpp
@@ -0,0 +1,83 @@
+#ifndef OSMIUM_OSM_TYPES_HPP
+#define OSMIUM_OSM_TYPES_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 <cstdint>
+#include <cstdlib>
+
+namespace osmium {
+
+ /*
+ * The following typedefs are chosen so that they can represent all needed
+ * numbers and still be reasonably space efficient. As the OSM database
+ * needs 64 bit IDs for nodes, this size is used for all object IDs.
+ */
+ typedef int64_t object_id_type; ///< Type for OSM object (node, way, or relation) IDs.
+ typedef uint64_t unsigned_object_id_type; ///< Type for OSM object (node, way, or relation) IDs where we only allow positive IDs.
+ typedef uint32_t object_version_type; ///< Type for OSM object version number.
+ typedef uint32_t changeset_id_type; ///< Type for OSM changeset IDs.
+ typedef uint32_t user_id_type; ///< Type for OSM user IDs.
+ typedef int32_t signed_user_id_type; ///< Type for signed OSM user IDs.
+ typedef uint32_t num_changes_type; ///< Type for changeset num_changes.
+
+ /**
+ * Size for strings in OSM data such as user names, tag keys, roles, etc.
+ * In Osmium they can be up to 2^16 bytes long, but OSM usually has lower
+ * defined limits.
+ */
+ typedef uint16_t string_size_type;
+
+ inline object_id_type string_to_object_id(const char* string) {
+ return std::atoll(string);
+ }
+
+ inline object_version_type string_to_object_version(const char* string) {
+ return static_cast<object_version_type>(std::atol(string));
+ }
+
+ inline changeset_id_type string_to_changeset_id(const char* string) {
+ return static_cast<changeset_id_type>(std::atol(string));
+ }
+
+ inline signed_user_id_type string_to_user_id(const char* string) {
+ return static_cast<signed_user_id_type>(std::atol(string));
+ }
+
+ inline num_changes_type string_to_num_changes(const char* string) {
+ return static_cast<num_changes_type>(std::atol(string));
+ }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_TYPES_HPP
diff --git a/third_party/osmium/osm/undirected_segment.hpp b/third_party/osmium/osm/undirected_segment.hpp
new file mode 100644
index 0000000..487e7bf
--- /dev/null
+++ b/third_party/osmium/osm/undirected_segment.hpp
@@ -0,0 +1,100 @@
+#ifndef OSMIUM_OSM_UNDIRECTED_SEGMENT_HPP
+#define OSMIUM_OSM_UNDIRECTED_SEGMENT_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 <iosfwd>
+
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/segment.hpp>
+
+namespace osmium {
+
+ /**
+ * Undirected connection between two Locations. The first Location is
+ * always equal or "smaller" than the second Location, ie to the left
+ * and down.
+ */
+ class UndirectedSegment : public Segment {
+
+ public:
+
+ explicit UndirectedSegment(const osmium::Location& location1, const osmium::Location& location2) :
+ Segment(location1, location2) {
+ if (location2 < location1) {
+ swap_locations();
+ }
+ }
+
+ UndirectedSegment(const UndirectedSegment&) = default;
+ UndirectedSegment(UndirectedSegment&&) = default;
+
+ UndirectedSegment& operator=(const UndirectedSegment&) = default;
+ UndirectedSegment& operator=(UndirectedSegment&&) = default;
+
+ ~UndirectedSegment() = default;
+
+ }; // class UndirectedSegment
+
+ /**
+ * UndirectedSegments are "smaller" if they are to the left and down of another
+ * segment. The first() location is checked first() and only if they have the
+ * same first() location the second() location is taken into account.
+ */
+ inline bool operator<(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
+ return (lhs.first() == rhs.first() && lhs.second() < rhs.second()) || lhs.first() < rhs.first();
+ }
+
+ inline bool operator>(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
+ return rhs < lhs;
+ }
+
+ inline bool operator<=(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
+ return ! (rhs < lhs);
+ }
+
+ inline bool operator>=(const UndirectedSegment& lhs, const UndirectedSegment& rhs) noexcept {
+ return ! (lhs < rhs);
+ }
+
+ /**
+ * Output UndirectedSegment to a stream.
+ */
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::UndirectedSegment& segment) {
+ return out << segment.first() << "--" << segment.second();
+ }
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_UNDIRECTED_SEGMENT_HPP
diff --git a/third_party/osmium/osm/way.hpp b/third_party/osmium/osm/way.hpp
new file mode 100644
index 0000000..a30cf91
--- /dev/null
+++ b/third_party/osmium/osm/way.hpp
@@ -0,0 +1,115 @@
+#ifndef OSMIUM_OSM_WAY_HPP
+#define OSMIUM_OSM_WAY_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 <osmium/memory/item.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/node_ref_list.hpp>
+
+namespace osmium {
+
+ namespace builder {
+ template <class T> class ObjectBuilder;
+ }
+
+ /**
+ * List of node references (id and location) in a way.
+ */
+ class WayNodeList : public NodeRefList<osmium::item_type::way_node_list> {
+
+ public:
+
+ WayNodeList():
+ NodeRefList<osmium::item_type::way_node_list>() {
+ }
+
+ }; // class WayNodeList
+
+ static_assert(sizeof(WayNodeList) % osmium::memory::align_bytes == 0, "Class osmium::WayNodeList has wrong size to be aligned properly!");
+
+ class Way : public OSMObject {
+
+ friend class osmium::builder::ObjectBuilder<osmium::Way>;
+
+ Way() noexcept :
+ OSMObject(sizeof(Way), osmium::item_type::way) {
+ }
+
+ public:
+
+ WayNodeList& nodes() {
+ return osmium::detail::subitem_of_type<WayNodeList>(begin(), end());
+ }
+
+ const WayNodeList& nodes() const {
+ return osmium::detail::subitem_of_type<const WayNodeList>(cbegin(), cend());
+ }
+
+ /**
+ * Update all nodes in a way with the ID of the given NodeRef with the
+ * location of the given NodeRef.
+ */
+ void update_node_location(const NodeRef& new_node_ref) {
+ for (auto& node_ref : nodes()) {
+ if (node_ref.ref() == new_node_ref.ref()) {
+ node_ref.set_location(new_node_ref.location());
+ }
+ }
+ }
+
+ /**
+ * Do the nodes in this way form a closed ring?
+ */
+ bool is_closed() const {
+ return nodes().is_closed();
+ }
+
+ bool ends_have_same_id() const {
+ return nodes().ends_have_same_id();
+ }
+
+ bool ends_have_same_location() const {
+ return nodes().ends_have_same_location();
+ }
+
+ }; // class Way
+
+ static_assert(sizeof(Way) % osmium::memory::align_bytes == 0, "Class osmium::Way has wrong size to be aligned properly!");
+
+} // namespace osmium
+
+#endif // OSMIUM_OSM_WAY_HPP
diff --git a/third_party/osmium/relations/collector.hpp b/third_party/osmium/relations/collector.hpp
new file mode 100644
index 0000000..60864d3
--- /dev/null
+++ b/third_party/osmium/relations/collector.hpp
@@ -0,0 +1,544 @@
+#ifndef OSMIUM_RELATIONS_COLLECTOR_HPP
+#define OSMIUM_RELATIONS_COLLECTOR_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 <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <iomanip>
+#include <iostream>
+#include <vector>
+
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp> // IWYU pragma: keep
+#include <osmium/osm/types.hpp>
+#include <osmium/handler.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/visitor.hpp>
+
+#include <osmium/relations/detail/relation_meta.hpp>
+#include <osmium/relations/detail/member_meta.hpp>
+
+namespace osmium {
+
+ class Node;
+ class Way;
+
+ /**
+ * @brief Code related to the assembly of OSM relations
+ */
+ namespace relations {
+
+ /**
+ * The Collector class collects members of a relation. This is a generic
+ * base class that can be used to assemble all kinds of relations. It has numerous
+ * hooks you can implement in derived classes to customize its behaviour.
+ *
+ * The collector provides two handlers (HandlerPass1 and HandlerPass2) for a first
+ * and second pass through an input file, respectively. In the first pass all
+ * relations we are interested in are stored in RelationMeta objects in the
+ * m_relations vector. All members we are interested in are stored in MemberMeta
+ * objects in the m_member_meta vectors.
+ * The MemberMeta objects also store the information where the relations containing
+ * those members are to be found.
+ *
+ * Later the m_member_meta vectors are sorted according to the
+ * member ids so that a binary search (with std::equal_range) can be used in the second
+ * pass to find the parent relations for each node, way, or relation coming along.
+ * The member objects are stored together with their relation and once a relation
+ * is complete the complete_relation() method is called which you must overwrite in
+ * a derived class of Collector.
+ *
+ * @tparam TCollector Derived class of this class.
+ *
+ * @tparam TNodes Are we interested in member nodes?
+ *
+ * @tparam TWays Are we interested in member ways?
+ *
+ * @tparam TRelations Are we interested in member relations?
+ */
+ template <class TCollector, bool TNodes, bool TWays, bool TRelations>
+ class Collector {
+
+ /**
+ * This is the handler class for the first pass of the Collector.
+ */
+ class HandlerPass1 : public osmium::handler::Handler {
+
+ TCollector& m_collector;
+
+ public:
+
+ HandlerPass1(TCollector& collector) noexcept :
+ m_collector(collector) {
+ }
+
+ void relation(const osmium::Relation& relation) {
+ if (m_collector.keep_relation(relation)) {
+ m_collector.add_relation(relation);
+ }
+ }
+
+ }; // class HandlerPass1
+
+ public:
+
+ /**
+ * This is the handler class for the second pass of the Collector.
+ */
+ class HandlerPass2 : public osmium::handler::Handler {
+
+ TCollector& m_collector;
+
+ /**
+ * This variable is initialized with the number of different
+ * kinds of OSM objects we are interested in. If we only need
+ * way members (for instance for the multipolygon collector)
+ * it is intialized with 1 for instance. If node and way
+ * members are needed, it is initialized with 2.
+ *
+ * In the after_* methods of this handler, it is decremented
+ * and once it reaches 0, we know we have all members available
+ * that we are ever going to get.
+ */
+ int m_want_types;
+
+ /**
+ * Find this object in the member vectors and add it to all
+ * relations that need it.
+ *
+ * @returns true if the member was added to at least one
+ * relation and false otherwise
+ */
+ bool find_and_add_object(const osmium::OSMObject& object) {
+ auto& mmv = m_collector.member_meta(object.type());
+ auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(object.id()));
+
+ if (osmium::relations::count_not_removed(range.first, range.second) == 0) {
+ // nothing found
+ return false;
+ }
+
+ {
+ m_collector.members_buffer().add_item(object);
+ const size_t member_offset = m_collector.members_buffer().commit();
+
+ for (auto it = range.first; it != range.second; ++it) {
+ it->set_buffer_offset(member_offset);
+ }
+ }
+
+ for (auto it = range.first; it != range.second; ++it) {
+ MemberMeta& member_meta = *it;
+ if (member_meta.removed()) {
+ break;
+ }
+ assert(member_meta.member_id() == object.id());
+ assert(member_meta.relation_pos() < m_collector.m_relations.size());
+ RelationMeta& relation_meta = m_collector.m_relations[member_meta.relation_pos()];
+// std::cerr << " => " << member_meta.member_pos() << " < " << m_collector.get_relation(relation_meta).members().size() << " (id=" << m_collector.get_relation(relation_meta).id() << ")\n";
+ assert(member_meta.member_pos() < m_collector.get_relation(relation_meta).members().size());
+// std::cerr << " add way " << member_meta.member_id() << " to rel " << m_collector.get_relation(relation_meta).id() << " at pos " << member_meta.member_pos() << "\n";
+ relation_meta.got_one_member();
+ if (relation_meta.has_all_members()) {
+ const size_t relation_offset = member_meta.relation_pos();
+ m_collector.complete_relation(relation_meta);
+ m_collector.m_relations[relation_offset] = RelationMeta();
+ m_collector.possibly_purge_removed_members();
+ }
+ }
+
+ // Remove MemberMetas that were marked as removed.
+ mmv.erase(std::remove_if(mmv.begin(), mmv.end(), [](MemberMeta& mm) {
+ return mm.removed();
+ }), mmv.end());
+
+ return true;
+ }
+
+ public:
+
+ HandlerPass2(TCollector& collector) noexcept :
+ m_collector(collector),
+ m_want_types((TNodes?1:0) + (TWays?1:0) + (TRelations?1:0)) {
+ }
+
+ void node(const osmium::Node& node) {
+ if (TNodes) {
+ if (! find_and_add_object(node)) {
+ m_collector.node_not_in_any_relation(node);
+ }
+ }
+ }
+
+ void way(const osmium::Way& way) {
+ if (TWays) {
+ if (! find_and_add_object(way)) {
+ m_collector.way_not_in_any_relation(way);
+ }
+ }
+ }
+
+ void relation(const osmium::Relation& relation) {
+ if (TRelations) {
+ if (! find_and_add_object(relation)) {
+ m_collector.relation_not_in_any_relation(relation);
+ }
+ }
+ }
+
+ void flush() {
+ m_collector.flush();
+ }
+
+ }; // class HandlerPass2
+
+ HandlerPass2 m_handler_pass2;
+
+ // All relations we are interested in will be kept in this buffer
+ osmium::memory::Buffer m_relations_buffer;
+
+ // All members we are interested in will be kept in this buffer
+ osmium::memory::Buffer m_members_buffer;
+
+ /// Vector with all relations we are interested in
+ std::vector<RelationMeta> m_relations;
+
+ /**
+ * One vector each for nodes, ways, and relations containing all
+ * mappings from member ids to their relations.
+ */
+ std::vector<MemberMeta> m_member_meta[3];
+
+ int m_count_complete = 0;
+
+ typedef std::function<void(osmium::memory::Buffer&&)> callback_func_type;
+ callback_func_type m_callback;
+
+ static constexpr size_t initial_buffer_size = 1024 * 1024;
+
+ public:
+
+ /**
+ * Create an Collector.
+ */
+ Collector() :
+ m_handler_pass2(*static_cast<TCollector*>(this)),
+ m_relations_buffer(initial_buffer_size, osmium::memory::Buffer::auto_grow::yes),
+ m_members_buffer(initial_buffer_size, osmium::memory::Buffer::auto_grow::yes),
+ m_relations(),
+ m_member_meta() {
+ }
+
+ protected:
+
+ std::vector<MemberMeta>& member_meta(const item_type type) {
+ return m_member_meta[static_cast<uint16_t>(type) - 1];
+ }
+
+ callback_func_type callback() {
+ return m_callback;
+ }
+
+ const std::vector<RelationMeta>& relations() const {
+ return m_relations;
+ }
+
+ /**
+ * This method is called from the first pass handler for every
+ * relation in the input, to check whether it should be kept.
+ *
+ * Overwrite this method in a child class to only add relations
+ * you are interested in, for instance depending on the type tag.
+ * Storing relations takes a lot of memory, so it makes sense to
+ * filter this as much as possible.
+ */
+ bool keep_relation(const osmium::Relation& /*relation*/) const {
+ return true;
+ }
+
+ /**
+ * This method is called for every member of every relation that
+ * should be kept. It should decide if the member is interesting or
+ * not and return true or false to signal that. Only interesting
+ * members are later added to the relation.
+ *
+ * Overwrite this method in a child class. In the MultiPolygonCollector
+ * this is for instance used to only keep members of type way and
+ * ignore all others.
+ */
+ bool keep_member(const osmium::relations::RelationMeta& /*relation_meta*/, const osmium::RelationMember& /*member*/) const {
+ return true;
+ }
+
+ /**
+ * This method is called for all nodes that are not a member of
+ * any relation.
+ *
+ * Overwrite this method in a child class if you are interested
+ * in this.
+ */
+ void node_not_in_any_relation(const osmium::Node& /*node*/) {
+ }
+
+ /**
+ * This method is called for all ways that are not a member of
+ * any relation.
+ *
+ * Overwrite this method in a child class if you are interested
+ * in this.
+ */
+ void way_not_in_any_relation(const osmium::Way& /*way*/) {
+ }
+
+ /**
+ * This method is called for all relations that are not a member of
+ * any relation.
+ *
+ * Overwrite this method in a child class if you are interested
+ * in this.
+ */
+ void relation_not_in_any_relation(const osmium::Relation& /*relation*/) {
+ }
+
+ /**
+ * This method is called from the 2nd pass handler when all objects
+ * of types we are interested in have been seen.
+ *
+ * Overwrite this method in a child class if you are interested
+ * in this.
+ *
+ * Note that even after this call members might be missing if they
+ * were not in the input file! The derived class has to handle this
+ * case.
+ */
+ void flush() {
+ }
+
+ /**
+ * This removes all relations that have already been assembled
+ * from the m_relations vector.
+ */
+ void clean_assembled_relations() {
+ m_relations.erase(
+ std::remove_if(m_relations.begin(), m_relations.end(), has_all_members()),
+ m_relations.end()
+ );
+ }
+
+ const osmium::Relation& get_relation(size_t offset) const {
+ return m_relations_buffer.get<osmium::Relation>(offset);
+ }
+
+ /**
+ * Get the relation from a relation_meta.
+ */
+ const osmium::Relation& get_relation(const RelationMeta& relation_meta) const {
+ return get_relation(relation_meta.relation_offset());
+ }
+
+ osmium::OSMObject& get_member(size_t offset) const {
+ return m_members_buffer.get<osmium::OSMObject>(offset);
+ }
+
+ /**
+ * Tell the Collector that you are interested in this relation
+ * and want it kept until all members have been assembled and
+ * it is handed back to you.
+ *
+ * The relation is copied and stored in a buffer inside the
+ * collector.
+ */
+ void add_relation(const osmium::Relation& relation) {
+ const size_t offset = m_relations_buffer.committed();
+ m_relations_buffer.add_item(relation);
+
+ RelationMeta relation_meta(offset);
+
+ 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);
+ relation_meta.increment_need_members();
+ } else {
+ member.ref(0); // set member id to zero to indicate we are not interested
+ }
+ ++n;
+ }
+
+ assert(offset == m_relations_buffer.committed());
+ if (relation_meta.has_all_members()) {
+ m_relations_buffer.rollback();
+ } else {
+ m_relations_buffer.commit();
+ m_relations.push_back(std::move(relation_meta));
+// std::cerr << "added relation id=" << relation.id() << "\n";
+ }
+ }
+
+ /**
+ * Sort the vectors with the member infos so that we can do binary
+ * search on them.
+ */
+ void sort_member_meta() {
+/* std::cerr << "relations: " << m_relations.size() << "\n";
+ std::cerr << "node members: " << m_member_meta[0].size() << "\n";
+ std::cerr << "way members: " << m_member_meta[1].size() << "\n";
+ std::cerr << "relation members: " << m_member_meta[2].size() << "\n";*/
+ std::sort(m_member_meta[0].begin(), m_member_meta[0].end());
+ std::sort(m_member_meta[1].begin(), m_member_meta[1].end());
+ std::sort(m_member_meta[2].begin(), m_member_meta[2].end());
+ }
+
+ public:
+
+ uint64_t used_memory() const {
+ const uint64_t nmembers = m_member_meta[0].capacity() + m_member_meta[1].capacity() + m_member_meta[2].capacity();
+ const uint64_t members = nmembers * sizeof(MemberMeta);
+ const uint64_t relations = m_relations.capacity() * sizeof(RelationMeta);
+ const uint64_t relations_buffer_capacity = m_relations_buffer.capacity();
+ const uint64_t members_buffer_capacity = m_members_buffer.capacity();
+
+ std::cout << " nR = m_relations.capacity() ........... = " << std::setw(12) << m_relations.capacity() << "\n";
+ std::cout << " nMN = m_member_meta[NODE].capacity() ... = " << std::setw(12) << m_member_meta[0].capacity() << "\n";
+ std::cout << " nMW = m_member_meta[WAY].capacity() .... = " << std::setw(12) << m_member_meta[1].capacity() << "\n";
+ std::cout << " nMR = m_member_meta[RELATION].capacity() = " << std::setw(12) << m_member_meta[2].capacity() << "\n";
+ std::cout << " nM = m_member_meta[*].capacity() ...... = " << std::setw(12) << nmembers << "\n";
+
+ std::cout << " sRM = sizeof(RelationMeta) ............. = " << std::setw(12) << sizeof(RelationMeta) << "\n";
+ std::cout << " sMM = sizeof(MemberMeta) ............... = " << std::setw(12) << sizeof(MemberMeta) << "\n\n";
+
+ std::cout << " nR * sRM ............................... = " << std::setw(12) << relations << "\n";
+ std::cout << " nM * sMM ............................... = " << std::setw(12) << members << "\n";
+ std::cout << " relations_buffer_capacity .............. = " << std::setw(12) << relations_buffer_capacity << "\n";
+ std::cout << " members_buffer_capacity ................ = " << std::setw(12) << members_buffer_capacity << "\n";
+
+ const uint64_t total = relations + members + relations_buffer_capacity + members_buffer_capacity;
+
+ std::cout << " total .................................. = " << std::setw(12) << total << "\n";
+ std::cout << " =======================================================\n";
+
+ return relations_buffer_capacity + members_buffer_capacity + relations + members;
+ }
+
+ /**
+ * Return reference to second pass handler.
+ */
+ HandlerPass2& handler(const callback_func_type& callback = nullptr) {
+ m_callback = callback;
+ return m_handler_pass2;
+ }
+
+ osmium::memory::Buffer& members_buffer() {
+ return m_members_buffer;
+ }
+
+ size_t get_offset(osmium::item_type type, osmium::object_id_type id) {
+ const auto& mmv = member_meta(type);
+ const auto range = std::equal_range(mmv.cbegin(), mmv.cend(), MemberMeta(id));
+ assert(range.first != range.second);
+ return range.first->buffer_offset();
+ }
+
+ template <class TIter>
+ void read_relations(TIter begin, TIter end) {
+ HandlerPass1 handler(*static_cast<TCollector*>(this));
+ osmium::apply(begin, end, handler);
+ sort_member_meta();
+ }
+
+ template <class TSource>
+ void read_relations(TSource& source) {
+ read_relations(std::begin(source), std::end(source));
+ source.close();
+ }
+
+ void moving_in_buffer(size_t old_offset, size_t new_offset) {
+ const osmium::OSMObject& object = m_members_buffer.get<osmium::OSMObject>(old_offset);
+ auto& mmv = member_meta(object.type());
+ auto range = std::equal_range(mmv.begin(), mmv.end(), osmium::relations::MemberMeta(object.id()));
+ for (auto it = range.first; it != range.second; ++it) {
+ assert(it->buffer_offset() == old_offset);
+ it->set_buffer_offset(new_offset);
+ }
+ }
+
+ /**
+ * Decide whether to purge removed members and then do it.
+ *
+ * Currently the purging is done every thousand calls.
+ * This could probably be improved upon.
+ */
+ void possibly_purge_removed_members() {
+ ++m_count_complete;
+ if (m_count_complete > 10000) { // XXX
+ 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;
+ 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";
+ m_count_complete = 0;
+ }
+ }
+
+ /**
+ * Get a vector with pointers to all Relations that could not
+ * be completed, because members were missing in the input
+ * data.
+ *
+ * Note that these pointers point into memory allocated and
+ * owned by the Collector object.
+ */
+ std::vector<const osmium::Relation*> get_incomplete_relations() const {
+ std::vector<const osmium::Relation*> relations;
+ for (const auto& relation_meta : m_relations) {
+ if (!relation_meta.has_all_members()) {
+ relations.push_back(&get_relation(relation_meta));
+ }
+ }
+ return relations;
+ }
+
+ }; // class Collector
+
+ } // namespace relations
+
+} // namespace osmium
+
+#endif // OSMIUM_RELATIONS_COLLECTOR_HPP
diff --git a/third_party/osmium/relations/detail/member_meta.hpp b/third_party/osmium/relations/detail/member_meta.hpp
new file mode 100644
index 0000000..5463a1c
--- /dev/null
+++ b/third_party/osmium/relations/detail/member_meta.hpp
@@ -0,0 +1,158 @@
+#ifndef OSMIUM_RELATIONS_DETAIL_MEMBER_META_HPP
+#define OSMIUM_RELATIONS_DETAIL_MEMBER_META_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 <algorithm>
+#include <cstddef>
+#include <iosfwd>
+#include <iterator>
+
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+ namespace relations {
+
+ /**
+ * Helper class for the Collector class.
+ *
+ * Stores an object ID and information where the object should be
+ * stored.
+ */
+ class MemberMeta {
+
+ /**
+ * Object ID of this relation member. Can be a node, way, or relation ID.
+ * It depends on the vector in which this object is stored which kind of
+ * object is referenced here.
+ */
+ osmium::object_id_type m_member_id;
+
+ /**
+ * Position of the relation this member is a part of in the
+ * m_relations vector.
+ */
+ size_t m_relation_pos;
+
+ /**
+ * Position of this member in the list of members of the
+ * relation this member is a part of.
+ */
+ size_t m_member_pos;
+
+ /**
+ * Offset in the buffer where the object is stored.
+ */
+ size_t m_buffer_offset { 0 };
+
+ bool m_removed = false;
+
+ public:
+
+ /**
+ * Create new MemberMeta. The variant with zeros for relation_pos and
+ * member_pos is used to create dummy MemberMeta that can be compared
+ * to the MemberMeta in the vectors using the equal_range algorithm.
+ */
+ explicit MemberMeta(osmium::object_id_type member_id, size_t relation_pos=0, size_t member_pos=0) noexcept :
+ m_member_id(member_id),
+ m_relation_pos(relation_pos),
+ m_member_pos(member_pos) {
+ }
+
+ osmium::object_id_type member_id() const noexcept {
+ return m_member_id;
+ }
+
+ size_t relation_pos() const noexcept {
+ return m_relation_pos;
+ }
+
+ size_t member_pos() const noexcept {
+ return m_member_pos;
+ }
+
+ size_t buffer_offset() const noexcept {
+ return m_buffer_offset;
+ }
+
+ void set_buffer_offset(size_t offset) noexcept {
+ m_buffer_offset = offset;
+ }
+
+ bool removed() const noexcept {
+ return m_removed;
+ }
+
+ void remove() noexcept {
+ m_removed = true;
+ }
+
+ }; // class MemberMeta
+
+ /**
+ * Compares two MemberMeta objects by only looking at the member id.
+ * Used to sort a vector of MemberMeta objects and to later find
+ * them using binary search.
+ */
+ inline bool operator<(const MemberMeta& a, const MemberMeta& b) noexcept {
+ return a.member_id() < b.member_id();
+ }
+
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const MemberMeta& mm) {
+ out << "MemberMeta(member_id=" << mm.member_id() << " relation_pos=" << mm.relation_pos() << " member_pos=" << mm.member_pos() << " buffer_offset=" << mm.buffer_offset() << ")";
+ return out;
+ }
+
+ /**
+ * Count the number of MemberMeta objects in the iterator range
+ * that are not marked as removed.
+ *
+ * @tparam TIter Iterator that dereferences to a MemberMeta
+ * @param begin Begin of iterator range
+ * @param end End of iterator range
+ */
+ template <class TIter>
+ inline typename std::iterator_traits<TIter>::difference_type count_not_removed(TIter begin, TIter end) {
+ return std::count_if(begin, end, [](MemberMeta& mm) {
+ return !mm.removed();
+ });
+ }
+
+ } // namespace relations
+
+} // namespace osmium
+
+#endif // OSMIUM_RELATIONS_DETAIL_MEMBER_META_HPP
diff --git a/third_party/osmium/relations/detail/relation_meta.hpp b/third_party/osmium/relations/detail/relation_meta.hpp
new file mode 100644
index 0000000..77ca0c1
--- /dev/null
+++ b/third_party/osmium/relations/detail/relation_meta.hpp
@@ -0,0 +1,136 @@
+#ifndef OSMIUM_RELATIONS_DETAIL_RELATION_META_HPP
+#define OSMIUM_RELATIONS_DETAIL_RELATION_META_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 <cstddef>
+#include <iosfwd>
+
+namespace osmium {
+
+ namespace relations {
+
+ /**
+ * Helper class for the Collector class.
+ *
+ * Stores information needed to collect all members of a relation. This
+ * includes the offset of the relation in a buffer plus the information
+ * needed to add members to this relation.
+ */
+ class RelationMeta {
+
+ /// The relation we are assembling.
+ size_t m_relation_offset;
+
+ /**
+ * The number of members still needed before the relation is
+ * complete. This will be set to the number of members we are
+ * interested in and then count down for every member we find.
+ * When it is 0, the relation is complete.
+ */
+ int m_need_members = 0;
+
+ public:
+
+ /**
+ * Initialize an empty RelationMeta. This is needed to zero out
+ * relations that have been completed.
+ */
+ RelationMeta() noexcept :
+ m_relation_offset(0) {
+ }
+
+ explicit RelationMeta(size_t relation_offset) noexcept :
+ m_relation_offset(relation_offset) {
+ }
+
+ /**
+ * Get offset of relation in buffer.
+ */
+ size_t relation_offset() const noexcept {
+ return m_relation_offset;
+ }
+
+ /**
+ * Increment the m_need_members counter.
+ */
+ void increment_need_members() noexcept {
+ ++m_need_members;
+ }
+
+ /**
+ * This decrements the "members needed" counter.
+ */
+ void got_one_member() {
+ assert(m_need_members > 0);
+ --m_need_members;
+ }
+
+ /**
+ * Returns true if all members for this relation are available.
+ */
+ bool has_all_members() const noexcept {
+ return m_need_members == 0;
+ }
+
+ }; // class RelationMeta
+
+ template <typename TChar, typename TTraits>
+ inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const RelationMeta& rm) {
+ out << "RelationMeta(relation_offset=" << rm.relation_offset() << " has_all_members=" << rm.has_all_members() << ")";
+ return out;
+ }
+
+ /**
+ * Function object to check if a relation is complete.
+ */
+ struct has_all_members {
+
+ typedef RelationMeta& argument_type;
+ typedef bool result_type;
+
+ /**
+ * @returns true if this relation is complete, false otherwise.
+ */
+ bool operator()(RelationMeta& relation_info) const {
+ return relation_info.has_all_members();
+ }
+
+ }; // struct has_all_members
+
+ } // namespace relations
+
+} // namespace osmium
+
+#endif // OSMIUM_RELATIONS_DETAIL_RELATION_META_HPP
diff --git a/third_party/osmium/tags/filter.hpp b/third_party/osmium/tags/filter.hpp
new file mode 100644
index 0000000..0a0fd3b
--- /dev/null
+++ b/third_party/osmium/tags/filter.hpp
@@ -0,0 +1,148 @@
+#ifndef OSMIUM_TAGS_FILTER_HPP
+#define OSMIUM_TAGS_FILTER_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 <string>
+#include <type_traits>
+#include <vector>
+
+#include <boost/iterator/filter_iterator.hpp>
+
+#include <osmium/memory/collection.hpp>
+#include <osmium/osm/tag.hpp>
+
+namespace osmium {
+
+ namespace tags {
+
+ template <class TKey>
+ struct match_key {
+ bool operator()(const TKey& rule_key, const char* tag_key) {
+ return rule_key == tag_key;
+ }
+ }; // struct match_key
+
+ struct match_key_prefix {
+ bool operator()(const std::string& rule_key, const char* tag_key) {
+ return rule_key.compare(0, std::string::npos, tag_key, 0, rule_key.size()) == 0;
+ }
+ }; // struct match_key_prefix
+
+ template <class TValue>
+ struct match_value {
+ bool operator()(const TValue& rule_value, const char* tag_value) {
+ return rule_value == tag_value;
+ }
+ }; // struct match_value
+
+ template <>
+ struct match_value<void> {
+ bool operator()(const bool, const char*) {
+ return true;
+ }
+ }; // struct match_value<void>
+
+ template <class TKey, class TValue=void, class TKeyComp=match_key<TKey>, class TValueComp=match_value<TValue>>
+ class Filter {
+
+ typedef TKey key_type;
+ typedef typename std::conditional<std::is_void<TValue>::value, bool, TValue>::type value_type;
+
+ struct Rule {
+ key_type key;
+ value_type value;
+ bool ignore_value;
+ bool result;
+
+ explicit Rule(bool r, bool ignore, const key_type& k, const value_type& v) :
+ key(k),
+ value(v),
+ ignore_value(ignore),
+ result(r) {
+ }
+
+ explicit Rule(bool r, bool ignore, const key_type& k) :
+ key(k),
+ value(),
+ ignore_value(ignore),
+ result(r) {
+ }
+
+ }; // struct Rule
+
+ std::vector<Rule> m_rules;
+ bool m_default_result;
+
+ public:
+
+ typedef Filter<TKey, TValue, TKeyComp, TValueComp> filter_type;
+ typedef const osmium::Tag& argument_type;
+ typedef bool result_type;
+ typedef boost::filter_iterator<filter_type, osmium::TagList::const_iterator> iterator;
+
+ explicit Filter(bool default_result = false) :
+ m_default_result(default_result) {
+ }
+
+ template <class V=TValue, typename std::enable_if<!std::is_void<V>::value, int>::type = 0>
+ Filter& add(bool result, const key_type& key, const value_type& value) {
+ m_rules.emplace_back(result, false, key, value);
+ return *this;
+ }
+
+ Filter& add(bool result, const key_type& key) {
+ m_rules.emplace_back(result, true, key);
+ return *this;
+ }
+
+ bool operator()(const osmium::Tag& tag) const {
+ for (const Rule& rule : m_rules) {
+ if (TKeyComp()(rule.key, tag.key()) && (rule.ignore_value || TValueComp()(rule.value, tag.value()))) {
+ return rule.result;
+ }
+ }
+ return m_default_result;
+ }
+
+ }; // class Filter
+
+ typedef Filter<std::string, std::string> KeyValueFilter;
+ typedef Filter<std::string> KeyFilter;
+ typedef Filter<std::string, void, match_key_prefix> KeyPrefixFilter;
+
+ } // namespace tags
+
+} // namespace osmium
+
+#endif // OSMIUM_TAGS_FILTER_HPP
diff --git a/third_party/osmium/tags/regex_filter.hpp b/third_party/osmium/tags/regex_filter.hpp
new file mode 100644
index 0000000..ae2703a
--- /dev/null
+++ b/third_party/osmium/tags/regex_filter.hpp
@@ -0,0 +1,58 @@
+#ifndef OSMIUM_TAGS_REGEX_FILTER_HPP
+#define OSMIUM_TAGS_REGEX_FILTER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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 <regex>
+#include <string>
+
+#include <osmium/tags/filter.hpp>
+
+namespace osmium {
+
+ namespace tags {
+
+ template <>
+ struct match_value<std::regex> {
+ bool operator()(const std::regex& rule_value, const char* tag_value) {
+ return std::regex_match(tag_value, rule_value);
+ }
+ }; // struct match_value<std::regex>
+
+ typedef Filter<std::string, std::regex> RegexFilter;
+
+ } // namespace tags
+
+} // namespace osmium
+
+#endif // OSMIUM_TAGS_REGEX_FILTER_HPP
diff --git a/third_party/osmium/tags/taglist.hpp b/third_party/osmium/tags/taglist.hpp
new file mode 100644
index 0000000..41ef993
--- /dev/null
+++ b/third_party/osmium/tags/taglist.hpp
@@ -0,0 +1,67 @@
+#ifndef OSMIUM_TAGS_TAGLIST_HPP
+#define OSMIUM_TAGS_TAGLIST_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 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 <algorithm>
+#include <utility>
+
+#include <osmium/osm/tag.hpp>
+
+namespace osmium {
+
+ /**
+ * @brief Code related to working with OSM tags
+ */
+ namespace tags {
+
+ 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));
+ }
+
+ 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));
+ }
+
+ 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));
+ }
+
+ } // namespace tags
+
+} // namespace osmium
+
+#endif // OSMIUM_TAGS_TAGLIST_HPP
diff --git a/third_party/osmium/thread/checked_task.hpp b/third_party/osmium/thread/checked_task.hpp
new file mode 100644
index 0000000..75c664c
--- /dev/null
+++ b/third_party/osmium/thread/checked_task.hpp
@@ -0,0 +1,106 @@
+#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/function_wrapper.hpp b/third_party/osmium/thread/function_wrapper.hpp
new file mode 100644
index 0000000..dbb47ff
--- /dev/null
+++ b/third_party/osmium/thread/function_wrapper.hpp
@@ -0,0 +1,110 @@
+#ifndef OSMIUM_THREAD_FUNCTION_WRAPPER_HPP
+#define OSMIUM_THREAD_FUNCTION_WRAPPER_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 <algorithm>
+#include <memory>
+
+namespace osmium {
+
+ namespace thread {
+
+ /**
+ * This function wrapper can collect move-only functions unlike
+ * std::function which needs copyable functions.
+ * Taken from the book "C++ Concurrency in Action".
+ */
+ class function_wrapper {
+
+ struct impl_base {
+
+ virtual ~impl_base() = default;
+ virtual void call() = 0;
+
+ }; // struct impl_base
+
+ std::unique_ptr<impl_base> impl;
+
+ template <typename F>
+ struct impl_type : impl_base {
+ F m_functor;
+
+ impl_type(F&& functor) :
+ m_functor(std::move(functor)) {
+ }
+
+ void call() override {
+ m_functor();
+ }
+ }; // struct impl_type
+
+ public:
+
+ // Constructor must not be "explicit" for wrapper
+ // to work seemlessly.
+ template <typename F>
+ function_wrapper(F&& f) :
+ impl(new impl_type<F>(std::move(f))) {
+ }
+
+ void operator()() {
+ impl->call();
+ }
+
+ function_wrapper() = default;
+
+ function_wrapper(function_wrapper&& other) :
+ impl(std::move(other.impl)) {
+ }
+
+ function_wrapper& operator=(function_wrapper&& other) {
+ impl = std::move(other.impl);
+ return *this;
+ }
+
+ function_wrapper(const function_wrapper&) = delete;
+ function_wrapper(function_wrapper&) = delete;
+ function_wrapper& operator=(const function_wrapper&) = delete;
+
+ explicit operator bool() const {
+ return static_cast<bool>(impl);
+ }
+
+ }; // class function_wrapper
+
+ } // namespace thread
+
+} // namespace osmium
+
+#endif // OSMIUM_THREAD_FUNCTION_WRAPPER_HPP
diff --git a/third_party/osmium/thread/name.hpp b/third_party/osmium/thread/name.hpp
new file mode 100644
index 0000000..20ec5c4
--- /dev/null
+++ b/third_party/osmium/thread/name.hpp
@@ -0,0 +1,61 @@
+#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/thread/pool.hpp b/third_party/osmium/thread/pool.hpp
new file mode 100644
index 0000000..702be66
--- /dev/null
+++ b/third_party/osmium/thread/pool.hpp
@@ -0,0 +1,180 @@
+#ifndef OSMIUM_THREAD_POOL_HPP
+#define OSMIUM_THREAD_POOL_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 <algorithm>
+#include <atomic>
+#include <cstddef>
+#include <cstdlib>
+#include <future>
+#include <thread>
+#include <type_traits>
+#include <vector>
+
+#include <osmium/thread/function_wrapper.hpp>
+#include <osmium/thread/queue.hpp>
+#include <osmium/thread/util.hpp>
+#include <osmium/util/config.hpp>
+
+namespace osmium {
+
+ /**
+ * @brief Threading-related low-level code
+ */
+ namespace thread {
+
+ /**
+ * Thread pool.
+ */
+ class Pool {
+
+ /**
+ * This class makes sure all pool threads will be joined when
+ * the pool is destructed.
+ */
+ class thread_joiner {
+
+ std::vector<std::thread>& m_threads;
+
+ public:
+
+ explicit thread_joiner(std::vector<std::thread>& threads) :
+ m_threads(threads) {
+ }
+
+ ~thread_joiner() {
+ for (auto& thread : m_threads) {
+ if (thread.joinable()) {
+ thread.join();
+ }
+ }
+ }
+
+ }; // class thread_joiner
+
+ std::atomic<bool> m_done;
+ osmium::thread::Queue<function_wrapper> m_work_queue;
+ std::vector<std::thread> m_threads;
+ thread_joiner m_joiner;
+ int m_num_threads;
+
+ void worker_thread() {
+ osmium::thread::set_thread_name("_osmium_worker");
+ while (!m_done) {
+ function_wrapper task;
+ m_work_queue.wait_and_pop_with_timeout(task);
+ if (task) {
+ task();
+ }
+ }
+ }
+
+ /**
+ * Create thread pool with the given number of threads. If
+ * num_threads is 0, the number of threads is read from
+ * the environment variable OSMIUM_POOL_THREADS. The default
+ * value in that case is -2.
+ *
+ * If the number of threads is a negative number, it will be
+ * set to the actual number of cores on the system plus the
+ * given number, ie it will leave a number of cores unused.
+ *
+ * In all cases the minimum number of threads in the pool is 1.
+ */
+ explicit Pool(int num_threads, size_t max_queue_size) :
+ m_done(false),
+ m_work_queue(max_queue_size, "work"),
+ m_threads(),
+ m_joiner(m_threads),
+ m_num_threads(num_threads) {
+
+ if (m_num_threads == 0) {
+ m_num_threads = osmium::config::get_pool_threads();
+ }
+
+ if (m_num_threads <= 0) {
+ m_num_threads = std::max(1, static_cast<int>(std::thread::hardware_concurrency()) + m_num_threads);
+ }
+
+ try {
+ for (int i=0; i < m_num_threads; ++i) {
+ m_threads.push_back(std::thread(&Pool::worker_thread, this));
+ }
+ } catch (...) {
+ m_done = true;
+ throw;
+ }
+ }
+
+ public:
+
+ static constexpr int default_num_threads = 0;
+ static constexpr size_t max_work_queue_size = 10;
+
+ static Pool& instance() {
+ static Pool pool(default_num_threads, max_work_queue_size);
+ return pool;
+ }
+
+ ~Pool() {
+ m_done = true;
+ }
+
+ size_t queue_size() const {
+ return m_work_queue.size();
+ }
+
+ bool queue_empty() const {
+ return m_work_queue.empty();
+ }
+
+ template <typename TFunction>
+ std::future<typename std::result_of<TFunction()>::type> submit(TFunction f) {
+
+ typedef typename std::result_of<TFunction()>::type result_type;
+
+ std::packaged_task<result_type()> task(std::move(f));
+ std::future<result_type> future_result(task.get_future());
+ m_work_queue.push(std::move(task));
+
+ return future_result;
+ }
+
+ }; // class Pool
+
+ } // namespace thread
+
+} // namespace osmium
+
+#endif // OSMIUM_THREAD_POOL_HPP
diff --git a/third_party/osmium/thread/queue.hpp b/third_party/osmium/thread/queue.hpp
new file mode 100644
index 0000000..b01dd39
--- /dev/null
+++ b/third_party/osmium/thread/queue.hpp
@@ -0,0 +1,178 @@
+#ifndef OSMIUM_THREAD_QUEUE_HPP
+#define OSMIUM_THREAD_QUEUE_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 <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <cstddef>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <utility>
+
+namespace osmium {
+
+ namespace thread {
+
+ constexpr std::chrono::milliseconds full_queue_sleep_duration { 10 }; // XXX
+
+ /**
+ * A thread-safe queue.
+ */
+ template <typename T>
+ class Queue {
+
+ /// Maximum size of this queue. If the queue is full pushing to
+ /// the queue will block.
+ const size_t m_max_size;
+
+ /// Name of this queue (for debugging only).
+ const std::string m_name;
+
+ mutable std::mutex m_mutex;
+
+ std::queue<T> m_queue;
+
+ /// Used to signal readers when data is available in the queue.
+ std::condition_variable m_data_available;
+
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+ /// The largest size the queue has been so far.
+ size_t m_largest_size;
+
+ /// The number of times the queue was full and a thread pushing
+ /// to the queue was blocked.
+ std::atomic<int> m_full_counter;
+#endif
+
+ public:
+
+ /**
+ * Construct a multithreaded queue.
+ *
+ * @param max_size Maximum number of elements in the queue. Set to
+ * 0 for an unlimited size.
+ * @param name Optional name for this queue. (Used for debugging.)
+ */
+ Queue(size_t max_size = 0, const std::string& name = "") :
+ m_max_size(max_size),
+ m_name(name),
+ m_mutex(),
+ m_queue(),
+ m_data_available()
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+ ,
+ m_largest_size(0),
+ m_full_counter(0)
+#endif
+ {
+ }
+
+ ~Queue() {
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+ std::cerr << "queue '" << m_name << "' with max_size=" << m_max_size << " had largest size " << m_largest_size << " and was full " << m_full_counter << " times\n";
+#endif
+ }
+
+ /**
+ * Push an element onto the queue. If the queue has a max size, this
+ * call will block if the queue is full.
+ */
+ void push(T value) {
+ if (m_max_size) {
+ while (size() >= m_max_size) {
+ std::this_thread::sleep_for(full_queue_sleep_duration);
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+ ++m_full_counter;
+#endif
+ }
+ }
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_queue.push(std::move(value));
+#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+ if (m_largest_size < m_queue.size()) {
+ m_largest_size = m_queue.size();
+ }
+#endif
+ m_data_available.notify_one();
+ }
+
+ void wait_and_pop(T& value) {
+ std::unique_lock<std::mutex> lock(m_mutex);
+ m_data_available.wait(lock, [this] {
+ return !m_queue.empty();
+ });
+ value=std::move(m_queue.front());
+ m_queue.pop();
+ }
+
+ void wait_and_pop_with_timeout(T& value) {
+ std::unique_lock<std::mutex> lock(m_mutex);
+ if (!m_data_available.wait_for(lock, std::chrono::seconds(1), [this] {
+ return !m_queue.empty();
+ })) {
+ return;
+ }
+ value=std::move(m_queue.front());
+ m_queue.pop();
+ }
+
+ bool try_pop(T& value) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (m_queue.empty()) {
+ return false;
+ }
+ value=std::move(m_queue.front());
+ m_queue.pop();
+ return true;
+ }
+
+ bool empty() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_queue.empty();
+ }
+
+ size_t size() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_queue.size();
+ }
+
+ }; // class Queue
+
+ } // namespace thread
+
+} // namespace osmium
+
+#endif // OSMIUM_THREAD_QUEUE_HPP
diff --git a/third_party/osmium/thread/sorted_queue.hpp b/third_party/osmium/thread/sorted_queue.hpp
new file mode 100644
index 0000000..e33dfe6
--- /dev/null
+++ b/third_party/osmium/thread/sorted_queue.hpp
@@ -0,0 +1,159 @@
+#ifndef OSMIUM_THREAD_SORTED_QUEUE_HPP
+#define OSMIUM_THREAD_SORTED_QUEUE_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 <condition_variable>
+#include <cstddef>
+#include <deque>
+#include <mutex>
+
+namespace osmium {
+
+ namespace thread {
+
+ /**
+ * This implements a sorted queue. It is a bit like a priority
+ * queue. We have n worker threads pushing items into the queue
+ * and one thread pulling them out again "in order". The order
+ * is defined by the monotonically increasing "num" parameter
+ * to the push() method. The wait_and_pop() and try_pop() methods
+ * will only give out the next numbered item. This way several
+ * workers can work in their own time on different pieces of
+ * some incoming data, but it all gets serialized properly again
+ * after the workers have done their work.
+ */
+ template <typename T>
+ class SortedQueue {
+
+ typedef typename std::deque<T>::size_type size_type;
+
+ mutable std::mutex m_mutex;
+ std::deque<T> m_queue;
+ std::condition_variable m_data_available;
+
+ size_type m_offset;
+
+ // this method expects that we already have the lock
+ bool empty_intern() const {
+ return m_queue.front() == T();
+ }
+
+ public:
+
+ SortedQueue() :
+ m_mutex(),
+ m_queue(1),
+ m_data_available(),
+ m_offset(0) {
+ }
+
+ /**
+ * Push an item into the queue.
+ *
+ * @param value The item to push into the queue.
+ * @param num Number to describe ordering for the items.
+ * It must increase monotonically.
+ */
+ void push(T value, size_type num) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ num -= m_offset;
+ if (m_queue.size() <= num + 1) {
+ m_queue.resize(num + 2);
+ }
+ m_queue[num] = std::move(value);
+
+ m_data_available.notify_one();
+ }
+
+ /**
+ * Wait until the next item becomes available and make it
+ * available through value.
+ */
+ void wait_and_pop(T& value) {
+ std::unique_lock<std::mutex> lock(m_mutex);
+
+ m_data_available.wait(lock, [this] {
+ return !empty_intern();
+ });
+ value=std::move(m_queue.front());
+ m_queue.pop_front();
+ ++m_offset;
+ }
+
+ /**
+ * Get next item if it is available and return true. Or
+ * return false otherwise.
+ */
+ bool try_pop(T& value) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ if (empty_intern()) {
+ return false;
+ }
+ value=std::move(m_queue.front());
+ m_queue.pop_front();
+ ++m_offset;
+ return true;
+ }
+
+ /**
+ * The queue is empty. This means try_pop() would fail if called.
+ * It does not mean that there is nothing on the queue. Because
+ * the queue is sorted, it could mean that the next item in the
+ * queue is not available, but other items are.
+ */
+ bool empty() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ return empty_intern();
+ }
+
+ /**
+ * Returns the number of items in the queue, regardless of whether
+ * they can be accessed. If this is =0 it
+ * implies empty()==true, but not the other way around.
+ */
+ size_t size() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_queue.size();
+ }
+
+ }; // class SortedQueue
+
+ } // namespace thread
+
+} // namespace osmium
+
+#endif // OSMIUM_THREAD_SORTED_QUEUE_HPP
diff --git a/third_party/osmium/thread/util.hpp b/third_party/osmium/thread/util.hpp
new file mode 100644
index 0000000..286ea5e
--- /dev/null
+++ b/third_party/osmium/thread/util.hpp
@@ -0,0 +1,87 @@
+#ifndef OSMIUM_THREAD_UTIL_HPP
+#define OSMIUM_THREAD_UTIL_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>
+
+#ifdef __linux__
+# include <sys/prctl.h>
+#endif
+
+namespace osmium {
+
+ namespace thread {
+
+ /**
+ * Check if the future resulted in an exception. This will re-throw
+ * the exception stored in the future if there was one. Otherwise it
+ * will just return.
+ */
+ template <class T>
+ inline void check_for_exception(std::future<T>& future) {
+ if (future.valid() && future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+ future.get();
+ }
+ }
+
+ /**
+ * Wait until the given future becomes ready. Will block if the future
+ * is not ready. Can be called more than once unless future.get().
+ */
+ template <class T>
+ inline void wait_until_done(std::future<T>& future) {
+ if (future.valid()) {
+ future.get();
+ }
+ }
+
+ /**
+ * 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_UTIL_HPP
diff --git a/third_party/osmium/util/cast.hpp b/third_party/osmium/util/cast.hpp
new file mode 100644
index 0000000..7503267
--- /dev/null
+++ b/third_party/osmium/util/cast.hpp
@@ -0,0 +1,72 @@
+#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/osmium/util/compatibility.hpp b/third_party/osmium/util/compatibility.hpp
new file mode 100644
index 0000000..48a6db0
--- /dev/null
+++ b/third_party/osmium/util/compatibility.hpp
@@ -0,0 +1,47 @@
+#ifndef OSMIUM_UTIL_COMPATIBILITY_HPP
+#define OSMIUM_UTIL_COMPATIBILITY_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.
+
+*/
+
+// Workarounds for MSVC which doesn't support
+// * constexpr in all cases yet
+// * [[noreturn]]
+#ifdef _MSC_VER
+# define OSMIUM_CONSTEXPR
+# define OSMIUM_NORETURN __declspec(noreturn)
+#else
+# define OSMIUM_CONSTEXPR constexpr
+# define OSMIUM_NORETURN [[noreturn]]
+#endif
+
+#endif // OSMIUM_UTIL_COMPATIBILITY_HPP
diff --git a/third_party/osmium/util/config.hpp b/third_party/osmium/util/config.hpp
new file mode 100644
index 0000000..6c86d68
--- /dev/null
+++ b/third_party/osmium/util/config.hpp
@@ -0,0 +1,73 @@
+#ifndef OSMIUM_UTIL_CONFIG_HPP
+#define OSMIUM_UTIL_CONFIG_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 <cstdlib>
+#include <cstring>
+
+#ifdef _MSC_VER
+#define strncasecmp _strnicmp
+#define strcasecmp _stricmp
+#endif
+
+namespace osmium {
+
+ namespace config {
+
+ inline int get_pool_threads() {
+ const char* env = getenv("OSMIUM_POOL_THREADS");
+ if (env) {
+ return std::atoi(env);
+ }
+ return -2;
+ }
+
+ inline bool use_pool_threads_for_pbf_parsing() {
+ const char* env = getenv("OSMIUM_USE_POOL_THREADS_FOR_PBF_PARSING");
+ if (env) {
+ if (!strcasecmp(env, "off") ||
+ !strcasecmp(env, "false") ||
+ !strcasecmp(env, "no") ||
+ !strcasecmp(env, "0")) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ } // namespace config
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_CONFIG_HPP
diff --git a/third_party/osmium/util/double.hpp b/third_party/osmium/util/double.hpp
new file mode 100644
index 0000000..91f4ac7
--- /dev/null
+++ b/third_party/osmium/util/double.hpp
@@ -0,0 +1,91 @@
+#ifndef OSMIUM_UTIL_DOUBLE_HPP
+#define OSMIUM_UTIL_DOUBLE_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 <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstdio>
+
+namespace osmium {
+
+ namespace util {
+
+ constexpr int max_double_length = 20; // should fit any double
+
+ /**
+ * Write double to iterator, removing superfluous '0' characters at
+ * the end. The decimal dot will also be removed if necessary.
+ *
+ * @tparam T iterator type
+ * @param iterator output iterator
+ * @param value the value that should be written
+ * @param precision max number of digits after the decimal point (must be <= 17)
+ */
+ template <typename T>
+ inline T double2string(T iterator, double value, int precision) {
+ assert(precision <= 17);
+
+ char buffer[max_double_length];
+
+#ifndef _MSC_VER
+ int len = snprintf(buffer, max_double_length, "%.*f", precision, value);
+#else
+ int len = _snprintf(buffer, max_double_length, "%.*f", precision, value);
+#endif
+ assert(len > 0 && len < max_double_length);
+
+ while (buffer[len-1] == '0') --len;
+ if (buffer[len-1] == '.') --len;
+
+ return std::copy_n(buffer, len, iterator);
+ }
+
+ /**
+ * Write double to string, removing superfluous '0' characters at
+ * the end. The decimal dot will also be removed if necessary.
+ *
+ * @param out string
+ * @param value the value that should be written
+ * @param precision max number of digits after the decimal point
+ */
+ inline void double2string(std::string& out, double value, int precision) {
+ double2string(std::back_inserter(out), value, precision);
+ }
+
+ } // namespace util
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_DOUBLE_HPP
diff --git a/third_party/osmium/util/options.hpp b/third_party/osmium/util/options.hpp
new file mode 100644
index 0000000..fc74980
--- /dev/null
+++ b/third_party/osmium/util/options.hpp
@@ -0,0 +1,155 @@
+#ifndef OSMIUM_UTIL_OPTIONS_HPP
+#define OSMIUM_UTIL_OPTIONS_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 <initializer_list>
+#include <map>
+#include <string>
+#include <utility>
+
+namespace osmium {
+
+ namespace util {
+
+ /**
+ * Stores key=value type options. This class can be used stand-alone or
+ * as a base class. Options are stored and retrieved by key using the
+ * different set() and get() methods.
+ *
+ * You can iterate over all set options. Dereferencing an iterator
+ * yields a std::pair of the key and value strings.
+ */
+ class Options {
+
+ typedef std::map<std::string, std::string> option_map;
+ option_map m_options;
+
+ public:
+
+ typedef option_map::iterator iterator;
+ typedef option_map::const_iterator const_iterator;
+ typedef option_map::value_type value_type;
+
+ Options() = default;
+
+ explicit Options(const std::initializer_list<value_type>& values) :
+ m_options(values) {
+ }
+
+ Options(const Options&) = default;
+ Options& operator=(const Options&) = default;
+
+ Options(Options&&) = default;
+ Options& operator=(Options&&) = default;
+
+ ~Options() = default;
+
+ void set(const std::string& key, const std::string& value) {
+ m_options[key] = value;
+ }
+
+ void set(const std::string& key, const char* value) {
+ m_options[key] = value;
+ }
+
+ void set(const std::string& key, bool value) {
+ m_options[key] = value ? "true" : "false";
+ }
+
+ void set(std::string data) {
+ size_t pos = data.find_first_of('=');
+ if (pos == std::string::npos) {
+ m_options[data] = "true";
+ } else {
+ std::string value = data.substr(pos+1);
+ data.erase(pos);
+ set(data, value);
+ }
+ }
+
+ /**
+ * Get value of "key" option. If not set the default_value (or
+ * empty string) is returned.
+ */
+ std::string get(const std::string& key, const std::string& default_value="") const noexcept {
+ auto it = m_options.find(key);
+ if (it == m_options.end()) {
+ return default_value;
+ }
+ return it->second;
+ }
+
+ /**
+ * Is this option set to a true value ("true" or "yes")?
+ */
+ bool is_true(const std::string& key) const noexcept {
+ std::string value = get(key);
+ return (value == "true" || value == "yes");
+ }
+
+ size_t size() const noexcept {
+ return m_options.size();
+ }
+
+ iterator begin() noexcept {
+ return m_options.begin();
+ }
+
+ iterator end() noexcept {
+ return m_options.end();
+ }
+
+ const_iterator begin() const noexcept {
+ return m_options.cbegin();
+ }
+
+ const_iterator end() const noexcept {
+ return m_options.cend();
+ }
+
+ const_iterator cbegin() const noexcept {
+ return m_options.cbegin();
+ }
+
+ const_iterator cend() const noexcept {
+ return m_options.cend();
+ }
+
+ }; // class Options
+
+ } // namespace util
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_OPTIONS_HPP
diff --git a/third_party/osmium/util/verbose_output.hpp b/third_party/osmium/util/verbose_output.hpp
new file mode 100644
index 0000000..8709441
--- /dev/null
+++ b/third_party/osmium/util/verbose_output.hpp
@@ -0,0 +1,139 @@
+#ifndef OSMIUM_UTIL_VERBOSE_OUTPUT_HPP
+#define OSMIUM_UTIL_VERBOSE_OUTPUT_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 <time.h>
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+namespace osmium {
+
+ /**
+ * @brief Helpful utility classes and functions not strictly OSM related
+ */
+ namespace util {
+
+ /**
+ * Osmium programs often run for a long time because of the amount of
+ * OSM data processed. This class helps with keeping the user up to
+ * date by offering an easy way for programs to optionally output
+ * verbose information about what's going on.
+ *
+ * Use an object of this class instead of std::cerr as an output
+ * stream. Nothing is actually written if the object is not set to
+ * verbose mode. If it is set to verbose mode, each line is prepended
+ * with the running time, ie the time since the VerboseOutput object
+ * was created.
+ */
+ class VerboseOutput {
+
+ /// all time output will be relative to this start time
+ time_t m_start;
+
+ /// is verbose mode enabled?
+ bool m_verbose;
+
+ /// a newline was written, start next output with runtime
+ bool m_newline;
+
+ /**
+ * If we remember that a newline was written as the last thing
+ * write out the time elapsed and reset the newline flag.
+ */
+ void start_line() {
+ if (m_newline) {
+ time_t elapsed = runtime();
+
+ char old_fill = std::cerr.fill();
+ std::cerr << '[' << std::setw(2) << (elapsed / 60) << ':' << std::setw(2) << std::setfill('0') << (elapsed % 60) << "] ";
+ std::cerr.fill(old_fill);
+
+ m_newline = false;
+ }
+ }
+
+ public:
+
+ explicit VerboseOutput(bool verbose=false) noexcept :
+ m_start(time(NULL)),
+ m_verbose(verbose),
+ m_newline(true) {
+ }
+
+ ~VerboseOutput() = default;
+
+ VerboseOutput(const VerboseOutput&) = default;
+ VerboseOutput& operator=(const VerboseOutput&) = default;
+ VerboseOutput(VerboseOutput&&) = default;
+ VerboseOutput& operator=(VerboseOutput&&) = default;
+
+ time_t runtime() const noexcept {
+ return time(NULL) - m_start;
+ }
+
+ /// Get "verbose" setting.
+ bool verbose() const noexcept {
+ return m_verbose;
+ }
+
+ /// Set "verbose" setting.
+ void verbose(bool verbose) noexcept {
+ m_verbose = verbose;
+ }
+
+ template<typename T>
+ friend VerboseOutput& operator<<(VerboseOutput& verbose_output, const T& value) {
+ if (verbose_output.m_verbose) {
+ verbose_output.start_line();
+ std::cerr << value;
+
+ // check if there was a newline a the end and remember that
+ std::ostringstream output_buffer;
+ output_buffer << value;
+ if (!output_buffer.str().empty() && output_buffer.str().back() == '\n') {
+ verbose_output.m_newline = true;
+ }
+ }
+ return verbose_output;
+ }
+
+ }; // class VerboseOutput
+
+ } // namespace util
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_VERBOSE_OUTPUT_HPP
diff --git a/third_party/osmium/visitor.hpp b/third_party/osmium/visitor.hpp
new file mode 100644
index 0000000..d71a2e0
--- /dev/null
+++ b/third_party/osmium/visitor.hpp
@@ -0,0 +1,255 @@
+#ifndef OSMIUM_VISITOR_HPP
+#define OSMIUM_VISITOR_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 <type_traits>
+
+#include <osmium/io/reader_iterator.hpp> // IWYU pragma: keep
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm.hpp>
+#include <osmium/osm/entity.hpp>
+#include <osmium/osm/item_type.hpp>
+
+namespace osmium {
+
+ class TagList;
+ class WayNodeList;
+ class RelationMemberList;
+ class OuterRing;
+ class InnerRing;
+
+ namespace memory {
+ class Item;
+ }
+
+ namespace detail {
+
+ template <typename T, typename U>
+ using ConstIfConst = typename std::conditional<std::is_const<T>::value, typename std::add_const<U>::type, U>::type;
+
+ template <class THandler, class TItem>
+ inline void apply_item_recurse(TItem& item, THandler& handler) {
+ switch (item.type()) {
+ case osmium::item_type::undefined:
+ break;
+ case osmium::item_type::node:
+ handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+ handler.node(static_cast<ConstIfConst<TItem, osmium::Node>&>(item));
+ break;
+ case osmium::item_type::way:
+ handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+ handler.way(static_cast<ConstIfConst<TItem, osmium::Way>&>(item));
+ break;
+ case osmium::item_type::relation:
+ handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+ handler.relation(static_cast<ConstIfConst<TItem, osmium::Relation>&>(item));
+ break;
+ case osmium::item_type::area:
+ handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+ handler.area(static_cast<ConstIfConst<TItem, osmium::Area>&>(item));
+ break;
+ case osmium::item_type::changeset:
+ handler.changeset(static_cast<ConstIfConst<TItem, osmium::Changeset>&>(item));
+ break;
+ case osmium::item_type::tag_list:
+ handler.tag_list(static_cast<ConstIfConst<TItem, osmium::TagList>&>(item));
+ break;
+ case osmium::item_type::way_node_list:
+ handler.way_node_list(static_cast<ConstIfConst<TItem, osmium::WayNodeList>&>(item));
+ break;
+ case osmium::item_type::relation_member_list:
+ case osmium::item_type::relation_member_list_with_full_members:
+ handler.relation_member_list(static_cast<ConstIfConst<TItem, osmium::RelationMemberList>&>(item));
+ break;
+ case osmium::item_type::outer_ring:
+ handler.outer_ring(static_cast<ConstIfConst<TItem, osmium::OuterRing>&>(item));
+ break;
+ case osmium::item_type::inner_ring:
+ handler.inner_ring(static_cast<ConstIfConst<TItem, osmium::InnerRing>&>(item));
+ break;
+ }
+ }
+
+ template <class THandler>
+ inline void apply_item_recurse(const osmium::OSMEntity& item, THandler& handler) {
+ switch (item.type()) {
+ case osmium::item_type::node:
+ handler.osm_object(static_cast<const osmium::OSMObject&>(item));
+ handler.node(static_cast<const osmium::Node&>(item));
+ break;
+ case osmium::item_type::way:
+ handler.osm_object(static_cast<const osmium::OSMObject&>(item));
+ handler.way(static_cast<const osmium::Way&>(item));
+ break;
+ case osmium::item_type::relation:
+ handler.osm_object(static_cast<const osmium::OSMObject&>(item));
+ handler.relation(static_cast<const osmium::Relation&>(item));
+ break;
+ case osmium::item_type::area:
+ handler.osm_object(static_cast<const osmium::OSMObject&>(item));
+ handler.area(static_cast<const osmium::Area&>(item));
+ break;
+ case osmium::item_type::changeset:
+ handler.changeset(static_cast<const osmium::Changeset&>(item));
+ break;
+ default:
+ throw osmium::unknown_type();
+ }
+ }
+
+ template <class THandler>
+ inline void apply_item_recurse(osmium::OSMEntity& item, THandler& handler) {
+ switch (item.type()) {
+ case osmium::item_type::node:
+ handler.osm_object(static_cast<osmium::OSMObject&>(item));
+ handler.node(static_cast<osmium::Node&>(item));
+ break;
+ case osmium::item_type::way:
+ handler.osm_object(static_cast<osmium::OSMObject&>(item));
+ handler.way(static_cast<osmium::Way&>(item));
+ break;
+ case osmium::item_type::relation:
+ handler.osm_object(static_cast<osmium::OSMObject&>(item));
+ handler.relation(static_cast<osmium::Relation&>(item));
+ break;
+ case osmium::item_type::area:
+ handler.osm_object(static_cast<osmium::OSMObject&>(item));
+ handler.area(static_cast<osmium::Area&>(item));
+ break;
+ case osmium::item_type::changeset:
+ handler.changeset(static_cast<osmium::Changeset&>(item));
+ break;
+ default:
+ throw osmium::unknown_type();
+ }
+ }
+
+ template <class THandler>
+ inline void apply_item_recurse(const osmium::OSMObject& item, THandler& handler) {
+ switch (item.type()) {
+ case osmium::item_type::node:
+ handler.osm_object(item);
+ handler.node(static_cast<const osmium::Node&>(item));
+ break;
+ case osmium::item_type::way:
+ handler.osm_object(item);
+ handler.way(static_cast<const osmium::Way&>(item));
+ break;
+ case osmium::item_type::relation:
+ handler.osm_object(item);
+ handler.relation(static_cast<const osmium::Relation&>(item));
+ break;
+ case osmium::item_type::area:
+ handler.osm_object(item);
+ handler.area(static_cast<const osmium::Area&>(item));
+ break;
+ default:
+ throw osmium::unknown_type();
+ }
+ }
+
+ template <class THandler>
+ inline void apply_item_recurse(osmium::OSMObject& item, THandler& handler) {
+ switch (item.type()) {
+ case osmium::item_type::node:
+ handler.osm_object(item);
+ handler.node(static_cast<osmium::Node&>(item));
+ break;
+ case osmium::item_type::way:
+ handler.osm_object(item);
+ handler.way(static_cast<osmium::Way&>(item));
+ break;
+ case osmium::item_type::relation:
+ handler.osm_object(item);
+ handler.relation(static_cast<osmium::Relation&>(item));
+ break;
+ case osmium::item_type::area:
+ handler.osm_object(item);
+ handler.area(static_cast<osmium::Area&>(item));
+ break;
+ default:
+ throw osmium::unknown_type();
+ }
+ }
+
+ template <class THandler, class TItem, class ...TRest>
+ inline void apply_item_recurse(TItem& item, THandler& handler, TRest&... more) {
+ apply_item_recurse(item, handler);
+ apply_item_recurse(item, more...);
+ }
+
+ template <class THandler>
+ inline void flush_recurse(THandler& handler) {
+ handler.flush();
+ }
+
+ template <class THandler, class ...TRest>
+ inline void flush_recurse(THandler& handler, TRest&... more) {
+ flush_recurse(handler);
+ flush_recurse(more...);
+ }
+
+ } // namespace detail
+
+ template <class ...THandlers>
+ inline void apply_item(const osmium::memory::Item& item, THandlers&... handlers) {
+ detail::apply_item_recurse(item, handlers...);
+ }
+
+ template <class ...THandlers>
+ inline void apply_item(osmium::memory::Item& item, THandlers&... handlers) {
+ detail::apply_item_recurse(item, handlers...);
+ }
+
+ template <class TIterator, class ...THandlers>
+ inline void apply(TIterator it, TIterator end, THandlers&... handlers) {
+ for (; it != end; ++it) {
+ detail::apply_item_recurse(*it, handlers...);
+ }
+ detail::flush_recurse(handlers...);
+ }
+
+ template <class TContainer, class ...THandlers>
+ inline void apply(TContainer& c, THandlers&... handlers) {
+ apply(std::begin(c), std::end(c), handlers...);
+ }
+
+ template <class ...THandlers>
+ inline void apply(const osmium::memory::Buffer& buffer, THandlers&... handlers) {
+ apply(buffer.cbegin(), buffer.cend(), handlers...);
+ }
+
+} // namespace osmium
+
+#endif // OSMIUM_VISITOR_HPP
diff --git a/third_party/variant/optional.hpp b/third_party/variant/optional.hpp
new file mode 100644
index 0000000..133e2c8
--- /dev/null
+++ b/third_party/variant/optional.hpp
@@ -0,0 +1,69 @@
+#ifndef MAPBOX_UTIL_OPTIONAL_HPP
+#define MAPBOX_UTIL_OPTIONAL_HPP
+
+#include <type_traits>
+
+#include "variant.hpp"
+
+namespace mapbox
+{
+namespace util
+{
+
+template <typename T> class optional
+{
+ static_assert(!std::is_reference<T>::value, "optional doesn't support references");
+
+ struct none_type
+ {
+ };
+
+ variant<none_type, T> variant_;
+
+ public:
+ optional() = default;
+
+ optional(optional const &rhs)
+ {
+ if (this != &rhs)
+ { // protect against invalid self-assignment
+ variant_ = rhs.variant_;
+ }
+ }
+
+ optional(T const &v) { variant_ = v; }
+
+ explicit operator bool() const noexcept { return variant_.template is<T>(); }
+
+ T const &get() const { return variant_.template get<T>(); }
+ T &get() { return variant_.template get<T>(); }
+
+ T const &operator*() const { return this->get(); }
+ T operator*() { return this->get(); }
+
+ optional &operator=(T const &v)
+ {
+ variant_ = v;
+ return *this;
+ }
+
+ optional &operator=(optional const &rhs)
+ {
+ if (this != &rhs)
+ {
+ variant_ = rhs.variant_;
+ }
+ return *this;
+ }
+
+ template <typename... Args> void emplace(Args &&... args)
+ {
+ variant_ = T{std::forward<Args>(args)...};
+ }
+
+ void reset() { variant_ = none_type{}; }
+};
+}
+}
+
+#endif
diff --git a/third_party/variant/recursive_wrapper.hpp b/third_party/variant/recursive_wrapper.hpp
new file mode 100644
index 0000000..54b2763
--- /dev/null
+++ b/third_party/variant/recursive_wrapper.hpp
@@ -0,0 +1,127 @@
+#ifndef MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
+#define MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
+
+#include <utility>
+
+namespace mapbox { namespace util {
+
+template <typename T>
+class recursive_wrapper
+{
+public:
+ using type = T;
+private:
+
+ T* p_;
+
+public:
+
+ ~recursive_wrapper();
+ recursive_wrapper();
+
+ recursive_wrapper(recursive_wrapper const& operand);
+ recursive_wrapper(T const& operand);
+ recursive_wrapper(recursive_wrapper&& operand);
+ recursive_wrapper(T&& operand);
+
+private:
+
+ void assign(const T& rhs);
+
+public:
+
+ inline recursive_wrapper& operator=(recursive_wrapper const& rhs)
+ {
+ assign( rhs.get() );
+ return *this;
+ }
+
+ inline recursive_wrapper& operator=(T const& rhs)
+ {
+ assign( rhs );
+ return *this;
+ }
+
+ inline void swap(recursive_wrapper& operand) noexcept
+ {
+ T* temp = operand.p_;
+ operand.p_ = p_;
+ p_ = temp;
+ }
+
+
+ recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept
+ {
+ swap(rhs);
+ return *this;
+ }
+
+ recursive_wrapper& operator=(T&& rhs)
+ {
+ get() = std::move(rhs);
+ return *this;
+ }
+
+
+public:
+
+ T& get() { return *get_pointer(); }
+ const T& get() const { return *get_pointer(); }
+ T* get_pointer() { return p_; }
+ const T* get_pointer() const { return p_; }
+ operator T const&() const { return this->get(); }
+ operator T&() { return this->get(); }
+};
+
+template <typename T>
+recursive_wrapper<T>::~recursive_wrapper()
+{
+ delete p_;
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper()
+ : p_(new T)
+{
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper(recursive_wrapper const& operand)
+ : p_(new T( operand.get() ))
+{
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper(T const& operand)
+ : p_(new T(operand))
+{
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper(recursive_wrapper&& operand)
+ : p_(operand.p_)
+{
+ operand.p_ = nullptr;
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper(T&& operand)
+ : p_(new T( std::move(operand) ))
+{
+}
+
+template <typename T>
+void recursive_wrapper<T>::assign(const T& rhs)
+{
+ this->get() = rhs;
+}
+
+template <typename T>
+inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
+{
+ lhs.swap(rhs);
+}
+
+}}
+
+#endif // MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
diff --git a/third_party/variant/variant.hpp b/third_party/variant/variant.hpp
new file mode 100644
index 0000000..3b56594
--- /dev/null
+++ b/third_party/variant/variant.hpp
@@ -0,0 +1,740 @@
+#ifndef MAPBOX_UTIL_VARIANT_HPP
+#define MAPBOX_UTIL_VARIANT_HPP
+
+#include <utility>
+#include <typeinfo>
+#include <type_traits>
+#include <stdexcept> // runtime_error
+#include <new> // operator new
+#include <cstddef> // size_t
+#include <iosfwd>
+#include <string>
+
+#include "recursive_wrapper.hpp"
+
+#ifdef _MSC_VER
+ // http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx
+ #ifdef NDEBUG
+ #define VARIANT_INLINE __forceinline
+ #else
+ #define VARIANT_INLINE __declspec(noinline)
+ #endif
+#else
+ #ifdef NDEBUG
+ #define VARIANT_INLINE inline __attribute__((always_inline))
+ #else
+ #define VARIANT_INLINE __attribute__((noinline))
+ #endif
+#endif
+
+#define VARIANT_MAJOR_VERSION 0
+#define VARIANT_MINOR_VERSION 1
+#define VARIANT_PATCH_VERSION 0
+
+// translates to 100
+#define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION)
+
+namespace mapbox { namespace util { namespace detail {
+
+static constexpr std::size_t invalid_value = std::size_t(-1);
+
+template <typename T, typename...Types>
+struct direct_type;
+
+template <typename T, typename First, typename...Types>
+struct direct_type<T, First, Types...>
+{
+ static constexpr std::size_t index = std::is_same<T, First>::value
+ ? sizeof...(Types) : direct_type<T, Types...>::index;
+};
+
+template <typename T>
+struct direct_type<T>
+{
+ static constexpr std::size_t index = invalid_value;
+};
+
+template <typename T, typename...Types>
+struct convertible_type;
+
+template <typename T, typename First, typename...Types>
+struct convertible_type<T, First, Types...>
+{
+ static constexpr std::size_t index = std::is_convertible<T, First>::value
+ ? sizeof...(Types) : convertible_type<T, Types...>::index;
+};
+
+template <typename T>
+struct convertible_type<T>
+{
+ static constexpr std::size_t index = invalid_value;
+};
+
+template <typename T, typename...Types>
+struct value_traits
+{
+ static constexpr std::size_t direct_index = direct_type<T, Types...>::index;
+ static constexpr std::size_t index =
+ (direct_index == invalid_value) ? convertible_type<T, Types...>::index : direct_index;
+};
+
+template <typename T, typename...Types>
+struct is_valid_type;
+
+template <typename T, typename First, typename... Types>
+struct is_valid_type<T, First, Types...>
+{
+ static constexpr bool value = std::is_convertible<T, First>::value
+ || is_valid_type<T, Types...>::value;
+};
+
+template <typename T>
+struct is_valid_type<T> : std::false_type {};
+
+template <std::size_t N, typename ... Types>
+struct select_type
+{
+ static_assert(N < sizeof...(Types), "index out of bounds");
+};
+
+template <std::size_t N, typename T, typename ... Types>
+struct select_type<N, T, Types...>
+{
+ using type = typename select_type<N - 1, Types...>::type;
+};
+
+template <typename T, typename ... Types>
+struct select_type<0, T, Types...>
+{
+ using type = T;
+};
+
+} // namespace detail
+
+// static visitor
+template <typename R = void>
+struct static_visitor
+{
+ using result_type = R;
+protected:
+ static_visitor() {}
+ ~static_visitor() {}
+};
+
+
+template <std::size_t arg1, std::size_t ... others>
+struct static_max;
+
+template <std::size_t arg>
+struct static_max<arg>
+{
+ static const std::size_t value = arg;
+};
+
+template <std::size_t arg1, std::size_t arg2, std::size_t ... others>
+struct static_max<arg1, arg2, others...>
+{
+ static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value :
+ static_max<arg2, others...>::value;
+};
+
+template<typename... Types>
+struct variant_helper;
+
+template<typename T, typename... Types>
+struct variant_helper<T, Types...>
+{
+ VARIANT_INLINE static void destroy(const std::size_t id, void * data)
+ {
+ if (id == sizeof...(Types))
+ {
+ reinterpret_cast<T*>(data)->~T();
+ }
+ else
+ {
+ variant_helper<Types...>::destroy(id, data);
+ }
+ }
+
+ VARIANT_INLINE static void move(const std::size_t old_id, void * old_value, void * new_value)
+ {
+ if (old_id == sizeof...(Types))
+ {
+ new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
+ //std::memcpy(new_value, old_value, sizeof(T));
+ // ^^ DANGER: this should only be considered for relocatable types e.g built-in types
+ // Also, I don't see any measurable performance benefit just yet
+ }
+ else
+ {
+ variant_helper<Types...>::move(old_id, old_value, new_value);
+ }
+ }
+
+ VARIANT_INLINE static void copy(const std::size_t old_id, const void * old_value, void * new_value)
+ {
+ if (old_id == sizeof...(Types))
+ {
+ new (new_value) T(*reinterpret_cast<const T*>(old_value));
+ }
+ else
+ {
+ variant_helper<Types...>::copy(old_id, old_value, new_value);
+ }
+ }
+};
+
+template<> struct variant_helper<>
+{
+ VARIANT_INLINE static void destroy(const std::size_t, void *) {}
+ VARIANT_INLINE static void move(const std::size_t, void *, void *) {}
+ VARIANT_INLINE static void copy(const std::size_t, const void *, void *) {}
+};
+
+namespace detail {
+
+template <typename T>
+struct unwrapper
+{
+ T const& operator() (T const& obj) const
+ {
+ return obj;
+ }
+
+ T& operator() (T & obj) const
+ {
+ return obj;
+ }
+};
+
+
+template <typename T>
+struct unwrapper<recursive_wrapper<T>>
+{
+ auto operator() (recursive_wrapper<T> const& obj) const
+ -> typename recursive_wrapper<T>::type const&
+ {
+ return obj.get();
+ }
+};
+
+
+template <typename F, typename V, typename...Types>
+struct dispatcher;
+
+template <typename F, typename V, typename T, typename...Types>
+struct dispatcher<F, V, T, Types...>
+{
+ using result_type = typename F::result_type;
+ VARIANT_INLINE static result_type apply_const(V const& v, F f)
+ {
+ if (v.get_type_index() == sizeof...(Types))
+ {
+ return f(unwrapper<T>()(v. template get<T>()));
+ }
+ else
+ {
+ return dispatcher<F, V, Types...>::apply_const(v, f);
+ }
+ }
+
+ VARIANT_INLINE static result_type apply(V & v, F f)
+ {
+ if (v.get_type_index() == sizeof...(Types))
+ {
+ return f(unwrapper<T>()(v. template get<T>()));
+ }
+ else
+ {
+ return dispatcher<F, V, Types...>::apply(v, f);
+ }
+ }
+};
+
+template<typename F, typename V>
+struct dispatcher<F, V>
+{
+ using result_type = typename F::result_type;
+ VARIANT_INLINE static result_type apply_const(V const&, F)
+ {
+ throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
+ }
+
+ VARIANT_INLINE static result_type apply(V &, F)
+ {
+ throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
+ }
+};
+
+
+template <typename F, typename V, 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...>
+{
+ using result_type = typename F::result_type;
+ 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
+ {
+ return f(unwrapper<T0>()(lhs. template get<T0>()),
+ unwrapper<T1>()(rhs. template get<T1>()));
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, T0, Types...>::apply_const(lhs, rhs, f);
+ }
+ }
+
+ VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
+ {
+ if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
+ {
+ return f(unwrapper<T0>()(lhs. template get<T0>()),
+ unwrapper<T1>()(rhs. template get<T1>()));
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, T0, Types...>::apply(lhs, rhs, f);
+ }
+ }
+
+};
+
+template<typename F, typename V, typename T>
+struct binary_dispatcher_rhs<F, V, T>
+{
+ using result_type = typename F::result_type;
+ VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+ {
+ throw std::runtime_error("binary dispatch: FAIL");
+ }
+ VARIANT_INLINE static result_type apply(V &, V &, F)
+ {
+ throw std::runtime_error("binary dispatch: FAIL");
+ }
+};
+
+
+template <typename F, typename V, 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...>
+{
+ using result_type = typename F::result_type;
+ 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
+ {
+ return f(lhs. template get<T1>(), rhs. template get<T0>());
+ }
+ else
+ {
+ return binary_dispatcher_lhs<F, V, T0, Types...>::apply_const(lhs, rhs, f);
+ }
+ }
+
+ VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
+ {
+ if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
+ {
+ return f(lhs. template get<T1>(), rhs. template get<T0>());
+ }
+ else
+ {
+ return binary_dispatcher_lhs<F, V, T0, Types...>::apply(lhs, rhs, f);
+ }
+ }
+
+};
+
+template<typename F, typename V, typename T>
+struct binary_dispatcher_lhs<F, V, T>
+{
+ using result_type = typename F::result_type;
+ VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+ {
+ throw std::runtime_error("binary dispatch: FAIL");
+ }
+
+ VARIANT_INLINE static result_type apply(V &, V &, F)
+ {
+ throw std::runtime_error("binary dispatch: FAIL");
+ }
+};
+
+template <typename F, typename V, typename...Types>
+struct binary_dispatcher;
+
+template <typename F, typename V, typename T, typename...Types>
+struct binary_dispatcher<F, V, T, Types...>
+{
+ using result_type = typename F::result_type;
+ VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f)
+ {
+ if (v0.get_type_index() == sizeof...(Types))
+ {
+ if (v0.get_type_index() == v1.get_type_index())
+ {
+ return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, 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<F, V, Types...>::apply_const(v0, v1, f);
+ }
+
+ VARIANT_INLINE static result_type apply(V & v0, V & v1, F f)
+ {
+ if (v0.get_type_index() == sizeof...(Types))
+ {
+ if (v0.get_type_index() == v1.get_type_index())
+ {
+ return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, 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<F, V, Types...>::apply(v0, v1, f);
+ }
+};
+
+template<typename F, typename V>
+struct binary_dispatcher<F, V>
+{
+ using result_type = typename F::result_type;
+ VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+ {
+ throw std::runtime_error("binary dispatch: FAIL");
+ }
+
+ VARIANT_INLINE static result_type apply(V &, V &, F)
+ {
+ throw std::runtime_error("binary dispatch: FAIL");
+ }
+};
+
+// comparator functors
+struct equal_comp
+{
+ template <typename T>
+ bool operator()(T const& lhs, T const& rhs) const
+ {
+ return lhs == rhs;
+ }
+};
+
+struct less_comp
+{
+ template <typename T>
+ bool operator()(T const& lhs, T const& rhs) const
+ {
+ return lhs < rhs;
+ }
+};
+
+template <typename Variant, typename Comp>
+class comparer : public static_visitor<bool>
+{
+public:
+ explicit comparer(Variant const& lhs) noexcept
+ : lhs_(lhs) {}
+ comparer& operator=(comparer const&) = delete;
+ // visitor
+ template<typename T>
+ bool operator()(T const& rhs_content) const
+ {
+ T const& lhs_content = lhs_.template get<T>();
+ return Comp()(lhs_content, rhs_content);
+ }
+private:
+ 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
+
+struct no_init {};
+
+template<typename... Types>
+class variant
+{
+private:
+
+ static const std::size_t data_size = static_max<sizeof(Types)...>::value;
+ static const std::size_t data_align = static_max<alignof(Types)...>::value;
+
+ using data_type = typename std::aligned_storage<data_size, data_align>::type;
+ using helper_type = variant_helper<Types...>;
+
+ std::size_t type_index;
+ data_type data;
+
+public:
+
+
+ VARIANT_INLINE variant()
+ : type_index(sizeof...(Types) - 1)
+ {
+ new (&data) typename detail::select_type<0, Types...>::type();
+ }
+
+ VARIANT_INLINE variant(no_init)
+ : type_index(detail::invalid_value) {}
+
+ // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
+ template <typename T, class = typename std::enable_if<
+ detail::is_valid_type<typename std::remove_reference<T>::type, Types...>::value>::type>
+ VARIANT_INLINE variant(T && val) noexcept
+ : type_index(detail::value_traits<typename std::remove_reference<T>::type, Types...>::index)
+ {
+ constexpr std::size_t index = sizeof...(Types) - detail::value_traits<typename std::remove_reference<T>::type, Types...>::index - 1;
+ using target_type = typename detail::select_type<index, Types...>::type;
+ new (&data) target_type(std::forward<T>(val)); // nothrow
+ }
+
+ VARIANT_INLINE variant(variant<Types...> const& old)
+ : type_index(old.type_index)
+ {
+ helper_type::copy(old.type_index, &old.data, &data);
+ }
+
+ VARIANT_INLINE variant(variant<Types...>&& old) noexcept
+ : type_index(old.type_index)
+ {
+ helper_type::move(old.type_index, &old.data, &data);
+ }
+
+ friend void swap(variant<Types...> & first, variant<Types...> & second)
+ {
+ using std::swap; //enable ADL
+ swap(first.type_index, second.type_index);
+ swap(first.data, second.data);
+ }
+
+ VARIANT_INLINE variant<Types...>& operator=(variant<Types...> other)
+ {
+ swap(*this, other);
+ return *this;
+ }
+
+ // conversions
+ // move-assign
+ template <typename T>
+ VARIANT_INLINE variant<Types...>& operator=(T && rhs) noexcept
+ {
+ variant<Types...> temp(std::forward<T>(rhs));
+ swap(*this, temp);
+ return *this;
+ }
+
+ // copy-assign
+ template <typename T>
+ VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
+ {
+ variant<Types...> temp(rhs);
+ swap(*this, temp);
+ return *this;
+ }
+
+ template<typename T>
+ VARIANT_INLINE bool is() const
+ {
+ return (type_index == detail::direct_type<T, Types...>::index);
+ }
+
+ VARIANT_INLINE bool valid() const
+ {
+ return (type_index != detail::invalid_value);
+ }
+
+ template<typename T, typename... Args>
+ VARIANT_INLINE void set(Args&&... args)
+ {
+ helper_type::destroy(type_index, &data);
+ new (&data) T(std::forward<Args>(args)...);
+ type_index = detail::direct_type<T, Types...>::index;
+ }
+
+ template<typename T>
+ VARIANT_INLINE T& get()
+ {
+ if (type_index == detail::direct_type<T, Types...>::index)
+ {
+ return *reinterpret_cast<T*>(&data);
+ }
+ else
+ {
+ throw std::runtime_error("in get()");
+ }
+ }
+
+ template<typename T>
+ VARIANT_INLINE T const& get() const
+ {
+ if (type_index == detail::direct_type<T, Types...>::index)
+ {
+ return *reinterpret_cast<T const*>(&data);
+ }
+ else
+ {
+ throw std::runtime_error("in get()");
+ }
+ }
+
+ VARIANT_INLINE std::size_t get_type_index() const
+ {
+ return type_index;
+ }
+
+ // 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))
+ {
+ return detail::dispatcher<F, V, 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))
+ {
+ return detail::dispatcher<F, V, Types...>::apply(v, f);
+ }
+
+ // binary
+ // const
+ template <typename F, typename V>
+ auto VARIANT_INLINE
+ static binary_visit(V const& v0, V const& v1, F f)
+ -> decltype(detail::binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f))
+ {
+ return detail::binary_dispatcher<F, V, 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))
+ {
+ return detail::binary_dispatcher<F, V, Types...>::apply(v0, v1, f);
+ }
+
+ ~variant() noexcept
+ {
+ helper_type::destroy(type_index, &data);
+ }
+
+ // comparison operators
+ // equality
+ VARIANT_INLINE bool operator==(variant const& rhs) const
+ {
+ if (this->get_type_index() != rhs.get_type_index())
+ return false;
+ detail::comparer<variant, detail::equal_comp> visitor(*this);
+ return visit(rhs, visitor);
+ }
+ // less than
+ VARIANT_INLINE bool operator<(variant const& rhs) const
+ {
+ if (this->get_type_index() != rhs.get_type_index())
+ {
+ return this->get_type_index() < rhs.get_type_index();
+ // ^^ borrowed from boost::variant
+ }
+ detail::comparer<variant, detail::less_comp> visitor(*this);
+ return visit(rhs, visitor);
+ }
+};
+
+// unary visitor interface
+
+// const
+template <typename V, typename F>
+auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f))
+{
+ return V::visit(v, f);
+}
+// non-const
+template <typename V, typename F>
+auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f))
+{
+ return V::visit(v, f);
+}
+
+// binary visitor interface
+// const
+template <typename V, typename F>
+auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f))
+{
+ return V::binary_visit(v0, v1, f);
+}
+// non-const
+template <typename V, typename F>
+auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f))
+{
+ return V::binary_visit(v0, v1, f);
+}
+
+// getter interface
+template<typename ResultType, typename T>
+ResultType & get(T & var)
+{
+ return var.template get<ResultType>();
+}
+
+template<typename ResultType, typename T>
+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/Tools/.gitignore b/tools/.gitignore
similarity index 100%
rename from Tools/.gitignore
rename to tools/.gitignore
diff --git a/tools/check-hsgr.cpp b/tools/check-hsgr.cpp
new file mode 100644
index 0000000..9173dc4
--- /dev/null
+++ b/tools/check-hsgr.cpp
@@ -0,0 +1,112 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+#include "../data_structures/percent.hpp"
+#include "../data_structures/query_edge.hpp"
+#include "../data_structures/static_graph.hpp"
+#include "../Util/integer_range.hpp"
+#include "../Util/graph_loader.hpp"
+#include "../Util/simple_logger.hpp"
+#include "../Util/osrm_exception.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/filesystem.hpp>
+
+#include <memory>
+#include <vector>
+
+using EdgeData = QueryEdge::EdgeData;
+using QueryGraph = StaticGraph<EdgeData>;
+
+int main(int argc, char *argv[])
+{
+ LogPolicy::GetInstance().Unmute();
+ try
+ {
+ if (argc != 2)
+ {
+ SimpleLogger().Write(logWARNING) << "usage: " << argv[0] << " <file.hsgr>";
+ return 1;
+ }
+
+ boost::filesystem::path hsgr_path(argv[1]);
+
+ std::vector<QueryGraph::NodeArrayEntry> node_list;
+ std::vector<QueryGraph::EdgeArrayEntry> edge_list;
+ SimpleLogger().Write() << "loading graph from " << hsgr_path.string();
+
+ unsigned m_check_sum = 0;
+ unsigned m_number_of_nodes =
+ readHSGRFromStream(hsgr_path, node_list, edge_list, &m_check_sum);
+ SimpleLogger().Write() << "expecting " << m_number_of_nodes
+ << " nodes, checksum: " << m_check_sum;
+ BOOST_ASSERT_MSG(0 != node_list.size(), "node list empty");
+ SimpleLogger().Write() << "loaded " << node_list.size() << " nodes and " << edge_list.size()
+ << " edges";
+ auto m_query_graph = std::make_shared<QueryGraph>(node_list, edge_list);
+
+ BOOST_ASSERT_MSG(0 == node_list.size(), "node list not flushed");
+ BOOST_ASSERT_MSG(0 == edge_list.size(), "edge list not flushed");
+
+ Percent progress(m_query_graph->GetNumberOfNodes());
+ for (const auto node_u : osrm::irange(0u, m_query_graph->GetNumberOfNodes()))
+ {
+ for (const auto eid : m_query_graph->GetAdjacentEdgeRange(node_u))
+ {
+ const EdgeData &data = m_query_graph->GetEdgeData(eid);
+ if (!data.shortcut)
+ {
+ continue;
+ }
+ const unsigned node_v = m_query_graph->GetTarget(eid);
+ const EdgeID edge_id_1 = m_query_graph->FindEdgeInEitherDirection(node_u, data.id);
+ if (SPECIAL_EDGEID == edge_id_1)
+ {
+ throw osrm::exception("cannot find first segment of edge (" +
+ std::to_string(node_u) + "," + std::to_string(data.id) +
+ "," + std::to_string(node_v) + "), eid: " +
+ std::to_string(eid));
+ }
+ const EdgeID edge_id_2 = m_query_graph->FindEdgeInEitherDirection(data.id, node_v);
+ if (SPECIAL_EDGEID == edge_id_2)
+ {
+ throw osrm::exception("cannot find second segment of edge (" +
+ std::to_string(node_u) + "," + std::to_string(data.id) +
+ "," + std::to_string(node_v) + "), eid: " +
+ std::to_string(eid));
+ }
+ }
+ progress.printStatus(node_u);
+ }
+ m_query_graph.reset();
+ SimpleLogger().Write() << "Data file " << argv[0] << " appears to be OK";
+ }
+ catch (const std::exception &e)
+ {
+ SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+ }
+ return 0;
+}
diff --git a/tools/components.cpp b/tools/components.cpp
new file mode 100644
index 0000000..607d86b
--- /dev/null
+++ b/tools/components.cpp
@@ -0,0 +1,293 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "../typedefs.h"
+#include "../algorithms/tiny_components.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 <boost/filesystem.hpp>
+
+#if defined(__APPLE__) || defined (_WIN32)
+#include <gdal.h>
+#include <ogrsf_frmts.h>
+#else
+#include <gdal/gdal.h>
+#include <gdal/ogrsf_frmts.h>
+#endif
+
+#include <osrm/Coordinate.h>
+
+#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;
+
+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;
+ unsigned name_id;
+};
+
+using TarjanDynamicGraph = DynamicGraph<TarjanEdgeData>;
+using TarjanEdge = TarjanDynamicGraph::InputEdge;
+
+void DeleteFileIfExists(const std::string &file_name)
+{
+ if (boost::filesystem::exists(file_name))
+ {
+ boost::filesystem::remove(file_name);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ 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((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((char *)&usable_restrictions, sizeof(uint32_t));
+ restriction_list.resize(usable_restrictions);
+
+ // load restrictions
+ if (usable_restrictions > 0)
+ {
+ restriction_ifstream.read((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
+ DeallocatingVector<TarjanEdge> graph_edge_list;
+ for (const NodeBasedEdge &input_edge : edge_list)
+ {
+ if (input_edge.source == input_edge.target)
+ {
+ continue;
+ }
+
+ if (input_edge.forward)
+ {
+ graph_edge_list.emplace_back(input_edge.source,
+ input_edge.target,
+ (std::max)((int)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);
+ }
+ }
+ 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(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();
+
+ SimpleLogger().Write() << "Starting SCC graph traversal";
+
+ RestrictionMap restriction_map(restriction_list);
+ auto tarjan = osrm::make_unique<TarjanSCC<TarjanDynamicGraph>>(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";
+
+ // output
+ TIMER_START(SCC_RUN_SETUP);
+
+ // remove files from previous run if exist
+ DeleteFileIfExists("component.dbf");
+ DeleteFileIfExists("component.shx");
+ DeleteFileIfExists("component.shp");
+
+ Percent p(graph->GetNumberOfNodes());
+
+ OGRRegisterAll();
+
+ const char *pszDriverName = "ESRI Shapefile";
+ OGRSFDriver *poDriver =
+ OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(pszDriverName);
+ if (nullptr == poDriver)
+ {
+ throw osrm::exception("ESRI Shapefile driver not available");
+ }
+ OGRDataSource *poDS = poDriver->CreateDataSource("component.shp", nullptr);
+
+ if (nullptr == poDS)
+ {
+ throw osrm::exception("Creation of output file failed");
+ }
+
+ OGRSpatialReference *poSRS = new OGRSpatialReference();
+ poSRS->importFromEPSG(4326);
+
+ OGRLayer *poLayer = poDS->CreateLayer("component", poSRS, wkbLineString, nullptr);
+
+ if (nullptr == poLayer)
+ {
+ throw osrm::exception("Layer creation failed.");
+ }
+ TIMER_STOP(SCC_RUN_SETUP);
+ SimpleLogger().Write() << "shapefile setup took " << TIMER_MSEC(SCC_RUN_SETUP)/1000. << "s";
+
+ uint64_t total_network_distance = 0;
+ p.reinit(graph->GetNumberOfNodes());
+ TIMER_START(SCC_OUTPUT);
+ for (const NodeID source : osrm::irange(0u, graph->GetNumberOfNodes()))
+ {
+ p.printIncrement();
+ for (const auto current_edge : graph->GetAdjacentEdgeRange(source))
+ {
+ const TarjanDynamicGraph::NodeIterator target = graph->GetTarget(current_edge);
+
+ if (source < target || graph->EndEdges(target) == 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);
+
+ 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));
+
+ // edges that end on bollard nodes may actually be in two distinct components
+ if (size_of_containing_component < 1000)
+ {
+ OGRLineString lineString;
+ lineString.addPoint(coordinate_list[source].lon / COORDINATE_PRECISION,
+ coordinate_list[source].lat / COORDINATE_PRECISION);
+ lineString.addPoint(coordinate_list[target].lon / COORDINATE_PRECISION,
+ coordinate_list[target].lat / COORDINATE_PRECISION);
+
+ OGRFeature *poFeature = OGRFeature::CreateFeature(poLayer->GetLayerDefn());
+
+ poFeature->SetGeometry(&lineString);
+ if (OGRERR_NONE != poLayer->CreateFeature(poFeature))
+ {
+ throw osrm::exception("Failed to create feature in shapefile.");
+ }
+ OGRFeature::DestroyFeature(poFeature);
+ }
+ }
+ }
+ }
+ OGRSpatialReference::DestroySpatialReference(poSRS);
+ OGRDataSource::DestroyDataSource(poDS);
+ TIMER_STOP(SCC_OUTPUT);
+ SimpleLogger().Write() << "generating output took: " << TIMER_MSEC(SCC_OUTPUT)/1000. << "s";
+
+ SimpleLogger().Write() << "total network distance: "
+ << (uint64_t)total_network_distance / 100 / 1000. << " km";
+
+ SimpleLogger().Write() << "finished component analysis";
+ }
+ catch (const std::exception &e)
+ {
+ SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+ }
+ return 0;
+}
diff --git a/Tools/io-benchmark.cpp b/tools/io-benchmark.cpp
similarity index 80%
rename from Tools/io-benchmark.cpp
rename to tools/io-benchmark.cpp
index 6304aae..c6da3ad 100644
--- a/Tools/io-benchmark.cpp
+++ b/tools/io-benchmark.cpp
@@ -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,17 +25,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "../Util/GitDescription.h"
-#include "../Util/OSRMException.h"
-#include "../Util/SimpleLogger.h"
-#include "../Util/TimingUtil.h"
+#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>
#include <cmath>
#include <cstdio>
-#include <cstdlib>
#include <fcntl.h>
#ifdef __linux__
#include <malloc.h>
@@ -45,6 +44,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <chrono>
#include <iomanip>
#include <numeric>
+#include <random>
#include <vector>
const unsigned number_of_elements = 268435456;
@@ -70,40 +70,39 @@ void RunStatistics(std::vector<double> &timings_vector, Statistics &stats)
int main(int argc, char *argv[])
{
- LogPolicy::GetInstance().Unmute();
-
- SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << ", "
- << "compiled at " << __DATE__ << ", " __TIME__;
#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;
+#ifdef _WIN32
+ SimpleLogger().Write() << "Not supported on Windows";
+ return 0;
#else
-
- if (1 == argc)
+ LogPolicy::GetInstance().Unmute();
+ boost::filesystem::path test_path;
+ try
{
- SimpleLogger().Write(logWARNING) << "usage: " << argv[0] << " /path/on/device";
- return -1;
- }
+ SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION;
- boost::filesystem::path test_path = boost::filesystem::path(argv[1]);
- test_path /= "osrm.tst";
- SimpleLogger().Write(logDEBUG) << "temporary file: " << test_path.string();
+ if (1 == argc)
+ {
+ SimpleLogger().Write(logWARNING) << "usage: " << argv[0] << " /path/on/device";
+ return -1;
+ }
+
+ test_path = boost::filesystem::path(argv[1]);
+ test_path /= "osrm.tst";
+ SimpleLogger().Write(logDEBUG) << "temporary file: " << test_path.string();
- try
- {
// create files for testing
if (2 == argc)
{
// create file to test
if (boost::filesystem::exists(test_path))
{
- throw OSRMException("Data file already exists");
+ throw osrm::exception("Data file already exists");
}
int *random_array = new int[number_of_elements];
@@ -118,27 +117,26 @@ int main(int argc, char *argv[])
fclose(fd);
#endif
#ifdef __linux__
- int f =
+ int file_desc =
open(test_path.string().c_str(), O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, S_IRWXU);
- if (-1 == f)
+ if (-1 == file_desc)
{
- throw OSRMException("Could not open random data file");
+ throw osrm::exception("Could not open random data file");
}
TIMER_START(write_1gb);
- int ret = write(f, random_array, number_of_elements * sizeof(unsigned));
+ int ret = write(file_desc, random_array, number_of_elements * sizeof(unsigned));
if (0 > ret)
{
- throw OSRMException("could not write random data file");
+ throw osrm::exception("could not write random data file");
}
TIMER_STOP(write_1gb);
- close(f);
+ close(file_desc);
#endif
delete[] random_array;
SimpleLogger().Write(logDEBUG) << "writing raw 1GB took " << TIMER_SEC(write_1gb)
<< "s";
SimpleLogger().Write() << "raw write performance: " << std::setprecision(5)
- << std::fixed << 1024 * 1024 / TIMER_SEC(write_1gb)
- << "MB/sec";
+ << std::fixed << 1024 * 1024 / TIMER_SEC(write_1gb) << "MB/sec";
SimpleLogger().Write(logDEBUG)
<< "finished creation of random data. Flush disk cache now!";
@@ -148,7 +146,7 @@ int main(int argc, char *argv[])
// Run Non-Cached I/O benchmarks
if (!boost::filesystem::exists(test_path))
{
- throw OSRMException("data file does not exist");
+ throw osrm::exception("data file does not exist");
}
// volatiles do not get optimized
@@ -164,8 +162,8 @@ int main(int argc, char *argv[])
#ifdef __linux__
char *single_block = (char *)memalign(512, 1024 * sizeof(unsigned));
- int f = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
- if (-1 == f)
+ int file_desc = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
+ if (-1 == file_desc)
{
SimpleLogger().Write(logDEBUG) << "opened, error: " << strerror(errno);
return -1;
@@ -179,17 +177,16 @@ int main(int argc, char *argv[])
fd = fopen(test_path.string().c_str(), "r");
#endif
#ifdef __linux__
- int ret = read(f, raw_array, number_of_elements * sizeof(unsigned));
+ int ret = read(file_desc, raw_array, number_of_elements * sizeof(unsigned));
SimpleLogger().Write(logDEBUG) << "read " << ret
<< " bytes, error: " << strerror(errno);
- close(f);
- f = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
+ close(file_desc);
+ file_desc = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
SimpleLogger().Write(logDEBUG) << "opened, error: " << strerror(errno);
#endif
TIMER_STOP(read_1gb);
- SimpleLogger().Write(logDEBUG) << "reading raw 1GB took " << TIMER_SEC(read_1gb)
- << "s";
+ SimpleLogger().Write(logDEBUG) << "reading raw 1GB took " << TIMER_SEC(read_1gb) << "s";
SimpleLogger().Write() << "raw read performance: " << std::setprecision(5) << std::fixed
<< 1024 * 1024 / TIMER_SEC(read_1gb) << "MB/sec";
@@ -200,13 +197,16 @@ int main(int argc, char *argv[])
fseek(fd, 0, SEEK_SET);
#endif
#ifdef __linux__
- lseek(f, 0, SEEK_SET);
+ lseek(file_desc, 0, SEEK_SET);
#endif
// make 1000 random access, time each I/O seperately
unsigned number_of_blocks = (number_of_elements * sizeof(unsigned) - 1) / 4096;
+ std::random_device rd;
+ std::default_random_engine e1(rd());
+ std::uniform_int_distribution<unsigned> uniform_dist(0, number_of_blocks - 1);
for (unsigned i = 0; i < 1000; ++i)
{
- unsigned block_to_read = std::rand() % number_of_blocks;
+ unsigned block_to_read =uniform_dist(e1);
off_t current_offset = block_to_read * 4096;
TIMER_START(random_access);
#ifdef __APPLE__
@@ -220,21 +220,21 @@ int main(int argc, char *argv[])
#endif
#ifdef __linux__
- int ret1 = lseek(f, current_offset, SEEK_SET);
- int ret2 = read(f, (char *)single_block, 4096);
+ int ret1 = lseek(file_desc, current_offset, SEEK_SET);
+ int ret2 = read(file_desc, (char *)single_block, 4096);
#endif
TIMER_STOP(random_access);
- if (((off_t) - 1) == ret1)
+ if (((off_t)-1) == ret1)
{
SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
SimpleLogger().Write(logWARNING) << "seek error " << strerror(errno);
- throw OSRMException("seek error");
+ throw osrm::exception("seek error");
}
if (-1 == ret2)
{
SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
- throw OSRMException("read error");
+ throw osrm::exception("read error");
}
timing_results_raw_random.push_back(TIMER_SEC(random_access));
}
@@ -261,7 +261,7 @@ int main(int argc, char *argv[])
fseek(fd, 0, SEEK_SET);
#endif
#ifdef __linux__
- lseek(f, 0, SEEK_SET);
+ lseek(file_desc, 0, SEEK_SET);
#endif
// read every 100th block
@@ -280,22 +280,22 @@ int main(int argc, char *argv[])
#endif
#ifdef __linux__
- int ret1 = lseek(f, current_offset, SEEK_SET);
+ int ret1 = lseek(file_desc, current_offset, SEEK_SET);
- int ret2 = read(f, (char *)single_block, 4096);
+ int ret2 = read(file_desc, (char *)single_block, 4096);
#endif
TIMER_STOP(read_every_100);
- if (((off_t) - 1) == ret1)
+ if (((off_t)-1) == ret1)
{
SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
SimpleLogger().Write(logWARNING) << "seek error " << strerror(errno);
- throw OSRMException("seek error");
+ throw osrm::exception("seek error");
}
if (-1 == ret2)
{
SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
- throw OSRMException("read error");
+ throw osrm::exception("read error");
}
timing_results_raw_seq.push_back(TIMER_SEC(read_every_100));
}
@@ -306,7 +306,7 @@ int main(int argc, char *argv[])
// free(single_block);
#endif
#ifdef __linux__
- close(f);
+ close(file_desc);
#endif
// Do statistics
SimpleLogger().Write(logDEBUG) << "running sequential I/O statistics";
diff --git a/Tools/simpleclient.cpp b/tools/simpleclient.cpp
similarity index 84%
rename from Tools/simpleclient.cpp
rename to tools/simpleclient.cpp
index 68d4b1d..d9c8217 100644
--- a/Tools/simpleclient.cpp
+++ b/tools/simpleclient.cpp
@@ -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,
@@ -26,9 +26,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "../Library/OSRM.h"
-#include "../Util/GitDescription.h"
+#include "../Util/git_sha.hpp"
#include "../Util/ProgramOptions.h"
-#include "../Util/SimpleLogger.h"
+#include "../Util/simple_logger.hpp"
#include <osrm/Reply.h>
#include <osrm/RouteParameters.h>
@@ -66,22 +66,24 @@ int main(int argc, const char *argv[])
{
std::string ip_address;
int ip_port, requested_thread_num;
- bool use_shared_memory = false, trial = false;
+ bool use_shared_memory = false, trial_run = false;
ServerPaths server_paths;
- if (!GenerateServerProgramOptions(argc,
- argv,
- server_paths,
- ip_address,
- ip_port,
- requested_thread_num,
- use_shared_memory,
- trial))
+
+ 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)
{
return 0;
}
- SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << ", "
- << "compiled at " << __DATE__ << ", " __TIME__;
+ SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION;
OSRM routing_machine(server_paths, use_shared_memory);
diff --git a/tools/springclean.cpp b/tools/springclean.cpp
new file mode 100644
index 0000000..878940a
--- /dev/null
+++ b/tools/springclean.cpp
@@ -0,0 +1,102 @@
+/*
+
+Copyright (c) 2015, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <cstdio>
+
+#include "../data_structures/shared_memory_factory.hpp"
+#include "../Server/DataStructures/SharedDataType.h"
+#include "../Util/git_sha.hpp"
+#include "../Util/simple_logger.hpp"
+
+void delete_region(const SharedDataType region)
+{
+ if (SharedMemory::RegionExists(region) && !SharedMemory::Remove(region))
+ {
+ const std::string name = [&]
+ {
+ switch (region)
+ {
+ case CURRENT_REGIONS:
+ return "CURRENT_REGIONS";
+ case LAYOUT_1:
+ return "LAYOUT_1";
+ case DATA_1:
+ return "DATA_1";
+ case LAYOUT_2:
+ return "LAYOUT_2";
+ case DATA_2:
+ return "DATA_2";
+ case LAYOUT_NONE:
+ return "LAYOUT_NONE";
+ default: // DATA_NONE:
+ return "DATA_NONE";
+ }
+ }();
+
+ SimpleLogger().Write(logWARNING) << "could not delete shared memory region " << name;
+ }
+}
+
+// find all existing shmem regions and remove them.
+void springclean()
+{
+ SimpleLogger().Write() << "spring-cleaning all shared memory regions";
+ delete_region(DATA_1);
+ delete_region(LAYOUT_1);
+ delete_region(DATA_2);
+ delete_region(LAYOUT_2);
+ delete_region(CURRENT_REGIONS);
+}
+
+int main()
+{
+ LogPolicy::GetInstance().Unmute();
+ try
+ {
+ SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << "\n\n";
+ SimpleLogger().Write() << "Releasing all locks";
+ SimpleLogger().Write() << "ATTENTION! BE CAREFUL!";
+ SimpleLogger().Write() << "----------------------";
+ SimpleLogger().Write() << "This tool may put osrm-routed into an undefined state!";
+ SimpleLogger().Write() << "Type 'Y' to acknowledge that you know what your are doing.";
+ SimpleLogger().Write() << "\n\nDo you want to purge all shared memory allocated " <<
+ "by osrm-datastore? [type 'Y' to confirm]";
+
+ const auto letter = getchar();
+ if (letter != 'Y')
+ {
+ SimpleLogger().Write() << "aborted.";
+ return 0;
+ }
+ springclean();
+ }
+ catch (const std::exception &e)
+ {
+ SimpleLogger().Write(logWARNING) << "[excpetion] " << e.what();
+ }
+ return 0;
+}
diff --git a/Tools/unlock_all_mutexes.cpp b/tools/unlock_all_mutexes.cpp
similarity index 88%
rename from Tools/unlock_all_mutexes.cpp
rename to tools/unlock_all_mutexes.cpp
index 4d4156f..faef736 100644
--- a/Tools/unlock_all_mutexes.cpp
+++ b/tools/unlock_all_mutexes.cpp
@@ -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,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "../Util/GitDescription.h"
-#include "../Util/SimpleLogger.h"
+#include "../Util/git_sha.hpp"
+#include "../Util/simple_logger.hpp"
#include "../Server/DataStructures/SharedBarriers.h"
#include <iostream>
@@ -36,8 +36,7 @@ int main()
LogPolicy::GetInstance().Unmute();
try
{
- SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << ", "
- << "compiled at " << __DATE__ << ", " __TIME__;
+ SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION;
SimpleLogger().Write() << "Releasing all locks";
SharedBarriers barrier;
barrier.pending_update_mutex.unlock();
diff --git a/typedefs.h b/typedefs.h
index ff1d2a1..d1b0a53 100644
--- a/typedefs.h
+++ b/typedefs.h
@@ -32,19 +32,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Necessary workaround for Windows as VS doesn't implement C99
#ifdef _MSC_VER
+#define WIN32_LEAN_AND_MEAN
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
-#define constexpr const static
#endif
-typedef unsigned int NodeID;
-typedef unsigned int EdgeID;
-typedef int EdgeWeight;
+using NodeID = unsigned int;
+using EdgeID = unsigned int;
+using EdgeWeight = int;
-constexpr NodeID SPECIAL_NODEID = std::numeric_limits<unsigned>::max();
-constexpr EdgeID SPECIAL_EDGEID = std::numeric_limits<unsigned>::max();
-constexpr unsigned INVALID_NAMEID = std::numeric_limits<unsigned>::max();
-constexpr EdgeWeight INVALID_EDGE_WEIGHT = std::numeric_limits<int>::max();
+static const NodeID SPECIAL_NODEID = std::numeric_limits<unsigned>::max();
+static const EdgeID SPECIAL_EDGEID = std::numeric_limits<unsigned>::max();
+static const unsigned INVALID_NAMEID = std::numeric_limits<unsigned>::max();
+static const EdgeWeight INVALID_EDGE_WEIGHT = std::numeric_limits<int>::max();
#endif /* TYPEDEFS_H */
--
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